src/rt/vg/* -whitespace
src/rt/linenoise/* -whitespace
src/rt/jemalloc/**/* -whitespace
+src/rt/jemalloc/include/jemalloc/jemalloc.h.in text eol=lf
+src/rt/jemalloc/include/jemalloc/jemalloc_defs.h.in text eol=lf
+src/rt/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in text eol=lf
branch = master
[submodule "src/libuv"]
path = src/libuv
- url = https://github.com/brson/libuv.git
+ url = https://github.com/alexcrichton/libuv.git
branch = master
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
CFG_RUSTC_FLAGS +=
else
- CFG_RUSTC_FLAGS += -O
+ # The rtopt cfg turns off runtime sanity checks
+ CFG_RUSTC_FLAGS += -O --cfg rtopt
endif
ifdef CFG_ENABLE_DEBUG
# fn add(x: int, y: int) -> int { 0 }
let x: int = add(1, 2);
-let pi = FromStr::from_str::<f32>("3.14");
+let pi: Option<f32> = FromStr::from_str("3.14");
~~~~
### Lambda expressions
}
~~~
-By default, the scheduler multiplexes tasks across the available cores, running
-in parallel. Thus, on a multicore machine, running the following code
-should interleave the output in vaguely random order.
-
-~~~
-# use std::io::print;
-# use std::task::spawn;
-
-for child_task_number in range(0, 20) {
- do spawn {
- print(fmt!("I am child number %d\n", child_task_number));
- }
-}
-~~~
-
## Communication
Now that we have spawned a new task, it would be nice if we could
that does not implement `Clone`.
While most traits can be defined and implemented by user code,
-two traits are automatically derived and implemented
+three traits are automatically derived and implemented
for all applicable types by the compiler,
and may not be overridden:
Intrinsically mutable values include `@mut`
and `Cell` in the standard library.
+* `'static` - Non-borrowed types.
+These are types that do not contain any data whose lifetime is bound to
+a particular stack frame. These are types that do not contain any
+borrowed pointers, or types where the only contained borrowed pointers
+have the `'static` lifetime.
+
> ***Note:*** These two traits were referred to as 'kinds' in earlier
> iterations of the language, and often still are.
This usage of traits is similar to Java interfaces.
+By default, each of the three storage classes for traits enforce a
+particular set of built-in kinds that their contents must fulfill in
+order to be packaged up in a trait object of that storage class.
+
+* The contents of owned traits (`~Trait`) must fulfill the `Send` bound.
+* The contents of managed traits (`@Trait`) must fulfill the `'static` bound.
+* The contents of borrowed traits (`&Trait`) are not constrained by any bound.
+
+Consequently, the trait objects themselves automatically fulfill their
+respective kind bounds. However, this default behavior can be overridden by
+specifying a list of bounds on the trait type, for example, by writing `~Trait:`
+(which indicates that the contents of the owned trait need not fulfill any
+bounds), or by writing `~Trait:Send+Freeze`, which indicates that in addition
+to fulfilling `Send`, contents must also fulfill `Freeze`, and as a consequence,
+the trait itself fulfills `Freeze`.
+
+* `~Trait:Send` is equivalent to `~Trait`.
+* `@Trait:'static` is equivalent to `@Trait`.
+* `&Trait:` is equivalent to `&Trait`.
+
+Builtin kind bounds can also be specified on closure types in the same way (for
+example, by writing `fn:Freeze()`), and the default behaviours are the same as
+for traits of the same storage class.
+
## Trait inheritance
We can write a trait declaration that _inherits_ from other traits, called _supertraits_.
`TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`,
`IterBytes`, `Rand`, `Zero`, and `ToStr`.
-# Modules and crates
+# Crates and the module system
+
+Rust's module system is very powerful, but because of that also somewhat complex.
+Nevertheless, this section will try to explain every important aspect of it.
+
+## Crates
+
+In order to speak about the module system, we first need to define the medium it exists in:
-The Rust namespace is arranged in a hierarchy of modules. Each source
-(.rs) file represents a single module and may in turn contain
-additional modules.
+Let's say you've written a program or a library, compiled it, and got the resulting binary.
+In Rust, the content of all source code that the compiler directly had to compile in order to end up with
+that binary is collectively called a 'crate'.
+For example, for a simple hello world program your crate only consists of this code:
+
+~~~~
+// main.rs
+fn main() {
+ println("Hello world!");
+}
~~~~
+
+A crate is also the unit of independent compilation in Rust: `rustc` always compiles a single crate at a time,
+from which it produces either a library or an executable.
+
+Note that merely using an already compiled library in your code does not make it part of your crate.
+
+## The module hierarchy
+
+For every crate, all the code in it is arranged in a hierarchy of modules starting with a single
+root module. That root module is called the 'crate root'.
+
+All modules in a crate below the crate root are declared with the `mod` keyword:
+
+~~~~
+// This is the crate root
+
mod farm {
- pub fn chicken() -> &str { "cluck cluck" }
- pub fn cow() -> &str { "mooo" }
+ // This is the body of module 'farm' declared in the crate root.
+
+ fn chicken() { println("cluck cluck"); }
+ fn cow() { println("mooo"); }
+
+ mod barn {
+ // Body of module 'barn'
+
+ fn hay() { println("..."); }
+ }
}
fn main() {
- println(farm::chicken());
+ println("Hello farm!");
}
~~~~
-The contents of modules can be imported into the current scope
-with the `use` keyword, optionally giving it an alias. `use`
-may appear at the beginning of crates, `mod`s, `fn`s, and other
-blocks.
+As you can see, your module hierarchy is now three modules deep: There is the crate root, which contains your `main()`
+function, and the module `farm`. The module `farm` also contains two functions and a third module `barn`,
+which contains a function `hay`.
-~~~
-# mod farm { pub fn chicken() { } }
-# fn main() {
-// Bring `chicken` into scope
-use farm::chicken;
+(In case you already stumbled over `extern mod`: It isn't directly related to a bare `mod`, we'll get to it later. )
+
+## Paths and visibility
+
+We've now defined a nice module hierarchy. But how do we access the items in it from our `main` function?
+One way to do it is to simply fully qualifying it:
-fn chicken_farmer() {
- // The same, but name it `my_chicken`
- use my_chicken = farm::chicken;
- ...
-# my_chicken();
+~~~~ {.xfail-test}
+mod farm {
+ fn chicken() { println("cluck cluck"); }
+ // ...
}
-# chicken();
-# }
-~~~
-These farm animal functions have a new keyword, `pub`, attached to
-them. The `pub` keyword modifies an item's visibility, making it
-visible outside its containing module. An expression with `::`, like
-`farm::chicken`, can name an item outside of its containing
-module. Items, such as those declared with `fn`, `struct`, `enum`,
-`type`, or `static`, are module-private by default.
+fn main() {
+ println("Hello chicken!");
+
+ ::farm::chicken(); // Won't compile yet, see further down
+}
+~~~~
+
+The `::farm::chicken` construct is what we call a 'path'.
+
+Because it's starting with a `::`, it's also a 'global path',
+which qualifies an item by its full path in the module hierarchy
+relative to the crate root.
+
+If the path were to start with a regular identifier, like `farm::chicken`, it would be
+a 'local path' instead. We'll get to them later.
+
+Now, if you actually tried to compile this code example, you'll notice
+that you get a `unresolved name: 'farm::chicken'` error. That's because per default,
+items (`fn`, `struct`, `static`, `mod`, ...) are only visible inside the module
+they are defined in.
+
+To make them visible outside their containing modules, you need to mark them _public_ with `pub`:
+
+~~~~
+mod farm {
+ pub fn chicken() { println("cluck cluck"); }
+ pub fn cow() { println("mooo"); }
+ // ...
+}
+
+fn main() {
+ println("Hello chicken!");
+ ::farm::chicken(); // This compiles now
+}
+~~~~
Visibility restrictions in Rust exist only at module boundaries. This
is quite different from most object-oriented languages that also
enforce restrictions on objects themselves. That's not to say that
Rust doesn't support encapsulation: both struct fields and methods can
be private. But this encapsulation is at the module level, not the
-struct level. Note that fields and methods are _public_ by default.
+struct level.
+
+For convenience, fields are _public_ by default, and can be made _private_ with the `priv` keyword:
~~~
-pub mod farm {
+mod farm {
# pub type Chicken = int;
-# type Cow = int;
# struct Human(int);
# impl Human { fn rest(&self) { } }
-# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }
+# pub fn make_me_a_farm() -> Farm { Farm { chickens: ~[], farmer: Human(0) } }
pub struct Farm {
priv chickens: ~[Chicken],
- priv cows: ~[Cow],
farmer: Human
}
impl Farm {
fn feed_chickens(&self) { ... }
- fn feed_cows(&self) { ... }
pub fn add_chicken(&self, c: Chicken) { ... }
}
pub fn feed_animals(farm: &Farm) {
farm.feed_chickens();
- farm.feed_cows();
}
}
fn main() {
- let f = make_me_a_farm();
- f.add_chicken(make_me_a_chicken());
- farm::feed_animals(&f);
- f.farmer.rest();
+ let f = make_me_a_farm();
+ f.add_chicken(make_me_a_chicken());
+ farm::feed_animals(&f);
+ f.farmer.rest();
+
+ // This wouldn't compile because both are private:
+ // f.feed_chickens();
+ // let chicken_counter = f.chickens.len();
}
# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
# fn make_me_a_chicken() -> farm::Chicken { 0 }
~~~
-## Crates
+> ***Note:*** Visibility rules are currently buggy and not fully defined, you might have to add or remove `pub` along a path until it works.
-The unit of independent compilation in Rust is the crate: rustc
-compiles a single crate at a time, from which it produces either a
-library or an executable.
-
-When compiling a single `.rs` source file, the file acts as the whole crate.
-You can compile it with the `--lib` compiler switch to create a shared
-library, or without, provided that your file contains a `fn main`
-somewhere, to create an executable.
-
-Larger crates typically span multiple files and are, by convention,
-compiled from a source file with the `.rc` extension, called a *crate file*.
-The crate file extension distinguishes source files that represent
-crates from those that do not, but otherwise source files and crate files are identical.
-
-A typical crate file declares attributes associated with the crate that
-may affect how the compiler processes the source.
-Crate attributes specify metadata used for locating and linking crates,
-the type of crate (library or executable),
-and control warning and error behavior,
-among other things.
-Crate files additionally declare the external crates they depend on
-as well as any modules loaded from other files.
-
-~~~~ { .xfail-test }
-// Crate linkage metadata
-#[link(name = "farm", vers = "2.5", author = "mjh")];
+## Files and modules
-// Make a library ("bin" is the default)
-#[crate_type = "lib"];
+One important aspect about Rusts module system is that source files are not important:
+You define a module hierarchy, populate it with all your definitions, define visibility,
+maybe put in a `fn main()`, and that's it: No need to think about source files.
-// Turn on a warning
-#[warn(non_camel_case_types)]
+The only file that's relevant is the one that contains the body of your crate root,
+and it's only relevant because you have to pass that file to `rustc` to compile your crate.
-// Link to the standard library
-extern mod std;
+And in principle, that's all you need: You can write any Rust program as one giant source file that contains your
+crate root and everything below it in `mod ... { ... }` declarations.
+
+However, in practice you usually want to split you code up into multiple source files to make it more manageable.
+In order to do that, Rust allows you to move the body of any module into it's own source file, which works like this:
-// Load some modules from other files
-mod cow;
-mod chicken;
-mod horse;
+If you declare a module without its body, like `mod foo;`, the compiler will look for the
+files `foo.rs` and `foo/mod.rs`. If it finds either, it uses the content of that file as the body of the module.
+If it finds both, that's a compile error.
+
+So, if we want to move the content of `mod farm` into it's own file, it would look like this:
+
+~~~~ {.ignore}
+// main.rs - contains body of the crate root
+mod farm; // Compiler will look for 'farm.rs' and 'farm/mod.rs'
fn main() {
- ...
+ println("Hello farm!");
+ ::farm::cow();
}
~~~~
-Compiling this file will cause `rustc` to look for files named
-`cow.rs`, `chicken.rs`, and `horse.rs` in the same directory as the
-`.rc` file, compile them all together, and, based on the presence of
-the `crate_type = "lib"` attribute, output a shared library or an
-executable. (If the line `#[crate_type = "lib"];` was omitted,
-`rustc` would create an executable.)
+~~~~
+// farm.rs - contains body of module 'farm' in the crate root
+pub fn chicken() { println("cluck cluck"); }
+pub fn cow() { println("mooo"); }
+
+pub mod barn {
+ pub fn hay() { println("..."); }
+}
+# fn main() { }
+~~~~
-The `#[link(...)]` attribute provides meta information about the
-module, which other crates can use to load the right module. More
-about that later.
+So, in short `mod foo;` is just syntactic sugar for `mod foo { /* include content of foo.rs or foo/mod.rs here */ }`.
-To have a nested directory structure for your source files, you can
-nest mods:
+This also means that having two or more identical `mod foo;` somewhere
+in your crate hierarchy is generally a bad idea,
+just like copy-and-paste-ing a module into two or more places is one.
+Both will result in duplicate and mutually incompatible definitions.
-~~~~ {.ignore}
-mod poultry {
- mod chicken;
- mod turkey;
+The directory the compiler looks in for those two files is determined by starting with
+the same directory as the source file that contains the `mod foo;` declaration, and concatenating to that a
+path equivalent to the relative path of all nested `mod { ... }` declarations the `mod foo;` is contained in, if any.
+
+For example, given a file with this module body:
+
+~~~ {.ignore}
+// src/main.rs
+mod plants;
+mod fungi;
+mod animals {
+ mod fish;
+ mod mammals {
+ mod humans;
+ }
+}
+~~~
+
+The compiler would then try all these files:
+
+~~~ {.notrust}
+src/plants.rs
+src/plants/mod.rs
+
+src/fungi.rs
+src/fungi/mod.rs
+
+src/animals/fish.rs
+src/animals/fish/mod.rs
+
+src/animals/mammals/humans.rs
+src/animals/mammals/humans/mod.rs
+~~~
+
+These rules per default result in any directory structure mirroring
+the crates's module hierarchy, and allow you to have both small modules that only need
+to consist of one source file, and big modules that group the source files of submodules together.
+
+If you need to circumvent those defaults, you can also overwrite the path a `mod foo;` would take:
+
+~~~ {.ignore}
+#[path="../../area51/classified.rs"]
+mod alien;
+~~~
+
+## Importing names into the local scope
+
+Always referring to definitions in other modules with their global
+path gets old really fast, so Rust has a way to import
+them into the local scope of your module: `use`-statements.
+
+They work like this: At the beginning of any module body, `fn` body, or any other block
+you can write a list of `use`-statements, consisting of the keyword `use` and a __global path__ to an item
+without the `::` prefix. For example, this imports `cow` into the local scope:
+
+~~~
+use farm::cow;
+# mod farm { pub fn cow() { println("I'm a hidden ninja cow!") } }
+# fn main() { cow() }
+~~~
+
+The path you give to `use` is per default global, meaning relative to the crate root,
+no matter how deep the module hierarchy is, or whether the module body it's written in
+is contained in its own file (remember: files are irrelevant).
+
+This is different to other languages, where you often only find a single import construct that combines the semantic
+of `mod foo;` and `use`-statements, and which tend to work relative to the source file or use an absolute file path
+- Rubys `require` or C/C++'s `#include` come to mind.
+
+However, it's also possible to import things relative to the module of the `use`-statement:
+Adding a `super::` in front of the path will start in the parent module,
+while adding a `self::` prefix will start in the current module:
+
+~~~
+# mod workaround {
+# pub fn some_parent_item(){ println("...") }
+# mod foo {
+use super::some_parent_item;
+use self::some_child_module::some_item;
+# pub fn bar() { some_parent_item(); some_item() }
+# pub mod some_child_module { pub fn some_item() {} }
+# }
+# }
+~~~
+
+Again - relative to the module, not to the file.
+
+Imports are also shadowed by local definitions:
+For each name you mention in a module/block, `rust`
+will first look at all items that are defined locally,
+and only if that results in no match look at items you brought in
+scope with corresponding `use` statements.
+
+~~~ {.ignore}
+# // XXX: Allow unused import in doc test
+use farm::cow;
+// ...
+# mod farm { pub fn cow() { println("Hidden ninja cow is hidden.") } }
+fn cow() { println("Mooo!") }
+
+fn main() {
+ cow() // resolves to the locally defined cow() function
}
+~~~
+
+To make this behavior more obvious, the rule has been made that `use`-statement always need to be written
+before any declaration, like in the example above. This is a purely artificial rule introduced
+because people always assumed they shadowed each other based on order, despite the fact that all items in rust are
+mutually recursive, order independent definitions.
+
+One odd consequence of that rule is that `use` statements also go in front of any `mod` declaration,
+even if they refer to things inside them:
+
+~~~
+use farm::cow;
+mod farm {
+ pub fn cow() { println("Moooooo?") }
+}
+
+fn main() { cow() }
+~~~
+
+This is what our `farm` example looks like with `use` statements:
+
~~~~
+use farm::chicken;
+use farm::cow;
+use farm::barn;
-The compiler will now look for `poultry/chicken.rs` and
-`poultry/turkey.rs`, and export their content in `poultry::chicken`
-and `poultry::turkey`. You can also provide a `poultry.rs` to add
-content to the `poultry` module itself.
+mod farm {
+ pub fn chicken() { println("cluck cluck"); }
+ pub fn cow() { println("mooo"); }
-## Using other crates
+ pub mod barn {
+ pub fn hay() { println("..."); }
+ }
+}
-The `extern mod` directive lets you use a crate (once it's been
-compiled into a library) from inside another crate. `extern mod` can
-appear at the top of a crate file or at the top of modules. It will
-cause the compiler to look in the library search path (which you can
-extend with the `-L` switch) for a compiled Rust library with the
-right name, then add a module with that crate's name into the local
-scope.
+fn main() {
+ println("Hello farm!");
-For example, `extern mod std` links the [standard library].
+ // Can now refer to those names directly:
+ chicken();
+ cow();
+ barn::hay();
+}
+~~~~
-[standard library]: std/index.html
+And here an example with multiple files:
+~~~{.ignore}
+// a.rs - crate root
+use b::foo;
+mod b;
+fn main() { foo(); }
+~~~
+~~~{.ignore}
+// b.rs
+use b::c::bar;
+pub mod c;
+pub fn foo() { bar(); }
+~~~
+~~~
+// c.rs
+pub fn bar() { println("Baz!"); }
+~~~
+
+There also exist two short forms for importing multiple names at once:
+
+1. Explicit mention multiple names as the last element of an `use` path:
+~~~
+use farm::{chicken, cow};
+# mod farm {
+# pub fn cow() { println("Did I already mention how hidden and ninja I am?") }
+# pub fn chicken() { println("I'm Bat-chicken, guardian of the hidden tutorial code.") }
+# }
+# fn main() { cow(); chicken() }
+~~~
+
+2. Import everything in a module with a wildcard:
+~~~
+use farm::*;
+# mod farm {
+# pub fn cow() { println("Bat-chicken? What a stupid name!") }
+# pub fn chicken() { println("Says the 'hidden ninja' cow.") }
+# }
+# fn main() { cow(); chicken() }
+~~~
+
+However, that's not all. You can also rename an item while you're bringing it into scope:
+
+~~~
+use egg_layer = farm::chicken;
+# mod farm { pub fn chicken() { println("Laying eggs is fun!") } }
+// ...
+
+fn main() {
+ egg_layer();
+}
+~~~
+
+In general, `use` creates an local alias:
+An alternate path and a possibly different name to access the same item,
+whiteout touching the original, and with both being interchangeable.
+
+## Reexporting names
+
+It is also possible to reexport items to be accessible under your module.
+
+For that, you write `pub use`:
+
+~~~
+mod farm {
+ pub use self::barn::hay;
+
+ pub fn chicken() { println("cluck cluck"); }
+ pub fn cow() { println("mooo"); }
+
+ mod barn {
+ pub fn hay() { println("..."); }
+ }
+}
+
+fn main() {
+ farm::chicken();
+ farm::cow();
+ farm::hay();
+}
+~~~
+
+Just like in normal `use` statements, the exported names
+merely represent an alias to the same thing and can also be renamed.
+
+The above example also demonstrate what you can use `pub use` for:
+The nested `barn` module is private, but the `pub use` allows users
+of the module `farm` to access a function from `barn` without needing
+to know that `barn` exists.
+
+In other words, you can use them to decouple an public api from their internal implementation.
+
+## Using libraries
+
+So far we've only talked about how to define and structure your own crate.
+
+However, most code out there will want to use preexisting libraries,
+as there really is no reason to start from scratch each time you start a new project.
+
+In Rust terminology, we need a way to refer to other crates.
+
+For that, Rust offers you the `extern mod` declaration:
+
+~~~
+extern mod extra;
+// extra ships with Rust, you'll find more details further down.
+
+fn main() {
+ // The rational number '1/2':
+ let one_half = ::extra::rational::Ratio::new(1, 2);
+}
+~~~
+
+Despite its name, `extern mod` is a distinct construct from regular `mod` declarations:
+A statement of the form `extern mod foo;` will cause `rustc` to search for the crate `foo`,
+and if it finds a matching binary it lets you use it from inside your crate.
+
+The effect it has on your module hierarchy mirrors aspects of both `mod` and `use`:
+
+- Like `mod`, it causes `rustc` to actually emit code:
+ The linkage information the binary needs to use the library `foo`.
+
+- But like `use`, all `extern mod` statements that refer to the same library are interchangeable,
+ as each one really just presents an alias to an external module (the crate root of the library your linking against).
+
+Remember how `use`-statements have to go before local declarations because the latter shadows the former?
+Well, `extern mod` statements also have their own rules in that regard:
+Both `use` and local declarations can shadow them, so the rule is that `extern mod` has to go in front
+of both `use` and local declarations.
+
+Which can result in something like this:
+
+~~~
+extern mod extra;
+
+use farm::dog;
+use extra::rational::Ratio;
+
+mod farm {
+ pub fn dog() { println("woof"); }
+}
+
+fn main() {
+ farm::dog();
+ let a_third = Ratio::new(1, 3);
+}
+~~~
+
+It's a bit weird, but it's the result of shadowing rules that have been set that way because
+they model most closely what people expect to shadow.
+
+## Package ids
+
+If you use `extern mod`, per default `rustc` will look for libraries in the the library search path (which you can
+extend with the `-L` switch).
+
+However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
+libraries if you use it for building your crate. How it works is explained [here][rustpkg],
+but for this tutorial it's only important to know that you can optionally annotate an
+`extern mod` statement with an package id that rustpkg can use to identify it:
+
+~~~ {.ignore}
+extern mod rust = "github.com/mozilla/rust"; // pretend Rust is an simple library
+~~~
-When a comma-separated list of name/value pairs appears after `extern
-mod`, the compiler front-end matches these pairs against the
-attributes provided in the `link` attribute of the crate file. The
-front-end will only select this crate for use if the actual pairs
-match the declared attributes. You can provide a `name` value to
-override the name used to search for the crate.
+[rustpkg]: rustpkg.html
-Our example crate declared this set of `link` attributes:
+## Crate metadata and settings
+
+For every crate you can define a number of metadata items, such as link name, version or author.
+You can also toggle settings that have crate-global consequences. Both mechanism
+work by providing attributes in the crate root.
+
+For example, Rust uniquely identifies crates by their link metadate, which includes
+the link name and the version. It also hashes the filename and the symbols in a binary
+based on the link metadata, allowing you to use two different versions of the same library in a crate
+without conflict.
+
+Therefor, if you plan to compile your crate as a library, you should annotate it with that information:
~~~~
-#[link(name = "farm", vers = "2.5", author = "mjh")];
+// lib.rs
+
+# #[crate_type = "lib"];
+// Crate linkage metadata
+#[link(name = "farm", vers = "2.5")];
+
+// ...
+# pub fn farm() {}
~~~~
-Which you can then link with any (or all) of the following:
+You can also in turn require in a `extern mod` statement that certain link metadata items match some criteria.
+For that, Rust currently parses a comma-separated list of name/value pairs that appear after
+it, and ensures that they match the attributes provided in the `link` attribute of a crate file.
+This enables you to, eg, pick a a crate based on it's version number, or to link an library under an
+different name. For example, this two mod statements would both accept and select the crate define above:
~~~~ {.xfail-test}
-extern mod farm;
-extern mod my_farm (name = "farm", vers = "2.5");
-extern mod my_auxiliary_farm (name = "farm", author = "mjh");
+extern mod farm(vers = "2.5");
+extern mod my_farm(name = "farm", vers = "2.5");
~~~~
-If any of the requested metadata do not match, then the crate
-will not be compiled successfully.
+Other crate settings and metadata include things like enabling/disabling certain errors or warnings,
+or setting the crate type (library or executable) explicitly:
+
+~~~~
+// lib.rs
+// ...
+
+// This crate is a library ("bin" is the default)
+#[crate_type = "lib"];
+
+// Turn on a warning
+#[warn(non_camel_case_types)]
+# pub fn farm() {}
+~~~~
+
+If you're compiling your crate with `rustpkg`,
+link annotations will not be necessary, because they get
+inferred by `rustpkg` based on the Package id and naming conventions.
+
+
+> ***Note:*** The rules regarding link metadata, both as attributes and on `extern mod`,
+ as well as their interaction with `rustpkg`
+ are currently not clearly defined and will likely change in the future.
## A minimal example
-Now for something that you can actually compile yourself, we have
-these two files:
+Now for something that you can actually compile yourself.
+
+We define two crates, and use one of them as a library in the other.
~~~~
// world.rs
-#[link(name = "world", vers = "1.0")];
-pub fn explore() -> &str { "world" }
+#[link(name = "world", vers = "0.42")];
+pub fn explore() -> &'static str { "world" }
~~~~
~~~~ {.xfail-test}
// main.rs
extern mod world;
-fn main() { println(~"hello " + world::explore()); }
+fn main() { println("hello " + world::explore()); }
~~~~
Now compile and run like this (adjust to your platform if necessary):
~~~~ {.notrust}
-> rustc --lib world.rs # compiles libworld-94839cbfe144198-1.0.so
+> rustc --lib world.rs # compiles libworld-<HASH>-0.42.so
> rustc main.rs -L . # compiles main
> ./main
"hello world"
~~~~
-Notice that the library produced contains the version in the filename
-as well as an inscrutable string of alphanumerics. These are both
-part of Rust's library versioning scheme. The alphanumerics are
-a hash representing the crate metadata.
+Notice that the library produced contains the version in the file name
+as well as an inscrutable string of alphanumerics. As explained in the previous paragraph,
+these are both part of Rust's library versioning scheme. The alphanumerics are
+a hash representing the crates link metadata.
+
+## The standard library and the prelude
+
+While reading the examples in this tutorial, you might have asked yourself where all
+those magical predefined items like `println()` are coming from.
+
+The truth is, there's nothing magical about them: They are all defined normally
+in the `std` library, which is a crate that ships with Rust.
+
+The only magical thing that happens is that `rustc` automatically inserts this line into your crate root:
+
+~~~ {.ignore}
+extern mod std;
+~~~
+
+As well as this line into every module body:
+
+~~~ {.ignore}
+use std::prelude::*;
+~~~
+
+The role of the `prelude` module is to re-exports common definitions from `std`.
+
+This allows you to use common types and functions like `Option<T>` or `println`
+without needing to import them. And if you need something from `std` that's not in the prelude,
+you just have to import it with an `use` statement.
+
+For example, it re-exports `println` which is defined in `std::io::println`:
-## The standard library
+~~~
+use puts = std::io::println;
+
+fn main() {
+ println("println is imported per default.");
+ puts("Doesn't hinder you from importing it under an different name yourself.");
+ ::std::io::println("Or from not using the automatic import.");
+}
+~~~
+
+Both auto-insertions can be disabled with an attribute if necessary:
+
+~~~
+// In the crate root:
+#[no_std];
+~~~
+
+~~~
+// In any module:
+#[no_implicit_prelude];
+~~~
+
+## The standard library in detail
The Rust standard library provides runtime features required by the language,
including the task scheduler and memory allocators, as well as library
common traits ([`kinds`], [`ops`], [`cmp`], [`num`],
[`to_str`], [`clone`]), and complete bindings to the C standard library ([`libc`]).
-### Standard Library injection and the Rust prelude
-
-`std` is imported at the topmost level of every crate by default, as
-if the first line of each crate was
-
- extern mod std;
-
-This means that the contents of std can be accessed from from any context
-with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`,
-etc.
-
-Additionally, `std` contains a `prelude` module that reexports many of the
-most common standard modules, types and traits. The contents of the prelude are
-imported into every *module* by default. Implicitly, all modules behave as if
-they contained the following prologue:
-
- use std::prelude::*;
+The full documentation for `std` can be found here: [standard library].
+[standard library]: std/index.html
[`std`]: std/index.html
[`bool`]: std/bool.html
[tuples]: std/tuple.html
[`clone`]: std/clone.html
[`libc`]: std/libc.html
+## The extra library
+
+Rust also ships with the [extra library], an accumulation of
+useful things, that are however not important enough
+to deserve a place in the standard library.
+You can use them by linking to `extra` with an `extern mod extra;`.
+
+[extra library]: extra/index.html
+
+Right now `extra` contains those definitions directly, but in the future it will likely just
+re-export a bunch of 'officially blessed' crates that get managed with `rustpkg`.
+
# What next?
Now that you know the essentials, check out any of the additional
* [Macros][macros]
* [The foreign function interface][ffi]
* [Containers and iterators](tutorial-container.html)
+* [Error-handling and Conditions](tutorial-conditions.html)
-There is further documentation on the [wiki].
+There is further documentation on the [wiki], however those tend to be even more out of date as this document.
[borrow]: tutorial-borrowed-ptr.html
[tasks]: tutorial-tasks.html
endif
RUNTIME_CXXS_$(1)_$(2) := \
- rt/sync/timer.cpp \
rt/sync/lock_and_signal.cpp \
rt/sync/rust_thread.cpp \
rt/rust_builtin.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
rt/rust_crate_map.cpp \
- rt/rust_gc_metadata.cpp \
- rt/rust_util.cpp \
rt/rust_log.cpp \
- rt/rust_exchange_alloc.cpp \
rt/isaac/randport.cpp \
rt/miniz.cpp \
- rt/rust_abi.cpp \
rt/memory_region.cpp \
rt/boxed_region.cpp \
rt/arch/$$(HOST_$(1))/context.cpp \
$$(S)src/libuv/*/*/*/*)
endif
+LIBUV_GYP := $$(S)src/libuv/build/gyp
+LIBUV_MAKEFILE_$(1)_$(2) := $$(CFG_BUILD_DIR)rt/$(1)/stage$(2)/libuv/Makefile
+LIBUV_NO_LOAD = run-benchmarks.target.mk run-tests.target.mk \
+ uv_dtrace_header.target.mk uv_dtrace_provider.target.mk
+
+$$(LIBUV_MAKEFILE_$(1)_$(2)): $$(LIBUV_GYP)
+ (cd $(S)src/libuv/ && \
+ $$(CFG_PYTHON) ./gyp_uv -f make -Dtarget_arch=$$(HOST_$(1)) -D ninja \
+ -Goutput_dir=$$(@D) --generator-output $$(@D))
+
# XXX: Shouldn't need platform-specific conditions here
ifdef CFG_WINDOWSY_$(1)
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
- $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
- builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
- OS=mingw \
+ $$(Q)rm -f $$(S)src/libuv/libuv.a
+ $$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
+ CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
+ AR="$$(AR_$(1))" \
V=$$(VERBOSE)
+ $$(Q)cp $$(S)src/libuv/libuv.a $$@
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
- $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
+ $$(Q)$$(MAKE) -C $$(@D) \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
- BUILDTYPE=Release \
- builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
host=android OS=linux \
+ builddir="." \
+ BUILDTYPE=Release \
+ NO_LOAD="$$(LIBUV_NO_LOAD)" \
V=$$(VERBOSE)
else
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
- $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
+ $$(Q)$$(MAKE) -C $$(@D) \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
- builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+ builddir="." \
+ BUILDTYPE=Release \
+ NO_LOAD="$$(LIBUV_NO_LOAD)" \
V=$$(VERBOSE)
endif
$(foreach stage,$(STAGES), \
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
+
+$(LIBUV_GYP):
+ mkdir -p $(S)src/libuv/build
+ git clone https://git.chromium.org/external/gyp.git $(S)src/libuv/build/gyp
# Whether to ratchet or merely save benchmarks
ifdef CFG_RATCHET_BENCH
-CRATE_TEST_BENCH_ARGS=\
+CRATE_TEST_EXTRA_ARGS=\
--test $(TEST_BENCH) \
--ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
--ratchet-noise-percent $(TEST_RATCHET_NOISE_PERCENT)
else
-CRATE_TEST_BENCH_ARGS=\
+CRATE_TEST_EXTRA_ARGS=\
--test $(TEST_BENCH) \
--save-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4))
endif
+# If we're sharding the testsuite between parallel testers,
+# pass this argument along to the compiletest and crate test
+# invocations.
+ifdef TEST_SHARD
+ CTEST_TESTARGS += --test-shard=$(TEST_SHARD)
+ CRATE_TEST_EXTRA_ARGS += --test-shard=$(TEST_SHARD)
+endif
+
define DEF_TARGET_COMMANDS
ifdef CFG_UNIXY_$(1)
@$$(call E, run: $$<)
$$(Q)$$(call CFG_RUN_TEST_$(2),$$<,$(2),$(3)) $$(TESTARGS) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \
- $$(call CRATE_TEST_BENCH_ARGS,$(1),$(2),$(3),$(4)) \
+ $$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)) \
&& touch $$@
endef
@$(CFG_ADB) shell '(cd $(CFG_ADB_TEST_DIR); LD_LIBRARY_PATH=. \
./$$(notdir $$<) \
--logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log \
- $$(call CRATE_TEST_BENCH_ARGS,$(1),$(2),$(3),$(4)))' \
+ $$(call CRATE_TEST_EXTRA_ARGS,$(1),$(2),$(3),$(4)))' \
> tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
@cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp
@touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
// Percent change in metrics to consider noise
ratchet_noise_percent: Option<f64>,
+ // "Shard" of the testsuite to run: this has the form of
+ // two numbers (a,b), and causes only those tests with
+ // positional order equal to a mod b to run.
+ test_shard: Option<(uint,uint)>,
+
// A command line to prefix program execution with,
// for running under valgrind
runtool: Option<~str>,
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "adb-path", "path to the android debugger", "PATH"),
optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
+ optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite", "A.B"),
optflag("h", "help", "show this message"),
];
~"") { true }
else { false }
} else { false },
+ test_shard: test::opt_shard(getopts::opt_maybe_str(matches, "test-shard")),
verbose: getopts::opt_present(matches, "verbose")
}
}
logv(c, fmt!("adb_path: %s", config.adb_path));
logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
+ match config.test_shard {
+ None => logv(c, ~"test_shard: (all)"),
+ Some((a,b)) => logv(c, fmt!("test_shard: %u.%u", a, b))
+ }
logv(c, fmt!("verbose: %b", config.verbose));
logv(c, fmt!("\n"));
}
ratchet_metrics: config.ratchet_metrics.clone(),
ratchet_noise_percent: config.ratchet_noise_percent.clone(),
save_metrics: config.save_metrics.clone(),
+ test_shard: config.test_shard.clone()
}
}
in_fd: None,
out_fd: None,
err_fd: None
- });
+ }).unwrap();
for input in input.iter() {
- proc.input().write_str(*input);
+ proc.input().write(input.as_bytes());
}
let output = proc.finish_with_output();
use util;
use util::logv;
-use std::cell::Cell;
use std::io;
use std::os;
use std::str;
-use std::task::{spawn_sched, SingleThreaded};
use std::vec;
-use std::unstable::running_on_valgrind;
use extra::test::MetricMap;
pub fn run(config: config, testfile: ~str) {
- let config = Cell::new(config);
- let testfile = Cell::new(testfile);
- // FIXME #6436: Creating another thread to run the test because this
- // is going to call waitpid. The new scheduler has some strange
- // interaction between the blocking tasks and 'friend' schedulers
- // that destroys parallelism if we let normal schedulers block.
- // It should be possible to remove this spawn once std::run is
- // rewritten to be non-blocking.
- //
- // We do _not_ create another thread if we're running on V because
- // it serializes all threads anyways.
- if running_on_valgrind() {
- let config = config.take();
- let testfile = testfile.take();
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
- } else {
- do spawn_sched(SingleThreaded) {
- let config = config.take();
- let testfile = testfile.take();
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
- }
- }
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
}
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
}
// write debugger script
- let script_str = cmds.append("\nquit\n");
+ let script_str = [~"set charset UTF-8",
+ cmds,
+ ~"quit\n"].connect("\n");
debug!("script_str = %s", script_str);
dump_output_file(config, testfile, script_str, "debugger.script");
(provide 'rust-mode)
+;; Issue #6887: Rather than inheriting the 'gnu compilation error
+;; regexp (which is broken on a few edge cases), add our own 'rust
+;; compilation error regexp and use it instead.
+(defvar rustc-compilation-regexps
+ (let ((file "\\([^\n]+\\)")
+ (start-line "\\([0-9]+\\)")
+ (start-col "\\([0-9]+\\)")
+ (end-line "\\([0-9]+\\)")
+ (end-col "\\([0-9]+\\)")
+ (error-or-warning "\\(?:[Ee]rror\\|\\([Ww]arning\\)\\)"))
+ (let ((re (concat "^" file ":" start-line ":" start-col
+ ": " end-line ":" end-col
+ " \\(?:[Ee]rror\\|\\([Ww]arning\\)\\):")))
+ (cons re '(1 (2 . 4) (3 . 5) (6)))))
+ "Specifications for matching errors in rustc invocations.
+See `compilation-error-regexp-alist for help on their format.")
+
+(eval-after-load 'compile
+ '(progn
+ (add-to-list 'compilation-error-regexp-alist-alist
+ (cons 'rustc rustc-compilation-regexps))
+ (add-to-list 'compilation-error-regexp-alist 'rustc)))
+
;;; rust-mode.el ends here
--- /dev/null
+#!/usr/bin/env python
+# xfail-license
+# Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+"""
+This script takes a list of keywords and generates a testcase, that checks
+if using the keyword as identifier fails, for every keyword. The generate
+test files are set read-only.
+Test for https://github.com/mozilla/rust/issues/2275
+
+sample usage: src/etc/generate-keyword-tests.py as break
+"""
+
+import sys
+import os
+import datetime
+import stat
+
+
+template = """// Copyright %d The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py %s'
+
+fn main() {
+ let %s = "foo"; //~ error: ident
+}
+"""
+
+test_dir = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), '../test/compile-fail')
+)
+
+for kw in sys.argv[1:]:
+ test_file = os.path.join(test_dir, 'keyword-%s-as-identifier.rs' % kw)
+
+ # set write permission if file exists, so it can be changed
+ if os.path.exists(test_file):
+ os.chmod(test_file, stat.S_IWUSR)
+
+ with open(test_file, 'wt') as f:
+ f.write(template % (datetime.datetime.now().year, kw, kw))
+
+ # mark file read-only
+ os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
fun:uv__platform_loop_init
fun:uv__loop_init
fun:uv_loop_new
- fun:rust_uv_loop_new__c_stack_shim
...
}
\ No newline at end of file
use sync::{Mutex, RWLock};
use std::cast;
-use std::unstable::sync::UnsafeAtomicRcBox;
+use std::unstable::sync::UnsafeArc;
use std::task;
use std::borrow;
****************************************************************************/
/// An atomically reference counted wrapper for shared immutable state.
-pub struct Arc<T> { priv x: UnsafeAtomicRcBox<T> }
+pub struct Arc<T> { priv x: UnsafeArc<T> }
/**
impl<T:Freeze+Send> Arc<T> {
/// Create an atomically reference counted wrapper.
pub fn new(data: T) -> Arc<T> {
- Arc { x: UnsafeAtomicRcBox::new(data) }
+ Arc { x: UnsafeArc::new(data) }
}
pub fn get<'a>(&'a self) -> &'a T {
#[doc(hidden)]
struct MutexArcInner<T> { priv lock: Mutex, priv failed: bool, priv data: T }
/// An Arc with mutable data protected by a blocking mutex.
-struct MutexArc<T> { priv x: UnsafeAtomicRcBox<MutexArcInner<T>> }
+struct MutexArc<T> { priv x: UnsafeArc<MutexArcInner<T>> }
impl<T:Send> Clone for MutexArc<T> {
lock: Mutex::new_with_condvars(num_condvars),
failed: false, data: user_data
};
- MutexArc { x: UnsafeAtomicRcBox::new(data) }
+ MutexArc { x: UnsafeArc::new(data) }
}
/**
*/
#[no_freeze]
struct RWArc<T> {
- priv x: UnsafeAtomicRcBox<RWArcInner<T>>,
+ priv x: UnsafeArc<RWArcInner<T>>,
}
impl<T:Freeze + Send> Clone for RWArc<T> {
lock: RWLock::new_with_condvars(num_condvars),
failed: false, data: user_data
};
- RWArc { x: UnsafeAtomicRcBox::new(data), }
+ RWArc { x: UnsafeArc::new(data), }
}
/**
#[test]
#[should_fail]
fn test_add_bytes_to_bits_tuple_overflow2() {
- add_bytes_to_bits_tuple::<u64>((Bounded::max_value::<u64>() - 1, 0), 0x8000000000000000);
+ let value: u64 = Bounded::max_value();
+ add_bytes_to_bits_tuple::<u64>((value - 1, 0), 0x8000000000000000);
}
}
#[test]
fn test_basic() {
- let mut m = DList::new::<~int>();
+ let mut m: DList<~int> = DList::new();
assert_eq!(m.pop_front(), None);
assert_eq!(m.pop_back(), None);
assert_eq!(m.pop_front(), None);
#[test]
fn test_rotate() {
- let mut n = DList::new::<int>();
+ let mut n: DList<int> = DList::new();
n.rotate_backward(); check_links(&n);
assert_eq!(n.len(), 0);
n.rotate_forward(); check_links(&n);
#[cfg(test)]
fn fuzz_test(sz: int) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
let mut v = ~[];
for i in range(0, sz) {
check_links(&m);
#[bench]
fn bench_push_front(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
do b.iter {
m.push_front(0);
}
#[bench]
fn bench_push_back(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
do b.iter {
m.push_back(0);
}
#[bench]
fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
do b.iter {
m.push_back(0);
m.pop_back();
#[bench]
fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
do b.iter {
m.push_front(0);
m.pop_front();
#[bench]
fn bench_rotate_forward(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
m.push_front(0);
m.push_front(1);
do b.iter {
#[bench]
fn bench_rotate_backward(b: &mut test::BenchHarness) {
- let mut m = DList::new::<int>();
+ let mut m: DList<int> = DList::new();
m.push_front(0);
m.push_front(1);
do b.iter {
#[link_name = "rustrt"]
extern {
- pub fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
+ pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)
-> *c_void;
- pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
+ pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)
}
}
- // FIXME: #5516
+ // FIXME: #5516 should be graphemes not codepoints
// here we just need to indent the start of the description
- let rowlen = row.len();
+ let rowlen = row.char_len();
if rowlen < 24 {
do (24 - rowlen).times {
row.push_char(' ')
desc_normalized_whitespace.push_char(' ');
}
- // FIXME: #5516
+ // FIXME: #5516 should be graphemes not codepoints
let mut desc_rows = ~[];
do each_split_within(desc_normalized_whitespace, 54) |substr| {
desc_rows.push(substr.to_owned());
true
};
- // FIXME: #5516
+ // FIXME: #5516 should be graphemes not codepoints
// wrapped description
row.push_str(desc_rows.connect(desc_sep));
cont
};
- ss.iter().enumerate().advance(|x| machine(x));
+ ss.char_offset_iter().advance(|x| machine(x));
// Let the automaton 'run out' by supplying trailing whitespace
while cont && match state { B | C => true, A => false } {
debug!("generated: <<%s>>", usage);
assert!(usage == expected)
}
+
+ #[test]
+ fn test_groups_usage_description_multibyte_handling() {
+ let optgroups = ~[
+ groups::optflag("k", "k\u2013w\u2013",
+ "The word kiwi is normally spelled with two i's"),
+ groups::optflag("a", "apple",
+ "This \u201Cdescription\u201D has some characters that could \
+confuse the line wrapping; an apple costs 0.51€ in some parts of Europe."),
+ ];
+
+ let expected =
+~"Usage: fruits
+
+Options:
+ -k --k–w– The word kiwi is normally spelled with two i's
+ -a --apple This “description” has some characters that could
+ confuse the line wrapping; an apple costs 0.51€ in
+ some parts of Europe.
+";
+
+ let usage = groups::usage("Usage: fruits", optgroups);
+
+ debug!("expected: <<%s>>", expected);
+ debug!("generated: <<%s>>", usage);
+ assert!(usage == expected)
+ }
}
}
}
-/// Encodes a json value into a io::writer
-pub fn to_writer(wr: @io::Writer, json: &Json) {
- let mut encoder = Encoder(wr);
- json.encode(&mut encoder)
-}
-
-/// Encodes a json value into a string
-pub fn to_str(json: &Json) -> ~str {
- io::with_str_writer(|wr| to_writer(wr, json))
-}
+impl Json{
+ /// Encodes a json value into a io::writer. Uses a single line.
+ pub fn to_writer(&self, wr: @io::Writer) {
+ let mut encoder = Encoder(wr);
+ self.encode(&mut encoder)
+ }
-/// Encodes a json value into a io::writer
-pub fn to_pretty_writer(wr: @io::Writer, json: &Json) {
- let mut encoder = PrettyEncoder(wr);
- json.encode(&mut encoder)
-}
+ /// Encodes a json value into a io::writer.
+ /// Pretty-prints in a more readable format.
+ pub fn to_pretty_writer(&self, wr: @io::Writer) {
+ let mut encoder = PrettyEncoder(wr);
+ self.encode(&mut encoder)
+ }
-/// Encodes a json value into a string
-pub fn to_pretty_str(json: &Json) -> ~str {
- io::with_str_writer(|wr| to_pretty_writer(wr, json))
+ /// Encodes a json value into a string
+ pub fn to_pretty_str(&self) -> ~str {
+ io::with_str_writer(|wr| self.to_pretty_writer(wr))
+ }
}
pub struct Parser<T> {
}
impl to_str::ToStr for Json {
- fn to_str(&self) -> ~str { to_str(self) }
+ /// Encodes a json value into a string
+ fn to_str(&self) -> ~str {
+ io::with_str_writer(|wr| self.to_writer(wr))
+ }
}
impl to_str::ToStr for Error {
#[test]
fn test_write_null() {
- assert_eq!(to_str(&Null), ~"null");
- assert_eq!(to_pretty_str(&Null), ~"null");
+ assert_eq!(Null.to_str(), ~"null");
+ assert_eq!(Null.to_pretty_str(), ~"null");
}
#[test]
fn test_write_number() {
- assert_eq!(to_str(&Number(3f)), ~"3");
- assert_eq!(to_pretty_str(&Number(3f)), ~"3");
+ assert_eq!(Number(3f).to_str(), ~"3");
+ assert_eq!(Number(3f).to_pretty_str(), ~"3");
- assert_eq!(to_str(&Number(3.1f)), ~"3.1");
- assert_eq!(to_pretty_str(&Number(3.1f)), ~"3.1");
+ assert_eq!(Number(3.1f).to_str(), ~"3.1");
+ assert_eq!(Number(3.1f).to_pretty_str(), ~"3.1");
- assert_eq!(to_str(&Number(-1.5f)), ~"-1.5");
- assert_eq!(to_pretty_str(&Number(-1.5f)), ~"-1.5");
+ assert_eq!(Number(-1.5f).to_str(), ~"-1.5");
+ assert_eq!(Number(-1.5f).to_pretty_str(), ~"-1.5");
- assert_eq!(to_str(&Number(0.5f)), ~"0.5");
- assert_eq!(to_pretty_str(&Number(0.5f)), ~"0.5");
+ assert_eq!(Number(0.5f).to_str(), ~"0.5");
+ assert_eq!(Number(0.5f).to_pretty_str(), ~"0.5");
}
#[test]
fn test_write_str() {
- assert_eq!(to_str(&String(~"")), ~"\"\"");
- assert_eq!(to_pretty_str(&String(~"")), ~"\"\"");
+ assert_eq!(String(~"").to_str(), ~"\"\"");
+ assert_eq!(String(~"").to_pretty_str(), ~"\"\"");
- assert_eq!(to_str(&String(~"foo")), ~"\"foo\"");
- assert_eq!(to_pretty_str(&String(~"foo")), ~"\"foo\"");
+ assert_eq!(String(~"foo").to_str(), ~"\"foo\"");
+ assert_eq!(String(~"foo").to_pretty_str(), ~"\"foo\"");
}
#[test]
fn test_write_bool() {
- assert_eq!(to_str(&Boolean(true)), ~"true");
- assert_eq!(to_pretty_str(&Boolean(true)), ~"true");
+ assert_eq!(Boolean(true).to_str(), ~"true");
+ assert_eq!(Boolean(true).to_pretty_str(), ~"true");
- assert_eq!(to_str(&Boolean(false)), ~"false");
- assert_eq!(to_pretty_str(&Boolean(false)), ~"false");
+ assert_eq!(Boolean(false).to_str(), ~"false");
+ assert_eq!(Boolean(false).to_pretty_str(), ~"false");
}
#[test]
fn test_write_list() {
- assert_eq!(to_str(&List(~[])), ~"[]");
- assert_eq!(to_pretty_str(&List(~[])), ~"[]");
+ assert_eq!(List(~[]).to_str(), ~"[]");
+ assert_eq!(List(~[]).to_pretty_str(), ~"[]");
- assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]");
+ assert_eq!(List(~[Boolean(true)]).to_str(), ~"[true]");
assert_eq!(
- to_pretty_str(&List(~[Boolean(true)])),
+ List(~[Boolean(true)]).to_pretty_str(),
~"\
[\n \
true\n\
]"
);
- assert_eq!(to_str(&List(~[
+ let longTestList = List(~[
Boolean(false),
Null,
- List(~[String(~"foo\nbar"), Number(3.5f)])
- ])), ~"[false,null,[\"foo\\nbar\",3.5]]");
+ List(~[String(~"foo\nbar"), Number(3.5f)])]);
+
+ assert_eq!(longTestList.to_str(),
+ ~"[false,null,[\"foo\\nbar\",3.5]]");
assert_eq!(
- to_pretty_str(&List(~[
- Boolean(false),
- Null,
- List(~[String(~"foo\nbar"), Number(3.5f)])
- ])),
+ longTestList.to_pretty_str(),
~"\
[\n \
false,\n \
#[test]
fn test_write_object() {
- assert_eq!(to_str(&mk_object([])), ~"{}");
- assert_eq!(to_pretty_str(&mk_object([])), ~"{}");
+ assert_eq!(mk_object([]).to_str(), ~"{}");
+ assert_eq!(mk_object([]).to_pretty_str(), ~"{}");
assert_eq!(
- to_str(&mk_object([(~"a", Boolean(true))])),
+ mk_object([(~"a", Boolean(true))]).to_str(),
~"{\"a\":true}"
);
assert_eq!(
- to_pretty_str(&mk_object([(~"a", Boolean(true))])),
+ mk_object([(~"a", Boolean(true))]).to_pretty_str(),
~"\
{\n \
\"a\": true\n\
}"
);
- assert_eq!(
- to_str(&mk_object([
+ let complexObj = mk_object([
(~"b", List(~[
mk_object([(~"c", String(~"\x0c\r"))]),
mk_object([(~"d", String(~""))])
]))
- ])),
+ ]);
+
+ assert_eq!(
+ complexObj.to_str(),
~"{\
\"b\":[\
{\"c\":\"\\f\\r\"},\
}"
);
assert_eq!(
- to_pretty_str(&mk_object([
- (~"b", List(~[
- mk_object([(~"c", String(~"\x0c\r"))]),
- mk_object([(~"d", String(~""))])
- ]))
- ])),
+ complexObj.to_pretty_str(),
~"\
{\n \
\"b\": [\n \
// We can't compare the strings directly because the object fields be
// printed in a different order.
- assert_eq!(a.clone(), from_str(to_str(&a)).unwrap());
- assert_eq!(a.clone(), from_str(to_pretty_str(&a)).unwrap());
+ assert_eq!(a.clone(), from_str(a.to_str()).unwrap());
+ assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap());
}
#[test]
A BigDigit is half the size of machine word size.
*/
-#[cfg(target_arch = "x86")]
-#[cfg(target_arch = "arm")]
-#[cfg(target_arch = "mips")]
+#[cfg(target_word_size = "32")]
pub type BigDigit = u16;
/**
A BigDigit is half the size of machine word size.
*/
-#[cfg(target_arch = "x86_64")]
+#[cfg(target_word_size = "64")]
pub type BigDigit = u32;
pub static ZERO_BIG_DIGIT: BigDigit = 0;
pub mod BigDigit {
use bigint::BigDigit;
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch = "arm")]
- #[cfg(target_arch = "mips")]
+ #[cfg(target_word_size = "32")]
pub static bits: uint = 16;
- #[cfg(target_arch = "x86_64")]
+ #[cfg(target_word_size = "64")]
pub static bits: uint = 32;
pub static base: uint = 1 << bits;
static hi_mask: uint = (-1 as uint) << bits;
static lo_mask: uint = (-1 as uint) >> bits;
-
+ #[inline]
fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit }
-
+ #[inline]
fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit }
/// Split one machine sized unsigned integer into two BigDigits.
-
+ #[inline]
pub fn from_uint(n: uint) -> (BigDigit, BigDigit) {
(get_hi(n), get_lo(n))
}
/// Join two BigDigits into one machine sized unsigned integer
-
+ #[inline]
pub fn to_uint(hi: BigDigit, lo: BigDigit) -> uint {
(lo as uint) | ((hi as uint) << bits)
}
}
impl Eq for BigUint {
-
+ #[inline]
fn eq(&self, other: &BigUint) -> bool { self.equals(other) }
-
- fn ne(&self, other: &BigUint) -> bool { !self.equals(other) }
}
impl TotalEq for BigUint {
-
+ #[inline]
fn equals(&self, other: &BigUint) -> bool {
match self.cmp(other) { Equal => true, _ => false }
}
}
impl Ord for BigUint {
-
+ #[inline]
fn lt(&self, other: &BigUint) -> bool {
match self.cmp(other) { Less => true, _ => false}
}
-
- fn le(&self, other: &BigUint) -> bool {
- match self.cmp(other) { Less | Equal => true, _ => false }
- }
-
- fn ge(&self, other: &BigUint) -> bool {
- match self.cmp(other) { Greater | Equal => true, _ => false }
- }
-
- fn gt(&self, other: &BigUint) -> bool {
- match self.cmp(other) { Greater => true, _ => false }
- }
}
impl TotalOrd for BigUint {
-
+ #[inline]
fn cmp(&self, other: &BigUint) -> Ordering {
let (s_len, o_len) = (self.data.len(), other.data.len());
if s_len < o_len { return Less; }
}
impl ToStr for BigUint {
-
+ #[inline]
fn to_str(&self) -> ~str { self.to_str_radix(10) }
}
impl FromStr for BigUint {
-
+ #[inline]
fn from_str(s: &str) -> Option<BigUint> {
FromStrRadix::from_str_radix(s, 10)
}
impl Num for BigUint {}
impl Orderable for BigUint {
-
+ #[inline]
fn min(&self, other: &BigUint) -> BigUint {
if self < other { self.clone() } else { other.clone() }
}
-
+ #[inline]
fn max(&self, other: &BigUint) -> BigUint {
if self > other { self.clone() } else { other.clone() }
}
-
+ #[inline]
fn clamp(&self, mn: &BigUint, mx: &BigUint) -> BigUint {
if self > mx { mx.clone() } else
if self < mn { mn.clone() } else { self.clone() }
}
impl Shl<uint, BigUint> for BigUint {
-
+ #[inline]
fn shl(&self, rhs: &uint) -> BigUint {
let n_unit = *rhs / BigDigit::bits;
let n_bits = *rhs % BigDigit::bits;
}
impl Shr<uint, BigUint> for BigUint {
-
+ #[inline]
fn shr(&self, rhs: &uint) -> BigUint {
let n_unit = *rhs / BigDigit::bits;
let n_bits = *rhs % BigDigit::bits;
}
impl Zero for BigUint {
-
+ #[inline]
fn zero() -> BigUint { BigUint::new(~[]) }
-
+ #[inline]
fn is_zero(&self) -> bool { self.data.is_empty() }
}
impl One for BigUint {
-
+ #[inline]
fn one() -> BigUint { BigUint::new(~[1]) }
}
impl Unsigned for BigUint {}
impl Add<BigUint, BigUint> for BigUint {
-
fn add(&self, other: &BigUint) -> BigUint {
let new_len = num::max(self.data.len(), other.data.len());
}
impl Sub<BigUint, BigUint> for BigUint {
-
fn sub(&self, other: &BigUint) -> BigUint {
let new_len = num::max(self.data.len(), other.data.len());
return BigUint::new(prod);
}
-
+ #[inline]
fn cut_at(a: &BigUint, n: uint) -> (BigUint, BigUint) {
let mid = num::min(a.data.len(), n);
return (BigUint::from_slice(a.data.slice(mid, a.data.len())),
BigUint::from_slice(a.data.slice(0, mid)));
}
-
+ #[inline]
fn sub_sign(a: BigUint, b: BigUint) -> (Ordering, BigUint) {
match a.cmp(&b) {
Less => (Less, b - a),
}
impl Div<BigUint, BigUint> for BigUint {
-
+ #[inline]
fn div(&self, other: &BigUint) -> BigUint {
let (q, _) = self.div_rem(other);
return q;
}
impl Rem<BigUint, BigUint> for BigUint {
-
+ #[inline]
fn rem(&self, other: &BigUint) -> BigUint {
let (_, r) = self.div_rem(other);
return r;
}
impl Neg<BigUint> for BigUint {
-
+ #[inline]
fn neg(&self) -> BigUint { fail!() }
}
impl Integer for BigUint {
-
+ #[inline]
fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) {
self.div_mod_floor(other)
}
-
+ #[inline]
fn div_floor(&self, other: &BigUint) -> BigUint {
let (d, _) = self.div_mod_floor(other);
return d;
}
-
+ #[inline]
fn mod_floor(&self, other: &BigUint) -> BigUint {
let (_, m) = self.div_mod_floor(other);
return m;
}
-
fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) {
if other.is_zero() { fail!() }
if self.is_zero() { return (Zero::zero(), Zero::zero()); }
fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) {
let mut m = a;
- let mut d = Zero::zero::<BigUint>();
+ let mut d: BigUint = Zero::zero();
let mut n = 1;
while m >= b {
let (d0, d_unit, b_unit) = div_estimate(&m, &b, n);
if shift == 0 {
return (BigUint::new(d), One::one(), (*b).clone());
}
+ let one: BigUint = One::one();
return (BigUint::from_slice(d).shl_unit(shift),
- One::one::<BigUint>().shl_unit(shift),
+ one.shl_unit(shift),
b.shl_unit(shift));
}
}
*
* The result is always positive
*/
-
+ #[inline]
fn gcd(&self, other: &BigUint) -> BigUint {
// Use Euclid's algorithm
let mut m = (*self).clone();
/**
* 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
-
+ #[inline]
fn is_multiple_of(&self, other: &BigUint) -> bool { (*self % *other).is_zero() }
/// Returns `true` if the number is divisible by `2`
-
+ #[inline]
fn is_even(&self) -> bool {
// Considering only the last digit.
if self.data.is_empty() {
}
/// Returns `true` if the number is not divisible by `2`
-
+ #[inline]
fn is_odd(&self) -> bool { !self.is_even() }
}
impl IntConvertible for BigUint {
-
+ #[inline]
fn to_int(&self) -> int {
num::min(self.to_uint(), int::max_value as uint) as int
}
-
+ #[inline]
fn from_int(n: int) -> BigUint {
if (n < 0) { Zero::zero() } else { BigUint::from_uint(n as uint) }
}
}
impl ToStrRadix for BigUint {
-
fn to_str_radix(&self, radix: uint) -> ~str {
assert!(1 < radix && radix <= 16);
let (base, max_len) = get_radix_base(radix);
}
return fill_concat(convert_base((*self).clone(), base), radix, max_len);
-
fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] {
let divider = BigUint::from_uint(base);
let mut result = ~[];
return result;
}
-
fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str {
if v.is_empty() { return ~"0" }
let mut s = str::with_capacity(v.len() * l);
impl FromStrRadix for BigUint {
/// Creates and initializes an BigUint.
-
+ #[inline]
fn from_str_radix(s: &str, radix: uint)
-> Option<BigUint> {
BigUint::parse_bytes(s.as_bytes(), radix)
impl BigUint {
/// Creates and initializes an BigUint.
-
+ #[inline]
pub fn new(v: ~[BigDigit]) -> BigUint {
// omit trailing zeros
let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1);
}
/// Creates and initializes an BigUint.
-
+ #[inline]
pub fn from_uint(n: uint) -> BigUint {
match BigDigit::from_uint(n) {
(0, 0) => Zero::zero(),
}
/// Creates and initializes an BigUint.
-
+ #[inline]
pub fn from_slice(slice: &[BigDigit]) -> BigUint {
return BigUint::new(slice.to_owned());
}
/// Creates and initializes an BigUint.
-
pub fn parse_bytes(buf: &[u8], radix: uint)
-> Option<BigUint> {
let (base, unit_len) = get_radix_base(radix);
/// Converts this big integer into a uint, returning the uint::max_value if
/// it's too large to fit in a uint.
+ #[inline]
pub fn to_uint(&self) -> uint {
match self.data.len() {
0 => 0,
}
}
-
+ #[inline]
fn shl_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 || self.is_zero() { return (*self).clone(); }
+ self.data);
}
-
+ #[inline]
fn shl_bits(&self, n_bits: uint) -> BigUint {
if n_bits == 0 || self.is_zero() { return (*self).clone(); }
return BigUint::new(shifted);
}
-
+ #[inline]
fn shr_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 { return (*self).clone(); }
if self.data.len() < n_unit { return Zero::zero(); }
);
}
-
+ #[inline]
fn shr_bits(&self, n_bits: uint) -> BigUint {
if n_bits == 0 || self.data.is_empty() { return (*self).clone(); }
}
}
-#[cfg(target_arch = "x86_64")]
-
+#[cfg(target_word_size = "64")]
+#[inline]
fn get_radix_base(radix: uint) -> (uint, uint) {
assert!(1 < radix && radix <= 16);
match radix {
}
}
-#[cfg(target_arch = "arm")]
-#[cfg(target_arch = "x86")]
-#[cfg(target_arch = "mips")]
-
+#[cfg(target_word_size = "32")]
+#[inline]
fn get_radix_base(radix: uint) -> (uint, uint) {
assert!(1 < radix && radix <= 16);
match radix {
pub enum Sign { Minus, Zero, Plus }
impl Ord for Sign {
-
+ #[inline]
fn lt(&self, other: &Sign) -> bool {
match self.cmp(other) { Less => true, _ => false}
}
-
- fn le(&self, other: &Sign) -> bool {
- match self.cmp(other) { Less | Equal => true, _ => false }
- }
-
- fn ge(&self, other: &Sign) -> bool {
- match self.cmp(other) { Greater | Equal => true, _ => false }
- }
-
- fn gt(&self, other: &Sign) -> bool {
- match self.cmp(other) { Greater => true, _ => false }
- }
}
impl TotalEq for Sign {
- fn equals(&self, other: &Sign) -> bool {
- *self == *other
- }
+ #[inline]
+ fn equals(&self, other: &Sign) -> bool { *self == *other }
}
impl TotalOrd for Sign {
-
+ #[inline]
fn cmp(&self, other: &Sign) -> Ordering {
match (*self, *other) {
(Minus, Minus) | (Zero, Zero) | (Plus, Plus) => Equal,
impl Neg<Sign> for Sign {
/// Negate Sign value.
-
+ #[inline]
fn neg(&self) -> Sign {
match *self {
Minus => Plus,
}
impl Eq for BigInt {
-
+ #[inline]
fn eq(&self, other: &BigInt) -> bool { self.equals(other) }
-
- fn ne(&self, other: &BigInt) -> bool { !self.equals(other) }
}
impl TotalEq for BigInt {
-
+ #[inline]
fn equals(&self, other: &BigInt) -> bool {
match self.cmp(other) { Equal => true, _ => false }
}
}
impl Ord for BigInt {
-
+ #[inline]
fn lt(&self, other: &BigInt) -> bool {
match self.cmp(other) { Less => true, _ => false}
}
-
- fn le(&self, other: &BigInt) -> bool {
- match self.cmp(other) { Less | Equal => true, _ => false }
- }
-
- fn ge(&self, other: &BigInt) -> bool {
- match self.cmp(other) { Greater | Equal => true, _ => false }
- }
-
- fn gt(&self, other: &BigInt) -> bool {
- match self.cmp(other) { Greater => true, _ => false }
- }
}
impl TotalOrd for BigInt {
-
+ #[inline]
fn cmp(&self, other: &BigInt) -> Ordering {
let scmp = self.sign.cmp(&other.sign);
if scmp != Equal { return scmp; }
}
impl ToStr for BigInt {
-
+ #[inline]
fn to_str(&self) -> ~str { self.to_str_radix(10) }
}
impl FromStr for BigInt {
-
+ #[inline]
fn from_str(s: &str) -> Option<BigInt> {
FromStrRadix::from_str_radix(s, 10)
}
impl Num for BigInt {}
impl Orderable for BigInt {
-
+ #[inline]
fn min(&self, other: &BigInt) -> BigInt {
if self < other { self.clone() } else { other.clone() }
}
-
+ #[inline]
fn max(&self, other: &BigInt) -> BigInt {
if self > other { self.clone() } else { other.clone() }
}
-
+ #[inline]
fn clamp(&self, mn: &BigInt, mx: &BigInt) -> BigInt {
if self > mx { mx.clone() } else
if self < mn { mn.clone() } else { self.clone() }
}
impl Shl<uint, BigInt> for BigInt {
-
+ #[inline]
fn shl(&self, rhs: &uint) -> BigInt {
BigInt::from_biguint(self.sign, self.data << *rhs)
}
}
impl Shr<uint, BigInt> for BigInt {
-
+ #[inline]
fn shr(&self, rhs: &uint) -> BigInt {
BigInt::from_biguint(self.sign, self.data >> *rhs)
}
}
impl Zero for BigInt {
-
+ #[inline]
fn zero() -> BigInt {
BigInt::from_biguint(Zero, Zero::zero())
}
-
+ #[inline]
fn is_zero(&self) -> bool { self.sign == Zero }
}
impl One for BigInt {
-
+ #[inline]
fn one() -> BigInt {
BigInt::from_biguint(Plus, One::one())
}
}
impl Signed for BigInt {
-
+ #[inline]
fn abs(&self) -> BigInt {
match self.sign {
Plus | Zero => self.clone(),
}
}
-
+ #[inline]
fn abs_sub(&self, other: &BigInt) -> BigInt {
if *self <= *other { Zero::zero() } else { *self - *other }
}
-
+ #[inline]
fn signum(&self) -> BigInt {
match self.sign {
Plus => BigInt::from_biguint(Plus, One::one()),
}
}
-
+ #[inline]
fn is_positive(&self) -> bool { self.sign == Plus }
-
+ #[inline]
fn is_negative(&self) -> bool { self.sign == Minus }
}
impl Add<BigInt, BigInt> for BigInt {
-
+ #[inline]
fn add(&self, other: &BigInt) -> BigInt {
match (self.sign, other.sign) {
(Zero, _) => other.clone(),
}
impl Sub<BigInt, BigInt> for BigInt {
-
+ #[inline]
fn sub(&self, other: &BigInt) -> BigInt {
match (self.sign, other.sign) {
(Zero, _) => -other,
}
impl Mul<BigInt, BigInt> for BigInt {
-
+ #[inline]
fn mul(&self, other: &BigInt) -> BigInt {
match (self.sign, other.sign) {
(Zero, _) | (_, Zero) => Zero::zero(),
}
impl Div<BigInt, BigInt> for BigInt {
-
+ #[inline]
fn div(&self, other: &BigInt) -> BigInt {
let (q, _) = self.div_rem(other);
return q;
}
impl Rem<BigInt, BigInt> for BigInt {
-
+ #[inline]
fn rem(&self, other: &BigInt) -> BigInt {
let (_, r) = self.div_rem(other);
return r;
}
impl Neg<BigInt> for BigInt {
-
+ #[inline]
fn neg(&self) -> BigInt {
BigInt::from_biguint(self.sign.neg(), self.data.clone())
}
}
impl Integer for BigInt {
-
+ #[inline]
fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
// r.sign == self.sign
let (d_ui, r_ui) = self.data.div_mod_floor(&other.data);
}
}
-
+ #[inline]
fn div_floor(&self, other: &BigInt) -> BigInt {
let (d, _) = self.div_mod_floor(other);
return d;
}
-
+ #[inline]
fn mod_floor(&self, other: &BigInt) -> BigInt {
let (_, m) = self.div_mod_floor(other);
return m;
}
-
fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) {
// m.sign == other.sign
let (d_ui, m_ui) = self.data.div_rem(&other.data);
*
* 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`
*/
-
+ #[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
-
+ #[inline]
fn is_multiple_of(&self, other: &BigInt) -> bool { self.data.is_multiple_of(&other.data) }
/// 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`
-
+ #[inline]
fn is_odd(&self) -> bool { self.data.is_odd() }
}
impl IntConvertible for BigInt {
-
+ #[inline]
fn to_int(&self) -> int {
match self.sign {
Plus => num::min(self.to_uint(), int::max_value as uint) as int,
}
}
-
+ #[inline]
fn from_int(n: int) -> BigInt {
if n > 0 {
return BigInt::from_biguint(Plus, BigUint::from_uint(n as uint));
}
impl ToStrRadix for BigInt {
-
+ #[inline]
fn to_str_radix(&self, radix: uint) -> ~str {
match self.sign {
Plus => self.data.to_str_radix(radix),
impl FromStrRadix for BigInt {
/// Creates and initializes an BigInt.
-
- fn from_str_radix(s: &str, radix: uint)
- -> Option<BigInt> {
+ #[inline]
+ fn from_str_radix(s: &str, radix: uint) -> Option<BigInt> {
BigInt::parse_bytes(s.as_bytes(), radix)
}
}
impl BigInt {
/// Creates and initializes an BigInt.
+ #[inline]
pub fn new(sign: Sign, v: ~[BigDigit]) -> BigInt {
BigInt::from_biguint(sign, BigUint::new(v))
}
/// Creates and initializes an BigInt.
-
+ #[inline]
pub fn from_biguint(sign: Sign, data: BigUint) -> BigInt {
if sign == Zero || data.is_zero() {
return BigInt { sign: Zero, data: Zero::zero() };
}
/// Creates and initializes an BigInt.
-
+ #[inline]
pub fn from_uint(n: uint) -> BigInt {
if n == 0 { return Zero::zero(); }
return BigInt::from_biguint(Plus, BigUint::from_uint(n));
}
/// Creates and initializes an BigInt.
-
+ #[inline]
pub fn from_slice(sign: Sign, slice: &[BigDigit]) -> BigInt {
BigInt::from_biguint(sign, BigUint::from_slice(slice))
}
/// Creates and initializes an BigInt.
-
pub fn parse_bytes(buf: &[u8], radix: uint)
-> Option<BigInt> {
if buf.is_empty() { return None; }
.map_move(|bu| BigInt::from_biguint(sign, bu));
}
+ #[inline]
pub fn to_uint(&self) -> uint {
match self.sign {
Plus => self.data.to_uint(),
#[test]
fn test_shl() {
- fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) {
- assert_eq!(BigUint::new(v) << shift, BigUint::new(ans));
- }
-
- check(~[], 3, ~[]);
- check(~[1, 1, 1], 3, ~[1 << 3, 1 << 3, 1 << 3]);
- check(~[1 << (BigDigit::bits - 2)], 2, ~[0, 1]);
- check(~[1 << (BigDigit::bits - 2)], 3, ~[0, 2]);
- check(~[1 << (BigDigit::bits - 2)], 3 + BigDigit::bits, ~[0, 0, 2]);
-
- test_shl_bits();
-
- #[cfg(target_arch = "x86_64")]
- fn test_shl_bits() {
- check(~[0x7654_3210, 0xfedc_ba98,
- 0x7654_3210, 0xfedc_ba98], 4,
- ~[0x6543_2100, 0xedcb_a987,
- 0x6543_210f, 0xedcb_a987, 0xf]);
- check(~[0x2222_1111, 0x4444_3333,
- 0x6666_5555, 0x8888_7777], 16,
- ~[0x1111_0000, 0x3333_2222,
- 0x5555_4444, 0x7777_6666, 0x8888]);
- }
-
- #[cfg(target_arch = "arm")]
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch = "mips")]
- fn test_shl_bits() {
- check(~[0x3210, 0x7654, 0xba98, 0xfedc,
- 0x3210, 0x7654, 0xba98, 0xfedc], 4,
- ~[0x2100, 0x6543, 0xa987, 0xedcb,
- 0x210f, 0x6543, 0xa987, 0xedcb, 0xf]);
- check(~[0x1111, 0x2222, 0x3333, 0x4444,
- 0x5555, 0x6666, 0x7777, 0x8888], 16,
- ~[0x0000, 0x1111, 0x2222, 0x3333,
- 0x4444, 0x5555, 0x6666, 0x7777, 0x8888]);
- }
-
+ fn check(s: &str, shift: uint, ans: &str) {
+ let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16);
+ let bu = (opt_biguint.unwrap() << shift).to_str_radix(16);
+ assert_eq!(bu.as_slice(), ans);
+ }
+
+ check("0", 3, "0");
+ check("1", 3, "8");
+
+ check("1" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 3,
+ "8" + "0000" + "0000" + "0000" + "0008" + "0000" + "0000" + "0000" + "0008");
+ check("1" + "0000" + "0001" + "0000" + "0001", 2,
+ "4" + "0000" + "0004" + "0000" + "0004");
+ check("1" + "0001" + "0001", 1,
+ "2" + "0002" + "0002");
+
+ check("" + "4000" + "0000" + "0000" + "0000", 3,
+ "2" + "0000" + "0000" + "0000" + "0000");
+ check("" + "4000" + "0000", 2,
+ "1" + "0000" + "0000");
+ check("" + "4000", 2,
+ "1" + "0000");
+
+ check("" + "4000" + "0000" + "0000" + "0000", 67,
+ "2" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000" + "0000");
+ check("" + "4000" + "0000", 35,
+ "2" + "0000" + "0000" + "0000" + "0000");
+ check("" + "4000", 19,
+ "2" + "0000" + "0000");
+
+ check("" + "fedc" + "ba98" + "7654" + "3210" + "fedc" + "ba98" + "7654" + "3210", 4,
+ "f" + "edcb" + "a987" + "6543" + "210f" + "edcb" + "a987" + "6543" + "2100");
+ check("88887777666655554444333322221111", 16,
+ "888877776666555544443333222211110000");
}
#[test]
- #[ignore(cfg(target_arch = "x86"))]
- #[ignore(cfg(target_arch = "arm"))]
- #[ignore(cfg(target_arch = "mips"))]
fn test_shr() {
- fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) {
- assert_eq!(BigUint::new(v) >> shift, BigUint::new(ans));
- }
-
- check(~[], 3, ~[]);
- check(~[1, 1, 1], 3,
- ~[1 << (BigDigit::bits - 3), 1 << (BigDigit::bits - 3)]);
- check(~[1 << 2], 2, ~[1]);
- check(~[1, 2], 3, ~[1 << (BigDigit::bits - 2)]);
- check(~[1, 1, 2], 3 + BigDigit::bits, ~[1 << (BigDigit::bits - 2)]);
- check(~[0, 1], 1, ~[0x80000000]);
- test_shr_bits();
-
- #[cfg(target_arch = "x86_64")]
- fn test_shr_bits() {
- check(~[0x6543_2100, 0xedcb_a987,
- 0x6543_210f, 0xedcb_a987, 0xf], 4,
- ~[0x7654_3210, 0xfedc_ba98,
- 0x7654_3210, 0xfedc_ba98]);
- check(~[0x1111_0000, 0x3333_2222,
- 0x5555_4444, 0x7777_6666, 0x8888], 16,
- ~[0x2222_1111, 0x4444_3333,
- 0x6666_5555, 0x8888_7777]);
- }
-
- #[cfg(target_arch = "arm")]
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch = "mips")]
- fn test_shr_bits() {
- check(~[0x2100, 0x6543, 0xa987, 0xedcb,
- 0x210f, 0x6543, 0xa987, 0xedcb, 0xf], 4,
- ~[0x3210, 0x7654, 0xba98, 0xfedc,
- 0x3210, 0x7654, 0xba98, 0xfedc]);
- check(~[0x0000, 0x1111, 0x2222, 0x3333,
- 0x4444, 0x5555, 0x6666, 0x7777, 0x8888], 16,
- ~[0x1111, 0x2222, 0x3333, 0x4444,
- 0x5555, 0x6666, 0x7777, 0x8888]);
- }
+ fn check(s: &str, shift: uint, ans: &str) {
+ let opt_biguint: Option<BigUint> =
+ FromStrRadix::from_str_radix(s, 16);
+ let bu = (opt_biguint.unwrap() >> shift).to_str_radix(16);
+ assert_eq!(bu.as_slice(), ans);
+ }
+
+ check("0", 3, "0");
+ check("f", 3, "1");
+
+ check("1" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 3,
+ "" + "2000" + "0000" + "0000" + "0000" + "2000" + "0000" + "0000" + "0000");
+ check("1" + "0000" + "0001" + "0000" + "0001", 2,
+ "" + "4000" + "0000" + "4000" + "0000");
+ check("1" + "0001" + "0001", 1,
+ "" + "8000" + "8000");
+
+ check("2" + "0000" + "0000" + "0000" + "0001" + "0000" + "0000" + "0000" + "0001", 67,
+ "" + "4000" + "0000" + "0000" + "0000");
+ check("2" + "0000" + "0001" + "0000" + "0001", 35,
+ "" + "4000" + "0000");
+ check("2" + "0001" + "0001", 19,
+ "" + "4000");
+
+ check("1" + "0000" + "0000" + "0000" + "0000", 1,
+ "" + "8000" + "0000" + "0000" + "0000");
+ check("1" + "0000" + "0000", 1,
+ "" + "8000" + "0000");
+ check("1" + "0000", 1,
+ "" + "8000");
+ check("f" + "edcb" + "a987" + "6543" + "210f" + "edcb" + "a987" + "6543" + "2100", 4,
+ "" + "fedc" + "ba98" + "7654" + "3210" + "fedc" + "ba98" + "7654" + "3210");
+
+ check("888877776666555544443333222211110000", 16,
+ "88887777666655554444333322221111");
}
#[test]
#[test]
fn test_is_even() {
- assert!(FromStr::from_str::<BigUint>("1").unwrap().is_odd());
- assert!(FromStr::from_str::<BigUint>("2").unwrap().is_even());
- assert!(FromStr::from_str::<BigUint>("1000").unwrap().is_even());
- assert!(FromStr::from_str::<BigUint>("1000000000000000000000").unwrap().is_even());
- assert!(FromStr::from_str::<BigUint>("1000000000000000000001").unwrap().is_odd());
+ let one: Option<BigUint> = FromStr::from_str("1");
+ let two: Option<BigUint> = FromStr::from_str("2");
+ let thousand: Option<BigUint> = FromStr::from_str("1000");
+ let big: Option<BigUint> =
+ FromStr::from_str("1000000000000000000000");
+ let bigger: Option<BigUint> =
+ FromStr::from_str("1000000000000000000001");
+ assert!(one.unwrap().is_odd());
+ assert!(two.unwrap().is_even());
+ assert!(thousand.unwrap().is_even());
+ assert!(big.unwrap().is_even());
+ assert!(bigger.unwrap().is_odd());
assert!((BigUint::from_uint(1) << 64).is_even());
assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd());
}
}
}
- assert_eq!(FromStrRadix::from_str_radix::<BigUint>("Z", 10), None);
- assert_eq!(FromStrRadix::from_str_radix::<BigUint>("_", 2), None);
- assert_eq!(FromStrRadix::from_str_radix::<BigUint>("-1", 10), None);
+ let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10);
+ assert_eq!(zed, None);
+ let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2);
+ assert_eq!(blank, None);
+ let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1",
+ 10);
+ assert_eq!(minus_one, None);
}
#[test]
fn test_factor() {
fn factor(n: uint) -> BigUint {
- let mut f= One::one::<BigUint>();
+ let mut f: BigUint = One::one();
for i in range(2, n + 1) {
// FIXME(#6102): Assignment operator for BigInt causes ICE
// f *= BigUint::from_uint(i);
#[cfg(test)]
mod bigint_tests {
-
use super::*;
use std::cmp::{Less, Equal, Greater};
#[test]
fn test_abs_sub() {
- assert_eq!((-One::one::<BigInt>()).abs_sub(&One::one()), Zero::zero());
- assert_eq!(One::one::<BigInt>().abs_sub(&One::one()), Zero::zero());
- assert_eq!(One::one::<BigInt>().abs_sub(&Zero::zero()), One::one());
- assert_eq!(One::one::<BigInt>().abs_sub(&-One::one::<BigInt>()),
- IntConvertible::from_int(2));
+ let zero: BigInt = Zero::zero();
+ let one: BigInt = One::one();
+ assert_eq!((-one).abs_sub(&one), zero);
+ let one: BigInt = One::one();
+ let zero: BigInt = Zero::zero();
+ assert_eq!(one.abs_sub(&one), zero);
+ let one: BigInt = One::one();
+ let zero: BigInt = Zero::zero();
+ assert_eq!(one.abs_sub(&zero), one);
+ let one: BigInt = One::one();
+ assert_eq!(one.abs_sub(&-one), IntConvertible::from_int(2));
}
#[test]
fn test_to_str_radix() {
fn check(n: int, ans: &str) {
- assert!(ans == IntConvertible::from_int::<BigInt>(n).to_str_radix(10));
+ let n: BigInt = IntConvertible::from_int(n);
+ assert!(ans == n.to_str_radix(10));
}
check(10, "10");
check(1, "1");
#[test]
fn test_from_str_radix() {
fn check(s: &str, ans: Option<int>) {
- let ans = ans.map_move(|n| IntConvertible::from_int::<BigInt>(n));
+ let ans = ans.map_move(|n| {
+ let x: BigInt = IntConvertible::from_int(n);
+ x
+ });
assert_eq!(FromStrRadix::from_str_radix(s, 10), ans);
}
check("10", Some(10));
BigInt::new(Minus, ~[1, 1, 1]));
assert!(-BigInt::new(Minus, ~[1, 1, 1]) ==
BigInt::new(Plus, ~[1, 1, 1]));
- assert_eq!(-Zero::zero::<BigInt>(), Zero::zero::<BigInt>());
+ let zero: BigInt = Zero::zero();
+ assert_eq!(-zero, zero);
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ use super::*;
+ use std::{iterator, util};
+ use std::num::{Zero, One};
+ use extra::test::BenchHarness;
+
+ fn factorial(n: uint) -> BigUint {
+ let mut f: BigUint = One::one();
+ for i in iterator::range_inclusive(1, n) {
+ f = f * BigUint::from_uint(i);
+ }
+ f
+ }
+
+ 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;
+ f0 = util::replace(&mut f1, f2);
+ }
+ f0
+ }
+
+ #[bench]
+ fn factorial_100(bh: &mut BenchHarness) {
+ do bh.iter { factorial(100); }
+ }
+
+ #[bench]
+ fn fib_100(bh: &mut BenchHarness) {
+ do bh.iter { fib(100); }
+ }
+
+ #[bench]
+ fn to_str(bh: &mut BenchHarness) {
+ let fac = factorial(100);
+ let fib = fib(100);
+ do bh.iter { fac.to_str(); }
+ do bh.iter { fib.to_str(); }
}
}
/// Parses `numer/denom`.
fn from_str(s: &str) -> Option<Ratio<T>> {
let split: ~[&str] = s.splitn_iter('/', 1).collect();
- if split.len() < 2 { return None; }
- do FromStr::from_str::<T>(split[0]).chain |a| {
- do FromStr::from_str::<T>(split[1]).chain |b| {
+ if split.len() < 2 {
+ return None
+ }
+ let a_option: Option<T> = FromStr::from_str(split[0]);
+ do a_option.chain |a| {
+ let b_option: Option<T> = FromStr::from_str(split[1]);
+ do b_option.chain |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
let split: ~[&str] = s.splitn_iter('/', 1).collect();
- if split.len() < 2 { None }
- else {
- do FromStrRadix::from_str_radix::<T>(split[0], radix).chain |a| {
- do FromStrRadix::from_str_radix::<T>(split[1], radix).chain |b| {
+ if split.len() < 2 {
+ None
+ } else {
+ let a_option: Option<T> = FromStrRadix::from_str_radix(split[0],
+ radix);
+ do a_option.chain |a| {
+ let b_option: Option<T> =
+ FromStrRadix::from_str_radix(split[1], radix);
+ do b_option.chain |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
#[test]
fn test_from_str_fail() {
fn test(s: &str) {
- assert_eq!(FromStr::from_str::<Rational>(s), None);
+ let rational: Option<Rational> = FromStr::from_str(s);
+ assert_eq!(rational, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
#[test]
fn test_from_str_radix_fail() {
fn test(s: &str) {
- assert_eq!(FromStrRadix::from_str_radix::<Rational>(s, 3), None);
+ let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
+ assert_eq!(radix, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];
#[test]
#[should_fail]
- fn test_empty_pop() { let mut heap = PriorityQueue::new::<int>(); heap.pop(); }
+ fn test_empty_pop() {
+ let mut heap: PriorityQueue<int> = PriorityQueue::new();
+ heap.pop();
+ }
#[test]
fn test_empty_maybe_pop() {
- let mut heap = PriorityQueue::new::<int>();
+ let mut heap: PriorityQueue<int> = PriorityQueue::new();
assert!(heap.maybe_pop().is_none());
}
#[test]
#[should_fail]
- fn test_empty_top() { let empty = PriorityQueue::new::<int>(); empty.top(); }
+ fn test_empty_top() {
+ let empty: PriorityQueue<int> = PriorityQueue::new();
+ empty.top();
+ }
#[test]
fn test_empty_maybe_top() {
- let empty = PriorityQueue::new::<int>();
+ let empty: PriorityQueue<int> = PriorityQueue::new();
assert!(empty.maybe_top().is_none());
}
#[test]
#[should_fail]
- fn test_empty_replace() { let mut heap = PriorityQueue::new(); heap.replace(5); }
+ fn test_empty_replace() {
+ let mut heap: PriorityQueue<int> = PriorityQueue::new();
+ heap.replace(5);
+ }
#[test]
fn test_from_iter() {
#[bench]
fn bench_new(b: &mut test::BenchHarness) {
do b.iter {
- let _ = RingBuf::new::<u64>();
+ let _: RingBuf<u64> = RingBuf::new();
}
}
/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
- let mut map = hashmap::HashMap::new::<U, uint>();
+ let mut map: hashmap::HashMap<U,uint> = hashmap::HashMap::new();
for elem in iter {
map.insert_or_update_with(elem, 1, |_, count| *count += 1);
}
use std::comm::SendDeferred;
use std::comm::{GenericPort, Peekable};
use std::task;
-use std::unstable::sync::{Exclusive, UnsafeAtomicRcBox};
+use std::unstable::sync::{Exclusive, UnsafeArc};
use std::unstable::atomics;
use std::unstable::finally::Finally;
use std::util;
do task::unkillable {
do (|| {
self.acquire();
- unsafe {
- do task::rekillable { blk() }
- }
+ do task::rekillable { blk() }
}).finally {
self.release();
}
// signaller already sent -- I mean 'unconditionally' in contrast
// with acquire().)
do (|| {
- unsafe {
- do task::rekillable {
- let _ = WaitEnd.take_unwrap().recv();
- }
+ do task::rekillable {
+ let _ = WaitEnd.take_unwrap().recv();
}
}).finally {
// Reacquire the condvar. Note this is back in the unkillable
pub struct RWLock {
priv order_lock: Semaphore,
priv access_lock: Sem<~[WaitQueue]>,
- priv state: UnsafeAtomicRcBox<RWLockInner>,
+ priv state: UnsafeArc<RWLockInner>,
}
impl RWLock {
* Similar to mutex_with_condvars.
*/
pub fn new_with_condvars(num_condvars: uint) -> RWLock {
- let state = UnsafeAtomicRcBox::new(RWLockInner {
+ let state = UnsafeArc::new(RWLockInner {
read_mode: false,
read_count: atomics::AtomicUint::new(0),
});
* 'write' from other tasks will run concurrently with this one.
*/
pub fn write<U>(&self, blk: &fn() -> U) -> U {
- unsafe {
- do task::unkillable {
- (&self.order_lock).acquire();
- do (&self.access_lock).access {
- (&self.order_lock).release();
- do task::rekillable {
- blk()
- }
+ do task::unkillable {
+ (&self.order_lock).acquire();
+ do (&self.access_lock).access {
+ (&self.order_lock).release();
+ do task::rekillable {
+ blk()
}
}
}
// which can't happen until T2 finishes the downgrade-read entirely.
// The astute reader will also note that making waking writers use the
// order_lock is better for not starving readers.
- unsafe {
- do task::unkillable {
- (&self.order_lock).acquire();
- do (&self.access_lock).access_cond |cond| {
- (&self.order_lock).release();
- do task::rekillable {
- let opt_lock = Just(&self.order_lock);
- blk(&Condvar { sem: cond.sem, order: opt_lock,
- token: NonCopyable::new() })
- }
+ do task::unkillable {
+ (&self.order_lock).acquire();
+ do (&self.access_lock).access_cond |cond| {
+ (&self.order_lock).release();
+ do task::rekillable {
+ let opt_lock = Just(&self.order_lock);
+ blk(&Condvar { sem: cond.sem, order: opt_lock,
+ token: NonCopyable::new() })
}
}
}
(&self.access_lock).acquire();
(&self.order_lock).release();
do (|| {
- unsafe {
- do task::rekillable {
- blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
- }
+ do task::rekillable {
+ blk(RWLockWriteMode { lock: self, token: NonCopyable::new() })
}
}).finally {
let writer_or_last_reader;
use std::to_str::ToStr;
use std::f64;
use std::os;
+use std::uint;
// The name of a test. By convention this follows the rules for rust
ratchet_metrics: Option<Path>,
ratchet_noise_percent: Option<f64>,
save_metrics: Option<Path>,
+ test_shard: Option<(uint,uint)>,
logfile: Option<Path>
}
"Tests within N% of the recorded metrics will be \
considered as passing", "PERCENTAGE"),
groups::optopt("", "logfile", "Write logs to the specified file instead \
- of stdout", "PATH")]
+ of stdout", "PATH"),
+ groups::optopt("", "test-shard", "run shard A, of B shards, worth of the testsuite",
+ "A.B")]
}
fn usage(binary: &str, helpstr: &str) -> ! {
let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
let save_metrics = save_metrics.map_move(|s| Path(s));
+ let test_shard = getopts::opt_maybe_str(&matches, "test-shard");
+ let test_shard = opt_shard(test_shard);
+
let test_opts = TestOpts {
filter: filter,
run_ignored: run_ignored,
ratchet_metrics: ratchet_metrics,
ratchet_noise_percent: ratchet_noise_percent,
save_metrics: save_metrics,
+ test_shard: test_shard,
logfile: logfile
};
either::Left(test_opts)
}
+pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
+ match maybestr {
+ None => None,
+ Some(s) => {
+ match s.split_iter('.').to_owned_vec() {
+ [a, b] => match (uint::from_str(a), uint::from_str(b)) {
+ (Some(a), Some(b)) => Some((a,b)),
+ _ => None
+ },
+ _ => None
+ }
+ }
+ }
+}
+
+
#[deriving(Clone, Eq)]
pub struct BenchSamples {
ns_iter_summ: stats::Summary,
}
sort::quick_sort(filtered, lteq);
- filtered
+ // Shard the remaining tests, if sharding requested.
+ match opts.test_shard {
+ None => filtered,
+ Some((a,b)) =>
+ filtered.move_iter().enumerate()
+ .filter(|&(i,_)| i % b == a)
+ .map(|(_,t)| t)
+ .to_owned_vec()
+ }
}
struct TestFuture {
/// Write MetricDiff to a file.
pub fn save(&self, p: &Path) {
let f = io::file_writer(p, [io::Create, io::Truncate]).unwrap();
- json::to_pretty_writer(f, &self.to_json());
+ self.to_json().to_pretty_writer(f);
}
/// Compare against another MetricMap. Optionally compare all
ratchet_noise_percent: None,
ratchet_metrics: None,
save_metrics: None,
+ test_shard: None
};
let tests = ~[
ratchet_noise_percent: None,
ratchet_metrics: None,
save_metrics: None,
+ test_shard: None
};
let names =
}
pub fn empty_tm() -> Tm {
+ // 64 is the max size of the timezone buffer allocated on windows
+ // in rust_localtime. In glibc the max timezone size is supposedly 3.
+ let zone = str::with_capacity(64);
Tm {
tm_sec: 0_i32,
tm_min: 0_i32,
tm_yday: 0_i32,
tm_isdst: 0_i32,
tm_gmtoff: 0_i32,
- tm_zone: ~"",
+ tm_zone: zone,
tm_nsec: 0_i32,
}
}
#[test]
fn find_empty() {
- let m = TreeMap::new::<int, int>(); assert!(m.find(&5) == None);
+ let m: TreeMap<int,int> = TreeMap::new();
+ assert!(m.find(&5) == None);
}
#[test]
#[test]
fn test_rand_int() {
- let mut map = TreeMap::new::<int, int>();
+ let mut map: TreeMap<int,int> = TreeMap::new();
let mut ctrl = ~[];
check_equal(ctrl, &map);
pub fn parse_str(bh: &mut BenchHarness) {
let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
do bh.iter {
- let u = Uuid::parse_string(s);
+ Uuid::parse_string(s);
}
}
}
use driver::session;
use metadata::loader::meta_section_name;
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
return target_strs::t {
module_asm: ~"",
}
},
- target_triple: match target_os {
- session::os_macos => ~"arm-apple-darwin",
- session::os_win32 => ~"arm-pc-mingw32",
- session::os_linux => ~"arm-unknown-linux-gnueabihf",
- session::os_android => ~"arm-linux-androideabi",
- session::os_freebsd => ~"arm-unknown-freebsd"
- },
+ target_triple: target_triple,
cc_args: ~[~"-marm"]
};
use std::hash::Streaming;
use std::hash;
use std::io;
-use std::libc::{c_int, c_uint};
use std::os::consts::{macos, freebsd, linux, android, win32};
use std::os;
use std::ptr;
}
}
-pub fn WriteOutputFile(sess: Session,
- PM: lib::llvm::PassManagerRef, M: ModuleRef,
- Triple: &str,
- Cpu: &str,
- Feature: &str,
+pub fn WriteOutputFile(
+ sess: Session,
+ Target: lib::llvm::TargetMachineRef,
+ PM: lib::llvm::PassManagerRef,
+ M: ModuleRef,
Output: &str,
- // FIXME: When #2334 is fixed, change
- // c_uint to FileType
- FileType: c_uint,
- OptLevel: c_int,
- EnableSegmentedStacks: bool) {
+ FileType: lib::llvm::FileType) {
unsafe {
- do Triple.with_c_str |Triple| {
- do Cpu.with_c_str |Cpu| {
- do Feature.with_c_str |Feature| {
- do Output.with_c_str |Output| {
- let result = llvm::LLVMRustWriteOutputFile(
- PM,
- M,
- Triple,
- Cpu,
- Feature,
- Output,
- FileType,
- OptLevel,
- EnableSegmentedStacks);
- if (!result) {
- llvm_err(sess, ~"Could not write output");
- }
- }
- }
+ do Output.with_c_str |Output| {
+ let result = llvm::LLVMRustWriteOutputFile(
+ Target, PM, M, Output, FileType);
+ if !result {
+ llvm_err(sess, ~"Could not write output");
}
}
}
use driver::session::Session;
use driver::session;
use lib::llvm::llvm;
- use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data};
- use lib::llvm::{ContextRef};
+ use lib::llvm::{ModuleRef, ContextRef};
use lib;
- use back::passes;
-
use std::c_str::ToCStr;
- use std::libc::{c_int, c_uint};
+ use std::libc::c_uint;
use std::path::Path;
use std::run;
use std::str;
- pub fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
- match ot {
- output_type_assembly | output_type_object | output_type_exe => true,
- _ => false
- }
- }
-
pub fn run_passes(sess: Session,
llcx: ContextRef,
llmod: ModuleRef,
unsafe {
llvm::LLVMInitializePasses();
- let opts = sess.opts;
- if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
- let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
- let pm = mk_pass_manager();
- llvm::LLVMAddTargetData(td.lltd, pm.llpm);
-
- // Generate a pre-optimization intermediate file if -save-temps
- // was specified.
- if opts.save_temps {
- match output_type {
- output_type_bitcode => {
- if opts.optimize != session::No {
- let filename = output.with_filetype("no-opt.bc");
- do filename.with_c_str |buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- }
- }
- }
- _ => {
- let filename = output.with_filetype("bc");
- do filename.with_c_str |buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- }
- }
+ // Only initialize the platforms supported by Rust here, because
+ // using --llvm-root will have multiple platforms that rustllvm
+ // doesn't actually link to and it's pointless to put target info
+ // into the registry that Rust can not generate machine code for.
+ llvm::LLVMInitializeX86TargetInfo();
+ llvm::LLVMInitializeX86Target();
+ llvm::LLVMInitializeX86TargetMC();
+ llvm::LLVMInitializeX86AsmPrinter();
+ llvm::LLVMInitializeX86AsmParser();
+
+ llvm::LLVMInitializeARMTargetInfo();
+ llvm::LLVMInitializeARMTarget();
+ llvm::LLVMInitializeARMTargetMC();
+ llvm::LLVMInitializeARMAsmPrinter();
+ llvm::LLVMInitializeARMAsmParser();
+
+ llvm::LLVMInitializeMipsTargetInfo();
+ llvm::LLVMInitializeMipsTarget();
+ llvm::LLVMInitializeMipsTargetMC();
+ llvm::LLVMInitializeMipsAsmPrinter();
+ llvm::LLVMInitializeMipsAsmParser();
+
+ if sess.opts.save_temps {
+ do output.with_filetype("no-opt.bc").with_c_str |buf| {
+ llvm::LLVMWriteBitcodeToFile(llmod, buf);
}
}
- let mut mpm = passes::PassManager::new(td.lltd);
-
- if !sess.no_verify() {
- mpm.add_pass_from_name("verify");
- }
+ // Copy what clan does by turning on loop vectorization at O2 and
+ // slp vectorization at O3
+ let vectorize_loop = !sess.no_vectorize_loops() &&
+ (sess.opts.optimize == session::Default ||
+ sess.opts.optimize == session::Aggressive);
+ let vectorize_slp = !sess.no_vectorize_slp() &&
+ sess.opts.optimize == session::Aggressive;
+ llvm::LLVMRustSetLLVMOptions(sess.print_llvm_passes(),
+ vectorize_loop,
+ vectorize_slp,
+ sess.time_llvm_passes());
+
+ let OptLevel = match sess.opts.optimize {
+ session::No => lib::llvm::CodeGenLevelNone,
+ session::Less => lib::llvm::CodeGenLevelLess,
+ session::Default => lib::llvm::CodeGenLevelDefault,
+ session::Aggressive => lib::llvm::CodeGenLevelAggressive,
+ };
- let passes = if sess.opts.custom_passes.len() > 0 {
- sess.opts.custom_passes.clone()
- } else {
- if sess.lint_llvm() {
- mpm.add_pass_from_name("lint");
+ let tm = do sess.targ_cfg.target_strs.target_triple.with_c_str |T| {
+ do sess.opts.target_cpu.with_c_str |CPU| {
+ do sess.opts.target_feature.with_c_str |Features| {
+ llvm::LLVMRustCreateTargetMachine(
+ T, CPU, Features,
+ lib::llvm::CodeModelDefault,
+ lib::llvm::RelocPIC,
+ OptLevel,
+ true
+ )
+ }
}
- passes::create_standard_passes(opts.optimize)
};
+ // Create the two optimizing pass managers. These mirror what clang
+ // does, and are by populated by LLVM's default PassManagerBuilder.
+ // Each manager has a different set of passes, but they also share
+ // some common passes. Each one is initialized with the analyis
+ // passes the target requires, and then further passes are added.
+ let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
+ let mpm = llvm::LLVMCreatePassManager();
+ llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+ llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+
+ // If we're verifying or linting, add them to the function pass
+ // manager.
+ let addpass = |pass: &str| {
+ do pass.with_c_str |s| { llvm::LLVMRustAddPass(fpm, s) }
+ };
+ if !sess.no_verify() { assert!(addpass("verify")); }
+ if sess.lint_llvm() { assert!(addpass("lint")); }
+
+ // Create the PassManagerBuilder for LLVM. We configure it with
+ // reasonable defaults and prepare it to actually populate the pass
+ // manager.
+ let builder = llvm::LLVMPassManagerBuilderCreate();
+ match sess.opts.optimize {
+ session::No => {
+ // Don't add lifetime intrinsics add O0
+ llvm::LLVMRustAddAlwaysInlinePass(builder, false);
+ }
+ // numeric values copied from clang
+ session::Less => {
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+ 225);
+ }
+ session::Default | session::Aggressive => {
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+ 275);
+ }
+ }
+ llvm::LLVMPassManagerBuilderSetOptLevel(builder, OptLevel as c_uint);
+ llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
+
+ // Use the builder to populate the function/module pass managers.
+ llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
+ llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+ llvm::LLVMPassManagerBuilderDispose(builder);
+
+ for pass in sess.opts.custom_passes.iter() {
+ do pass.with_c_str |s| {
+ if !llvm::LLVMRustAddPass(mpm, s) {
+ sess.warn(fmt!("Unknown pass %s, ignoring", *pass));
+ }
+ }
+ }
+
+ // Finally, run the actual optimization passes
+ llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
+ llvm::LLVMRunPassManager(mpm, llmod);
- debug!("Passes: %?", passes);
- passes::populate_pass_manager(sess, &mut mpm, passes);
+ // Deallocate managers that we're now done with
+ llvm::LLVMDisposePassManager(fpm);
+ llvm::LLVMDisposePassManager(mpm);
- debug!("Running Module Optimization Pass");
- mpm.run(llmod);
+ if sess.opts.save_temps {
+ do output.with_filetype("bc").with_c_str |buf| {
+ llvm::LLVMWriteBitcodeToFile(llmod, buf);
+ }
+ }
- if opts.jit {
+ if sess.opts.jit {
// If we are using JIT, go ahead and create and execute the
- // engine now. JIT execution takes ownership of the module and
- // context, so don't dispose and return.
+ // engine now. JIT execution takes ownership of the module and
+ // context, so don't dispose
jit::exec(sess, llcx, llmod, true);
+ } else {
+ // Create a codegen-specific pass manager to emit the actual
+ // assembly or object files. This may not end up getting used,
+ // but we make it anyway for good measure.
+ let cpm = llvm::LLVMCreatePassManager();
+ llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
+ llvm::LLVMRustAddLibraryInfo(cpm, llmod);
- if sess.time_llvm_passes() {
- llvm::LLVMRustPrintPassTimings();
- }
- return;
- } else if is_object_or_assembly_or_exe(output_type) {
- let LLVMOptNone = 0 as c_int; // -O0
- let LLVMOptLess = 1 as c_int; // -O1
- let LLVMOptDefault = 2 as c_int; // -O2, -Os
- let LLVMOptAggressive = 3 as c_int; // -O3
-
- let CodeGenOptLevel = match opts.optimize {
- session::No => LLVMOptNone,
- session::Less => LLVMOptLess,
- session::Default => LLVMOptDefault,
- session::Aggressive => LLVMOptAggressive
- };
-
- let FileType = match output_type {
- output_type_object | output_type_exe => lib::llvm::ObjectFile,
- _ => lib::llvm::AssemblyFile
- };
-
- // Write optimized bitcode if --save-temps was on.
-
- if opts.save_temps {
- // Always output the bitcode file with --save-temps
-
- let filename = output.with_filetype("opt.bc");
- do filename.with_c_str |buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf)
- };
- // Save the assembly file if -S is used
- if output_type == output_type_assembly {
- WriteOutputFile(
- sess,
- pm.llpm,
- llmod,
- sess.targ_cfg.target_strs.target_triple,
- opts.target_cpu,
- opts.target_feature,
- output.to_str(),
- lib::llvm::AssemblyFile as c_uint,
- CodeGenOptLevel,
- true);
+ match output_type {
+ output_type_none => {}
+ output_type_bitcode => {
+ do output.with_c_str |buf| {
+ llvm::LLVMWriteBitcodeToFile(llmod, buf);
+ }
}
-
- // Save the object file for -c or --save-temps alone
- // This .o is needed when an exe is built
- if output_type == output_type_object ||
- output_type == output_type_exe {
- WriteOutputFile(
- sess,
- pm.llpm,
- llmod,
- sess.targ_cfg.target_strs.target_triple,
- opts.target_cpu,
- opts.target_feature,
- output.to_str(),
- lib::llvm::ObjectFile as c_uint,
- CodeGenOptLevel,
- true);
+ output_type_llvm_assembly => {
+ do output.with_c_str |output| {
+ llvm::LLVMRustPrintModule(cpm, llmod, output)
+ }
+ }
+ output_type_assembly => {
+ WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+ lib::llvm::AssemblyFile);
+ }
+ output_type_exe | output_type_object => {
+ WriteOutputFile(sess, tm, cpm, llmod, output.to_str(),
+ lib::llvm::ObjectFile);
}
- } else {
- // If we aren't saving temps then just output the file
- // type corresponding to the '-c' or '-S' flag used
- WriteOutputFile(
- sess,
- pm.llpm,
- llmod,
- sess.targ_cfg.target_strs.target_triple,
- opts.target_cpu,
- opts.target_feature,
- output.to_str(),
- FileType as c_uint,
- CodeGenOptLevel,
- true);
}
- // Clean up and return
- llvm::LLVMDisposeModule(llmod);
- llvm::LLVMContextDispose(llcx);
- if sess.time_llvm_passes() {
- llvm::LLVMRustPrintPassTimings();
- }
- return;
+ llvm::LLVMDisposePassManager(cpm);
}
- if output_type == output_type_llvm_assembly {
- // Given options "-S --emit-llvm": output LLVM assembly
- do output.with_c_str |buf_o| {
- llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o);
- }
- } else {
- // If only a bitcode file is asked for by using the
- // '--emit-llvm' flag, then output it here
- do output.with_c_str |buf| {
- llvm::LLVMWriteBitcodeToFile(llmod, buf);
- }
+ llvm::LLVMRustDisposeTargetMachine(tm);
+ // the jit takes ownership of these two items
+ if !sess.opts.jit {
+ llvm::LLVMDisposeModule(llmod);
+ llvm::LLVMContextDispose(llcx);
}
-
- llvm::LLVMDisposeModule(llmod);
- llvm::LLVMContextDispose(llcx);
if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
}
}
use driver::session::sess_os_to_meta_os;
use metadata::loader::meta_section_name;
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
return target_strs::t {
module_asm: ~"",
}
},
- target_triple: match target_os {
- session::os_macos => ~"mips-apple-darwin",
- session::os_win32 => ~"mips-pc-mingw32",
- session::os_linux => ~"mips-unknown-linux-gnu",
- session::os_android => ~"mips-unknown-android-gnu",
- session::os_freebsd => ~"mips-unknown-freebsd"
- },
+ target_triple: target_triple,
cc_args: ~[]
};
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::c_str::ToCStr;
-use std::io;
-
-use driver::session::{OptLevel, No, Less, Aggressive};
-use driver::session::{Session};
-use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
-use lib::llvm::llvm;
-use lib;
-
-pub struct PassManager {
- priv llpm: PassManagerRef
-}
-
-impl Drop for PassManager {
- fn drop(&self) {
- unsafe {
- llvm::LLVMDisposePassManager(self.llpm);
- }
- }
-}
-
-impl PassManager {
- pub fn new(td: TargetDataRef) -> PassManager {
- unsafe {
- let pm = PassManager {
- llpm: llvm::LLVMCreatePassManager()
- };
- llvm::LLVMAddTargetData(td, pm.llpm);
-
- return pm;
- }
- }
-
- pub fn add_pass(&mut self, pass:PassRef) {
- unsafe {
- llvm::LLVMAddPass(self.llpm, pass);
- }
- }
-
- pub fn add_pass_from_name(&mut self, name:&str) {
- let pass = create_pass(name).unwrap();
- self.add_pass(pass);
- }
-
- pub fn run(&self, md:ModuleRef) -> bool {
- unsafe {
- llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
- }
- }
-}
-
-pub fn create_standard_passes(level: OptLevel) -> ~[~str] {
- let mut passes = ~[];
-
- // mostly identical to clang 3.3, all differences are documented with comments
-
- if level != No {
- passes.push(~"targetlibinfo");
- passes.push(~"no-aa");
- // "tbaa" omitted, we don't emit clang-style type-based alias analysis information
- passes.push(~"basicaa");
- passes.push(~"globalopt");
- passes.push(~"ipsccp");
- passes.push(~"deadargelim");
- passes.push(~"instcombine");
- passes.push(~"simplifycfg");
- }
-
- passes.push(~"basiccg");
-
- if level != No {
- passes.push(~"prune-eh");
- }
-
- passes.push(~"inline-cost");
-
- if level == No || level == Less {
- passes.push(~"always-inline");
- } else {
- passes.push(~"inline");
- }
-
- if level != No {
- passes.push(~"functionattrs");
- if level == Aggressive {
- passes.push(~"argpromotion");
- }
- passes.push(~"sroa");
- passes.push(~"domtree");
- passes.push(~"early-cse");
- passes.push(~"lazy-value-info");
- passes.push(~"jump-threading");
- passes.push(~"correlated-propagation");
- passes.push(~"simplifycfg");
- passes.push(~"instcombine");
- passes.push(~"tailcallelim");
- passes.push(~"simplifycfg");
- passes.push(~"reassociate");
- passes.push(~"domtree");
- passes.push(~"loops");
- passes.push(~"loop-simplify");
- passes.push(~"lcssa");
- passes.push(~"loop-rotate");
- passes.push(~"licm");
- passes.push(~"lcssa");
- passes.push(~"loop-unswitch");
- passes.push(~"instcombine");
- passes.push(~"scalar-evolution");
- passes.push(~"loop-simplify");
- passes.push(~"lcssa");
- passes.push(~"indvars");
- passes.push(~"loop-idiom");
- passes.push(~"loop-deletion");
- if level == Aggressive {
- passes.push(~"loop-simplify");
- passes.push(~"lcssa");
- passes.push(~"loop-vectorize");
- passes.push(~"loop-simplify");
- passes.push(~"lcssa");
- passes.push(~"scalar-evolution");
- passes.push(~"loop-simplify");
- passes.push(~"lcssa");
- }
- if level != Less {
- passes.push(~"loop-unroll");
- passes.push(~"memdep");
- passes.push(~"gvn");
- }
- passes.push(~"memdep");
- passes.push(~"memcpyopt");
- passes.push(~"sccp");
- passes.push(~"instcombine");
- passes.push(~"lazy-value-info");
- passes.push(~"jump-threading");
- passes.push(~"correlated-propagation");
- passes.push(~"domtree");
- passes.push(~"memdep");
- passes.push(~"dse");
- passes.push(~"adce");
- passes.push(~"simplifycfg");
- passes.push(~"instcombine");
- // clang does `strip-dead-prototypes` here, since it does not emit them
- }
-
- // rustc emits dead prototypes, so always ask LLVM to strip them
- passes.push(~"strip-dead-prototypes");
-
- if level != Less {
- passes.push(~"globaldce");
- passes.push(~"constmerge");
- }
-
- passes
-}
-
-pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
- for nm in pass_list.iter() {
- match create_pass(*nm) {
- Some(p) => pm.add_pass(p),
- None => sess.warn(fmt!("Unknown pass %s", *nm))
- }
- }
-}
-
-pub fn create_pass(name:&str) -> Option<PassRef> {
- do name.with_c_str |s| {
- unsafe {
- let p = llvm::LLVMCreatePass(s);
- if p.is_null() {
- None
- } else {
- Some(p)
- }
- }
- }
-}
-
-pub fn list_passes() {
- io::println("\nAvailable Passes:");
-
- io::println("\nAnalysis Passes:");
- for &(name, desc) in analysis_passes.iter() {
- printfln!(" %-30s -- %s", name, desc);
- }
- io::println("\nTransformation Passes:");
- for &(name, desc) in transform_passes.iter() {
- printfln!(" %-30s -- %s", name, desc);
- }
- io::println("\nUtility Passes:");
- for &(name, desc) in utility_passes.iter() {
- printfln!(" %-30s -- %s", name, desc);
- }
-}
-
-/** Analysis Passes */
-pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
- ("aa-eval", "Exhausive Alias Analysis Precision Evaluator"),
- ("asan", "AddressSanitizer"),
- ("basicaa", "Basic Alias Analysis"),
- ("basiccg", "Basic CallGraph Construction"),
- ("block-freq", "Block Frequency Analysis"),
- ("cost-model", "Cost Model Analysis"),
- ("count-aa", "Count Alias Analysis Query Responses"),
- ("da", "Dependence Analysis"),
- ("debug-aa", "AA Use Debugger"),
- ("domfrontier", "Dominance Frontier Construction"),
- ("domtree", "Dominator Tree Construction"),
- ("globalsmodref-aa", "Simple mod/ref analysis for globals"),
- ("instcount", "Count the various types of Instructions"),
- ("intervals", "Interval Partition Construction"),
- ("iv-users", "Induction Variable Users"),
- ("lazy-value-info", "Lazy Value Information Analysis"),
- ("libcall-aa", "LibCall Alias Analysis"),
- ("lint", "Statically lint-check LLVM IR"),
- ("loops", "Natural Loop Information"),
- ("memdep", "Memory Dependence Analysis"),
- ("module-debuginfo", "Decodes module-level debug info"),
- ("profile-estimator", "Estimate profiling information"),
- ("profile-loader", "Load profile information from llvmprof.out"),
- ("profile-verifier", "Verify profiling information"),
- ("regions", "Detect single entry single exit regions"),
- ("scalar-evolution", "Scalar Evolution Analysis"),
- ("scev-aa", "Scalar Evolution-based Alias Analysis"),
- ("tbaa", "Type-Based Alias Analysis"),
- ("tsan", "ThreadSanitizer"),
-];
-
-/** Transformation Passes */
-pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
- ("adce", "Aggressive Dead Code Elimination"),
- ("always-inline", "Inliner for #[inline] functions"),
- ("argpromotion", "Promote 'by reference' arguments to scalars"),
- ("bb-vectorize", "Basic-Block Vectorization"),
- ("block-placement", "Profile Guided Basic Block Placement"),
- ("bounds-checking", "Run-time bounds checking"),
- ("break-crit-edges", "Break critical edges in CFG"),
- ("codegenprepare", "Optimize for code generation"),
- ("constmerge", "Merge Duplicate Global Constants"),
- ("constprop", "Simple constant propagation"),
- ("correlated-propagation", "Value Propagation"),
- ("da", "Data Layout"),
- ("dce", "Dead Code Elimination"),
- ("deadargelim", "Dead Argument Elimination"),
- ("die", "Dead Instruction Elimination"),
- ("dse", "Dead Store Elimination"),
- ("early-cse", "Early CSE"),
- ("functionattrs", "Deduce function attributes"),
- ("globaldce", "Dead Global Elimination"),
- ("globalopt", "Global Variable Optimizer"),
- ("gvn", "Global Value Numbering"),
- ("indvars", "Canonicalize Induction Variables"),
- ("inline", "Function Integration/Inlining"),
- ("insert-edge-profiling", "Insert instrumentation for edge profiling"),
- ("insert-gcov-profiling", "Insert instrumentation for GCOV profiling"),
- ("insert-optimal-edge-profiling", "Insert optimal instrumentation for edge profiling"),
- ("instcombine", "Combine redundant instructions"),
- ("instsimplify", "Remove redundant instructions"),
- ("ipconstprop", "Interprocedural constant propagation"),
- ("ipsccp", "Interprocedural Sparse Conditional Constant Propagation"),
- ("jump-threading", "Jump Threading"),
- ("lcssa", "Loop-Closed SSA Form Pass"),
- ("licm", "Loop Invariant Code Motion"),
- ("loop-deletion", "Delete dead loops"),
- ("loop-extract", "Extract loops into new functions"),
- ("loop-extract-single", "Extract at most one loop into a new function"),
- ("loop-idiom", "Recognise loop idioms"),
- ("loop-instsimplify", "Simplify instructions in loops"),
- ("loop-reduce", "Loop Strength Reduction"),
- ("loop-rotate", "Rotate Loops"),
- ("loop-simplify", "Canonicalize natural loops"),
- ("loop-unroll", "Unroll loops"),
- ("loop-unswitch", "Unswitch loops"),
- ("loop-vectorize", "Loop Vectorization"),
- ("lower-expect", "Lower 'expect' Intrinsics"),
- ("mem2reg", "Promote Memory to Register"),
- ("memcpyopt", "MemCpy Optimization"),
- ("mergefunc", "Merge Functions"),
- ("mergereturn", "Unify function exit nodes"),
- ("partial-inliner", "Partial Inliner"),
- ("prune-eh", "Remove unused exception handling info"),
- ("reassociate", "Reassociate expressions"),
- ("reg2mem", "Demote all values to stack slots"),
- ("scalarrepl", "Scalar Replacement of Aggregates (DT)"),
- ("scalarrepl-ssa", "Scalar Replacement of Aggregates (SSAUp)"),
- ("sccp", "Sparse Conditional Constant Propagation"),
- ("simplifycfg", "Simplify the CFG"),
- ("sink", "Code sinking"),
- ("strip", "Strip all symbols from a module"),
- ("strip-dead-debug-info", "Strip debug info for unused symbols"),
- ("strip-dead-prototypes", "Strip Unused Function Prototypes"),
- ("strip-debug-declare", "Strip all llvm.dbg.declare intrinsics"),
- ("strip-nondebug", "Strip all symbols, except dbg symbols, from a module"),
- ("sroa", "Scalar Replacement of Aggregates"),
- ("tailcallelim", "Tail Call Elimination"),
-];
-
-/** Utility Passes */
-static utility_passes : &'static [(&'static str, &'static str)] = &'static [
- ("instnamer", "Assign names to anonymous instructions"),
- ("verify", "Module Verifier"),
-];
-
-#[test]
-fn passes_exist() {
- let mut failed = ~[];
- unsafe { llvm::LLVMInitializePasses(); }
- for &(name,_) in analysis_passes.iter() {
- let pass = create_pass(name);
- if !pass.is_some() {
- failed.push(name);
- } else {
- unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
- }
- }
- for &(name,_) in transform_passes.iter() {
- let pass = create_pass(name);
- if !pass.is_some() {
- failed.push(name);
- } else {
- unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
- }
- }
- for &(name,_) in utility_passes.iter() {
- let pass = create_pass(name);
- if !pass.is_some() {
- failed.push(name);
- } else {
- unsafe { llvm::LLVMDestroyPass(pass.unwrap()) }
- }
- }
-
- if failed.len() > 0 {
- io::println("Some passes don't exist:");
- for &n in failed.iter() {
- printfln!(" %s", n);
- }
- fail!();
- }
-}
use driver::session;
use metadata::loader::meta_section_name;
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
return target_strs::t {
module_asm: ~"",
}
},
- target_triple: match target_os {
- session::os_macos => ~"i686-apple-darwin",
- session::os_win32 => ~"i686-pc-mingw32",
- session::os_linux => ~"i686-unknown-linux-gnu",
- session::os_android => ~"i686-unknown-android-gnu",
- session::os_freebsd => ~"i686-unknown-freebsd"
- },
+ target_triple: target_triple,
cc_args: ~[~"-m32"]
};
use driver::session;
use metadata::loader::meta_section_name;
-pub fn get_target_strs(target_os: session::os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: session::os) -> target_strs::t {
return target_strs::t {
module_asm: ~"",
}
},
- target_triple: match target_os {
- session::os_macos => ~"x86_64-apple-darwin",
- session::os_win32 => ~"x86_64-pc-mingw32",
- session::os_linux => ~"x86_64-unknown-linux-gnu",
- session::os_android => ~"x86_64-unknown-android-gnu",
- session::os_freebsd => ~"x86_64-unknown-freebsd",
- },
+ target_triple: target_triple,
cc_args: ~[~"-m64"]
};
abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
};
+ let target_triple = sopts.target_triple.clone();
let target_strs = match arch {
- abi::X86 => x86::get_target_strs(os),
- abi::X86_64 => x86_64::get_target_strs(os),
- abi::Arm => arm::get_target_strs(os),
- abi::Mips => mips::get_target_strs(os)
+ abi::X86 => x86::get_target_strs(target_triple, os),
+ abi::X86_64 => x86_64::get_target_strs(target_triple, os),
+ abi::Arm => arm::get_target_strs(target_triple, os),
+ abi::Mips => mips::get_target_strs(target_triple, os)
};
let target_cfg = @session::config {
os: os,
optopt("", "opt-level",
"Optimize with possible levels 0-3", "LEVEL"),
optopt("", "passes", "Comma or space separated list of pass names to use. \
- Overrides the default passes for optimization levels,\n\
- a value of \"list\" will list the available passes.", "NAMES"),
+ Appends to the default list of passes to run for the \
+ specified current optimization level. A value of \
+ \"list\" will list all of the available passes", "NAMES"),
optopt( "", "out-dir",
"Write output to compiler-chosen filename
in <dir>", "DIR"),
pub static no_debug_borrows: uint = 1 << 24;
pub static lint_llvm: uint = 1 << 25;
pub static once_fns: uint = 1 << 26;
+pub static print_llvm_passes: uint = 1 << 27;
+pub static no_vectorize_loops: uint = 1 << 28;
+pub static no_vectorize_slp: uint = 1 << 29;
pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
(~"once-fns",
~"Allow 'once fn' closures to deinitialize captured variables",
once_fns),
+ (~"print-llvm-passes",
+ ~"Prints the llvm optimization passes being run",
+ print_llvm_passes),
+ (~"no-vectorize-loops",
+ ~"Don't run the loop vectorization optimization passes",
+ no_vectorize_loops),
+ (~"no-vectorize-slp",
+ ~"Don't run LLVM's SLP vectorization passes",
+ no_vectorize_slp),
]
}
self.opts.optimize == No && !self.debugging_opt(no_debug_borrows)
}
pub fn once_fns(@self) -> bool { self.debugging_opt(once_fns) }
+ pub fn print_llvm_passes(@self) -> bool {
+ self.debugging_opt(print_llvm_passes)
+ }
+ pub fn no_vectorize_loops(@self) -> bool {
+ self.debugging_opt(no_vectorize_loops)
+ }
+ pub fn no_vectorize_slp(@self) -> bool {
+ self.debugging_opt(no_vectorize_slp)
+ }
// pointless function, now...
pub fn str_of(@self, id: ast::ident) -> @str {
use syntax::codemap::dummy_sp;
use syntax::codemap;
use syntax::fold;
+use syntax::opt_vec;
static STD_VERSION: &'static str = "0.8-pre";
let prelude_path = ast::Path {
span: dummy_sp(),
global: false,
- idents: ~[
- sess.ident_of("std"),
- sess.ident_of("prelude")
+ segments: ~[
+ ast::PathSegment {
+ identifier: sess.ident_of("std"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ },
+ ast::PathSegment {
+ identifier: sess.ident_of("prelude"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ },
],
- rp: None,
- types: ~[]
};
let vp = @spanned(ast::view_path_glob(prelude_path, n2));
use std::vec;
use syntax::ast_util::*;
+use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, span, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold;
+use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
-use syntax::attr::AttrMetaMethods;
type node_id_gen = @fn() -> ast::NodeId;
}
fn path_node(ids: ~[ast::ident]) -> ast::Path {
- ast::Path { span: dummy_sp(),
- global: false,
- idents: ids,
- rp: None,
- types: ~[] }
+ ast::Path {
+ span: dummy_sp(),
+ global: false,
+ segments: ids.move_iter().map(|identifier| ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }).collect()
+ }
}
fn path_node_global(ids: ~[ast::ident]) -> ast::Path {
- ast::Path { span: dummy_sp(),
- global: true,
- idents: ids,
- rp: None,
- types: ~[] }
+ ast::Path {
+ span: dummy_sp(),
+ global: true,
+ segments: ids.move_iter().map(|identifier| ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }).collect()
+ }
}
#[cfg(stage0)]
SequentiallyConsistent = 7
}
-// FIXME: Not used right now, but will be once #2334 is fixed
// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
pub enum FileType {
AssemblyFile = 0,
AD_Intel = 1
}
+pub enum CodeGenOptLevel {
+ CodeGenLevelNone = 0,
+ CodeGenLevelLess = 1,
+ CodeGenLevelDefault = 2,
+ CodeGenLevelAggressive = 3,
+}
+
+pub enum RelocMode {
+ RelocDefault = 0,
+ RelocStatic = 1,
+ RelocPIC = 2,
+ RelocDynamicNoPic = 3,
+}
+
+pub enum CodeGenModel {
+ CodeModelDefault = 0,
+ CodeModelJITDefault = 1,
+ CodeModelSmall = 2,
+ CodeModelKernel = 3,
+ CodeModelMedium = 4,
+ CodeModelLarge = 5,
+}
+
// Opaque pointer types
pub enum Module_opaque {}
pub type ModuleRef = *Module_opaque;
pub type SectionIteratorRef = *SectionIterator_opaque;
pub enum Pass_opaque {}
pub type PassRef = *Pass_opaque;
+pub enum TargetMachine_opaque {}
+pub type TargetMachineRef = *TargetMachine_opaque;
pub mod debuginfo {
use super::{ValueRef};
use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef};
use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef};
use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef};
- use super::{ValueRef, PassRef};
+ use super::{ValueRef, TargetMachineRef, FileType};
+ use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
use super::debuginfo::*;
use std::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong};
/** Creates a pass manager. */
#[fast_ffi]
pub fn LLVMCreatePassManager() -> PassManagerRef;
+
/** Creates a function-by-function pass manager */
#[fast_ffi]
pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef)
#[fast_ffi]
pub fn LLVMInitializePasses();
- #[fast_ffi]
- pub fn LLVMAddPass(PM: PassManagerRef, P: PassRef);
-
- #[fast_ffi]
- pub fn LLVMCreatePass(PassName: *c_char) -> PassRef;
-
- #[fast_ffi]
- pub fn LLVMDestroyPass(P: PassRef);
-
/** Adds a verification pass. */
#[fast_ffi]
pub fn LLVMAddVerifierPass(PM: PassManagerRef);
pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *c_char)
-> MemoryBufferRef;
- #[fast_ffi]
- pub fn LLVMRustWriteOutputFile(PM: PassManagerRef,
- M: ModuleRef,
- Triple: *c_char,
- Cpu: *c_char,
- Feature: *c_char,
- Output: *c_char,
- // FIXME: When #2334 is fixed,
- // change c_uint to FileType
- FileType: c_uint,
- OptLevel: c_int,
- EnableSegmentedStacks: bool)
- -> bool;
-
/** Returns a string describing the last error caused by an LLVMRust*
call. */
#[fast_ffi]
EnableSegmentedStacks: bool)
-> ExecutionEngineRef;
- /** Parses the bitcode in the given memory buffer. */
- #[fast_ffi]
- pub fn LLVMRustParseBitcode(MemBuf: MemoryBufferRef) -> ModuleRef;
-
- /** Parses LLVM asm in the given file */
- #[fast_ffi]
- pub fn LLVMRustParseAssemblyFile(Filename: *c_char, C: ContextRef)
- -> ModuleRef;
-
- #[fast_ffi]
- pub fn LLVMRustAddPrintModulePass(PM: PassManagerRef,
- M: ModuleRef,
- Output: *c_char);
-
- /** Turn on LLVM pass-timing. */
- #[fast_ffi]
- pub fn LLVMRustEnableTimePasses();
-
/// Print the pass timings since static dtors aren't picking them up.
#[fast_ffi]
pub fn LLVMRustPrintPassTimings();
LineNo: c_uint,
ColumnNo: c_uint)
-> ValueRef;
+
+ pub fn LLVMInitializeX86TargetInfo();
+ pub fn LLVMInitializeX86Target();
+ pub fn LLVMInitializeX86TargetMC();
+ pub fn LLVMInitializeX86AsmPrinter();
+ pub fn LLVMInitializeX86AsmParser();
+ pub fn LLVMInitializeARMTargetInfo();
+ pub fn LLVMInitializeARMTarget();
+ pub fn LLVMInitializeARMTargetMC();
+ pub fn LLVMInitializeARMAsmPrinter();
+ pub fn LLVMInitializeARMAsmParser();
+ pub fn LLVMInitializeMipsTargetInfo();
+ pub fn LLVMInitializeMipsTarget();
+ pub fn LLVMInitializeMipsTargetMC();
+ pub fn LLVMInitializeMipsAsmPrinter();
+ pub fn LLVMInitializeMipsAsmParser();
+
+ pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: *c_char) -> bool;
+ pub fn LLVMRustCreateTargetMachine(Triple: *c_char,
+ CPU: *c_char,
+ Features: *c_char,
+ Model: CodeGenModel,
+ Reloc: RelocMode,
+ Level: CodeGenOptLevel,
+ EnableSegstk: bool) -> TargetMachineRef;
+ pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
+ pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef,
+ PM: PassManagerRef,
+ M: ModuleRef);
+ pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
+ M: ModuleRef);
+ pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef);
+ pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
+ pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
+ PM: PassManagerRef,
+ M: ModuleRef,
+ Output: *c_char,
+ FileType: FileType) -> bool;
+ pub fn LLVMRustPrintModule(PM: PassManagerRef,
+ M: ModuleRef,
+ Output: *c_char);
+ pub fn LLVMRustSetLLVMOptions(PrintPasses: bool,
+ VectorizeLoops: bool,
+ VectorizeSLP: bool,
+ TimePasses: bool);
+ pub fn LLVMRustPrintPasses();
+ pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *c_char);
+ pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef,
+ AddLifetimes: bool);
}
}
}
}
-
/* Memory-managed interface to target data. */
pub struct target_data_res {
pub static tag_item_method_provided_source: uint = 0x81;
pub static tag_item_impl_vtables: uint = 0x82;
+pub static tag_impls: uint = 0x83;
+pub static tag_impls_impl: uint = 0x84;
+
+pub static tag_items_data_item_inherent_impl: uint = 0x85;
+pub static tag_items_data_item_extension_impl: uint = 0x86;
+
pub struct LinkMeta {
name: @str,
vers: @str,
use syntax::diagnostic::span_handler;
use syntax::parse::token;
use syntax::parse::token::ident_interner;
-use syntax::oldvisit;
+use syntax::visit;
// Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc.
next_crate_num: 1,
intr: intr
};
- let v =
- oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor {
- visit_view_item: |a| visit_view_item(e, a),
- visit_item: |a| visit_item(e, a),
- .. *oldvisit::default_simple_visitor()});
+ let mut v = ReadCrateVisitor{ e:e };
visit_crate(e, crate);
- oldvisit::visit_crate(crate, ((), v));
+ visit::walk_crate(&mut v, crate, ());
dump_crates(*e.crate_cache);
warn_if_multiple_versions(e, diag, *e.crate_cache);
}
+struct ReadCrateVisitor { e:@mut Env }
+impl visit::Visitor<()> for ReadCrateVisitor {
+ fn visit_view_item(&mut self, a:&ast::view_item, _:()) {
+ visit_view_item(self.e, a);
+ visit::walk_view_item(self, a, ());
+ }
+ fn visit_item(&mut self, a:@ast::item, _:()) {
+ visit_item(self.e, a);
+ visit::walk_item(self, a, ());
+ }
+}
+
#[deriving(Clone)]
struct cache_entry {
cnum: int,
decoder::each_lang_item(crate_data, f)
}
-/// Iterates over all the paths in the given crate.
-pub fn each_path(cstore: @mut cstore::CStore,
- cnum: ast::CrateNum,
- f: &fn(&str, decoder::def_like, ast::visibility) -> bool)
- -> bool {
+/// Iterates over each child of the given item.
+pub fn each_child_of_item(cstore: @mut cstore::CStore,
+ def_id: ast::def_id,
+ callback: &fn(decoder::def_like, ast::ident)) {
+ let crate_data = cstore::get_crate_data(cstore, def_id.crate);
+ let get_crate_data: decoder::GetCrateDataCb = |cnum| {
+ cstore::get_crate_data(cstore, cnum)
+ };
+ decoder::each_child_of_item(cstore.intr,
+ crate_data,
+ def_id.node,
+ get_crate_data,
+ callback)
+}
+
+/// Iterates over each top-level crate item.
+pub fn each_top_level_item_of_crate(cstore: @mut cstore::CStore,
+ cnum: ast::CrateNum,
+ callback: &fn(decoder::def_like,
+ ast::ident)) {
let crate_data = cstore::get_crate_data(cstore, cnum);
let get_crate_data: decoder::GetCrateDataCb = |cnum| {
cstore::get_crate_data(cstore, cnum)
};
- decoder::each_path(cstore.intr, crate_data, get_crate_data, f)
+ decoder::each_top_level_item_of_crate(cstore.intr,
+ crate_data,
+ get_crate_data,
+ callback)
}
pub fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path {
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::get_link_args_for_crate(cdata)
}
+
+pub fn each_impl(cstore: @mut cstore::CStore,
+ crate_num: ast::CrateNum,
+ callback: &fn(ast::def_id)) {
+ let cdata = cstore::get_crate_data(cstore, crate_num);
+ decoder::each_impl(cdata, callback)
+}
+
+pub fn each_implementation_for_type(cstore: @mut cstore::CStore,
+ def_id: ast::def_id,
+ callback: &fn(ast::def_id)) {
+ let cdata = cstore::get_crate_data(cstore, def_id.crate);
+ decoder::each_implementation_for_type(cdata, def_id.node, callback)
+}
+
+pub fn each_implementation_for_trait(cstore: @mut cstore::CStore,
+ def_id: ast::def_id,
+ callback: &fn(ast::def_id)) {
+ let cdata = cstore::get_crate_data(cstore, def_id.crate);
+ decoder::each_implementation_for_trait(cdata, def_id.node, callback)
+}
+
+/// If the given def ID describes a method belonging to a trait (either a
+/// default method or an implementation of a trait method), returns the ID of
+/// the trait that the method belongs to. Otherwise, returns `None`.
+pub fn get_trait_of_method(cstore: @mut cstore::CStore,
+ def_id: ast::def_id,
+ tcx: ty::ctxt)
+ -> Option<ast::def_id> {
+ let cdata = cstore::get_crate_data(cstore, def_id.crate);
+ decoder::get_trait_of_method(cdata, def_id.node, tcx)
+}
+
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
+use middle::ty::{ImplContainer, TraitContainer};
use middle::ty;
use middle::typeck;
use middle::astencode::vtable_decoder_helpers;
-use std::hash::HashUtil;
-use std::uint;
+use std::u64;
use std::io::WriterUtil;
use std::io;
use std::option;
use syntax::attr;
use syntax::parse::token::{ident_interner, special_idents};
use syntax::print::pprust;
-use syntax::{ast, ast_util};
+use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
reader::tagged_docs(d, tag_items_data_item_reexport, f)
}
-fn variant_disr_val(d: ebml::Doc) -> Option<uint> {
+fn variant_disr_val(d: ebml::Doc) -> Option<ty::Disr> {
do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| {
- do reader::with_doc_data(val_doc) |data| { uint::parse_bytes(data, 10u) }
+ do reader::with_doc_data(val_doc) |data| { u64::parse_bytes(data, 10u) }
}
}
let purity = if fam == UnsafeStaticMethod { ast::unsafe_fn } else
{ ast::impure_fn };
// def_static_method carries an optional field of its enclosing
- // *trait*, but not an inclosing Impl (if this is an inherent
- // static method). So we need to detect whether this is in
- // a trait or not, which we do through the mildly hacky
- // way of checking whether there is a trait_method_sort.
- let trait_did_opt = if reader::maybe_get_doc(
+ // trait or enclosing impl (if this is an inherent static method).
+ // So we need to detect whether this is in a trait or not, which
+ // we do through the mildly hacky way of checking whether there is
+ // a trait_method_sort.
+ let provenance = if reader::maybe_get_doc(
item, tag_item_trait_method_sort).is_some() {
- Some(item_reqd_and_translated_parent_item(cnum, item))
- } else { None };
- dl_def(ast::def_static_method(did, trait_did_opt, purity))
+ ast::FromTrait(item_reqd_and_translated_parent_item(cnum,
+ item))
+ } else {
+ ast::FromImpl(item_reqd_and_translated_parent_item(cnum,
+ item))
+ };
+ dl_def(ast::def_static_method(did, provenance, purity))
}
Type | ForeignType => dl_def(ast::def_ty(did)),
Mod => dl_def(ast::def_mod(did)),
}
}
-/// Iterates over all the paths in the given crate.
-pub fn each_path(intr: @ident_interner,
- cdata: cmd,
- get_crate_data: GetCrateDataCb,
- f: &fn(&str, def_like, ast::visibility) -> bool)
- -> bool {
- // FIXME #4572: This function needs to be nuked, as it's impossible to
- // make fast. It's the source of most of the performance problems when
- // compiling small crates.
+fn each_child_of_item_or_crate(intr: @ident_interner,
+ cdata: cmd,
+ item_doc: ebml::Doc,
+ get_crate_data: GetCrateDataCb,
+ callback: &fn(def_like, ast::ident)) {
+ // Iterate over all children.
+ let _ = do reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| {
+ let child_def_id = reader::with_doc_data(child_info_doc,
+ parse_def_id);
+ let child_def_id = translate_def_id(cdata, child_def_id);
+
+ // This item may be in yet another crate if it was the child of a
+ // reexport.
+ let other_crates_items = if child_def_id.crate == cdata.cnum {
+ reader::get_doc(reader::Doc(cdata.data), tag_items)
+ } else {
+ let crate_data = get_crate_data(child_def_id.crate);
+ reader::get_doc(reader::Doc(crate_data.data), tag_items)
+ };
+
+ // Get the item.
+ match maybe_find_item(child_def_id.node, other_crates_items) {
+ None => {}
+ Some(child_item_doc) => {
+ // Hand off the item to the callback.
+ let child_name = item_name(intr, child_item_doc);
+ let def_like = item_to_def_like(child_item_doc,
+ child_def_id,
+ cdata.cnum);
+ callback(def_like, child_name);
+
+ }
+ }
+
+ true
+ };
+
+ // As a special case, iterate over all static methods of
+ // associated implementations too. This is a bit of a botch.
+ // --pcwalton
+ let _ = do reader::tagged_docs(item_doc,
+ tag_items_data_item_inherent_impl)
+ |inherent_impl_def_id_doc| {
+ let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc,
+ cdata);
+ let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
+ match maybe_find_item(inherent_impl_def_id.node, items) {
+ None => {}
+ Some(inherent_impl_doc) => {
+ let _ = do reader::tagged_docs(inherent_impl_doc,
+ tag_item_impl_method)
+ |impl_method_def_id_doc| {
+ let impl_method_def_id =
+ reader::with_doc_data(impl_method_def_id_doc,
+ parse_def_id);
+ let impl_method_def_id =
+ translate_def_id(cdata, impl_method_def_id);
+ match maybe_find_item(impl_method_def_id.node, items) {
+ None => {}
+ Some(impl_method_doc) => {
+ match item_family(impl_method_doc) {
+ StaticMethod | UnsafeStaticMethod => {
+ // Hand off the static method
+ // to the callback.
+ let static_method_name =
+ item_name(intr, impl_method_doc);
+ let static_method_def_like =
+ item_to_def_like(impl_method_doc,
+ impl_method_def_id,
+ cdata.cnum);
+ callback(static_method_def_like,
+ static_method_name);
+ }
+ _ => {}
+ }
+ }
+ }
+
+ true
+ };
+ }
+ }
+
+ true
+ };
+
+ // Iterate over all reexports.
+ let _ = do each_reexport(item_doc) |reexport_doc| {
+ let def_id_doc = reader::get_doc(reexport_doc,
+ tag_items_data_item_reexport_def_id);
+ let child_def_id = reader::with_doc_data(def_id_doc,
+ parse_def_id);
+ let child_def_id = translate_def_id(cdata, child_def_id);
+
+ let name_doc = reader::get_doc(reexport_doc,
+ tag_items_data_item_reexport_name);
+ let name = name_doc.as_str_slice();
+
+ // This reexport may be in yet another crate.
+ let other_crates_items = if child_def_id.crate == cdata.cnum {
+ reader::get_doc(reader::Doc(cdata.data), tag_items)
+ } else {
+ let crate_data = get_crate_data(child_def_id.crate);
+ reader::get_doc(reader::Doc(crate_data.data), tag_items)
+ };
+
+ // Get the item.
+ match maybe_find_item(child_def_id.node, other_crates_items) {
+ None => {}
+ Some(child_item_doc) => {
+ // Hand off the item to the callback.
+ let def_like = item_to_def_like(child_item_doc,
+ child_def_id,
+ cdata.cnum);
+ callback(def_like, token::str_to_ident(name));
+ }
+ }
+
+ true
+ };
+}
+
+/// Iterates over each child of the given item.
+pub fn each_child_of_item(intr: @ident_interner,
+ cdata: cmd,
+ id: ast::NodeId,
+ get_crate_data: GetCrateDataCb,
+ callback: &fn(def_like, ast::ident)) {
+ // Find the item.
+ let root_doc = reader::Doc(cdata.data);
+ let items = reader::get_doc(root_doc, tag_items);
+ let item_doc = match maybe_find_item(id, items) {
+ None => return,
+ Some(item_doc) => item_doc,
+ };
+ each_child_of_item_or_crate(intr,
+ cdata,
+ item_doc,
+ get_crate_data,
+ callback)
+}
+
+/// Iterates over all the top-level crate items.
+pub fn each_top_level_item_of_crate(intr: @ident_interner,
+ cdata: cmd,
+ get_crate_data: GetCrateDataCb,
+ callback: &fn(def_like, ast::ident)) {
let root_doc = reader::Doc(cdata.data);
let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
let crate_items_doc = reader::get_doc(misc_info_doc,
tag_misc_info_crate_items);
- let mut path_builder = ~"";
-
- let mut context = EachItemContext {
- intr: intr,
- cdata: cdata,
- get_crate_data: get_crate_data,
- path_builder: &mut path_builder,
- callback: f,
- };
-
- // Iterate over all top-level crate items.
- context.each_child_of_module_or_crate(crate_items_doc)
+ each_child_of_item_or_crate(intr,
+ cdata,
+ crate_items_doc,
+ get_crate_data,
+ callback)
}
pub fn get_item_path(cdata: cmd, id: ast::NodeId) -> ast_map::path {
fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ {
fn get_mutability(ch: u8) -> ast::mutability {
match ch as char {
- 'i' => { ast::m_imm }
- 'm' => { ast::m_mutbl }
- 'c' => { ast::m_const }
- _ => {
- fail!("unknown mutability character: `%c`", ch as char)
- }
+ 'i' => ast::m_imm,
+ 'm' => ast::m_mutbl,
+ _ => fail!("unknown mutability character: `%c`", ch as char),
}
}
{
let method_doc = lookup_item(id, cdata.data);
let def_id = item_def_id(method_doc, cdata);
+
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
method_doc);
+ let container_doc = lookup_item(container_id.node, cdata.data);
+ let container = match item_family(container_doc) {
+ Trait => TraitContainer(container_id),
+ _ => ImplContainer(container_id),
+ };
+
let name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
explicit_self,
vis,
def_id,
- container_id,
+ container,
provided_source
)
}
}
}
-fn iter_crate_items(intr: @ident_interner, cdata: cmd,
- get_crate_data: GetCrateDataCb,
- proc: &fn(path: &str, ast::def_id)) {
- do each_path(intr, cdata, get_crate_data) |path_string, def_like, _| {
- match def_like {
- dl_impl(*) | dl_field => {}
- dl_def(def) => {
- proc(path_string,
- ast_util::def_id_of_def(def))
- }
- }
- true
- };
-}
-
pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8],
out: @io::Writer) {
let hash = get_crate_hash(bytes);
};
result
}
+
+pub fn each_impl(cdata: cmd, callback: &fn(ast::def_id)) {
+ let impls_doc = reader::get_doc(reader::Doc(cdata.data), tag_impls);
+ let _ = do reader::tagged_docs(impls_doc, tag_impls_impl) |impl_doc| {
+ callback(item_def_id(impl_doc, cdata));
+ true
+ };
+}
+
+pub fn each_implementation_for_type(cdata: cmd,
+ id: ast::NodeId,
+ callback: &fn(ast::def_id)) {
+ let item_doc = lookup_item(id, cdata.data);
+ do reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl)
+ |impl_doc| {
+ let implementation_def_id = item_def_id(impl_doc, cdata);
+ callback(implementation_def_id);
+ true
+ };
+}
+
+pub fn each_implementation_for_trait(cdata: cmd,
+ id: ast::NodeId,
+ callback: &fn(ast::def_id)) {
+ let item_doc = lookup_item(id, cdata.data);
+
+ let _ = do reader::tagged_docs(item_doc,
+ tag_items_data_item_extension_impl)
+ |impl_doc| {
+ let implementation_def_id = item_def_id(impl_doc, cdata);
+ callback(implementation_def_id);
+ true
+ };
+}
+
+pub fn get_trait_of_method(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
+ -> Option<ast::def_id> {
+ let item_doc = lookup_item(id, cdata.data);
+ let parent_item_id = match item_parent_item(item_doc) {
+ None => return None,
+ Some(item_id) => item_id,
+ };
+ let parent_item_id = translate_def_id(cdata, parent_item_id);
+ let parent_item_doc = lookup_item(parent_item_id.node, cdata.data);
+ match item_family(parent_item_doc) {
+ Trait => Some(item_def_id(parent_item_doc, cdata)),
+ Impl => {
+ do reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref).map
+ |_| {
+ item_trait_ref(parent_item_doc, tcx, cdata).def_id
+ }
+ }
+ _ => None
+ }
+}
+
use middle::astencode;
use middle;
-use std::hash::HashUtil;
use std::hashmap::{HashMap, HashSet};
use std::io;
use std::str;
use syntax::diagnostic::span_handler;
use syntax::parse::token::special_idents;
use syntax::ast_util;
+use syntax::visit::Visitor;
use syntax::visit;
use syntax::parse::token;
use syntax;
dep_bytes: uint,
lang_item_bytes: uint,
link_args_bytes: uint,
+ impl_bytes: uint,
misc_bytes: uint,
item_bytes: uint,
index_bytes: uint,
fn encode_disr_val(_: &EncodeContext,
ebml_w: &mut writer::Encoder,
- disr_val: uint) {
+ disr_val: ty::Disr) {
ebml_w.start_tag(tag_disr_val);
let s = disr_val.to_str();
ebml_w.writer.write(s.as_bytes());
Some(ref exports) => {
debug!("(encoding info for module) found reexports for %d", id);
for exp in exports.iter() {
- debug!("(encoding info for module) reexport '%s' for %d",
- exp.name, id);
+ debug!("(encoding info for module) reexport '%s' (%d/%d) for \
+ %d",
+ exp.name,
+ exp.def_id.crate,
+ exp.def_id.node,
+ id);
ebml_w.start_tag(tag_items_data_item_reexport);
ebml_w.start_tag(tag_items_data_item_reexport_def_id);
ebml_w.wr_str(def_to_str(exp.def_id));
fn encode_mutability(ebml_w: &writer::Encoder,
m: ast::mutability) {
match m {
- m_imm => {
- ebml_w.writer.write(&[ 'i' as u8 ]);
- }
- m_mutbl => {
- ebml_w.writer.write(&[ 'm' as u8 ]);
- }
- m_const => {
- ebml_w.writer.write(&[ 'c' as u8 ]);
- }
+ m_imm => ebml_w.writer.write(&[ 'i' as u8 ]),
+ m_mutbl => ebml_w.writer.write(&[ 'm' as u8 ]),
}
}
}
}
}
+// Encodes the inherent implementations of a structure, enumeration, or trait.
+fn encode_inherent_implementations(ecx: &EncodeContext,
+ ebml_w: &mut writer::Encoder,
+ def_id: def_id) {
+ match ecx.tcx.inherent_impls.find(&def_id) {
+ None => {}
+ Some(&implementations) => {
+ for implementation in implementations.iter() {
+ ebml_w.start_tag(tag_items_data_item_inherent_impl);
+ encode_def_id(ebml_w, implementation.did);
+ ebml_w.end_tag();
+ }
+ }
+ }
+}
+
+// Encodes the implementations of a trait defined in this crate.
+fn encode_extension_implementations(ecx: &EncodeContext,
+ ebml_w: &mut writer::Encoder,
+ trait_def_id: def_id) {
+ match ecx.tcx.trait_impls.find(&trait_def_id) {
+ None => {}
+ Some(&implementations) => {
+ for implementation in implementations.iter() {
+ ebml_w.start_tag(tag_items_data_item_extension_impl);
+ encode_def_id(ebml_w, implementation.did);
+ ebml_w.end_tag();
+ }
+ }
+ }
+}
+
fn encode_info_for_item(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
item: @item,
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
+
+ // Encode inherent implementations for this enumeration.
+ encode_inherent_implementations(ecx, ebml_w, def_id);
+
ebml_w.end_tag();
encode_enum_variant_info(ecx,
}
}
+ // Encode inherent implementations for this structure.
+ encode_inherent_implementations(ecx, ebml_w, def_id);
+
/* Each class has its own index -- encode it */
let bkts = create_index(idx);
encode_index(ebml_w, bkts, write_i64);
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
match ty.node {
- ast::ty_path(ref path, ref bounds, _) if path.idents.len() == 1 => {
+ ast::ty_path(ref path, ref bounds, _) if path.segments
+ .len() == 1 => {
assert!(bounds.is_none());
encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path));
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
}
+
+ // Encode the implementations of this trait.
+ encode_extension_implementations(ecx, ebml_w, def_id);
+
ebml_w.end_tag();
// Now output the method info for each method.
ebml_w.end_tag();
}
+
+ // Encode inherent implementations for this trait.
+ encode_inherent_implementations(ecx, ebml_w, def_id);
}
item_mac(*) => fail!("item macros unimplemented")
}
}
impl visit::Visitor<()> for EncodeVisitor {
- fn visit_expr(&mut self, ex:@expr, _:()) { my_visit_expr(ex); }
+ fn visit_expr(&mut self, ex:@expr, _:()) {
+ visit::walk_expr(self, ex, ());
+ my_visit_expr(ex);
+ }
fn visit_item(&mut self, i:@item, _:()) {
visit::walk_item(self, i, ());
my_visit_item(i,
ebml_w.end_tag();
}
+struct ImplVisitor<'self> {
+ ecx: &'self EncodeContext<'self>,
+ ebml_w: &'self mut writer::Encoder,
+}
+
+impl<'self> Visitor<()> for ImplVisitor<'self> {
+ fn visit_item(&mut self, item: @item, _: ()) {
+ match item.node {
+ item_impl(_, Some(ref trait_ref), _, _) => {
+ let def_map = self.ecx.tcx.def_map;
+ let trait_def = def_map.get_copy(&trait_ref.ref_id);
+ let def_id = ast_util::def_id_of_def(trait_def);
+
+ // Load eagerly if this is an implementation of the Drop trait
+ // or if the trait is not defined in this crate.
+ if def_id == self.ecx.tcx.lang_items.drop_trait().unwrap() ||
+ def_id.crate != LOCAL_CRATE {
+ self.ebml_w.start_tag(tag_impls_impl);
+ encode_def_id(self.ebml_w, local_def(item.id));
+ self.ebml_w.end_tag();
+ }
+ }
+ _ => {}
+ }
+ visit::walk_item(self, item, ());
+ }
+}
+
+/// Encodes implementations that are eagerly loaded.
+///
+/// None of this is necessary in theory; we can load all implementations
+/// lazily. However, in two cases the optimizations to lazily load
+/// implementations are not yet implemented. These two cases, which require us
+/// to load implementations eagerly, are:
+///
+/// * Destructors (implementations of the Drop trait).
+///
+/// * Implementations of traits not defined in this crate.
+fn encode_impls(ecx: &EncodeContext,
+ crate: &Crate,
+ ebml_w: &mut writer::Encoder) {
+ ebml_w.start_tag(tag_impls);
+
+ {
+ let mut visitor = ImplVisitor {
+ ecx: ecx,
+ ebml_w: ebml_w,
+ };
+ visit::walk_crate(&mut visitor, crate, ());
+ }
+
+ ebml_w.end_tag();
+}
+
fn encode_misc_info(ecx: &EncodeContext,
crate: &Crate,
ebml_w: &mut writer::Encoder) {
dep_bytes: 0,
lang_item_bytes: 0,
link_args_bytes: 0,
+ impl_bytes: 0,
misc_bytes: 0,
item_bytes: 0,
index_bytes: 0,
encode_link_args(&ecx, &mut ebml_w);
ecx.stats.link_args_bytes = *wr.pos - i;
+ // Encode the def IDs of impls, for coherence checking.
+ i = *wr.pos;
+ encode_impls(&ecx, crate, &mut ebml_w);
+ ecx.stats.impl_bytes = *wr.pos - i;
+
// Encode miscellaneous info.
i = *wr.pos;
encode_misc_info(&ecx, crate, &mut ebml_w);
printfln!(" dep bytes: %u", ecx.stats.dep_bytes);
printfln!(" lang item bytes: %u", ecx.stats.lang_item_bytes);
printfln!(" link args bytes: %u", ecx.stats.link_args_bytes);
+ printfln!(" impl bytes: %u", ecx.stats.impl_bytes);
printfln!(" misc bytes: %u", ecx.stats.misc_bytes);
printfln!(" item bytes: %u", ecx.stats.item_bytes);
printfln!(" index bytes: %u", ecx.stats.index_bytes);
use std::os;
use std::hashmap::HashSet;
+pub enum FileMatch { FileMatches, FileDoesntMatch }
+
// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.
/// Functions with type `pick` take a parent directory as well as
/// a file found in that directory.
-pub type pick<'self, T> = &'self fn(path: &Path) -> Option<T>;
+pub type pick<'self> = &'self fn(path: &Path) -> FileMatch;
pub fn pick_file(file: Path, path: &Path) -> Option<Path> {
if path.file_path() == file {
pub trait FileSearch {
fn sysroot(&self) -> @Path;
- fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool;
+ fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch);
fn get_target_lib_path(&self) -> Path;
fn get_target_lib_file_path(&self, file: &Path) -> Path;
}
}
impl FileSearch for FileSearchImpl {
fn sysroot(&self) -> @Path { self.sysroot }
- fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
+ fn for_each_lib_search_path(&self, f: &fn(&Path) -> FileMatch) {
let mut visited_dirs = HashSet::new();
+ let mut found = false;
debug!("filesearch: searching additional lib search paths [%?]",
self.addl_lib_search_paths.len());
for path in self.addl_lib_search_paths.iter() {
- f(path);
+ match f(path) {
+ FileMatches => found = true,
+ FileDoesntMatch => ()
+ }
visited_dirs.insert(path.to_str());
}
let tlib_path = make_target_lib_path(self.sysroot,
self.target_triple);
if !visited_dirs.contains(&tlib_path.to_str()) {
- if !f(&tlib_path) {
- return false;
+ match f(&tlib_path) {
+ FileMatches => found = true,
+ FileDoesntMatch => ()
}
}
visited_dirs.insert(tlib_path.to_str());
// Try RUST_PATH
- let rustpath = rust_path();
- for path in rustpath.iter() {
+ if !found {
+ let rustpath = rust_path();
+ for path in rustpath.iter() {
+ debug!("is %s in visited_dirs? %?",
+ path.push("lib").to_str(),
+ visited_dirs.contains(&path.push("lib").to_str()));
+
if !visited_dirs.contains(&path.push("lib").to_str()) {
- f(&path.push("lib"));
visited_dirs.insert(path.push("lib").to_str());
+ // 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(&path.push("lib")) {
+ FileMatches => {
+ break;
+ }
+ FileDoesntMatch => ()
+ }
}
+ }
}
- true
}
fn get_target_lib_path(&self) -> Path {
make_target_lib_path(self.sysroot, self.target_triple)
} as @FileSearch
}
-pub fn search<T>(filesearch: @FileSearch, pick: pick<T>) -> Option<T> {
- let mut rslt = None;
+pub fn search(filesearch: @FileSearch, pick: pick) {
do filesearch.for_each_lib_search_path() |lib_search_path| {
debug!("searching %s", lib_search_path.to_str());
let r = os::list_dir_path(lib_search_path);
+ let mut rslt = FileDoesntMatch;
for path in r.iter() {
debug!("testing %s", path.to_str());
let maybe_picked = pick(path);
match maybe_picked {
- Some(_) => {
+ FileMatches => {
debug!("picked %s", path.to_str());
- rslt = maybe_picked;
- break;
+ rslt = FileMatches;
}
- None => {
+ FileDoesntMatch => {
debug!("rejected %s", path.to_str());
}
}
}
- rslt.is_none()
+ rslt
};
- return rslt;
}
pub fn relative_target_lib_path(target_triple: &str) -> Path {
use lib::llvm::{False, llvm, mk_object_file, mk_section_iter};
use metadata::decoder;
use metadata::encoder;
-use metadata::filesearch::FileSearch;
+use metadata::filesearch::{FileSearch, FileMatch, FileMatches, FileDoesntMatch};
use metadata::filesearch;
use syntax::codemap::span;
use syntax::diagnostic::span_handler;
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
let prefix = fmt!("%s%s-", prefix, crate_name);
let mut matches = ~[];
- filesearch::search(filesearch, |path| -> Option<()> {
+ filesearch::search(filesearch, |path| -> FileMatch {
let path_str = path.filename();
match path_str {
- None => None,
+ None => FileDoesntMatch,
Some(path_str) =>
if path_str.starts_with(prefix) && path_str.ends_with(suffix) {
debug!("%s is a candidate", path.to_str());
if !crate_matches(cvec, cx.metas, cx.hash) {
debug!("skipping %s, metadata doesn't match",
path.to_str());
- None
+ FileDoesntMatch
} else {
debug!("found %s with matching metadata", path.to_str());
matches.push((path.to_str(), cvec));
- None
+ FileMatches
},
_ => {
debug!("could not load metadata for %s", path.to_str());
- None
+ FileDoesntMatch
}
}
}
else {
- None
+ FileDoesntMatch
}
}
});
':' => { next(st); next(st); }
c => {
if c == '(' {
- return @ast::Path { span: dummy_sp(),
- global: false,
- idents: idents,
- rp: None,
- types: ~[] };
- } else { idents.push(parse_ident_(st, is_last)); }
+ return @ast::Path {
+ span: dummy_sp(),
+ global: false,
+ segments: idents.move_iter().map(|identifier| {
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect()
+ };
+ } else {
+ idents.push(parse_ident_(st, is_last));
+ }
}
}
};
fn parse_mutability(st: &mut PState) -> ast::mutability {
match peek(st) {
'm' => { next(st); ast::m_mutbl }
- '?' => { next(st); ast::m_const }
_ => { ast::m_imm }
}
}
match mt {
m_imm => (),
m_mutbl => w.write_char('m'),
- m_const => w.write_char('?')
}
}
fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def {
match *self {
ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p),
- ast::def_static_method(did, did2_opt, p) => {
+ ast::def_static_method(did, wrapped_did2, p) => {
ast::def_static_method(did.tr(xcx),
- did2_opt.map(|did2| did2.tr(xcx)),
+ match wrapped_did2 {
+ ast::FromTrait(did2) => {
+ ast::FromTrait(did2.tr(xcx))
+ }
+ ast::FromImpl(did2) => {
+ ast::FromImpl(did2.tr(xcx))
+ }
+ },
p)
}
ast::def_method(did0, did1) => {
ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
}
ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
- ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
+ ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }
use middle::borrowck::*;
use middle::moves;
use middle::ty;
-use syntax::ast::{m_mutbl, m_imm, m_const};
+use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
-use syntax::visit;
use syntax::visit::Visitor;
+use syntax::visit;
use util::ppaux::Repr;
#[deriving(Clone)]
}
impl<'self> CheckLoanCtxt<'self> {
+ fn check_by_move_capture(&self,
+ closure_id: ast::NodeId,
+ cap_var: &moves::CaptureVar,
+ move_path: @LoanPath) {
+ let move_err = self.analyze_move_out_from(closure_id, move_path);
+ match move_err {
+ MoveOk => {}
+ MoveWhileBorrowed(loan_path, loan_span) => {
+ self.bccx.span_err(
+ cap_var.span,
+ fmt!("cannot move `%s` into closure \
+ because it is borrowed",
+ self.bccx.loan_path_to_str(move_path)));
+ self.bccx.span_note(
+ loan_span,
+ fmt!("borrow of `%s` occurs here",
+ self.bccx.loan_path_to_str(loan_path)));
+ }
+ }
+ }
+
+ fn check_captured_variables(&self, closure_id: ast::NodeId, span: span) {
+ let cap_vars = self.bccx.capture_map.get(&closure_id);
+ for cap_var in cap_vars.iter() {
+ let var_id = ast_util::def_id_of_def(cap_var.def).node;
+ let var_path = @LpVar(var_id);
+ self.check_if_path_is_moved(closure_id, span,
+ MovedInCapture, var_path);
+ match cap_var.mode {
+ moves::CapRef | moves::CapCopy => {}
+ moves::CapMove => {
+ self.check_by_move_capture(closure_id, cap_var, var_path);
+ }
+ }
+ }
+ return;
+ }
+
pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
pub fn each_issued_loan(&self,
// Restrictions that would cause the new loan to be illegal:
let illegal_if = match loan2.mutbl {
- m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
- m_imm => RESTR_ALIAS | RESTR_FREEZE,
- m_const => RESTR_ALIAS,
+ MutableMutability => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
+ ImmutableMutability => RESTR_ALIAS | RESTR_FREEZE,
+ ConstMutability => RESTR_ALIAS,
};
debug!("illegal_if=%?", illegal_if);
if restr.loan_path != loan2.loan_path { loop; }
match (new_loan.mutbl, old_loan.mutbl) {
- (m_mutbl, m_mutbl) => {
+ (MutableMutability, MutableMutability) => {
self.bccx.span_err(
new_loan.span,
fmt!("cannot borrow `%s` as mutable \
mc::cat_rvalue(*) |
mc::cat_static_item |
- mc::cat_implicit_self |
mc::cat_copied_upvar(*) |
mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
mc::cat_deref(_, _, mc::gc_ptr(*)) |
mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
// Statically prohibit writes to `&mut` when aliasable
- match b.freely_aliasable() {
- None => {}
- Some(cause) => {
- this.bccx.report_aliasability_violation(
- expr.span,
- MutabilityViolation,
- cause);
- }
- }
+ check_for_aliasability_violation(this, expr, b);
}
mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
return true; // no errors reported
}
+ fn check_for_aliasability_violation(this: &CheckLoanCtxt,
+ expr: @ast::expr,
+ cmt: mc::cmt) -> bool {
+ let mut cmt = cmt;
+
+ loop {
+ match cmt.cat {
+ mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
+ mc::cat_downcast(b) |
+ mc::cat_stack_upvar(b) |
+ mc::cat_deref(b, _, mc::uniq_ptr) |
+ mc::cat_interior(b, _) |
+ mc::cat_discr(b, _) => {
+ // Aliasability depends on base cmt
+ cmt = b;
+ }
+
+ mc::cat_copied_upvar(_) |
+ mc::cat_rvalue(*) |
+ mc::cat_local(*) |
+ mc::cat_arg(_) |
+ mc::cat_self(*) |
+ mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
+ mc::cat_static_item(*) |
+ mc::cat_deref(_, _, mc::gc_ptr(_)) |
+ mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
+ // Aliasability is independent of base cmt
+ match cmt.freely_aliasable() {
+ None => {
+ return true;
+ }
+ Some(cause) => {
+ this.bccx.report_aliasability_violation(
+ expr.span,
+ MutabilityViolation,
+ cause);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
fn check_for_assignment_to_restricted_or_frozen_location(
this: &CheckLoanCtxt,
expr: @ast::expr,
// path, and check that the super path was not lent out as
// mutable or immutable (a const loan is ok).
//
+ // Mutability of a path can be dependent on the super path
+ // in two ways. First, it might be inherited mutability.
+ // Second, the pointee of an `&mut` pointer can only be
+ // mutated if it is found in an unaliased location, so we
+ // have to check that the owner location is not borrowed.
+ //
// Note that we are *not* checking for any and all
// restrictions. We are only interested in the pointers
// that the user created, whereas we add restrictions for
let mut loan_path = loan_path;
loop {
match *loan_path {
- // Peel back one layer if `loan_path` has
- // inherited mutability
- LpExtend(lp_base, mc::McInherited, _) => {
+ // Peel back one layer if, for `loan_path` to be
+ // mutable, `lp_base` must be mutable. This occurs
+ // with inherited mutability and with `&mut`
+ // pointers.
+ LpExtend(lp_base, mc::McInherited, _) |
+ LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
loan_path = lp_base;
}
// Otherwise stop iterating
LpExtend(_, mc::McDeclared, _) |
LpExtend(_, mc::McImmutable, _) |
- LpExtend(_, mc::McReadOnly, _) |
LpVar(_) => {
return true;
}
// Check for a non-const loan of `loan_path`
let cont = do this.each_in_scope_loan(expr.id) |loan| {
- if loan.loan_path == loan_path && loan.mutbl != m_const {
- this.report_illegal_mutation(expr, full_loan_path, loan);
+ if loan.loan_path == loan_path &&
+ loan.mutbl != ConstMutability {
+ this.report_illegal_mutation(expr,
+ full_loan_path,
+ loan);
false
} else {
true
visit::walk_block(vt, blk, this);
this.check_for_conflicting_loans(blk.id);
}
+
cmt0: mc::cmt,
cmt: mc::cmt) -> bool {
match cmt.cat {
- mc::cat_implicit_self(*) |
mc::cat_deref(_, _, mc::region_ptr(*)) |
mc::cat_deref(_, _, mc::gc_ptr(*)) |
mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
-use syntax::ast::{m_const, m_imm, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use util::ppaux::{note_and_explain_region};
span: span,
cmt: mc::cmt,
loan_region: ty::Region,
- loan_mutbl: ast::mutability) {
+ loan_mutbl: LoanMutability) {
debug!("guarantee_lifetime(cmt=%s, loan_region=%s)",
cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
span: span,
loan_region: ty::Region,
- loan_mutbl: ast::mutability,
+ loan_mutbl: LoanMutability,
cmt_original: mc::cmt
}
match cmt.cat {
mc::cat_rvalue(*) |
- mc::cat_implicit_self |
mc::cat_copied_upvar(*) | // L-Local
mc::cat_local(*) | // L-Local
mc::cat_arg(*) | // L-Local
// we need to dynamically mark it to prevent incompatible
// borrows from happening later.
let opt_dyna = match ptr_mutbl {
- m_imm | m_const => None,
+ m_imm => None,
m_mutbl => {
match self.loan_mutbl {
- m_mutbl => Some(DynaMut),
- m_imm | m_const => Some(DynaImm)
+ MutableMutability => Some(DynaMut),
+ ImmutableMutability | ConstMutability => Some(DynaImm)
}
}
};
}
mc::cat_rvalue(*) |
mc::cat_static_item |
- mc::cat_implicit_self |
mc::cat_copied_upvar(*) |
mc::cat_deref(*) => {
false
mc::cat_rvalue(cleanup_scope_id) => {
ty::re_scope(cleanup_scope_id)
}
- mc::cat_implicit_self |
mc::cat_copied_upvar(_) => {
ty::re_scope(self.item_scope_id)
}
use util::common::indenter;
use util::ppaux::{Repr};
-use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::ast_util::id_range;
use syntax::codemap::span;
// make sure that the thing we are pointing out stays valid
// for the lifetime `scope_r` of the resulting ptr:
let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex));
- this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r);
+ this.guarantee_valid(ex.id,
+ ex.span,
+ base_cmt,
+ LoanMutability::from_ast_mutability(mutbl),
+ scope_r);
visit::walk_expr(v, ex, this);
}
// adjustments).
let scope_r = ty::re_scope(ex.id);
let arg_cmt = this.bccx.cat_expr(arg);
- this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
+ this.guarantee_valid(arg.id,
+ arg.span,
+ arg_cmt,
+ ImmutableMutability,
+ scope_r);
visit::walk_expr(v, ex, this);
}
match *autoref {
ty::AutoPtr(r, m) => {
+ let loan_mutability =
+ LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt,
- m,
+ loan_mutability,
r)
}
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
+ let loan_mutability =
+ LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt_index,
- m,
+ loan_mutability,
r)
}
ty::AutoBorrowFn(r) => {
self.guarantee_valid(expr.id,
expr.span,
cmt_deref,
- m_imm,
+ ImmutableMutability,
r)
}
ty::AutoBorrowObj(r, m) => {
let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
+ let loan_mutability =
+ LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt_deref,
- m,
+ loan_mutability,
r)
}
ty::AutoUnsafe(_) => {}
borrow_id: ast::NodeId,
borrow_span: span,
cmt: mc::cmt,
- req_mutbl: ast::mutability,
+ req_mutbl: LoanMutability,
loan_region: ty::Region) {
debug!("guarantee_valid(borrow_id=%?, cmt=%s, \
req_mutbl=%?, loan_region=%?)",
let kill_scope = self.compute_kill_scope(loan_scope, loan_path);
debug!("kill_scope = %?", kill_scope);
- if req_mutbl == m_mutbl {
+ if req_mutbl == MutableMutability {
self.mark_loan_path_as_mutated(loan_path);
}
// index: all_loans.len(),
// loan_path: loan_path,
// cmt: cmt,
- // mutbl: m_const,
+ // mutbl: ConstMutability,
// gen_scope: borrow_id,
// kill_scope: kill_scope,
// span: borrow_span,
fn check_mutability(bccx: @BorrowckCtxt,
borrow_span: span,
cmt: mc::cmt,
- req_mutbl: ast::mutability) {
+ req_mutbl: LoanMutability) {
//! Implements the M-* rules in doc.rs.
match req_mutbl {
- m_const => {
+ ConstMutability => {
// Data of any mutability can be lent as const.
}
- m_imm => {
- match cmt.mutbl {
- mc::McImmutable | mc::McDeclared | mc::McInherited => {
- // both imm and mut data can be lent as imm;
- // for mutable data, this is a freeze
- }
- mc::McReadOnly => {
- bccx.report(BckError {span: borrow_span,
- cmt: cmt,
- code: err_mutbl(req_mutbl)});
- }
- }
+ ImmutableMutability => {
+ // both imm and mut data can be lent as imm;
+ // for mutable data, this is a freeze
}
- m_mutbl => {
+ MutableMutability => {
// Only mutable data can be lent as mutable.
if !cmt.mutbl.is_mutable() {
bccx.report(BckError {span: borrow_span,
}
}
- pub fn restriction_set(&self, req_mutbl: ast::mutability)
+ pub fn restriction_set(&self, req_mutbl: LoanMutability)
-> RestrictionSet {
match req_mutbl {
- m_const => RESTR_EMPTY,
- m_imm => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
- m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
+ ConstMutability => RESTR_EMPTY,
+ ImmutableMutability => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
+ MutableMutability => {
+ RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
+ }
}
}
self.mark_loan_path_as_mutated(base);
}
LpExtend(_, mc::McDeclared, _) |
- LpExtend(_, mc::McImmutable, _) |
- LpExtend(_, mc::McReadOnly, _) => {
+ LpExtend(_, mc::McImmutable, _) => {
+ // Nothing to do.
}
}
}
}
}
};
- self.guarantee_valid(pat.id, pat.span,
- cmt_discr, mutbl, scope_r);
+ let loan_mutability =
+ LoanMutability::from_ast_mutability(mutbl);
+ self.guarantee_valid(pat.id,
+ pat.span,
+ cmt_discr,
+ loan_mutability,
+ scope_r);
}
ast::bind_infer => {
// No borrows here, but there may be moves
self.vec_slice_info(slice_pat, slice_ty);
let mcx = self.bccx.mc_ctxt();
let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
+ let slice_loan_mutability =
+ LoanMutability::from_ast_mutability(slice_mutbl);
// Note: We declare here that the borrow occurs upon
// entering the `[...]` pattern. This implies that
// trans do the right thing, and it would only work
// for `~` vectors. It seems simpler to just require
// that people call `vec.pop()` or `vec.unshift()`.
- self.guarantee_valid(pat.id, pat.span,
- cmt_index, slice_mutbl, slice_r);
+ self.guarantee_valid(pat.id,
+ pat.span,
+ cmt_index,
+ slice_loan_mutability,
+ slice_r);
}
_ => {}
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
-use syntax::ast::{m_const, m_imm, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
use syntax::codemap::span;
pub enum RestrictionResult {
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
}
- mc::cat_deref(cmt_base, _, mc::uniq_ptr) => {
+ mc::cat_deref(cmt_base, _, pk @ mc::uniq_ptr) => {
// R-Deref-Send-Pointer
//
// When we borrow the interior of an owned pointer, we
let result = self.restrict(
cmt_base,
restrictions | RESTR_MUTATE | RESTR_CLAIM);
- self.extend(result, cmt.mutbl, LpDeref, restrictions)
+ self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
}
mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars
mc::cat_static_item(*) |
- mc::cat_implicit_self(*) |
mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) |
mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => {
// R-Deref-Imm-Borrowed
Safe
}
- mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
- mc::cat_deref(_, _, mc::gc_ptr(m_const)) => {
- // R-Deref-Freeze-Borrowed
- self.check_no_mutability_control(cmt, restrictions);
- Safe
- }
-
- mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => {
+ mc::cat_deref(cmt_base, _, pk @ mc::gc_ptr(m_mutbl)) => {
// R-Deref-Managed-Borrowed
//
// Technically, no restrictions are *necessary* here.
match opt_loan_path(cmt_base) {
None => Safe,
Some(lp_base) => {
- let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref);
+ let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref(pk));
SafeIf(lp, ~[Restriction {loan_path: lp,
set: restrictions}])
}
}
}
- mc::cat_deref(cmt_base, _, mc::region_ptr(m_mutbl, _)) => {
+ mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(m_mutbl, _)) => {
// Because an `&mut` pointer does not inherit its
// mutability, we can only prevent mutation or prevent
// freezing if it is not aliased. Therefore, in such
let result = self.restrict(
cmt_base,
RESTR_ALIAS | RESTR_MUTATE | RESTR_CLAIM);
- self.extend(result, cmt.mutbl, LpDeref, restrictions)
+ self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
} else {
// R-Deref-Mut-Borrowed-2
Safe
///////////////////////////////////////////////////////////////////////////
// Loans and loan paths
+#[deriving(Clone, Eq)]
+pub enum LoanMutability {
+ ImmutableMutability,
+ ConstMutability,
+ MutableMutability,
+}
+
+impl LoanMutability {
+ pub fn from_ast_mutability(ast_mutability: ast::mutability)
+ -> LoanMutability {
+ match ast_mutability {
+ ast::m_imm => ImmutableMutability,
+ ast::m_mutbl => MutableMutability,
+ }
+ }
+}
+
+impl ToStr for LoanMutability {
+ fn to_str(&self) -> ~str {
+ match *self {
+ ImmutableMutability => ~"immutable",
+ ConstMutability => ~"read-only",
+ MutableMutability => ~"mutable",
+ }
+ }
+}
+
/// Record of a loan that was issued.
pub struct Loan {
index: uint,
loan_path: @LoanPath,
cmt: mc::cmt,
- mutbl: ast::mutability,
+ mutbl: LoanMutability,
restrictions: ~[Restriction],
gen_scope: ast::NodeId,
kill_scope: ast::NodeId,
#[deriving(Eq, IterBytes)]
pub enum LoanPathElem {
- LpDeref, // `*LV` in doc.rs
+ LpDeref(mc::PointerKind), // `*LV` in doc.rs
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
}
match cmt.cat {
mc::cat_rvalue(*) |
mc::cat_static_item |
- mc::cat_copied_upvar(_) |
- mc::cat_implicit_self => {
+ mc::cat_copied_upvar(_) => {
None
}
Some(@LpVar(id))
}
- mc::cat_deref(cmt_base, _, _) => {
+ mc::cat_deref(cmt_base, _, pk) => {
do opt_loan_path(cmt_base).map_move |lp| {
- @LpExtend(lp, cmt.mutbl, LpDeref)
+ @LpExtend(lp, cmt.mutbl, LpDeref(pk))
}
}
// Errors that can occur
#[deriving(Eq)]
pub enum bckerr_code {
- err_mutbl(ast::mutability),
+ err_mutbl(LoanMutability),
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
err_freeze_aliasable_const
loan_path: &LoanPath,
out: &mut ~str) {
match *loan_path {
- LpExtend(_, _, LpDeref) => {
+ LpExtend(_, _, LpDeref(_)) => {
out.push_char('(');
self.append_loan_path_to_str(loan_path, out);
out.push_char(')');
out.push_str("[]");
}
- LpExtend(lp_base, _, LpDeref) => {
+ LpExtend(lp_base, _, LpDeref(_)) => {
out.push_char('*');
self.append_loan_path_to_str(lp_base, out);
}
mc.cmt_to_str(cmt)
}
- pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
- let mc = &mc::mem_categorization_ctxt {tcx: self.tcx,
- method_map: self.method_map};
- mc.mut_to_str(mutbl)
+ pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str {
+ mutbl.to_str()
}
pub fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str {
match mutbl {
ast::m_imm => "",
- ast::m_const => "const",
- ast::m_mutbl => "mut"
+ ast::m_mutbl => "mut",
}
}
}
fmt!("$(%?)", id)
}
- &LpExtend(lp, _, LpDeref) => {
+ &LpExtend(lp, _, LpDeref(_)) => {
fmt!("%s.*", lp.repr(tcx))
}
// to handle on-demand instantiation of functions via
// foo::<bar> in a const. Currently that is only done on
// a path in trans::callee that only works in block contexts.
- if pth.types.len() != 0 {
+ if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
sess.span_err(
e.span, "paths in constants may only refer to \
items without type parameters");
* lint attributes.
*
* At each node of the ast which can modify lint attributes, all known lint
- * passes are also applied. Each lint pass is an oldvisit::vt<()> structure.
+ * passes are also applied. Each lint pass is a visit::Visitor implementator.
* The visitors are constructed via the lint_*() functions below. There are
* also some lint checks which operate directly on ast nodes (such as
* @ast::item), and those are organized as check_item_*(). Each visitor added
}
}
- fn add_oldvisit_lint(&mut self, v: @mut OuterLint) {
+ fn add_old_lint(&mut self, v: @mut OuterLint) {
self.visitors.push(OldVisitor(v, v.inner_variant()));
}
}
}
}
- // Can't use oldvisit::visit_method_helper because the
+ // Can't use visit::walk_method_helper because the
// item_stopping_visitor has overridden visit_fn(&fk_method(... ))
// to be a no-op, so manually invoke visit_fn.
Method(m) => {
}
// Register each of the lint passes with the context
- cx.add_oldvisit_lint(lint_while_true());
- cx.add_oldvisit_lint(lint_path_statement());
- cx.add_oldvisit_lint(lint_heap());
- cx.add_oldvisit_lint(lint_type_limits());
- cx.add_oldvisit_lint(lint_unused_unsafe());
- cx.add_oldvisit_lint(lint_unused_mut());
- cx.add_oldvisit_lint(lint_unnecessary_allocations());
- cx.add_oldvisit_lint(lint_missing_doc());
+ cx.add_old_lint(lint_while_true());
+ cx.add_old_lint(lint_path_statement());
+ cx.add_old_lint(lint_heap());
+ cx.add_old_lint(lint_type_limits());
+ cx.add_old_lint(lint_unused_unsafe());
+ cx.add_old_lint(lint_unused_mut());
+ cx.add_old_lint(lint_unnecessary_allocations());
+ cx.add_old_lint(lint_missing_doc());
cx.add_lint(lint_session(cx));
// Actually perform the lint checks (iterating the ast)
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
use util::common::indenter;
-use syntax::ast::{m_imm, m_const, m_mutbl};
+use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use syntax::print::pprust;
#[deriving(Eq)]
pub enum categorization {
- cat_rvalue(ast::NodeId), // temporary val, argument is its scope
+ cat_rvalue(ast::NodeId), // temporary val, argument is its scope
cat_static_item,
- cat_implicit_self,
cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env
cat_stack_upvar(cmt), // by ref upvar from &fn
- cat_local(ast::NodeId), // local variable
- cat_arg(ast::NodeId), // formal argument
- cat_deref(cmt, uint, ptr_kind), // deref of a ptr
+ cat_local(ast::NodeId), // local variable
+ cat_arg(ast::NodeId), // formal argument
+ cat_deref(cmt, uint, PointerKind), // deref of a ptr
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
cat_downcast(cmt), // selects a particular enum variant (*)
- cat_discr(cmt, ast::NodeId), // match discriminant (see preserve())
- cat_self(ast::NodeId), // explicit `self`
+ cat_discr(cmt, ast::NodeId), // match discriminant (see preserve())
+ cat_self(ast::NodeId), // explicit `self`
// (*) downcast is only required if the enum has more than one variant
}
}
// different kinds of pointers:
-#[deriving(Eq)]
-pub enum ptr_kind {
+#[deriving(Eq, IterBytes)]
+pub enum PointerKind {
uniq_ptr,
gc_ptr(ast::mutability),
region_ptr(ast::mutability, ty::Region),
#[deriving(Eq, IterBytes)]
pub enum MutabilityCategory {
McImmutable, // Immutable.
- McReadOnly, // Read-only (`const`)
McDeclared, // Directly declared as mutable.
McInherited // Inherited from the fact that owner is mutable.
}
// We pun on *T to mean both actual deref of a ptr as well
// as accessing of components:
pub enum deref_kind {
- deref_ptr(ptr_kind),
+ deref_ptr(PointerKind),
deref_interior(InteriorKind),
}
pub fn from_mutbl(m: ast::mutability) -> MutabilityCategory {
match m {
m_imm => McImmutable,
- m_const => McReadOnly,
m_mutbl => McDeclared
}
}
pub fn inherit(&self) -> MutabilityCategory {
match *self {
McImmutable => McImmutable,
- McReadOnly => McReadOnly,
McDeclared => McInherited,
McInherited => McInherited
}
pub fn is_mutable(&self) -> bool {
match *self {
- McImmutable | McReadOnly => false,
+ McImmutable => false,
McDeclared | McInherited => true
}
}
pub fn is_immutable(&self) -> bool {
match *self {
McImmutable => true,
- McReadOnly | McDeclared | McInherited => false
+ McDeclared | McInherited => false
}
}
match *self {
McDeclared | McInherited => "mutable",
McImmutable => "immutable",
- McReadOnly => "const"
}
}
}
}
}
- ast::def_self(self_id, is_implicit) => {
- let cat = if is_implicit {
- cat_implicit_self
- } else {
- cat_self(self_id)
- };
-
+ ast::def_self(self_id) => {
@cmt_ {
id:id,
span:span,
- cat:cat,
+ cat:cat_self(self_id),
mutbl: McImmutable,
ty:expr_ty
}
-> MutabilityCategory {
match interior_m {
m_imm => base_m.inherit(),
- m_const => McReadOnly,
m_mutbl => McDeclared
}
}
pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
match mutbl {
m_mutbl => ~"mutable",
- m_const => ~"const",
m_imm => ~"immutable"
}
}
cat_static_item => {
~"static item"
}
- cat_implicit_self => {
- ~"self reference"
- }
cat_copied_upvar(_) => {
~"captured outer variable in a heap closure"
}
match self.cat {
cat_rvalue(*) |
cat_static_item |
- cat_implicit_self |
cat_copied_upvar(*) |
cat_local(*) |
cat_self(*) |
}
pub fn freely_aliasable(&self) -> Option<AliasableReason> {
- //! True if this lvalue resides in an area that is
- //! freely aliasable, meaning that rustc cannot track
- //! the alias//es with precision.
+ /*!
+ * Returns `Some(_)` if this lvalue represents a freely aliasable
+ * pointer type.
+ */
// Maybe non-obvious: copied upvars can only be considered
// non-aliasable in once closures, since any other kind can be
}
cat_copied_upvar(CopiedUpvar {onceness: ast::Many, _}) |
- cat_static_item(*) |
- cat_implicit_self(*) => {
+ cat_static_item(*) => {
Some(AliasableOther)
}
Some(AliasableManaged(m))
}
- cat_deref(_, _, region_ptr(m @ m_const, _)) |
cat_deref(_, _, region_ptr(m @ m_imm, _)) => {
Some(AliasableBorrowed(m))
}
- cat_downcast(b) |
- cat_stack_upvar(b) |
- cat_deref(b, _, uniq_ptr) |
- cat_interior(b, _) |
- cat_discr(b, _) => {
- b.freely_aliasable()
+ cat_downcast(*) |
+ cat_stack_upvar(*) |
+ cat_deref(_, _, uniq_ptr) |
+ cat_interior(*) |
+ cat_discr(*) => {
+ None
}
}
}
fn repr(&self, tcx: ty::ctxt) -> ~str {
match *self {
cat_static_item |
- cat_implicit_self |
cat_rvalue(*) |
cat_copied_upvar(*) |
cat_local(*) |
}
}
-pub fn ptr_sigil(ptr: ptr_kind) -> ~str {
+pub fn ptr_sigil(ptr: PointerKind) -> ~str {
match ptr {
uniq_ptr => ~"~",
gc_ptr(_) => ~"@",
use std::hashmap::{HashSet, HashMap};
use syntax::ast::*;
use syntax::ast_util;
-use syntax::oldvisit;
-use syntax::oldvisit::vt;
+use syntax::visit;
+use syntax::visit::Visitor;
use syntax::codemap::span;
#[deriving(Encodable, Decodable)]
Read // Read no matter what the type.
}
+struct ComputeModesVisitor;
+
+impl visit::Visitor<VisitContext> for ComputeModesVisitor {
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
+ b:&Block, s:span, n:NodeId, e:VisitContext) {
+ compute_modes_for_fn(*self, fk, fd, b, s, n, e);
+ }
+ fn visit_expr(&mut self, ex:@expr, e:VisitContext) {
+ compute_modes_for_expr(*self, ex, e);
+ }
+ fn visit_local(&mut self, l:@Local, e:VisitContext) {
+ compute_modes_for_local(*self, l, e);
+ }
+}
+
pub fn compute_moves(tcx: ty::ctxt,
method_map: method_map,
crate: &Crate) -> MoveMaps
{
- let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
- visit_fn: compute_modes_for_fn,
- visit_expr: compute_modes_for_expr,
- visit_local: compute_modes_for_local,
- .. *oldvisit::default_visitor()
- });
+ let mut visitor = ComputeModesVisitor;
let visit_cx = VisitContext {
tcx: tcx,
method_map: method_map,
moved_variables_set: @mut HashSet::new()
}
};
- oldvisit::visit_crate(crate, (visit_cx, visitor));
+ visit::walk_crate(&mut visitor, crate, visit_cx);
return visit_cx.move_maps;
}
def_binding(nid, _) |
def_arg(nid, _) |
def_local(nid, _) |
- def_self(nid, _) => Some(nid),
+ def_self(nid) => Some(nid),
_ => None
}
///////////////////////////////////////////////////////////////////////////
// Expressions
-fn compute_modes_for_local<'a>(local: @Local,
- (cx, v): (VisitContext,
- vt<VisitContext>)) {
+fn compute_modes_for_local<'a>(v: ComputeModesVisitor,
+ local: @Local,
+ cx: VisitContext) {
cx.use_pat(local.pat);
for &init in local.init.iter() {
cx.use_expr(init, Read, v);
}
}
-fn compute_modes_for_fn(fk: &oldvisit::fn_kind,
+fn compute_modes_for_fn(v: ComputeModesVisitor,
+ fk: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
span: span,
id: NodeId,
- (cx, v): (VisitContext,
- vt<VisitContext>)) {
+ cx: VisitContext) {
+ let mut v = v;
for a in decl.inputs.iter() {
cx.use_pat(a.pat);
}
- oldvisit::visit_fn(fk, decl, body, span, id, (cx, v));
+ visit::walk_fn(&mut v, fk, decl, body, span, id, cx);
}
-fn compute_modes_for_expr(expr: @expr,
- (cx, v): (VisitContext,
- vt<VisitContext>))
+fn compute_modes_for_expr(v: ComputeModesVisitor,
+ expr: @expr,
+ cx: VisitContext)
{
cx.consume_expr(expr, v);
}
impl VisitContext {
- pub fn consume_exprs(&self, exprs: &[@expr], visitor: vt<VisitContext>) {
+ pub fn consume_exprs(&self, exprs: &[@expr], visitor: ComputeModesVisitor) {
for expr in exprs.iter() {
self.consume_expr(*expr, visitor);
}
}
- pub fn consume_expr(&self, expr: @expr, visitor: vt<VisitContext>) {
+ pub fn consume_expr(&self, expr: @expr, visitor: ComputeModesVisitor) {
/*!
* Indicates that the value of `expr` will be consumed,
* meaning either copied or moved depending on its type.
};
}
- pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
+ pub fn consume_block(&self, blk: &Block, visitor: ComputeModesVisitor) {
/*!
* Indicates that the value of `blk` will be consumed,
* meaning either copied or moved depending on its type.
debug!("consume_block(blk.id=%?)", blk.id);
for stmt in blk.stmts.iter() {
- (visitor.visit_stmt)(*stmt, (*self, visitor));
+ let mut v = visitor;
+ v.visit_stmt(*stmt, *self);
}
for tail_expr in blk.expr.iter() {
pub fn use_expr(&self,
expr: @expr,
expr_mode: UseMode,
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
/*!
* Indicates that `expr` is used with a given mode. This will
* in turn trigger calls to the subcomponents of `expr`.
expr: &expr,
receiver_expr: @expr,
arg_exprs: &[@expr],
- visitor: vt<VisitContext>)
+ visitor: ComputeModesVisitor)
-> bool {
if !self.method_map.contains_key(&expr.id) {
return false;
return true;
}
- pub fn consume_arm(&self, arm: &arm, visitor: vt<VisitContext>) {
+ pub fn consume_arm(&self, arm: &arm, visitor: ComputeModesVisitor) {
for pat in arm.pats.iter() {
self.use_pat(*pat);
}
pub fn use_receiver(&self,
receiver_expr: @expr,
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
self.use_fn_arg(receiver_expr, visitor);
}
pub fn use_fn_args(&self,
_: NodeId,
arg_exprs: &[@expr],
- visitor: vt<VisitContext>) {
+ visitor: ComputeModesVisitor) {
//! Uses the argument expressions.
for arg_expr in arg_exprs.iter() {
self.use_fn_arg(*arg_expr, visitor);
}
}
- pub fn use_fn_arg(&self, arg_expr: @expr, visitor: vt<VisitContext>) {
+ pub fn use_fn_arg(&self, arg_expr: @expr, visitor: ComputeModesVisitor) {
//! Uses the argument.
self.consume_expr(arg_expr, visitor)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// A pass that checks to make sure private fields and methods aren't used
-// outside their scopes.
-
+//! A pass that checks to make sure private fields and methods aren't used
+//! outside their scopes.
use metadata::csearch;
use middle::ty::{ty_struct, ty_enum};
if method_id.crate == LOCAL_CRATE {
let is_private = self.method_is_private(span, method_id.node);
- let container_id = ty::method(self.tcx, method_id).container_id;
+ let container_id = ty::method(self.tcx, method_id).container_id();
if is_private &&
(container_id.crate != LOCAL_CRATE ||
!self.privileged_items.iter().any(|x| x == &(container_id.node))) {
match def {
def_static_method(method_id, _, _) => {
debug!("found static method def, checking it");
- self.check_method_common(span, method_id, path.idents.last())
+ self.check_method_common(span,
+ method_id,
+ &path.segments.last().identifier)
}
def_fn(def_id, _) => {
if def_id.crate == LOCAL_CRATE {
!self.privileged_items.iter().any(|x| x == &def_id.node) {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
- token::ident_to_str(path.idents.last())));
+ token::ident_to_str(
+ &path.segments
+ .last()
+ .identifier)));
}
} else if csearch::get_item_visibility(self.tcx.sess.cstore,
def_id) != public {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
- token::ident_to_str(path.idents.last())));
+ token::ident_to_str(
+ &path.segments
+ .last()
+ .identifier)));
}
}
_ => {}
Some(&ast::def_trait(did)) |
Some(&ast::def_struct(did)) => {
if did.crate == ast::LOCAL_CRATE {
- if cx.region_is_relevant(&path.rp) {
+ if cx.region_is_relevant(&path.segments.last().lifetime) {
cx.add_dep(did.node);
}
} else {
Some(variance) => {
debug!("reference to external, rp'd type %s",
pprust::ty_to_str(ty, sess.intr()));
- if cx.region_is_relevant(&path.rp) {
+ if cx.region_is_relevant(&path.segments.last().lifetime) {
let rv = cx.add_variance(variance);
cx.add_rp(cx.item_id, rv)
}
ast::ty_path(ref path, _, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
- for tp in path.types.iter() {
+ for tp in path.segments.iter().flat_map(|s| s.types.iter()) {
visitor.visit_ty(tp, cx);
}
}
use driver::session::Session;
-use metadata::csearch::{each_path, get_trait_method_def_ids};
+use metadata::csearch::get_trait_method_def_ids;
use metadata::csearch::get_method_name_and_explicit_self;
use metadata::csearch::get_static_methods_if_impl;
use metadata::csearch::{get_type_name_if_impl, get_struct_fields};
+use metadata::csearch;
use metadata::cstore::find_extern_mod_stmt_cnum;
use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
use middle::lang_items::LanguageItems;
// Trait method resolution
pub type TraitMap = HashMap<NodeId,@mut ~[def_id]>;
+// A summary of the generics on a trait.
+struct TraitGenerics {
+ has_lifetime: bool,
+ type_parameter_count: uint,
+}
+
// This is the replacement export map. It maps a module to all of the exports
// within.
pub type ExportMap2 = @mut HashMap<NodeId, ~[Export2]>;
pub enum SelfBinding {
NoSelfBinding,
- HasSelfBinding(NodeId, bool /* is implicit */)
+ HasSelfBinding(NodeId)
}
struct ResolveVisitor {
// The index of the import we're resolving.
resolved_import_count: uint,
+
+ // Whether this module is populated. If not populated, any attempt to
+ // access the children must be preceded with a
+ // `populate_module_if_necessary` call.
+ populated: bool,
}
pub fn Module(parent_link: ParentLink,
def_id: Option<def_id>,
- kind: ModuleKind)
- -> Module {
+ kind: ModuleKind,
+ external: bool)
+ -> Module {
Module {
parent_link: parent_link,
def_id: def_id,
anonymous_children: @mut HashMap::new(),
import_resolutions: @mut HashMap::new(),
glob_count: 0,
- resolved_import_count: 0
+ resolved_import_count: 0,
+ populated: !external,
}
}
parent_link: ParentLink,
def_id: Option<def_id>,
kind: ModuleKind,
+ external: bool,
sp: span) {
// Merges the module with the existing type def or creates a new one.
- let module_ = @mut Module(parent_link, def_id, kind);
+ let module_ = @mut Module(parent_link, def_id, kind, external);
match self.type_def {
None => {
self.type_def = Some(TypeNsDef {
parent_link: ParentLink,
def_id: Option<def_id>,
kind: ModuleKind,
+ external: bool,
_sp: span) {
match self.type_def {
None => {
- let module = @mut Module(parent_link, def_id, kind);
+ let module = @mut Module(parent_link, def_id, kind, external);
self.type_def = Some(TypeNsDef {
privacy: privacy,
module_def: Some(module),
Some(type_def) => {
match type_def.module_def {
None => {
- let module = @mut Module(parent_link, def_id, kind);
+ let module = @mut Module(parent_link,
+ def_id,
+ kind,
+ external);
self.type_def = Some(TypeNsDef {
privacy: privacy,
module_def: Some(module),
NoParentLink,
Some(def_id { crate: 0, node: 0 }),
NormalModuleKind,
+ false,
crate.span);
let current_module = graph_root.get_module();
parent_link,
Some(def_id),
NormalModuleKind,
+ false,
sp);
let new_parent =
parent_link,
Some(def_id),
ExternModuleKind,
+ false,
sp);
ModuleReducedGraphParent(name_bindings.get_module())
&Ty {
node: ty_path(ref path, _, _),
_
- } if path.idents.len() == 1 => {
+ } if path.segments.len() == 1 => {
let name = path_to_ident(path);
let new_parent = match parent.children.find(&name) {
parent_link,
Some(def_id),
ImplModuleKind,
+ false,
sp);
ModuleReducedGraphParent(
method.span);
let def = match method.explicit_self.node {
sty_static => {
- // Static methods become `def_fn`s.
- def_fn(local_def(method.id),
- method.purity)
+ // Static methods become
+ // `def_static_method`s.
+ def_static_method(local_def(method.id),
+ FromImpl(local_def(
+ item.id)),
+ method.purity)
}
_ => {
// Non-static methods become
parent_link,
Some(local_def(item.id)),
TraitModuleKind,
+ false,
sp);
let module_parent = ModuleReducedGraphParent(name_bindings.
get_module());
sty_static => {
// Static methods become `def_static_method`s.
def_static_method(local_def(ty_m.id),
- Some(local_def(item.id)),
+ FromTrait(local_def(item.id)),
ty_m.purity)
}
_ => {
let mut module_path = ~[];
match view_path.node {
view_path_simple(_, ref full_path, _) => {
- let path_len = full_path.idents.len();
+ let path_len = full_path.segments.len();
assert!(path_len != 0);
- for (i, ident) in full_path.idents.iter().enumerate() {
+ for (i, segment) in full_path.segments
+ .iter()
+ .enumerate() {
if i != path_len - 1 {
- module_path.push(*ident);
+ module_path.push(segment.identifier)
}
}
}
view_path_glob(ref module_ident_path, _) |
view_path_list(ref module_ident_path, _, _) => {
- for ident in module_ident_path.idents.iter() {
- module_path.push(*ident);
+ for segment in module_ident_path.segments.iter() {
+ module_path.push(segment.identifier)
}
}
}
let module_ = self.get_module_from_parent(parent);
match view_path.node {
view_path_simple(binding, ref full_path, id) => {
- let source_ident = *full_path.idents.last();
+ let source_ident =
+ full_path.segments.last().identifier;
let subclass = @SingleImport(binding,
source_ident);
self.build_import_directive(privacy,
(self.get_module_from_parent(parent), name);
let external_module = @mut Module(parent_link,
Some(def_id),
- NormalModuleKind);
+ NormalModuleKind,
+ false);
parent.external_module_children.insert(
name,
let new_module = @mut Module(
BlockParentLink(parent_module, block_id),
None,
- AnonymousModuleKind);
+ AnonymousModuleKind,
+ false);
parent_module.anonymous_children.insert(block_id, new_module);
new_parent = ModuleReducedGraphParent(new_module);
} else {
visit::walk_block(visitor, block, new_parent);
}
- pub fn handle_external_def(@mut self,
- def: def,
- visibility: ast::visibility,
- modules: &mut HashMap<def_id, @mut Module>,
- child_name_bindings: @mut NameBindings,
- final_ident: &str,
- ident: ident,
- new_parent: ReducedGraphParent) {
+ fn handle_external_def(@mut self,
+ def: def,
+ visibility: ast::visibility,
+ child_name_bindings: @mut NameBindings,
+ final_ident: &str,
+ ident: ident,
+ new_parent: ReducedGraphParent) {
let privacy = visibility_to_privacy(visibility);
match def {
- def_mod(def_id) | def_foreign_mod(def_id) => {
+ def_mod(def_id) | def_foreign_mod(def_id) | def_struct(def_id) |
+ def_ty(def_id) => {
match child_name_bindings.type_def {
Some(TypeNsDef { module_def: Some(module_def), _ }) => {
debug!("(building reduced graph for external crate) \
already created module");
module_def.def_id = Some(def_id);
- modules.insert(def_id, module_def);
}
Some(_) | None => {
debug!("(building reduced graph for \
%s", final_ident);
let parent_link = self.get_parent_link(new_parent, ident);
- // FIXME (#5074): this should be a match on find
- if !modules.contains_key(&def_id) {
- child_name_bindings.define_module(privacy,
- parent_link,
- Some(def_id),
- NormalModuleKind,
- dummy_sp());
- modules.insert(def_id,
- child_name_bindings.get_module());
- } else {
- let existing_module = *modules.get(&def_id);
-
- // Create an import resolution to avoid creating cycles in
- // the module graph.
-
- let resolution = @mut ImportResolution(Public, 0);
- resolution.outstanding_references = 0;
-
- match existing_module.parent_link {
- NoParentLink |
- BlockParentLink(*) => {
- fail!("can't happen");
- }
- ModuleParentLink(parent_module, ident) => {
- let name_bindings = parent_module.children.get(
- &ident);
- resolution.type_target =
- Some(Target(parent_module, *name_bindings));
- }
- }
-
- debug!("(building reduced graph for external crate) \
- ... creating import resolution");
-
- new_parent.import_resolutions.insert(ident, resolution);
- }
+ child_name_bindings.define_module(privacy,
+ parent_link,
+ Some(def_id),
+ NormalModuleKind,
+ true,
+ dummy_sp());
}
}
}
+ _ => {}
+ }
+
+ match def {
+ def_mod(_) | def_foreign_mod(_) => {}
def_variant(*) => {
debug!("(building reduced graph for external crate) building \
variant %s",
}
def_fn(*) | def_static_method(*) | def_static(*) => {
debug!("(building reduced graph for external \
- crate) building value %s", final_ident);
+ crate) building value (fn/static) %s", final_ident);
child_name_bindings.define_value(privacy, def, dummy_sp());
}
def_trait(def_id) => {
parent_link,
Some(def_id),
TraitModuleKind,
+ true,
dummy_sp())
}
def_ty(_) => {
}
}
- /**
- * Builds the reduced graph rooted at the 'use' directive for an external
- * crate.
- */
- pub fn build_reduced_graph_for_external_crate(@mut self,
- root: @mut Module) {
- let mut modules = HashMap::new();
-
- // Create all the items reachable by paths.
- do each_path(self.session.cstore, root.def_id.unwrap().crate)
- |path_string, def_like, visibility| {
-
- debug!("(building reduced graph for external crate) found path \
- entry: %s (%?)",
- path_string, def_like);
-
- let mut pieces: ~[&str] = path_string.split_str_iter("::").collect();
- let final_ident_str = pieces.pop();
- let final_ident = self.session.ident_of(final_ident_str);
-
- // Find the module we need, creating modules along the way if we
- // need to.
-
- let mut current_module = root;
- for ident_str in pieces.iter() {
- let ident = self.session.ident_of(*ident_str);
- // Create or reuse a graph node for the child.
- let (child_name_bindings, new_parent) =
- self.add_child(ident,
- ModuleReducedGraphParent(current_module),
- OverwriteDuplicates,
- dummy_sp());
-
- // Define or reuse the module node.
- match child_name_bindings.type_def {
- None => {
- debug!("(building reduced graph for external crate) \
- autovivifying missing type def %s",
- *ident_str);
- let parent_link = self.get_parent_link(new_parent,
- ident);
- child_name_bindings.define_module(Public,
- parent_link,
- None,
- NormalModuleKind,
- dummy_sp());
+ /// Builds the reduced graph for a single item in an external crate.
+ fn build_reduced_graph_for_external_crate_def(@mut self,
+ root: @mut Module,
+ def_like: def_like,
+ ident: ident) {
+ match def_like {
+ dl_def(def) => {
+ // Add the new child item, if necessary.
+ match def {
+ def_foreign_mod(def_id) => {
+ // Foreign modules have no names. Recur and populate
+ // eagerly.
+ do csearch::each_child_of_item(self.session.cstore,
+ def_id)
+ |def_like, child_ident| {
+ self.build_reduced_graph_for_external_crate_def(
+ root,
+ def_like,
+ child_ident)
+ }
}
- Some(type_ns_def)
- if type_ns_def.module_def.is_none() => {
- debug!("(building reduced graph for external crate) \
- autovivifying missing module def %s",
- *ident_str);
- let parent_link = self.get_parent_link(new_parent,
- ident);
- child_name_bindings.define_module(Public,
- parent_link,
- None,
- NormalModuleKind,
- dummy_sp());
+ _ => {
+ let (child_name_bindings, new_parent) =
+ self.add_child(ident,
+ ModuleReducedGraphParent(root),
+ OverwriteDuplicates,
+ dummy_sp());
+
+ self.handle_external_def(def,
+ public,
+ child_name_bindings,
+ self.session.str_of(ident),
+ ident,
+ new_parent);
}
- _ => {} // Fall through.
- }
-
- current_module = child_name_bindings.get_module();
- }
-
- match def_like {
- dl_def(def) => {
- // Add the new child item.
- let (child_name_bindings, new_parent) =
- self.add_child(final_ident,
- ModuleReducedGraphParent(
- current_module),
- OverwriteDuplicates,
- dummy_sp());
-
- self.handle_external_def(def,
- visibility,
- &mut modules,
- child_name_bindings,
- self.session.str_of(
- final_ident),
- final_ident,
- new_parent);
- }
- dl_impl(def) => {
- // We only process static methods of impls here.
- match get_type_name_if_impl(self.session.cstore, def) {
- None => {}
- Some(final_ident) => {
- let static_methods_opt =
- get_static_methods_if_impl(
- self.session.cstore, def);
- match static_methods_opt {
- Some(ref static_methods) if
- static_methods.len() >= 1 => {
- debug!("(building reduced graph for \
- external crate) processing \
- static methods for type name %s",
- self.session.str_of(
- final_ident));
-
- let (child_name_bindings, new_parent) =
- self.add_child(final_ident,
- ModuleReducedGraphParent(
- current_module),
- OverwriteDuplicates,
- dummy_sp());
-
- // Process the static methods. First,
- // create the module.
- let type_module;
- match child_name_bindings.type_def {
- Some(TypeNsDef {
- module_def: Some(module_def),
- _
- }) => {
- // We already have a module. This
- // is OK.
- type_module = module_def;
-
- // Mark it as an impl module if
- // necessary.
- type_module.kind = ImplModuleKind;
- }
- Some(_) | None => {
- let parent_link =
- self.get_parent_link(
- new_parent, final_ident);
- child_name_bindings.define_module(
- Public,
- parent_link,
- Some(def),
- ImplModuleKind,
- dummy_sp());
- type_module =
- child_name_bindings.
- get_module();
- }
+ }
+ }
+ dl_impl(def) => {
+ // We only process static methods of impls here.
+ match get_type_name_if_impl(self.session.cstore, def) {
+ None => {}
+ Some(final_ident) => {
+ let static_methods_opt =
+ get_static_methods_if_impl(self.session.cstore,
+ def);
+ match static_methods_opt {
+ Some(ref static_methods) if
+ static_methods.len() >= 1 => {
+ debug!("(building reduced graph for \
+ external crate) processing \
+ static methods for type name %s",
+ self.session.str_of(
+ final_ident));
+
+ let (child_name_bindings, new_parent) =
+ self.add_child(
+ final_ident,
+ ModuleReducedGraphParent(root),
+ OverwriteDuplicates,
+ dummy_sp());
+
+ // Process the static methods. First,
+ // create the module.
+ let type_module;
+ match child_name_bindings.type_def {
+ Some(TypeNsDef {
+ module_def: Some(module_def),
+ _
+ }) => {
+ // We already have a module. This
+ // is OK.
+ type_module = module_def;
+
+ // Mark it as an impl module if
+ // necessary.
+ type_module.kind = ImplModuleKind;
}
-
- // Add each static method to the module.
- let new_parent = ModuleReducedGraphParent(
- type_module);
- for static_method_info in static_methods.iter() {
- let ident = static_method_info.ident;
- debug!("(building reduced graph for \
- external crate) creating \
- static method '%s'",
- self.session.str_of(ident));
-
- let (method_name_bindings, _) =
- self.add_child(
- ident,
- new_parent,
- OverwriteDuplicates,
- dummy_sp());
- let def = def_fn(
- static_method_info.def_id,
- static_method_info.purity);
- method_name_bindings.define_value(
- Public, def, dummy_sp());
+ Some(_) | None => {
+ let parent_link =
+ self.get_parent_link(new_parent,
+ final_ident);
+ child_name_bindings.define_module(
+ Public,
+ parent_link,
+ Some(def),
+ ImplModuleKind,
+ true,
+ dummy_sp());
+ type_module =
+ child_name_bindings.
+ get_module();
}
}
- // Otherwise, do nothing.
- Some(_) | None => {}
+ // Add each static method to the module.
+ let new_parent =
+ ModuleReducedGraphParent(type_module);
+ for static_method_info in
+ static_methods.iter() {
+ let ident = static_method_info.ident;
+ debug!("(building reduced graph for \
+ external crate) creating \
+ static method '%s'",
+ self.session.str_of(ident));
+
+ let (method_name_bindings, _) =
+ self.add_child(ident,
+ new_parent,
+ OverwriteDuplicates,
+ dummy_sp());
+ let def = def_fn(
+ static_method_info.def_id,
+ static_method_info.purity);
+ method_name_bindings.define_value(
+ Public,
+ def,
+ dummy_sp());
+ }
}
+
+ // Otherwise, do nothing.
+ Some(_) | None => {}
}
}
}
- dl_field => {
- debug!("(building reduced graph for external crate) \
- ignoring field");
- }
}
- true
+ dl_field => {
+ debug!("(building reduced graph for external crate) \
+ ignoring field");
+ }
+ }
+ }
+
+ /// Builds the reduced graph rooted at the given external module.
+ fn populate_external_module(@mut self, module: @mut Module) {
+ debug!("(populating external module) attempting to populate %s",
+ self.module_to_str(module));
+
+ let def_id = match module.def_id {
+ None => {
+ debug!("(populating external module) ... no def ID!");
+ return
+ }
+ Some(def_id) => def_id,
};
+
+ do csearch::each_child_of_item(self.session.cstore, def_id)
+ |def_like, child_ident| {
+ debug!("(populating external module) ... found ident: %s",
+ token::ident_to_str(&child_ident));
+ self.build_reduced_graph_for_external_crate_def(module,
+ def_like,
+ child_ident)
+ }
+ module.populated = true
+ }
+
+ /// Ensures that the reduced graph rooted at the given external module
+ /// is built, building it if it is not.
+ fn populate_module_if_necessary(@mut self, module: @mut Module) {
+ if !module.populated {
+ self.populate_external_module(module)
+ }
+ assert!(module.populated)
+ }
+
+ /// Builds the reduced graph rooted at the 'use' directive for an external
+ /// crate.
+ pub fn build_reduced_graph_for_external_crate(@mut self,
+ root: @mut Module) {
+ do csearch::each_top_level_item_of_crate(self.session.cstore,
+ root.def_id.unwrap().crate)
+ |def_like, ident| {
+ self.build_reduced_graph_for_external_crate_def(root,
+ def_like,
+ ident)
+ }
}
/// Creates and adds an import directive to the given module.
self.module_to_str(module_));
self.resolve_imports_for_module(module_);
+ self.populate_module_if_necessary(module_);
for (_, &child_node) in module_.children.iter() {
match child_node.get_module_if_available() {
None => {
return result;
}
+ fn path_idents_to_str(@mut self, path: &Path) -> ~str {
+ let identifiers: ~[ast::ident] = path.segments
+ .iter()
+ .map(|seg| seg.identifier)
+ .collect();
+ self.idents_to_str(identifiers)
+ }
+
pub fn import_directive_subclass_to_str(@mut self,
subclass: ImportDirectiveSubclass)
-> @str {
let mut type_result = UnknownResult;
// Search for direct children of the containing module.
+ self.populate_module_if_necessary(containing_module);
match containing_module.children.find(&source) {
None => {
// Continue.
};
// Add all children from the containing module.
+ self.populate_module_if_necessary(containing_module);
for (&ident, name_bindings) in containing_module.children.iter() {
merge_import_resolution(ident, *name_bindings);
}
// The current module node is handled specially. First, check for
// its immediate children.
+ self.populate_module_if_necessary(module_);
match module_.children.find(&name) {
Some(name_bindings)
if name_bindings.defined_in_namespace(namespace) => {
self.module_to_str(module_));
// First, check the direct children of the module.
+ self.populate_module_if_necessary(module_);
match module_.children.find(&name) {
Some(name_bindings)
if name_bindings.defined_in_namespace(namespace) => {
}
// Descend into children and anonymous children.
+ self.populate_module_if_necessary(module_);
for (_, &child_node) in module_.children.iter() {
match child_node.get_module_if_available() {
None => {
}
self.record_exports_for_module(module_);
+ self.populate_module_if_necessary(module_);
for (_, &child_name_bindings) in module_.children.iter() {
match child_name_bindings.get_module_if_available() {
// Nothing to do.
}
Some(name) => {
+ self.populate_module_if_necessary(orig_module);
match orig_module.children.find(&name) {
None => {
debug!("!!! (with scope) didn't find `%s` in `%s`",
NoSelfBinding => {
// Nothing to do.
}
- HasSelfBinding(self_node_id, is_implicit) => {
- let def_like = dl_def(def_self(self_node_id,
- is_implicit));
+ HasSelfBinding(self_node_id) => {
+ let def_like = dl_def(def_self(self_node_id));
*function_value_rib.self_binding = Some(def_like);
}
}
reference_type: TraitReferenceType) {
match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) {
None => {
- let path_str = self.idents_to_str(trait_reference.path.idents);
-
+ let path_str = self.path_idents_to_str(&trait_reference.path);
let usage_str = match reference_type {
TraitBoundingTypeParameter => "bound type parameter with",
TraitImplementation => "implement",
generics: &Generics,
fields: &[@struct_field],
visitor: &mut ResolveVisitor) {
- let mut ident_map = HashMap::new::<ast::ident, @struct_field>();
+ let mut ident_map: HashMap<ast::ident,@struct_field> = HashMap::new();
for &field in fields.iter() {
match field.node.kind {
named_field(ident, _) => {
// we only have self ty if it is a non static method
let self_binding = match method.explicit_self.node {
sty_static => { NoSelfBinding }
- _ => { HasSelfBinding(method.self_id, false) }
+ _ => { HasSelfBinding(method.self_id) }
};
self.resolve_function(rib_kind,
let mut result_def = None;
// First, check to see whether the name is a primitive type.
- if path.idents.len() == 1 {
- let name = *path.idents.last();
+ if path.segments.len() == 1 {
+ let name = path.segments.last().identifier;
match self.primitive_type_table
.primitive_types
Some(&primitive_type) => {
result_def =
Some(def_prim_ty(primitive_type));
+
+ if path.segments
+ .iter()
+ .any(|s| s.lifetime.is_some()) {
+ self.session.span_err(path.span,
+ "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")
+ }
}
None => {
// Continue.
match result_def {
None => {
- match self.resolve_path(ty.id, path, TypeNS, true, visitor) {
+ match self.resolve_path(ty.id,
+ path,
+ TypeNS,
+ true,
+ visitor) {
Some(def) => {
debug!("(resolving type) resolved `%s` to \
type %?",
- self.session.str_of(
- *path.idents.last()),
+ self.session.str_of(path.segments
+ .last()
+ .identifier),
def);
result_def = Some(def);
}
}
}
}
- Some(_) => {
- // Continue.
- }
+ Some(_) => {} // Continue.
}
match result_def {
// Write the result into the def map.
debug!("(resolving type) writing resolution for `%s` \
(id %d)",
- self.idents_to_str(path.idents),
+ self.path_idents_to_str(path),
path_id);
self.record_def(path_id, def);
}
None => {
self.resolve_error
- (ty.span, fmt!("use of undeclared type name `%s`",
- self.idents_to_str(path.idents)));
+ (ty.span,
+ fmt!("use of undeclared type name `%s`",
+ self.path_idents_to_str(path)))
}
}
do walk_pat(pattern) |pattern| {
match pattern.node {
pat_ident(binding_mode, ref path, _)
- if !path.global && path.idents.len() == 1 => {
+ if !path.global && path.segments.len() == 1 => {
// The meaning of pat_ident with no type parameters
// depends on whether an enum variant or unit-like struct
// such a value is simply disallowed (since it's rarely
// what you want).
- let ident = path.idents[0];
+ let ident = path.segments[0].identifier;
match self.resolve_bare_identifier_pattern(ident) {
FoundStructOrEnumVariant(def)
}
// Check the types in the path pattern.
- for ty in path.types.iter() {
+ for ty in path.segments
+ .iter()
+ .flat_map(|seg| seg.types.iter()) {
self.resolve_type(ty, visitor);
}
}
path.span,
fmt!("`%s` is not an enum variant or constant",
self.session.str_of(
- *path.idents.last())));
+ path.segments.last().identifier)))
}
None => {
self.resolve_error(path.span,
}
// Check the types in the path pattern.
- for ty in path.types.iter() {
+ for ty in path.segments
+ .iter()
+ .flat_map(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
}
self.resolve_error(
path.span,
fmt!("`%s` is not an enum variant, struct or const",
- self.session.str_of(
- *path.idents.last())));
+ self.session
+ .str_of(path.segments
+ .last()
+ .identifier)));
}
None => {
self.resolve_error(path.span,
}
// Check the types in the path pattern.
- for ty in path.types.iter() {
+ for ty in path.segments
+ .iter()
+ .flat_map(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
}
self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
- self.idents_to_str(path.idents)));
+ self.path_idents_to_str(path)));
}
}
}
visitor: &mut ResolveVisitor)
-> Option<def> {
// First, resolve the types.
- for ty in path.types.iter() {
+ for ty in path.segments.iter().flat_map(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
namespace);
}
- let unqualified_def = self.resolve_identifier(
- *path.idents.last(), namespace, check_ribs, path.span);
+ let unqualified_def = self.resolve_identifier(path.segments
+ .last()
+ .identifier,
+ namespace,
+ check_ribs,
+ path.span);
- if path.idents.len() > 1 {
- let def = self.resolve_module_relative_path(
- path, self.xray_context, namespace);
+ if path.segments.len() > 1 {
+ let def = self.resolve_module_relative_path(path,
+ self.xray_context,
+ namespace);
match (def, unqualified_def) {
(Some(d), Some(ud)) if d == ud => {
self.session.add_lint(unnecessary_qualification,
- id, path.span,
+ id,
+ path.span,
~"unnecessary qualification");
}
_ => ()
}
+
return def;
}
xray: XrayFlag)
-> NameDefinition {
// First, search children.
+ self.populate_module_if_necessary(containing_module);
match containing_module.children.find(&name) {
Some(child_name_bindings) => {
match (child_name_bindings.def_for_namespace(namespace),
pub fn intern_module_part_of_path(@mut self, path: &Path) -> ~[ident] {
let mut module_path_idents = ~[];
- for (index, ident) in path.idents.iter().enumerate() {
- if index == path.idents.len() - 1 {
+ for (index, segment) in path.segments.iter().enumerate() {
+ if index == path.segments.len() - 1 {
break;
}
- module_path_idents.push(*ident);
+ module_path_idents.push(segment.identifier);
}
return module_path_idents;
}
}
- let name = *path.idents.last();
+ let name = path.segments.last().identifier;
let def = match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace,
}
}
- let name = *path.idents.last();
+ let name = path.segments.last().identifier;
match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace,
Some(def) => {
// Write the result into the def map.
debug!("(resolving expr) resolved `%s`",
- self.idents_to_str(path.idents));
+ self.path_idents_to_str(path));
// First-class methods are not supported yet; error
// out here.
self.record_def(expr.id, def);
}
None => {
- let wrong_name = self.idents_to_str(
- path.idents);
+ let wrong_name = self.path_idents_to_str(path);
if self.name_exists_in_scope_struct(wrong_name) {
self.resolve_error(expr.span,
fmt!("unresolved name `%s`. \
self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
- self.idents_to_str(path.idents)));
+ self.path_idents_to_str(path)));
}
}
}
// Look for trait children.
- for (_, &child_name_bindings) in search_module.children.iter() {
+ self.populate_module_if_necessary(search_module);
+ for (_, &child_name_bindings) in
+ search_module.children.iter() {
match child_name_bindings.def_for_namespace(TypeNS) {
Some(def) => {
match def {
debug!("Dump of module `%s`:", self.module_to_str(module_));
debug!("Children:");
+ self.populate_module_if_necessary(module_);
for (&name, _) in module_.children.iter() {
debug!("* %s", self.session.str_of(name));
}
use syntax::ast_map;
use syntax::attr;
use syntax::codemap::span;
-use visit = syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
use util::ppaux::Repr;
#[deriving(Clone)]
safe_stack: bool
}
+struct StackCheckVisitor;
+
+impl Visitor<Context> for StackCheckVisitor {
+ fn visit_item(&mut self, i:@ast::item, e:Context) {
+ stack_check_item(*self, i, e);
+ }
+ fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl,
+ b:&ast::Block, s:span, n:ast::NodeId, e:Context) {
+ stack_check_fn(*self, fk, fd, b, s, n, e);
+ }
+ fn visit_expr(&mut self, ex:@ast::expr, e:Context) {
+ stack_check_expr(*self, ex, e);
+ }
+}
+
pub fn stack_check_crate(tcx: ty::ctxt,
crate: &ast::Crate) {
let new_cx = Context {
tcx: tcx,
safe_stack: false
};
- let visitor = visit::mk_vt(@visit::Visitor {
- visit_item: stack_check_item,
- visit_fn: stack_check_fn,
- visit_expr: stack_check_expr,
- ..*visit::default_visitor()
- });
- visit::visit_crate(crate, (new_cx, visitor));
+ let mut visitor = StackCheckVisitor;
+ visit::walk_crate(&mut visitor, crate, new_cx);
}
-fn stack_check_item(item: @ast::item,
- (in_cx, v): (Context, visit::vt<Context>)) {
+fn stack_check_item(v: StackCheckVisitor,
+ item: @ast::item,
+ in_cx: Context) {
+ let mut v = v;
match item.node {
ast::item_fn(_, ast::extern_fn, _, _, _) => {
// an extern fn is already being called from C code...
let new_cx = Context {safe_stack: true, ..in_cx};
- visit::visit_item(item, (new_cx, v));
+ visit::walk_item(&mut v, item, new_cx);
}
ast::item_fn(*) => {
let safe_stack = fixed_stack_segment(item.attrs);
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
- visit::visit_item(item, (new_cx, v));
+ visit::walk_item(&mut v, item, new_cx);
}
ast::item_impl(_, _, _, ref methods) => {
// visit_method() would make this nicer
for &method in methods.iter() {
let safe_stack = fixed_stack_segment(method.attrs);
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
- visit::visit_method_helper(method, (new_cx, v));
+ visit::walk_method_helper(&mut v, method, new_cx);
}
}
_ => {
- visit::visit_item(item, (in_cx, v));
+ visit::walk_item(&mut v, item, in_cx);
}
}
}
}
-fn stack_check_fn<'a>(fk: &visit::fn_kind,
+fn stack_check_fn<'a>(v: StackCheckVisitor,
+ fk: &visit::fn_kind,
decl: &ast::fn_decl,
body: &ast::Block,
sp: span,
id: ast::NodeId,
- (in_cx, v): (Context, visit::vt<Context>)) {
+ in_cx: Context) {
let safe_stack = match *fk {
visit::fk_method(*) | visit::fk_item_fn(*) => {
in_cx.safe_stack // see stack_check_item above
};
let new_cx = Context {safe_stack: safe_stack, ..in_cx};
debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
- visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
+ let mut v = v;
+ visit::walk_fn(&mut v, fk, decl, body, sp, id, new_cx);
}
-fn stack_check_expr<'a>(expr: @ast::expr,
- (cx, v): (Context, visit::vt<Context>)) {
+fn stack_check_expr<'a>(v: StackCheckVisitor,
+ expr: @ast::expr,
+ cx: Context) {
debug!("stack_check_expr(safe_stack=%b, expr=%s)",
cx.safe_stack, expr.repr(cx.tcx));
if !cx.safe_stack {
_ => {}
}
}
- visit::visit_expr(expr, (cx, v));
+ let mut v = v;
+ visit::walk_expr(&mut v, expr, cx);
}
fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
// range)
enum Opt {
lit(Lit),
- var(/* disr val */ uint, @adt::Repr),
+ var(ty::Disr, @adt::Repr),
range(@ast::expr, @ast::expr),
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
fn extract_variant_args(bcx: @mut Block,
repr: &adt::Repr,
- disr_val: uint,
+ disr_val: ty::Disr,
val: ValueRef)
-> ExtractedBlock {
let _icx = push_ctxt("match::extract_variant_args");
use middle::trans::machine;
use middle::trans::type_of;
use middle::ty;
+use middle::ty::Disr;
use syntax::ast;
use util::ppaux::ty_to_str;
/// Representations.
pub enum Repr {
/// C-like enums; basically an int.
- CEnum(uint, uint), // discriminant range
+ CEnum(Disr, Disr), // discriminant range
/**
* Single-case variants, and structs/tuples/records.
*
* is represented such that `None` is a null pointer and `Some` is the
* identity function.
*/
- NullablePointer{ nonnull: Struct, nndiscr: uint, ptrfield: uint,
+ NullablePointer{ nonnull: Struct, nndiscr: Disr, ptrfield: uint,
nullfields: ~[ty::t] }
}
return Univariant(mk_struct(cx, ftys, packed), dtor)
}
ty::ty_enum(def_id, ref substs) => {
- struct Case { discr: uint, tys: ~[ty::t] };
+ struct Case { discr: Disr, tys: ~[ty::t] };
impl Case {
fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
mk_struct(cx, self.tys, false).size == 0
// Since there's at least one
// non-empty body, explicit discriminants should have
// been rejected by a checker before this point.
- if !cases.iter().enumerate().all(|(i,c)| c.discr == i) {
+ if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) {
cx.sess.bug(fmt!("non-C-like enum %s with specified \
discriminants",
ty::item_path_str(cx.tcx, def_id)))
-> ValueRef {
match *r {
CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
- Univariant(*) => C_uint(bcx.ccx(), 0),
- General(ref cases) => load_discr(bcx, scrutinee, 0, cases.len() - 1),
+ Univariant(*) => C_disr(bcx.ccx(), 0),
+ General(ref cases) => load_discr(bcx, scrutinee, 0, (cases.len() - 1) as Disr),
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee),
Type::enum_discrim(bcx.ccx()))
}
}
-fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: uint, ptrfield: uint,
+fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
scrutinee: ValueRef) -> ValueRef {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield]));
}
/// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: uint, max: uint)
+fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: Disr, max: Disr)
-> ValueRef {
let ptr = GEPi(bcx, scrutinee, [0, 0]);
if max + 1 == min {
*
* This should ideally be less tightly tied to `_match`.
*/
-pub fn trans_case(bcx: @mut Block, r: &Repr, discr: uint) -> _match::opt_result {
+pub fn trans_case(bcx: @mut Block, r: &Repr, discr: Disr) -> _match::opt_result {
match *r {
CEnum(*) => {
- _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
+ _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
}
Univariant(*) => {
bcx.ccx().sess.bug("no cases for univariants or structs")
}
General(*) => {
- _match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
+ _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
}
NullablePointer{ _ } => {
assert!(discr == 0 || discr == 1);
* representation. The fields, if any, should then be initialized via
* `trans_field_ptr`.
*/
-pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) {
+pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: Disr) {
match *r {
CEnum(min, max) => {
assert!(min <= discr && discr <= max);
- Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
+ Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
}
Univariant(ref st, true) => {
assert_eq!(discr, 0);
assert_eq!(discr, 0);
}
General(*) => {
- Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
+ Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
}
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
if discr != nndiscr {
* The number of fields in a given case; for use when obtaining this
* information from the type or definition is less convenient.
*/
-pub fn num_args(r: &Repr, discr: uint) -> uint {
+pub fn num_args(r: &Repr, discr: Disr) -> uint {
match *r {
CEnum(*) => 0,
Univariant(ref st, dtor) => {
}
/// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint,
+pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: Disr,
ix: uint) -> ValueRef {
// Note: if this ever needs to generate conditionals (e.g., if we
// decide to do some kind of cdr-coding-like non-unique repr
* this could be changed in the future to avoid allocating unnecessary
* space after values of shorter-than-maximum cases.
*/
-pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint,
+pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: Disr,
vals: &[ValueRef]) -> ValueRef {
match *r {
CEnum(min, max) => {
assert_eq!(vals.len(), 0);
assert!(min <= discr && discr <= max);
- C_uint(ccx, discr)
+ C_disr(ccx, discr)
}
Univariant(ref st, _dro) => {
assert_eq!(discr, 0);
General(ref cases) => {
let case = &cases[discr];
let max_sz = cases.iter().map(|x| x.size).max().unwrap();
- let discr_ty = C_uint(ccx, discr);
+ let discr_ty = C_disr(ccx, discr);
let contents = build_const_struct(ccx, case,
~[discr_ty] + vals);
C_struct(contents + &[padding(max_sz - case.size)])
/// Get the discriminant of a constant value. (Not currently used.)
pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
- -> uint {
+ -> Disr {
match *r {
- CEnum(*) => const_to_uint(val) as uint,
+ CEnum(*) => const_to_uint(val) as Disr,
Univariant(*) => 0,
- General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as uint,
+ General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr,
NullablePointer{ nndiscr, ptrfield, _ } => {
if is_null(const_struct_field(ccx, val, ptrfield)) {
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
- (1 - nndiscr) as uint
+ (1 - nndiscr) as Disr
} else {
nndiscr
}
* raw LLVM-level structs and arrays.)
*/
pub fn const_get_field(ccx: &mut CrateContext, r: &Repr, val: ValueRef,
- _discr: uint, ix: uint) -> ValueRef {
+ _discr: Disr, ix: uint) -> ValueRef {
match *r {
CEnum(*) => ccx.sess.bug("element access in C-like enum const"),
Univariant(*) => const_struct_field(ccx, val, ix),
_ => false
}
}
+
+fn C_disr(cx: &CrateContext, i: Disr) -> ValueRef {
+ return C_integral(cx.int_type, i, false);
+}
// field of the fn_ctxt with
pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
self_arg: self_arg,
- args: &[ast::arg])
+ args: &[ast::arg],
+ arg_tys: &[ty::t])
-> ~[ValueRef] {
let _icx = push_ctxt("create_llargs_for_fn_args");
// Return an array containing the ValueRefs that we get from
// llvm::LLVMGetParam for each argument.
- vec::from_fn(args.len(), |i| {
- unsafe {
- let arg_n = cx.arg_pos(i);
- let arg = &args[i];
- let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
-
- // FIXME #7260: aliasing should be determined by monomorphized ty::t
- match arg.ty.node {
- // `~` pointers never alias other parameters, because ownership was transferred
- ast::ty_uniq(_) => {
- llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+ do vec::from_fn(args.len()) |i| {
+ let arg_n = cx.arg_pos(i);
+ let arg_ty = arg_tys[i];
+ let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
+
+ match ty::get(arg_ty).sty {
+ // `~` pointers never alias other parameters, because
+ // ownership was transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+ unsafe {
+ llvm::LLVMAddAttribute(
+ llarg, lib::llvm::NoAliasAttribute as c_uint);
}
- // FIXME: #6785: `&mut` can only alias `&const` and `@mut`, we should check for
- // those in the other parameters and then mark it as `noalias` if there aren't any
- _ => {}
}
-
- llarg
+ // FIXME: #6785: `&mut` can only alias `&const` and
+ // `@mut`, we should check for those in the other
+ // parameters and then mark it as `noalias` if there
+ // aren't any
+ _ => {}
}
- })
+
+ llarg
+ }
}
pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
debug!("trans_closure(..., param_substs=%s)",
param_substs.repr(ccx.tcx));
- // Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(ccx,
path,
llfndecl,
body.info(),
Some(body.span));
- let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
-
- // Set the fixed stack segment flag if necessary.
- if attr::contains_name(attributes, "fixed_stack_segment") {
- set_no_inline(fcx.llfn);
- set_fixed_stack_segment(fcx.llfn);
- }
-
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
let bcx_top = fcx.entry_bcx.unwrap();
let mut bcx = bcx_top;
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 raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
+ decl.inputs, arg_tys);
+
+ // Set the fixed stack segment flag if necessary.
+ if attr::contains_name(attributes, "fixed_stack_segment") {
+ set_no_inline(fcx.llfn);
+ set_fixed_stack_segment(fcx.llfn);
+ }
+
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, raw_llargs, arg_tys);
maybe_load_env(fcx);
_enum_id: ast::NodeId,
variant: &ast::variant,
args: &[ast::variant_arg],
- disr: uint,
+ disr: ty::Disr,
param_substs: Option<@param_substs>,
llfndecl: ValueRef) {
let _icx = push_ctxt("trans_enum_variant");
ccx: @mut CrateContext,
ctor_id: ast::NodeId,
args: &[A],
- disr: uint,
+ disr: ty::Disr,
param_substs: Option<@param_substs>,
llfndecl: ValueRef)
{
None,
None);
- let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
+ let arg_tys = ty::ty_fn_args(ctor_ty);
+
+ let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
let bcx = fcx.entry_bcx.unwrap();
- let arg_tys = ty::ty_fn_args(ctor_ty);
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
&ccx.int_type);
// FIXME #4404 android JNI hacks
- let llfn = if *ccx.sess.building_library {
- decl_cdecl_fn(ccx.llmod, "amain", llfty)
+ let main_name = if *ccx.sess.building_library {
+ "amain"
} else {
- let main_name = match ccx.sess.targ_cfg.os {
- session::os_win32 => ~"WinMain@16",
- _ => ~"main",
- };
- decl_cdecl_fn(ccx.llmod, main_name, llfty)
+ "main"
};
+ let llfn = decl_cdecl_fn(ccx.llmod, main_name, llfty);
let llbb = do "top".with_c_str |buf| {
unsafe {
llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
fn trans_def(bcx: @mut Block, def: ast::def, ref_expr: @ast::expr) -> Callee {
match def {
- ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
+ ast::def_fn(did, _) |
+ ast::def_static_method(did, ast::FromImpl(_), _) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
}
- ast::def_static_method(impl_did, Some(trait_did), _) => {
+ ast::def_static_method(impl_did,
+ ast::FromTrait(trait_did),
+ _) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id))
self_ty: None,
tps: /*bad*/ type_params.to_owned() };
+ // Load the info for the appropriate trait if necessary.
+ match ty::trait_of_method(tcx, def_id) {
+ None => {}
+ Some(trait_id) => {
+ ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
+ }
+ }
+
// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
// So, what we need to do is find this substitution and
// compose it with the one we already have.
- let impl_id = ty::method(tcx, def_id).container_id;
+ let impl_id = ty::method(tcx, def_id).container_id();
let method = ty::method(tcx, source_id);
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
.expect("could not find trait_ref for impl with \
(expr::cast_enum, expr::cast_float) => {
let repr = adt::represent_type(cx, basety);
let discr = adt::const_get_discrim(cx, repr, v);
- let iv = C_uint(cx, discr);
+ let iv = C_integral(cx.int_type, discr, false);
let ety_cast = expr::cast_type_kind(ety);
match ety_cast {
expr::cast_integral => {
v
}
ast::expr_path(ref pth) => {
- assert_eq!(pth.types.len(), 0);
+ // Assert that there are no type parameters in this path.
+ assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
+
let tcx = cx.tcx;
match tcx.def_map.find(&e.id) {
Some(&ast::def_fn(def_id, _purity)) => {
llvm::LLVMSetDataLayout(llmod, buf)
};
do targ_triple.with_c_str |buf| {
- llvm::LLVMSetTarget(llmod, buf)
+ llvm::LLVMRustSetNormalizedTarget(llmod, buf)
};
let targ_cfg = sess.targ_cfg;
let _icx = push_ctxt("trans_def_datum_unadjusted");
let fn_data = match def {
- ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
+ ast::def_fn(did, _) |
+ ast::def_static_method(did, ast::FromImpl(_), _) => {
callee::trans_fn_ref(bcx, did, ref_expr.id)
}
- ast::def_static_method(impl_did, Some(trait_did), _) => {
- meth::trans_static_method_callee(bcx, impl_did,
+ ast::def_static_method(impl_did, ast::FromTrait(trait_did), _) => {
+ meth::trans_static_method_callee(bcx,
+ impl_did,
trait_did,
ref_expr.id)
}
ast::def_local(nid, _) | ast::def_binding(nid, _) => {
take_local(bcx, bcx.fcx.lllocals, nid)
}
- ast::def_self(nid, _) => {
+ ast::def_self(nid) => {
let self_info: ValSelfData = match bcx.fcx.llself {
Some(ref self_info) => *self_info,
None => {
pub fn with_field_tys<R>(tcx: ty::ctxt,
ty: ty::t,
node_id_opt: Option<ast::NodeId>,
- op: &fn(uint, (&[ty::field])) -> R) -> R {
+ op: &fn(ty::Disr, (&[ty::field])) -> R) -> R {
match ty::get(ty).sty {
ty::ty_struct(did, ref substs) => {
op(0, struct_fields(tcx, did, substs))
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
-fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
+fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: ty::Disr,
fields: &[(uint, @ast::expr)],
optbase: Option<StructBaseInfo>,
dest: Dest) -> @mut Block {
}) => {
match bcx.fcx.param_substs {
Some(substs) => {
+ ty::populate_implementations_for_trait_if_necessary(
+ bcx.tcx(),
+ trait_id);
+
let vtbl = find_vtable(bcx.tcx(), substs,
p, b);
trans_monomorphized_callee(bcx, callee_id, this, mentry,
callee_id);
let _indenter = indenter();
+ ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
+
// When we translate a static fn defined in a trait like:
//
// trait<T1...Tn> Trait {
make a vtable for a type impl!")
};
+ ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
+
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
do trait_method_def_ids.map |method_def_id| {
let ident = ty::method(tcx, *method_def_id).ident;
use middle::trans::type_use;
use middle::trans::intrinsic;
use middle::ty;
-use middle::ty::{FnSig};
use middle::typeck;
use util::ppaux::{Repr,ty_to_str};
use syntax::ast_map;
use syntax::ast_map::path_name;
use syntax::ast_util::local_def;
-use syntax::opt_vec;
-use syntax::abi::AbiSet;
pub fn monomorphic_fn(ccx: @mut CrateContext,
fn_id: ast::def_id,
let _icx = push_ctxt("monomorphic_fn");
let mut must_cast = false;
- let do_normalize = |t: &ty::t| {
- match normalize_for_monomorphization(ccx.tcx, *t) {
- Some(t) => { must_cast = true; t }
- None => *t
- }
- };
-
let psubsts = @param_substs {
- tys: real_substs.tps.map(|x| do_normalize(x)),
+ tys: real_substs.tps.to_owned(),
vtables: vtables,
- self_ty: real_substs.self_ty.map(|x| do_normalize(x)),
+ self_ty: real_substs.self_ty.clone(),
self_vtables: self_vtables
};
(lldecl, must_cast)
}
-pub fn normalize_for_monomorphization(tcx: ty::ctxt,
- ty: ty::t) -> Option<ty::t> {
- // FIXME[mono] could do this recursively. is that worthwhile? (#2529)
- return match ty::get(ty).sty {
- ty::ty_box(*) => {
- Some(ty::mk_opaque_box(tcx))
- }
- ty::ty_bare_fn(_) => {
- Some(ty::mk_bare_fn(
- tcx,
- ty::BareFnTy {
- purity: ast::impure_fn,
- abis: AbiSet::Rust(),
- sig: FnSig {bound_lifetime_names: opt_vec::Empty,
- inputs: ~[],
- output: ty::mk_nil()}}))
- }
- ty::ty_closure(ref fty) => {
- Some(normalized_closure_ty(tcx, fty.sigil))
- }
- ty::ty_trait(_, _, ref store, _, _) => {
- let sigil = match *store {
- ty::UniqTraitStore => ast::OwnedSigil,
- ty::BoxTraitStore => ast::ManagedSigil,
- ty::RegionTraitStore(_) => ast::BorrowedSigil,
- };
-
- // Traits have the same runtime representation as closures.
- Some(normalized_closure_ty(tcx, sigil))
- }
- ty::ty_ptr(_) => {
- Some(ty::mk_uint())
- }
- _ => {
- None
- }
- };
-
- fn normalized_closure_ty(tcx: ty::ctxt,
- sigil: ast::Sigil) -> ty::t
- {
- ty::mk_closure(
- tcx,
- ty::ClosureTy {
- purity: ast::impure_fn,
- sigil: sigil,
- onceness: ast::Many,
- region: ty::re_static,
- bounds: ty::EmptyBuiltinBounds(),
- sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty,
- inputs: ~[],
- output: ty::mk_nil()}})
- }
-}
-
pub fn make_mono_id(ccx: @mut CrateContext,
item: ast::def_id,
substs: ¶m_substs,
for (i, v) in variants.iter().enumerate() {
let name = ccx.sess.str_of(v.name);
let variant_args = ~[this.c_uint(i),
- this.c_uint(v.disr_val),
+ C_integral(self.bcx.ccx().int_type, v.disr_val, false),
this.c_uint(v.args.len()),
this.c_slice(name)];
do this.bracketed("enum_variant", variant_args) |this| {
"visit_tydesc" | "forget" | "frame_address" |
"morestack_addr" => 0,
- "offset" | "offset_inbounds" |
+ "offset" |
"memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
"memset32" | "memset64" => use_repr,
use syntax;
use extra::enum_set::{EnumSet, CLike};
-pub static INITIAL_DISCRIMINANT_VALUE: uint = 0;
+pub type Disr = u64;
+
+pub static INITIAL_DISCRIMINANT_VALUE: Disr = 0;
// Data types
mt: mt
}
+#[deriving(Clone)]
+pub enum MethodContainer {
+ TraitContainer(ast::def_id),
+ ImplContainer(ast::def_id),
+}
+
#[deriving(Clone)]
pub struct Method {
ident: ast::ident,
explicit_self: ast::explicit_self_,
vis: ast::visibility,
def_id: ast::def_id,
- container_id: ast::def_id,
+ container: MethodContainer,
// If this method is provided, we need to know where it came from
provided_source: Option<ast::def_id>
explicit_self: ast::explicit_self_,
vis: ast::visibility,
def_id: ast::def_id,
- container_id: ast::def_id,
+ container: MethodContainer,
provided_source: Option<ast::def_id>)
-> Method {
// Check the invariants.
explicit_self: explicit_self,
vis: vis,
def_id: def_id,
- container_id: container_id,
+ container: container,
provided_source: provided_source
}
}
+
+ pub fn container_id(&self) -> ast::def_id {
+ match self.container {
+ TraitContainer(id) => id,
+ ImplContainer(id) => id,
+ }
+ }
}
pub struct Impl {
used_mut_nodes: @mut HashSet<ast::NodeId>,
// vtable resolution information for impl declarations
- impl_vtables: typeck::impl_vtable_map
+ impl_vtables: typeck::impl_vtable_map,
+
+ // The set of external nominal types whose implementations have been read.
+ // This is used for lazy resolution of methods.
+ populated_external_types: @mut HashSet<ast::def_id>,
+
+ // The set of external traits whose implementations have been read. This
+ // is used for lazy resolution of traits.
+ populated_external_traits: @mut HashSet<ast::def_id>,
}
pub enum tbox_flag {
used_unsafe: @mut HashSet::new(),
used_mut_nodes: @mut HashSet::new(),
impl_vtables: @mut HashMap::new(),
+ populated_external_types: @mut HashSet::new(),
+ populated_external_traits: @mut HashSet::new(),
}
}
terr_ptr_mutability => ~"pointers differ in mutability",
terr_ref_mutability => ~"references differ in mutability",
terr_ty_param_size(values) => {
- fmt!("expected a type with %? type params \
- but found one with %? type params",
+ fmt!("expected a type with %u type params \
+ but found one with %u type params",
values.expected, values.found)
}
terr_tuple_size(values) => {
- fmt!("expected a tuple with %? elements \
- but found one with %? elements",
+ fmt!("expected a tuple with %u elements \
+ but found one with %u elements",
values.expected, values.found)
}
terr_record_size(values) => {
- fmt!("expected a record with %? fields \
- but found one with %? fields",
+ fmt!("expected a record with %u fields \
+ but found one with %u fields",
values.expected, values.found)
}
terr_record_mutability => {
}
}
-pub fn provided_source(cx: ctxt, id: ast::def_id)
- -> Option<ast::def_id> {
+pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option<ast::def_id> {
cx.provided_method_sources.find(&id).map_move(|x| *x)
}
ctor_ty: t,
name: ast::ident,
id: ast::def_id,
- disr_val: uint,
+ disr_val: Disr,
vis: visibility
}
/// Does not do any caching of the value in the type context.
pub fn from_ast_variant(cx: ctxt,
ast_variant: &ast::variant,
- discriminant: uint) -> VariantInfo {
+ discriminant: Disr) -> VariantInfo {
let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
node: ast::item_enum(ref enum_definition, _),
_
}, _) => {
- let mut last_discriminant: Option<uint> = None;
+ let mut last_discriminant: Option<Disr> = None;
@enum_definition.variants.iter().map(|variant| {
let mut discriminant = match last_discriminant {
match variant.node.disr_expr {
Some(e) => match const_eval::eval_const_expr_partial(&cx, e) {
- Ok(const_eval::const_int(val)) => discriminant = val as uint,
- Ok(const_eval::const_uint(val)) => discriminant = val as uint,
+ Ok(const_eval::const_int(val)) => discriminant = val as Disr,
+ Ok(const_eval::const_uint(val)) => discriminant = val as Disr,
Ok(_) => {
cx.sess.span_err(e.span, "expected signed integer constant");
}
ast::m_imm,
EmptyBuiltinBounds())))
}
+
+/// Records a trait-to-implementation mapping.
+fn record_trait_implementation(tcx: ctxt,
+ trait_def_id: def_id,
+ implementation: @Impl) {
+ let implementation_list;
+ match tcx.trait_impls.find(&trait_def_id) {
+ None => {
+ implementation_list = @mut ~[];
+ tcx.trait_impls.insert(trait_def_id, implementation_list);
+ }
+ Some(&existing_implementation_list) => {
+ implementation_list = existing_implementation_list
+ }
+ }
+
+ implementation_list.push(implementation);
+}
+
+/// Populates the type context with all the implementations for the given type
+/// if necessary.
+pub fn populate_implementations_for_type_if_necessary(tcx: ctxt,
+ type_id: ast::def_id) {
+ if type_id.crate == LOCAL_CRATE {
+ return
+ }
+ if tcx.populated_external_types.contains(&type_id) {
+ return
+ }
+
+ do csearch::each_implementation_for_type(tcx.sess.cstore, type_id)
+ |implementation_def_id| {
+ let implementation = @csearch::get_impl(tcx, implementation_def_id);
+
+ // Record the trait->implementation mappings, if applicable.
+ let associated_traits = csearch::get_impl_trait(tcx,
+ implementation.did);
+ for trait_ref in associated_traits.iter() {
+ record_trait_implementation(tcx,
+ trait_ref.def_id,
+ implementation);
+ }
+
+ // For any methods that use a default implementation, add them to
+ // the map. This is a bit unfortunate.
+ for method in implementation.methods.iter() {
+ for source in method.provided_source.iter() {
+ tcx.provided_method_sources.insert(method.def_id, *source);
+ }
+ }
+
+ // If this is an inherent implementation, record it.
+ if associated_traits.is_none() {
+ let implementation_list;
+ match tcx.inherent_impls.find(&type_id) {
+ None => {
+ implementation_list = @mut ~[];
+ tcx.inherent_impls.insert(type_id, implementation_list);
+ }
+ Some(&existing_implementation_list) => {
+ implementation_list = existing_implementation_list;
+ }
+ }
+ implementation_list.push(implementation);
+ }
+
+ // Store the implementation info.
+ tcx.impls.insert(implementation_def_id, implementation);
+ }
+
+ tcx.populated_external_types.insert(type_id);
+}
+
+/// Populates the type context with all the implementations for the given
+/// trait if necessary.
+pub fn populate_implementations_for_trait_if_necessary(
+ tcx: ctxt,
+ trait_id: ast::def_id) {
+ if trait_id.crate == LOCAL_CRATE {
+ return
+ }
+ if tcx.populated_external_traits.contains(&trait_id) {
+ return
+ }
+
+ do csearch::each_implementation_for_trait(tcx.sess.cstore, trait_id)
+ |implementation_def_id| {
+ let implementation = @csearch::get_impl(tcx, implementation_def_id);
+
+ // Record the trait->implementation mapping.
+ record_trait_implementation(tcx, trait_id, implementation);
+
+ // For any methods that use a default implementation, add them to
+ // the map. This is a bit unfortunate.
+ for method in implementation.methods.iter() {
+ for source in method.provided_source.iter() {
+ tcx.provided_method_sources.insert(method.def_id, *source);
+ }
+ }
+
+ // Store the implementation info.
+ tcx.impls.insert(implementation_def_id, implementation);
+ }
+
+ tcx.populated_external_traits.insert(trait_id);
+}
+
+/// If the given def ID describes a trait method, returns the ID of the trait
+/// that the method belongs to. Otherwise, returns `None`.
+pub fn trait_of_method(tcx: ctxt, def_id: ast::def_id)
+ -> Option<ast::def_id> {
+ match tcx.methods.find(&def_id) {
+ Some(method_descriptor) => {
+ match method_descriptor.container {
+ TraitContainer(id) => return Some(id),
+ _ => {}
+ }
+ }
+ None => {}
+ }
+
+ // If the method was in the local crate, then if we got here we know the
+ // answer is negative.
+ if def_id.crate == LOCAL_CRATE {
+ return None
+ }
+
+ let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
+
+ result
+}
+
use middle::typeck::lookup_def_tcx;
use std::result;
-use std::vec;
use syntax::abi::AbiSet;
use syntax::{ast, ast_util};
use syntax::codemap::span;
// If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
- let regions = match (&decl_generics.region_param, &path.rp) {
+ let regions = match (&decl_generics.region_param,
+ &path.segments.last().lifetime) {
(&None, &None) => {
opt_vec::Empty
}
}
(&Some(_), &Some(_)) => {
opt_vec::with(
- ast_region_to_region(this, rscope, path.span, &path.rp))
+ ast_region_to_region(this,
+ rscope,
+ path.span,
+ &path.segments.last().lifetime))
}
};
// Convert the type parameters supplied by the user.
- if !vec::same_length(*decl_generics.type_param_defs, path.types) {
+ let supplied_type_parameter_count =
+ path.segments.iter().flat_map(|s| s.types.iter()).len();
+ if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
this.tcx().sess.span_fatal(
path.span,
fmt!("wrong number of type arguments: expected %u but found %u",
- decl_generics.type_param_defs.len(), path.types.len()));
+ decl_generics.type_param_defs.len(),
+ supplied_type_parameter_count));
+ }
+ let tps = path.segments
+ .iter()
+ .flat_map(|s| s.types.iter())
+ .map(|a_t| ast_ty_to_ty(this, rscope, a_t))
+ .collect();
+
+ substs {
+ regions: ty::NonerasedRegions(regions),
+ self_ty: self_ty,
+ tps: tps
}
- let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
-
- substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps}
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,
match a_seq_ty.ty.node {
ast::ty_vec(ref mt) => {
let mut mt = ast_mt_to_mt(this, rscope, mt);
- if a_seq_ty.mutbl == ast::m_mutbl ||
- a_seq_ty.mutbl == ast::m_const {
+ if a_seq_ty.mutbl == ast::m_mutbl {
mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
}
return ty::mk_evec(tcx, mt, vst);
path: &ast::Path,
flags: uint) {
if (flags & NO_TPS) != 0u {
- if path.types.len() > 0u {
+ if !path.segments.iter().all(|s| s.types.is_empty()) {
tcx.sess.span_err(
path.span,
"type parameters are not allowed on this type");
}
if (flags & NO_REGIONS) != 0u {
- if path.rp.is_some() {
+ if path.segments.last().lifetime.is_some() {
tcx.sess.span_err(
path.span,
"region parameters are not allowed on this type");
Some((enm, var)) => {
// Assign the pattern the type of the *enum*, not the variant.
let enum_tpt = ty::lookup_item_type(tcx, enm);
- instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);
+ instantiate_path(pcx.fcx,
+ path,
+ enum_tpt,
+ v_def,
+ pat.span,
+ pat.id);
// check that the type of the value being matched is a subtype
// of the type of the pattern:
} else {
ctor_tpt
};
- instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id);
+ instantiate_path(pcx.fcx,
+ path,
+ struct_tpt,
+ s_def,
+ pat.span,
+ pat.id);
// Check that the type of the value being matched is a subtype of
// the type of the pattern.
use extra::list::Nil;
use syntax::ast::{def_id, sty_value, sty_region, sty_box};
use syntax::ast::{sty_uniq, sty_static, NodeId};
-use syntax::ast::{m_const, m_mutbl, m_imm};
+use syntax::ast::{m_mutbl, m_imm};
use syntax::ast;
use syntax::ast_map;
let opt_applicable_traits = trait_map.find(&self.expr.id);
for applicable_traits in opt_applicable_traits.iter() {
for trait_did in applicable_traits.iter() {
+ ty::populate_implementations_for_trait_if_necessary(
+ self.tcx(),
+ *trait_did);
+
// Look for explicit implementations.
let opt_impl_infos = self.tcx().trait_impls.find(trait_did);
for impl_infos in opt_impl_infos.iter() {
fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
+ // Read the inherent implementation candidates for this type from the
+ // metadata if necessary.
+ ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
+
let opt_impl_infos = self.tcx().inherent_impls.find(&did);
for impl_infos in opt_impl_infos.iter() {
for impl_info in impl_infos.iter() {
ty_evec(mt, vstore_fixed(_)) => {
// First try to borrow to a slice
let entry = self.search_for_some_kind_of_autorefd_method(
- AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl],
+ AutoBorrowVec, autoderefs, [m_imm, m_mutbl],
|m,r| ty::mk_evec(tcx,
ty::mt {ty:mt.ty, mutbl:m},
vstore_slice(r)));
// Then try to borrow to a slice *and* borrow a pointer.
self.search_for_some_kind_of_autorefd_method(
- AutoBorrowVecRef, autoderefs, [m_const, m_imm, m_mutbl],
+ AutoBorrowVecRef, autoderefs, [m_imm, m_mutbl],
|m,r| {
let slice_ty = ty::mk_evec(tcx,
ty::mt {ty:mt.ty, mutbl:m},
// Coerce ~/@/&Trait instances to &Trait.
self.search_for_some_kind_of_autorefd_method(
- AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl],
+ AutoBorrowObj, autoderefs, [m_imm, m_mutbl],
|trt_mut, reg| {
ty::mk_trait(tcx, trt_did, trt_substs.clone(),
RegionTraitStore(reg), trt_mut, b)
ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_struct(*) | ty_tup(*) |
ty_estr(*) | ty_evec(*) | ty_trait(*) | ty_closure(*) => {
self.search_for_some_kind_of_autorefd_method(
- AutoPtr, autoderefs, [m_const, m_imm, m_mutbl],
+ AutoPtr, autoderefs, [m_imm, m_mutbl],
|m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m}))
}
}
fn mutability_matches(self_mutbl: ast::mutability,
- candidate_mutbl: ast::mutability) -> bool {
+ candidate_mutbl: ast::mutability)
+ -> bool {
//! True if `self_mutbl <: candidate_mutbl`
-
- match (self_mutbl, candidate_mutbl) {
- (_, m_const) => true,
- (m_mutbl, m_mutbl) => true,
- (m_imm, m_imm) => true,
- (m_mutbl, m_imm) => false,
- (m_imm, m_mutbl) => false,
- (m_const, m_imm) => false,
- (m_const, m_mutbl) => false,
- }
+ self_mutbl == candidate_mutbl
}
}
use middle::lint::unreachable_code;
use middle::ty::{FnSig, VariantInfo};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
-use middle::ty::{substs, param_ty, ExprTyProvider};
+use middle::ty::{substs, param_ty, Disr, ExprTyProvider};
use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
self.assign(p.id, None);
debug!("Pattern binding %s is assigned to %s",
- self.tcx.sess.str_of(path.idents[0]),
+ self.tcx.sess.str_of(path.segments[0].identifier),
self.fcx.infcx().ty_to_str(
self.fcx.inh.locals.get_copy(&p.id)));
}
DoDerefArgs
}
-pub fn break_here() {
- debug!("break here!");
+// Given the provenance of a static method, returns the generics of the static
+// method's container.
+fn generics_of_static_method_container(type_context: ty::ctxt,
+ provenance: ast::MethodProvenance)
+ -> ty::Generics {
+ match provenance {
+ ast::FromTrait(trait_def_id) => {
+ ty::lookup_trait_def(type_context, trait_def_id).generics
+ }
+ ast::FromImpl(impl_def_id) => {
+ ty::lookup_item_type(type_context, impl_def_id).generics
+ }
+ }
+}
+
+// Verifies that type parameters supplied in paths are in the right
+// locations.
+fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt,
+ path: &ast::Path,
+ def: ast::def) {
+ // We only care about checking the case in which the path has two or
+ // more segments.
+ if path.segments.len() < 2 {
+ return
+ }
+
+ // Verify that no lifetimes or type parameters are present anywhere
+ // except the final two elements of the path.
+ for i in range(0, path.segments.len() - 2) {
+ match path.segments[i].lifetime {
+ None => {}
+ Some(lifetime) => {
+ function_context.tcx()
+ .sess
+ .span_err(lifetime.span,
+ "lifetime parameters may not \
+ appear here")
+ }
+ }
+
+ for typ in path.segments[i].types.iter() {
+ function_context.tcx()
+ .sess
+ .span_err(typ.span,
+ "type parameters may not appear here")
+ }
+ }
+
+ // If there are no parameters at all, there is nothing more to do; the
+ // rest of typechecking will (attempt to) infer everything.
+ if path.segments
+ .iter()
+ .all(|s| s.lifetime.is_none() && s.types.is_empty()) {
+ return
+ }
+
+ match def {
+ // If this is a static method of a trait or implementation, then
+ // ensure that the segment of the path which names the trait or
+ // implementation (the penultimate segment) is annotated with the
+ // right number of type parameters.
+ ast::def_static_method(_, provenance, _) => {
+ let generics =
+ generics_of_static_method_container(function_context.ccx.tcx,
+ provenance);
+ let name = match provenance {
+ ast::FromTrait(_) => "trait",
+ ast::FromImpl(_) => "impl",
+ };
+
+ let trait_segment = &path.segments[path.segments.len() - 2];
+
+ // Make sure lifetime parameterization agrees with the trait or
+ // implementation type.
+ match (generics.region_param, trait_segment.lifetime) {
+ (Some(_), None) => {
+ function_context.tcx()
+ .sess
+ .span_err(path.span,
+ fmt!("this %s has a lifetime \
+ parameter but no \
+ lifetime was specified",
+ name))
+ }
+ (None, Some(_)) => {
+ function_context.tcx()
+ .sess
+ .span_err(path.span,
+ fmt!("this %s has no lifetime \
+ parameter but a lifetime \
+ was specified",
+ name))
+ }
+ (Some(_), Some(_)) | (None, None) => {}
+ }
+
+ // Make sure the number of type parameters supplied on the trait
+ // or implementation segment equals the number of type parameters
+ // on the trait or implementation definition.
+ let trait_type_parameter_count = generics.type_param_defs.len();
+ let supplied_type_parameter_count = trait_segment.types.len();
+ if trait_type_parameter_count != supplied_type_parameter_count {
+ let trait_count_suffix = if trait_type_parameter_count == 1 {
+ ""
+ } else {
+ "s"
+ };
+ let supplied_count_suffix =
+ if supplied_type_parameter_count == 1 {
+ ""
+ } else {
+ "s"
+ };
+ function_context.tcx()
+ .sess
+ .span_err(path.span,
+ fmt!("the %s referenced by this \
+ path has %u type \
+ parameter%s, but %u type \
+ parameter%s were supplied",
+ name,
+ trait_type_parameter_count,
+ trait_count_suffix,
+ supplied_type_parameter_count,
+ supplied_count_suffix))
+ }
+ }
+ _ => {
+ // Verify that no lifetimes or type parameters are present on
+ // the penultimate segment of the path.
+ let segment = &path.segments[path.segments.len() - 2];
+ match segment.lifetime {
+ None => {}
+ Some(lifetime) => {
+ function_context.tcx()
+ .sess
+ .span_err(lifetime.span,
+ "lifetime parameters may not
+ appear here")
+ }
+ }
+ for typ in segment.types.iter() {
+ function_context.tcx()
+ .sess
+ .span_err(typ.span,
+ "type parameters may not appear \
+ here");
+ function_context.tcx()
+ .sess
+ .span_note(typ.span,
+ fmt!("this is a %?", def));
+ }
+ }
+ }
}
/// Invariant:
ast::expr_path(ref pth) => {
let defn = lookup_def(fcx, pth.span, id);
+ check_type_parameter_positions_in_path(fcx, pth, defn);
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
- instantiate_path(fcx, pth, tpt, expr.span, expr.id);
+ instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
}
ast::expr_self => {
let definition = lookup_def(fcx, expr.span, id);
let rty = ty::node_id_to_type(ccx.tcx, id);
let mut variants: ~[@ty::VariantInfo] = ~[];
- let mut disr_vals: ~[uint] = ~[];
- let mut prev_disr_val: Option<uint> = None;
+ let mut disr_vals: ~[ty::Disr] = ~[];
+ let mut prev_disr_val: Option<ty::Disr> = None;
for v in vs.iter() {
// handle, so we may still get an internal compiler error
match const_eval::eval_const_expr_partial(&ccx.tcx, e) {
- Ok(const_eval::const_int(val)) => current_disr_val = val as uint,
- Ok(const_eval::const_uint(val)) => current_disr_val = val as uint,
+ Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
+ Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
Ok(_) => {
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
}
defn: ast::def)
-> ty_param_bounds_and_ty {
match defn {
- ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid, _) |
+ ast::def_arg(nid, _) | ast::def_local(nid, _) | ast::def_self(nid) |
ast::def_binding(nid, _) => {
let typ = fcx.local_ty(sp, nid);
return no_params(typ);
pub fn instantiate_path(fcx: @mut FnCtxt,
pth: &ast::Path,
tpt: ty_param_bounds_and_ty,
+ def: ast::def,
span: span,
node_id: ast::NodeId) {
debug!(">>> instantiate_path");
let ty_param_count = tpt.generics.type_param_defs.len();
- let ty_substs_len = pth.types.len();
+ let mut ty_substs_len = 0;
+ for segment in pth.segments.iter() {
+ ty_substs_len += segment.types.len()
+ }
debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
tpt.repr(fcx.tcx()),
// determine the region bound, using the value given by the user
// (if any) and otherwise using a fresh region variable
- let regions = match pth.rp {
+ let regions = match pth.segments.last().lifetime {
Some(_) => { // user supplied a lifetime parameter...
match tpt.generics.region_param {
None => { // ...but the type is not lifetime parameterized!
}
Some(_) => { // ...and the type is lifetime parameterized, ok.
opt_vec::with(
- ast_region_to_region(fcx, fcx, span, &pth.rp))
+ ast_region_to_region(fcx,
+ fcx,
+ span,
+ &pth.segments.last().lifetime))
}
}
}
}
};
+ // Special case: If there is a self parameter, omit it from the list of
+ // type parameters.
+ //
+ // Here we calculate the "user type parameter count", which is the number
+ // of type parameters actually manifest in the AST. This will differ from
+ // the internal type parameter count when there are self types involved.
+ let (user_type_parameter_count, self_parameter_index) = match def {
+ ast::def_static_method(_, provenance @ ast::FromTrait(_), _) => {
+ let generics = generics_of_static_method_container(fcx.ccx.tcx,
+ provenance);
+ (ty_param_count - 1, Some(generics.type_param_defs.len()))
+ }
+ _ => (ty_param_count, None),
+ };
+
// determine values for type parameters, using the values given by
// the user (if any) and otherwise using fresh type variables
let tps = if ty_substs_len == 0 {
fcx.ccx.tcx.sess.span_err
(span, "this item does not take type parameters");
fcx.infcx().next_ty_vars(ty_param_count)
- } else if ty_substs_len > ty_param_count {
+ } else if ty_substs_len > user_type_parameter_count {
fcx.ccx.tcx.sess.span_err
(span,
fmt!("too many type parameters provided: expected %u, found %u",
- ty_param_count, ty_substs_len));
+ user_type_parameter_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
- } else if ty_substs_len < ty_param_count {
- let is_static_method = match fcx.ccx.tcx.def_map.find(&node_id) {
- Some(&ast::def_static_method(*)) => true,
- _ => false
- };
+ } else if ty_substs_len < user_type_parameter_count {
fcx.ccx.tcx.sess.span_err
(span,
fmt!("not enough type parameters provided: expected %u, found %u",
- ty_param_count, ty_substs_len));
- if is_static_method {
- fcx.ccx.tcx.sess.span_note
- (span, "Static methods have an extra implicit type parameter -- \
- did you omit the type parameter for the `Self` type?");
- }
+ user_type_parameter_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else {
- pth.types.map(|aty| fcx.to_ty(aty))
+ // Build up the list of type parameters, inserting the self parameter
+ // at the appropriate position.
+ let mut result = ~[];
+ let mut pushed = false;
+ for (i, ast_type) in pth.segments
+ .iter()
+ .flat_map(|segment| segment.types.iter())
+ .enumerate() {
+ match self_parameter_index {
+ Some(index) if index == i => {
+ result.push(fcx.infcx().next_ty_vars(1)[0]);
+ pushed = true;
+ }
+ _ => {}
+ }
+ result.push(fcx.to_ty(ast_type))
+ }
+
+ // If the self parameter goes at the end, insert it there.
+ if !pushed && self_parameter_index.is_some() {
+ result.push(fcx.infcx().next_ty_vars(1)[0])
+ }
+
+ assert_eq!(result.len(), ty_param_count)
+ result
};
- let substs = substs {regions: ty::NonerasedRegions(regions),
- self_ty: None,
- tps: tps };
+ let substs = substs {
+ regions: ty::NonerasedRegions(regions),
+ self_ty: None,
+ tps: tps
+ };
fcx.write_ty_substs(node_id, tpt.ty, substs);
debug!("<<<");
mutbl: ast::m_imm
}))
}
- "offset_inbounds" => {
- (1,
- ~[
- ty::mk_ptr(tcx, ty::mt {
- ty: param(ccx, 0),
- mutbl: ast::m_imm
- }),
- ty::mk_int()
- ],
- ty::mk_ptr(tcx, ty::mt {
- ty: param(ccx, 0),
- mutbl: ast::m_imm
- }))
- }
"memcpy32" => {
(1,
~[
let tcx = fcx.tcx();
match def {
def_local(node_id, _) | def_arg(node_id, _) |
- def_self(node_id, _) | def_binding(node_id, _) => {
+ def_self(node_id) | def_binding(node_id, _) => {
tcx.region_maps.encl_region(node_id)
}
def_upvar(_, subdef, closure_id, body_id) => {
use syntax::ast_util;
use syntax::codemap::span;
use syntax::print::pprust::expr_to_str;
-use syntax::oldvisit;
+use syntax::visit;
+use syntax::visit::Visitor;
// vtable resolution looks for places where trait bounds are
// substituted in and figures out which vtable is used. There is some
// ...and here trait_ref is each bound that was declared on A,
// expressed in terms of the type parameters.
+ ty::populate_implementations_for_trait_if_necessary(tcx,
+ trait_ref.def_id);
+
// Substitute the values of the type parameters that may
// appear in the bound.
let trait_ref = substs.map_default(trait_ref, |substs| {
let mut found = ~[];
let mut impls_seen = HashSet::new();
+ // Load the implementations from external metadata if necessary.
+ ty::populate_implementations_for_trait_if_necessary(tcx,
+ trait_ref.def_id);
+
// XXX: this is a bad way to do this, since we do
// pointless allocations.
let impls = tcx.trait_impls.find(&trait_ref.def_id)
}
}
-fn resolve_expr(ex: @ast::expr,
- (fcx, v): (@mut FnCtxt,
- oldvisit::vt<@mut FnCtxt>)) {
+fn resolve_expr(v: &mut VtableResolveVisitor,
+ ex: @ast::expr,
+ fcx: @mut FnCtxt) {
early_resolve_expr(ex, fcx, false);
- oldvisit::visit_expr(ex, (fcx, v));
+ visit::walk_expr(v, ex, fcx);
}
pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
}
}
+struct VtableResolveVisitor;
+
+impl visit::Visitor<@mut FnCtxt> for VtableResolveVisitor {
+ fn visit_expr(&mut self, ex:@ast::expr, e:@mut FnCtxt) {
+ resolve_expr(self, ex, e);
+ }
+ fn visit_item(&mut self, _:@ast::item, _:@mut FnCtxt) {
+ // no-op
+ }
+}
+
// Detect points where a trait-bounded type parameter is
// instantiated, resolve the impls for the parameters.
pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::Block) {
- oldvisit::visit_block(bl, (fcx, oldvisit::mk_vt(@oldvisit::Visitor {
- visit_expr: resolve_expr,
- visit_item: |_,_| {},
- .. *oldvisit::default_visitor()
- })));
+ let mut visitor = VtableResolveVisitor;
+ visit::walk_block(&mut visitor, bl, fcx);
}
// each trait in the system to its implementations.
-use metadata::csearch::{each_path, get_impl_trait};
+use metadata::csearch::{each_impl, get_impl_trait};
use metadata::csearch;
use metadata::cstore::iter_crate_data;
-use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::ty::get;
-use middle::ty::{lookup_item_type, subst};
+use middle::ty::{ImplContainer, lookup_item_type, subst};
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};
use syntax::ast_map::node_item;
use syntax::ast_map;
use syntax::ast_util::{def_id_of_def, local_def};
-use syntax::codemap::{span, dummy_sp};
+use syntax::codemap::span;
use syntax::opt_vec;
use syntax::visit;
use syntax::parse;
-use util::ppaux::ty_to_str;
-use std::hashmap::{HashMap, HashSet};
+use std::hashmap::HashSet;
use std::result::Ok;
use std::vec;
CoherenceChecker {
crate_context: crate_context,
inference_context: new_infer_ctxt(crate_context.tcx),
-
- base_type_def_ids: @mut HashMap::new(),
}
}
pub struct CoherenceChecker {
crate_context: @mut CrateCtxt,
inference_context: @mut InferCtxt,
-
- // A mapping from implementations to the corresponding base type
- // definition ID.
-
- base_type_def_ids: @mut HashMap<def_id,def_id>,
}
struct CoherenceCheckVisitor { cc: CoherenceChecker }
if associated_traits.len() == 0 {
self.add_inherent_impl(base_type_def_id, implementation);
}
-
- self.base_type_def_ids.insert(local_def(item.id),
- base_type_def_id);
}
}
let tcx = self.crate_context.tcx;
let implementation = @csearch::get_impl(tcx, impl_def_id);
- debug!("coherence: adding impl from external crate: %s",
- ty::item_path_str(tcx, implementation.did));
-
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(implementation.did) {
// Skip this one.
}
// Good. Continue.
- let self_type = lookup_item_type(tcx, implementation.did);
- let associated_traits = get_impl_trait(tcx,
- implementation.did);
+ let _ = lookup_item_type(tcx, implementation.did);
+ let associated_traits = get_impl_trait(tcx, implementation.did);
- // Do a sanity check to make sure that inherent methods have base
- // types.
- if associated_traits.is_none() {
- match get_base_type_def_id(self.inference_context,
- dummy_sp(),
- self_type.ty) {
- None => {
- tcx.sess.bug(fmt!("no base type for external impl with no \
- trait: %s (type %s)!",
- tcx.sess.str_of(implementation.ident),
- ty_to_str(tcx, self_type.ty)));
- }
- Some(_) => {} // Nothing to do.
- }
- }
+ // Do a sanity check.
+ assert!(associated_traits.is_some());
// Record all the trait methods.
for trait_ref in associated_traits.iter() {
}
}
- // Add the implementation to the mapping from implementation to base
- // type def ID, if there is a base type for this implementation.
- match get_base_type_def_id(self.inference_context,
- dummy_sp(),
- self_type.ty) {
- None => {} // Nothing to do.
- Some(base_type_def_id) => {
- // inherent methods apply to `impl Type` but not
- // `impl Trait for Type`:
- if associated_traits.is_none() {
- self.add_inherent_impl(base_type_def_id,
- implementation);
- }
-
- self.base_type_def_ids.insert(implementation.did,
- base_type_def_id);
- }
- }
-
tcx.impls.insert(implementation.did, implementation);
}
let crate_store = self.crate_context.tcx.sess.cstore;
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
- do each_path(crate_store, crate_number) |_, def_like, _| {
- match def_like {
- dl_impl(def_id) => {
- self.add_external_impl(&mut impls_seen, def_id)
- }
- dl_def(_) | dl_field => (), // Skip this.
- }
- true
- };
+ do each_impl(crate_store, crate_number) |def_id| {
+ assert_eq!(crate_number, def_id.crate);
+ self.add_external_impl(&mut impls_seen, def_id)
+ }
}
}
method.explicit_self,
method.vis,
new_def_id,
- impl_id,
+ ImplContainer(impl_id),
provided_source
)
}
use metadata::csearch;
-use middle::ty::{substs, ty_param_bounds_and_ty};
+use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
+use middle::ty::{ty_param_bounds_and_ty};
use middle::ty;
use middle::subst::Subst;
use middle::typeck::astconv::{AstConv, ty_of_arg};
// assume public, because this is only invoked on trait methods
ast::public,
local_def(*m_id),
- local_def(trait_id),
+ TraitContainer(local_def(trait_id)),
None
)
}
}
pub fn convert_methods(ccx: &CrateCtxt,
- container_id: ast::NodeId,
+ container: MethodContainer,
ms: &[@ast::method],
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
let m_ty_generics =
ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
num_rcvr_ty_params);
- let mty =
- @ty_of_method(ccx, container_id, *m, rcvr_ty_generics.region_param,
- untransformed_rcvr_ty,
- rcvr_ast_generics, rcvr_visibility,
- &m.generics);
+ let mty = @ty_of_method(ccx,
+ container,
+ *m,
+ rcvr_ty_generics.region_param,
+ untransformed_rcvr_ty,
+ rcvr_ast_generics,
+ rcvr_visibility,
+ &m.generics);
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
tcx.tcache.insert(
local_def(m.id),
}).collect();
fn ty_of_method(ccx: &CrateCtxt,
- container_id: ast::NodeId,
+ container: MethodContainer,
m: &ast::method,
rp: Option<ty::region_variance>,
untransformed_rcvr_ty: ty::t,
m.explicit_self.node,
method_vis,
local_def(m.id),
- local_def(container_id),
+ container,
None
)
}
it.vis
};
- let cms = convert_methods(ccx, it.id, *ms, selfty,
- &i_ty_generics, generics,
+ let cms = convert_methods(ccx,
+ ImplContainer(local_def(it.id)),
+ *ms,
+ selfty,
+ &i_ty_generics,
+ generics,
parent_visibility);
for t in opt_trait_ref.iter() {
// Prevent the builtin kind traits from being manually implemented.
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
let (ty_generics, _) = mk_item_substs(ccx, generics, rp,
Some(untransformed_rcvr_ty));
- let _ = convert_methods(ccx, it.id, provided_methods,
+ let _ = convert_methods(ccx,
+ TraitContainer(local_def(it.id)),
+ provided_methods,
untransformed_rcvr_ty,
- &ty_generics, generics,
+ &ty_generics,
+ generics,
it.vis);
// We need to do this *after* converting methods, since
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::isr_alist;
-use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
+use syntax::ast::{Many, Once, extern_fn, impure_fn, m_imm, m_mutbl};
use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity};
use util::common::{indenter};
match (a.mutbl, b.mutbl) {
// If one side or both is mut, then the GLB must use
// the precise type from the mut side.
- (m_mutbl, m_const) => {
- Sub(**self).tys(a.ty, b.ty).chain(|_t| {
- Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
- })
- }
- (m_const, m_mutbl) => {
- Sub(**self).tys(b.ty, a.ty).chain(|_t| {
- Ok(ty::mt {ty: b.ty, mutbl: m_mutbl})
- })
- }
(m_mutbl, m_mutbl) => {
eq_tys(self, a.ty, b.ty).then(|| {
Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
// If one side or both is immutable, we can use the GLB of
// both sides but mutbl must be `m_imm`.
- (m_imm, m_const) |
- (m_const, m_imm) |
(m_imm, m_imm) => {
self.tys(a.ty, b.ty).chain(|t| {
Ok(ty::mt {ty: t, mutbl: m_imm})
})
}
- // If both sides are const, then we can use GLB of both
- // sides and mutbl of only `m_const`.
- (m_const, m_const) => {
- self.tys(a.ty, b.ty).chain(|t| {
- Ok(ty::mt {ty: t, mutbl: m_const})
- })
- }
-
// There is no mutual subtype of these combinations.
(m_mutbl, m_imm) |
(m_imm, m_mutbl) => {
use util::ppaux::mt_to_str;
use extra::list;
-use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn};
+use syntax::ast::{Many, Once, extern_fn, impure_fn};
use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity};
mt_to_str(tcx, a),
mt_to_str(tcx, b));
- let m = if a.mutbl == b.mutbl {
- a.mutbl
- } else {
- m_const
- };
+ if a.mutbl != b.mutbl {
+ return Err(ty::terr_mutability)
+ }
+ let m = a.mutbl;
match m {
- m_imm | m_const => {
+ m_imm => {
self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) )
}
eq_tys(self, a.ty, b.ty).then(|| {
Ok(ty::mt {ty: a.ty, mutbl: m})
})
- }).chain_err(|_e| {
- self.tys(a.ty, b.ty).chain(|t| {
- Ok(ty::mt {ty: t, mutbl: m_const})
- })
- })
+ }).chain_err(|e| Err(e))
}
}
}
use extra::list::Nil;
use extra::list;
-use syntax::ast::{Onceness, m_const, purity};
+use syntax::ast::{Onceness, purity};
pub struct Sub(CombineFields); // "subtype", "subregion" etc
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx));
- if a.mutbl != b.mutbl && b.mutbl != m_const {
+ if a.mutbl != b.mutbl {
return Err(ty::terr_mutability);
}
// (i.e., invariant if mut):
eq_tys(self, a.ty, b.ty).then(|| Ok(*a))
}
- m_imm | m_const => {
+ m_imm => {
// Otherwise we can be covariant:
self.tys(a.ty, b.ty).chain(|_t| Ok(*a) )
}
pub mod x86_64;
pub mod rpath;
pub mod target_strs;
- pub mod passes;
}
pub mod metadata;
}
if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
- back::passes::list_passes();
+ unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
return;
}
match m {
ast::m_mutbl => ~"mut ",
ast::m_imm => ~"",
- ast::m_const => ~"const "
}
}
];
do generic_writer |markdown| {
- use std::io::WriterUtil;
-
debug!("pandoc cmd: %s", pandoc_cmd);
debug!("pandoc args: %s", pandoc_args.connect(" "));
- let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
+ let proc = run::Process::new(pandoc_cmd, pandoc_args,
+ run::ProcessOptions::new());
+ let mut proc = proc.unwrap();
- proc.input().write_str(markdown);
+ proc.input().write(markdown.as_bytes());
let output = proc.finish_with_output();
debug!("pandoc result: %i", output.status);
/// True if there's a directory in <workspace> with
/// pkgid's short name
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
+ debug!("Checking in src dir of %s for %s",
+ workspace.to_str(), pkgid.to_str());
+
let src_dir = workspace.push("src");
let mut found = false;
}
true
};
+
+ debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
+ else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
found
}
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace};
use source_control::is_git_dir;
-use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, in_workspace, cwd_to_workspace};
+use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
use context::Ctx;
use package_id::PkgId;
use package_source::PkgSrc;
match cmd {
"build" => {
if args.len() < 1 {
- if !in_workspace(|| { usage::build() } ) {
- return;
+ match cwd_to_workspace() {
+ None => { usage::build(); return }
+ Some((ws, pkgid)) => self.build(&ws, &pkgid)
}
- let (workspace, pkgid) = cwd_to_workspace();
- self.build(&workspace, &pkgid);
}
else {
// The package id is presumed to be the first command-line
}
"clean" => {
if args.len() < 1 {
- if !in_workspace(|| { usage::clean() } ) {
- return;
+ match cwd_to_workspace() {
+ None => { usage::clean(); return }
+ // tjc: Maybe clean should clean all the packages in the
+ // current workspace, though?
+ Some((ws, pkgid)) => self.clean(&ws, &pkgid)
}
- // tjc: Maybe clean should clean all the packages in the
- // current workspace, though?
- let (workspace, pkgid) = cwd_to_workspace();
- self.clean(&workspace, &pkgid);
}
else {
}
"install" => {
if args.len() < 1 {
- if !in_workspace(|| { usage::install() }) {
- return;
+ match cwd_to_workspace() {
+ None => { usage::install(); return }
+ Some((ws, pkgid)) => self.install(&ws, &pkgid)
}
- let (workspace, pkgid) = cwd_to_workspace();
- self.install(&workspace, &pkgid);
}
else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0]);
let workspaces = pkg_parent_workspaces(&pkgid);
+ debug!("package ID = %s, found it in %? workspaces",
+ pkgid.to_str(), workspaces.len());
if workspaces.is_empty() {
let rp = rust_path();
assert!(!rp.is_empty());
pub fn main_args(args: &[~str]) {
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
getopts::optflag("j"), getopts::optflag("json"),
- getopts::optmulti("c"), getopts::optmulti("cfg")];
+ getopts::optmulti("c"), getopts::optmulti("cfg"),
+ getopts::optflag("v"), getopts::optflag("version")];
let matches = &match getopts::getopts(args, opts) {
result::Ok(m) => m,
result::Err(f) => {
getopts::opt_present(matches, "help");
let json = getopts::opt_present(matches, "j") ||
getopts::opt_present(matches, "json");
+
+ if getopts::opt_present(matches, "v") ||
+ getopts::opt_present(matches, "version") {
+ rustc::version(args[0]);
+ return;
+ }
+
let mut args = matches.free.clone();
args.shift();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use path_util::installed_library_in_workspace;
+use path_util::{installed_library_in_workspace, rust_path};
+use version::Version;
/// If a library with path `p` matching pkg_id's name exists under sroot_opt,
/// return Some(p). Return None if there's no such path or if sroot_opt is None.
installed_library_in_workspace(short_name, sroot)
}
}
+
+/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
+/// return Some(p) (returns the first one of there are multiple matches.) Return
+/// None if there's no such path.
+/// FIXME #8711: This ignores the desired version.
+pub fn find_installed_library_in_rust_path(short_name: &str, _version: &Version) -> Option<Path> {
+ let rp = rust_path();
+ for p in rp.iter() {
+ match installed_library_in_workspace(short_name, p) {
+ Some(path) => return Some(path),
+ None => ()
+ }
+ }
+ None
+}
fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {
let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
- ,..ProcessOptions::new()});
+ ,..ProcessOptions::new()}).unwrap();
prog.finish_with_output()
}
use installed_packages::list_installed_packages;
use package_id::{PkgId};
use version::{ExactRevision, NoVersion, Version, Tagged};
-use path_util::{target_executable_in_workspace, target_library_in_workspace,
- target_test_in_workspace, target_bench_in_workspace,
- make_dir_rwx, U_RWX, library_in_workspace,
+use path_util::{target_executable_in_workspace, target_test_in_workspace,
+ target_bench_in_workspace, make_dir_rwx, U_RWX,
+ library_in_workspace, installed_library_in_workspace,
built_bench_in_workspace, built_test_in_workspace,
- built_library_in_workspace, built_executable_in_workspace,
- installed_library_in_workspace};
+ built_library_in_workspace, built_executable_in_workspace};
use rustc::metadata::filesearch::rust_path;
use rustc::driver::driver::host_triple;
use target::*;
fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
let cwd = (*cwd).clone();
- let mut prog = run::Process::new("git", args, run::ProcessOptions {
+ let prog = run::Process::new("git", args, run::ProcessOptions {
env: env,
dir: Some(&cwd),
in_fd: None,
out_fd: None,
err_fd: None
});
+ let mut prog = prog.unwrap();
let rslt = prog.finish_with_output();
if rslt.status != 0 {
fail!("%s [git returned %?, output = %s, error = %s]", err_msg,
in_fd: None,
out_fd: None,
err_fd: None
- });
+ }).unwrap();
let output = prog.finish_with_output();
debug!("Output from command %s with args %? was %s {%s}[%?]",
cmd, args, str::from_bytes(output.output),
push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
debug!("package_script_with_default_build: %s", source.to_str());
if !os::copy_file(&source,
- & dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
+ &dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
fail!("Couldn't copy file");
}
command_line_test([~"install", ~"fancy-lib"], &dir);
#[test]
fn rustpkg_build_no_arg() {
- let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed");
+ let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed")
+ .push(".rust");
let package_dir = tmp.push("src").push("foo");
assert!(os::mkdir_recursive(&package_dir, U_RWX));
#[test]
fn rustpkg_install_no_arg() {
let tmp = mkdtemp(&os::tmpdir(),
- "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed");
+ "rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed")
+ .push(".rust");
let package_dir = tmp.push("src").push("foo");
assert!(os::mkdir_recursive(&package_dir, U_RWX));
writeFile(&package_dir.push("lib.rs"),
#[test]
fn rustpkg_clean_no_arg() {
- let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed");
+ let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed")
+ .push(".rust");
let package_dir = tmp.push("src").push("foo");
assert!(os::mkdir_recursive(&package_dir, U_RWX));
assert!(bar_date < foo_date);
}
+// n.b. The following two tests are ignored; they worked "accidentally" before,
+// when the behavior was "always rebuild libraries" (now it's "never rebuild
+// libraries if they already exist"). They can be un-ignored once #7075 is done.
#[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
fn do_rebuild_dep_dates_change() {
let p_id = PkgId::new("foo");
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+ let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+ let bar_date = datestamp(&bar_lib_name);
+ debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
touch_source_file(&workspace, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+ let new_bar_date = datestamp(&bar_lib_name);
+ debug!("Datestamp on %s is %?", bar_lib_name.to_str(), new_bar_date);
assert!(new_bar_date > bar_date);
}
#[test]
+#[ignore(reason = "Workcache not yet implemented -- see #7075")]
fn do_rebuild_dep_only_contents_change() {
let p_id = PkgId::new("foo");
let dep_id = PkgId::new("bar");
test_sysroot().to_str(),
exec_file.to_str());
- let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
- ~"--sysroot", test_sysroot().to_str(),
- ~"-o", exec_file.to_str()],
- run::ProcessOptions {
+ let prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+ ~"--sysroot", test_sysroot().to_str(),
+ ~"-o", exec_file.to_str()],
+ run::ProcessOptions {
env: env,
dir: Some(&dir),
in_fd: None,
out_fd: None,
err_fd: None
});
+ let mut prog = prog.unwrap();
let outp = prog.finish_with_output();
if outp.status != 0 {
fail!("output was %s, error was %s",
os::EXE_SUFFIX))));
}
+#[test]
+fn multiple_workspaces() {
+// Make a package foo; build/install in directory A
+// Copy the exact same package into directory B and install it
+// Set the RUST_PATH to A:B
+// Make a third package that uses foo, make sure we can build/install it
+ let a_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+ let b_loc = mk_temp_workspace(&Path("foo"), &NoVersion).pop().pop();
+ debug!("Trying to install foo in %s", a_loc.to_str());
+ command_line_test([~"install", ~"foo"], &a_loc);
+ debug!("Trying to install foo in %s", b_loc.to_str());
+ command_line_test([~"install", ~"foo"], &b_loc);
+ let env = Some(~[(~"RUST_PATH", fmt!("%s:%s", a_loc.to_str(), b_loc.to_str()))]);
+ let c_loc = create_local_package_with_dep(&PkgId::new("bar"), &PkgId::new("foo"));
+ command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
+}
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
use rustc::driver::session::{lib_crate, bin_crate};
use context::{Ctx, in_target};
use package_id::PkgId;
-use search::find_library_in_search_path;
+use search::{find_library_in_search_path, find_installed_library_in_rust_path};
use path_util::{target_library_in_workspace, U_RWX};
pub use target::{OutputType, Main, Lib, Bench, Test};
+use version::NoVersion;
// It would be nice to have the list of commands in just one place -- for example,
// you could update the match in rustpkg.rc but forget to update this list. I think
debug!("It exists: %s", installed_path.to_str());
}
None => {
- // Try to install it
- let pkg_id = PkgId::new(lib_name);
- my_ctxt.install(&my_workspace, &pkg_id);
- // Also, add an additional search path
- debug!("let installed_path...")
- let installed_path = target_library_in_workspace(&pkg_id,
+ // FIXME #8711: need to parse version out of path_opt
+ match find_installed_library_in_rust_path(lib_name, &NoVersion) {
+ Some(installed_path) => {
+ debug!("Found library %s, not rebuilding it",
+ installed_path.to_str());
+ // Once workcache is implemented, we'll actually check
+ // whether or not the library at installed_path is fresh
+ save(installed_path.pop());
+ }
+ None => {
+ debug!("Trying to install library %s, rebuilding it",
+ lib_name.to_str());
+ // Try to install it
+ let pkg_id = PkgId::new(lib_name);
+ my_ctxt.install(&my_workspace, &pkg_id);
+ // Also, add an additional search path
+ debug!("let installed_path...")
+ let installed_path = target_library_in_workspace(&pkg_id,
&my_workspace).pop();
- debug!("Great, I installed %s, and it's in %s",
- lib_name, installed_path.to_str());
- save(installed_path);
+ debug!("Great, I installed %s, and it's in %s",
+ lib_name, installed_path.to_str());
+ save(installed_path);
+ }
}
}
+ }
}
// Ignore `use`s
_ => ()
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
// Check for extra '#' characters separately
if s.split_iter('#').len() > 2 {
- None
- }
- else {
- split_version_general(s, '#')
+ return None;
}
+ split_version_general(s, '#')
}
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
// rustpkg utilities having to do with workspaces
-use std::os;
+use std::{os,util};
use std::path::Path;
use path_util::workspace_contains_package_id;
use package_id::PkgId;
-use rustc::metadata::filesearch::rust_path;
+use path_util::rust_path;
pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
// Using the RUST_PATH, find workspaces that contain
.collect()
}
-pub fn in_workspace(complain: &fn()) -> bool {
- let dir_part = os::getcwd().pop().components.clone();
- if *(dir_part.last()) != ~"src" {
- complain();
- false
- }
- else {
- true
- }
-}
-
/// Construct a workspace and package-ID name based on the current directory.
/// This gets used when rustpkg gets invoked without a package-ID argument.
-pub fn cwd_to_workspace() -> (Path, PkgId) {
+pub fn cwd_to_workspace() -> Option<(Path, PkgId)> {
let cwd = os::getcwd();
- let ws = cwd.pop().pop();
- let cwd_ = cwd.clone();
- let pkgid = cwd_.components.last().to_str();
- (ws, PkgId::new(pkgid))
+ for path in rust_path().move_iter() {
+ let srcpath = path.push("src");
+ if srcpath.is_ancestor_of(&cwd) {
+ // I'd love to use srcpath.get_relative_to(cwd) but it behaves wrong
+ // I'd say broken, but it has tests enforcing the wrong behavior.
+ // instead, just hack up the components vec
+ let mut pkgid = cwd;
+ pkgid.is_absolute = false;
+ let comps = util::replace(&mut pkgid.components, ~[]);
+ pkgid.components = comps.move_iter().skip(srcpath.components.len()).collect();
+ return Some((path, PkgId::new(pkgid.components.connect("/"))))
+ }
+ }
+ None
}
use rt::local::Local;
use rt::task::Task;
- do Local::borrow::<Task, *()> |task| {
+ do Local::borrow |task: &mut Task| {
task.heap.realloc(ptr as *libc::c_void, size) as *()
}
}
do cs.with_mut_ref |buf| {
for i in range(0, self.len()) {
unsafe {
- let p = buf.offset_inbounds(i as int);
+ let p = buf.offset(i as int);
if *p == 0 {
match null_byte::cond.raise(self.to_owned()) {
Truncate => break,
if ch == 0 {
None
} else {
- self.ptr = ptr::offset(self.ptr, 1);
+ self.ptr = unsafe { ptr::offset(self.ptr, 1) };
Some(ch)
}
}
//! Unsafe casting functions
+use ptr::RawPtr;
use sys;
use unstable::intrinsics;
/// Coerce an immutable reference to be mutable.
#[inline]
-pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
+pub unsafe fn transmute_mut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *mut T {
transmute(ptr)
}
/// Coerce an immutable reference to be mutable.
#[inline]
-pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
+pub unsafe fn transmute_immut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *T {
transmute(ptr)
}
#[test]
#[should_fail]
fn test_take_empty() {
- let value_cell = Cell::new_empty::<~int>();
+ let value_cell: Cell<~int> = Cell::new_empty();
value_cell.take();
}
#[doc(hidden)];
use libc::c_void;
-use ptr::{mut_null};
+use ptr::null;
use unstable::intrinsics::TyDesc;
use unstable::raw;
use rt::local_heap;
let mut box = local_heap::live_allocs();
- while box != mut_null() {
+ while box != null() {
let next_before = (*box).next;
let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE;
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The Default trait
+
+/// A trait that types which have a useful default value should implement.
+pub trait Default {
+ /// Return the "default value" for a type.
+ fn default() -> Self;
+}
# The Formatting Module
-This module contains the runtime support for the `ifmt!` syntax extension. This
+This module contains the runtime support for the `format!` syntax extension. This
macro is implemented in the compiler to emit calls to this module in order to
format arguments at runtime into strings and streams.
The functions contained in this module should not normally be used in everyday
-use cases of `ifmt!`. The assumptions made by these functions are unsafe for all
+use cases of `format!`. The assumptions made by these functions are unsafe for all
inputs, and the compiler performs a large amount of validation on the arguments
-to `ifmt!` in order to ensure safety at runtime. While it is possible to call
+to `format!` in order to ensure safety at runtime. While it is possible to call
these functions directly, it is not recommended to do so in the general case.
## Usage
-The `ifmt!` macro is intended to be familiar to those coming from C's
-printf/sprintf functions or Python's `str.format` function. In its current
-revision, the `ifmt!` macro returns a `~str` type which is the result of the
+The `format!` macro is intended to be familiar to those coming from C's
+printf/fprintf functions or Python's `str.format` function. In its current
+revision, the `format!` macro returns a `~str` type which is the result of the
formatting. In the future it will also be able to pass in a stream to format
arguments directly while performing minimal allocations.
-Some examples of the `ifmt!` extension are:
+Some examples of the `format!` extension are:
~~~{.rust}
-ifmt!("Hello") // => ~"Hello"
-ifmt!("Hello, {:s}!", "world") // => ~"Hello, world!"
-ifmt!("The number is {:d}", 1) // => ~"The number is 1"
-ifmt!("{}", ~[3, 4]) // => ~"~[3, 4]"
-ifmt!("{value}", value=4) // => ~"4"
-ifmt!("{} {}", 1, 2) // => ~"1 2"
+format!("Hello") // => ~"Hello"
+format!("Hello, {:s}!", "world") // => ~"Hello, world!"
+format!("The number is {:d}", 1) // => ~"The number is 1"
+format!("{}", ~[3, 4]) // => ~"~[3, 4]"
+format!("{value}", value=4) // => ~"4"
+format!("{} {}", 1, 2) // => ~"1 2"
~~~
From these, you can see that the first argument is a format string. It is
### Named parameters
Rust itself does not have a Python-like equivalent of named parameters to a
-function, but the `ifmt!` macro is a syntax extension which allows it to
+function, but the `format!` macro is a syntax extension which allows it to
leverage named parameters. Named parameters are listed at the end of the
argument list and have the syntax:
## Internationalization
-The formatting syntax supported by the `ifmt!` extension supports
+The formatting syntax supported by the `format!` extension supports
internationalization by providing "methods" which execute various different
outputs depending on the input. The syntax and methods provided are similar to
other internationalization systems, so again nothing should seem alien.
example:
~~~
-ifmt!("{0, select, other{#}}", "hello") // => ~"hello"
+format!("{0, select, other{#}}", "hello") // => ~"hello"
~~~
This example is the equivalent of `{0:s}` essentially.
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
-/// The sprintf function takes a precompiled format string and a list of
+/// The `write` function takes an output stream, a precompiled format string,
+/// and a list of arguments. The arguments will be formatted according to the
+/// specified format string into the output stream provided.
+///
+/// See the documentation for `format` for why this function is unsafe and care
+/// should be taken if calling it manually.
+///
+/// Thankfully the rust compiler provides the macro `fmtf!` which will perform
+/// all of this validation at compile-time and provides a safe interface for
+/// invoking this function.
+///
+/// # Arguments
+///
+/// * output - the buffer to write output to
+/// * fmts - the precompiled format string to emit
+/// * args - the list of arguments to the format string. These are only the
+/// positional arguments (not named)
+///
+/// Note that this function assumes that there are enough arguments for the
+/// format string.
+pub unsafe fn write(output: &mut io::Writer,
+ fmt: &[rt::Piece], args: &[Argument]) {
+ let mut formatter = Formatter {
+ flags: 0,
+ width: None,
+ precision: None,
+ buf: output,
+ align: parse::AlignUnknown,
+ fill: ' ',
+ args: args,
+ curarg: args.iter(),
+ };
+ for piece in fmt.iter() {
+ formatter.run(piece, None);
+ }
+}
+
+/// The format function takes a precompiled format string and a list of
/// arguments, to return the resulting formatted string.
///
/// This is currently an unsafe function because the types of all arguments
/// for formatting the right type value. Because of this, the function is marked
/// as `unsafe` if this is being called manually.
///
-/// Thankfully the rust compiler provides the macro `ifmt!` which will perform
+/// Thankfully the rust compiler provides the macro `format!` which will perform
/// all of this validation at compile-time and provides a safe interface for
/// invoking this function.
///
///
/// Note that this function assumes that there are enough arguments for the
/// format string.
-pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
- let output = MemWriter::new();
- {
- let mut formatter = Formatter {
- flags: 0,
- width: None,
- precision: None,
- // FIXME(#8248): shouldn't need a transmute
- buf: cast::transmute(&output as &io::Writer),
- align: parse::AlignUnknown,
- fill: ' ',
- args: args,
- curarg: args.iter(),
- };
- for piece in fmt.iter() {
- formatter.run(piece, None);
- }
- }
+pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
+ let mut output = MemWriter::new();
+ write(&mut output as &mut io::Writer, fmt, args);
return str::from_bytes_owned(output.inner());
}
// First up is the collection of functions used to execute a format string
// at runtime. This consumes all of the compile-time statics generated by
- // the ifmt! syntax extension.
+ // the format! syntax extension.
fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
let setcount = |slot: &mut Option<uint>, cnt: &parse::Count| {
}
/// This is a function which calls are emitted to by the compiler itself to
-/// create the Argument structures that are passed into the `sprintf` function.
+/// create the Argument structures that are passed into the `format` function.
#[doc(hidden)]
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
t: &'a T) -> Argument<'a> {
}
}
-// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same
-// time.
-impl<T> Pointer for *const T {
- fn fmt(t: &*const T, f: &mut Formatter) {
+impl<T> Pointer for *T {
+ fn fmt(t: &*T, f: &mut Formatter) {
+ f.flags |= 1 << (parse::FlagAlternate as uint);
+ do ::uint::to_str_bytes(*t as uint, 16) |buf| {
+ f.pad_integral(buf, "0x", true);
+ }
+ }
+}
+
+impl<T> Pointer for *mut T {
+ fn fmt(t: &*mut T, f: &mut Formatter) {
f.flags |= 1 << (parse::FlagAlternate as uint);
do ::uint::to_str_bytes(*t as uint, 16) |buf| {
f.pad_integral(buf, "0x", true);
delegate!(f32 to Float)
delegate!(f64 to Float)
-impl<T> Default for *const T {
- fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
+impl<T> Default for *T {
+ fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) }
+}
+
+impl<T> Default for *mut T {
+ fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
* IterBytes trait, that feeds SipHash.
*/
fn hash_keyed(&self, k0: u64, k1: u64) -> u64;
-}
-
-// When we have default methods, won't need this.
-pub trait HashUtil {
- fn hash(&self) -> u64;
-}
-impl<A:Hash> HashUtil for A {
#[inline]
fn hash(&self) -> u64 { self.hash_keyed(0,0) }
}
#[test]
fn test_find_or_insert() {
- let mut m = HashMap::new::<int, int>();
+ let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.find_or_insert(1, 2), 2);
assert_eq!(*m.find_or_insert(1, 3), 2);
}
#[test]
fn test_find_or_insert_with() {
- let mut m = HashMap::new::<int, int>();
+ let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.find_or_insert_with(1, |_| 2), 2);
assert_eq!(*m.find_or_insert_with(1, |_| 3), 2);
}
#[test]
fn test_insert_or_update_with() {
- let mut m = HashMap::new::<int, int>();
+ let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2);
assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3);
}
use int;
use iterator::Iterator;
use libc::consts::os::posix88::*;
-use libc::{c_int, c_long, c_void, size_t, ssize_t};
+use libc::{c_int, c_void, size_t};
use libc;
use num;
use ops::Drop;
unsafe {
assert!(libc::fseek(*self,
- offset as c_long,
+ offset as libc::c_long,
convert_whence(whence)) == 0 as c_int);
}
}
unsafe {
assert!(libc::fseek(*self,
- offset as c_long,
+ offset as libc::c_long,
convert_whence(whence)) == 0 as c_int);
}
}
fn write(&self, v: &[u8]) {
#[fixed_stack_segment]; #[inline(never)];
+ #[cfg(windows)]
+ type IoSize = libc::c_uint;
+ #[cfg(windows)]
+ type IoRet = c_int;
+
+ #[cfg(unix)]
+ type IoSize = size_t;
+ #[cfg(unix)]
+ type IoRet = libc::ssize_t;
+
unsafe {
let mut count = 0u;
do v.as_imm_buf |vbuf, len| {
while count < len {
let vb = ptr::offset(vbuf, count as int) as *c_void;
- let nout = libc::write(*self, vb, len as size_t);
- if nout < 0 as ssize_t {
+ let nout = libc::write(*self, vb, len as IoSize);
+ if nout < 0 as IoRet {
error!("error writing buffer");
error!("%s", os::last_os_error());
fail!();
impl<A: Add<A, A> + Zero, T: Iterator<A>> AdditiveIterator<A> for T {
#[inline]
- fn sum(&mut self) -> A { self.fold(Zero::zero::<A>(), |s, x| s + x) }
+ fn sum(&mut self) -> A {
+ let zero: A = Zero::zero();
+ self.fold(zero, |s, x| s + x)
+ }
}
/// A trait for iterators over elements whose elements can be multiplied
impl<A: Mul<A, A> + One, T: Iterator<A>> MultiplicativeIterator<A> for T {
#[inline]
- fn product(&mut self) -> A { self.fold(One::one::<A>(), |p, x| p * x) }
+ fn product(&mut self) -> A {
+ let one: A = One::one();
+ self.fold(one, |p, x| p * x)
+ }
}
/// A trait for iterators over elements which can be compared to one another.
pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
}
}
+
+ #[cfg(target_arch = "x86_64")]
+ pub mod arch {
+ pub mod c95 {
+ pub type c_char = i8;
+ pub type c_schar = i8;
+ pub type c_uchar = u8;
+ pub type c_short = i16;
+ pub type c_ushort = u16;
+ pub type c_int = i32;
+ pub type c_uint = u32;
+ pub type c_long = i32;
+ pub type c_ulong = u32;
+ pub type c_float = f32;
+ pub type c_double = f64;
+ pub type size_t = u64;
+ pub type ptrdiff_t = i64;
+ pub type clock_t = i32;
+ pub type time_t = i64;
+ pub type wchar_t = u16;
+ }
+ pub mod c99 {
+ pub type c_longlong = i64;
+ pub type c_ulonglong = u64;
+ pub type intptr_t = int;
+ pub type uintptr_t = uint;
+ }
+ pub mod posix88 {
+ pub type off_t = i32; // XXX unless _FILE_OFFSET_BITS == 64
+ pub type dev_t = u32;
+ pub type ino_t = i16;
+ pub type pid_t = i64;
+ pub type useconds_t = u32;
+ pub type mode_t = u16;
+ pub type ssize_t = i64;
+ }
+ pub mod posix01 {
+ }
+ pub mod posix08 {
+ }
+ pub mod bsd44 {
+ }
+ pub mod extra {
+ use ptr;
+ use libc::types::common::c95::c_void;
+ use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t};
+ use libc::types::os::arch::c95::{c_ulong};
+ use libc::types::os::arch::c95::{wchar_t};
+ use libc::types::os::arch::c99::{c_ulonglong};
+
+ pub type BOOL = c_int;
+ pub type BYTE = u8;
+ pub type CCHAR = c_char;
+ pub type CHAR = c_char;
+
+ pub type DWORD = c_ulong;
+ pub type DWORDLONG = c_ulonglong;
+
+ pub type HANDLE = LPVOID;
+ pub type HMODULE = c_uint;
+
+ pub type LONG_PTR = i64; // changed
+
+ pub type LPCWSTR = *WCHAR;
+ pub type LPCSTR = *CHAR;
+ pub type LPCTSTR = *CHAR;
+ pub type LPTCH = *CHAR;
+
+ pub type LPWSTR = *mut WCHAR;
+ pub type LPSTR = *mut CHAR;
+ pub type LPTSTR = *mut CHAR;
+
+ // Not really, but opaque to us.
+ pub type LPSECURITY_ATTRIBUTES = LPVOID;
+
+ pub type LPVOID = *mut c_void;
+ pub type LPCVOID = *c_void;
+ pub type LPBYTE = *mut BYTE;
+ pub type LPWORD = *mut WORD;
+ pub type LPDWORD = *mut DWORD;
+ pub type LPHANDLE = *mut HANDLE;
+
+ pub type LRESULT = LONG_PTR;
+ pub type PBOOL = *mut BOOL;
+ pub type WCHAR = wchar_t;
+ pub type WORD = u16;
+ pub type SIZE_T = size_t;
+
+ pub type time64_t = i64;
+ pub type int64 = i64;
+
+ pub struct STARTUPINFO {
+ cb: DWORD,
+ lpReserved: LPTSTR,
+ lpDesktop: LPTSTR,
+ lpTitle: LPTSTR,
+ dwX: DWORD,
+ dwY: DWORD,
+ dwXSize: DWORD,
+ dwYSize: DWORD,
+ dwXCountChars: DWORD,
+ dwYCountCharts: DWORD,
+ dwFillAttribute: DWORD,
+ dwFlags: DWORD,
+ wShowWindow: WORD,
+ cbReserved2: WORD,
+ lpReserved2: LPBYTE,
+ hStdInput: HANDLE,
+ hStdOutput: HANDLE,
+ hStdError: HANDLE
+ }
+ pub type LPSTARTUPINFO = *mut STARTUPINFO;
+
+ pub struct PROCESS_INFORMATION {
+ hProcess: HANDLE,
+ hThread: HANDLE,
+ dwProcessId: DWORD,
+ dwThreadId: DWORD
+ }
+ pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
+
+ pub struct SYSTEM_INFO {
+ wProcessorArchitecture: WORD,
+ wReserved: WORD,
+ dwPageSize: DWORD,
+ lpMinimumApplicationAddress: LPVOID,
+ lpMaximumApplicationAddress: LPVOID,
+ dwActiveProcessorMask: DWORD,
+ dwNumberOfProcessors: DWORD,
+ dwProcessorType: DWORD,
+ dwAllocationGranularity: DWORD,
+ wProcessorLevel: WORD,
+ wProcessorRevision: WORD
+ }
+ pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
+
+ impl SYSTEM_INFO {
+ pub fn new() -> SYSTEM_INFO {
+ SYSTEM_INFO {
+ wProcessorArchitecture: 0,
+ wReserved: 0,
+ dwPageSize: 0,
+ lpMinimumApplicationAddress: ptr::mut_null(),
+ lpMaximumApplicationAddress: ptr::mut_null(),
+ dwActiveProcessorMask: 0,
+ dwNumberOfProcessors: 0,
+ dwProcessorType: 0,
+ dwAllocationGranularity: 0,
+ wProcessorLevel: 0,
+ wProcessorRevision: 0
+ }
+ }
+ }
+
+ pub struct MEMORY_BASIC_INFORMATION {
+ BaseAddress: LPVOID,
+ AllocationBase: LPVOID,
+ AllocationProtect: DWORD,
+ RegionSize: SIZE_T,
+ State: DWORD,
+ Protect: DWORD,
+ Type: DWORD
+ }
+ pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
+ }
+ }
}
#[cfg(target_os = "macos")]
LPSYSTEM_INFO};
use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
+ #[cfg(target_arch = "x86")]
#[abi = "stdcall"]
extern "stdcall" {
pub fn GetEnvironmentVariableW(n: LPCWSTR,
-> LPVOID;
pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
}
+
+ #[cfg(target_arch = "x86_64")]
+ extern {
+ pub fn GetEnvironmentVariableW(n: LPCWSTR,
+ v: LPWSTR,
+ nsize: DWORD)
+ -> DWORD;
+ pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
+ -> BOOL;
+ pub fn GetEnvironmentStringsA() -> LPTCH;
+ pub fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
+ pub fn GetModuleFileNameW(hModule: HMODULE,
+ lpFilename: LPWSTR,
+ nSize: DWORD)
+ -> DWORD;
+ pub fn CreateDirectoryW(lpPathName: LPCWSTR,
+ lpSecurityAttributes:
+ LPSECURITY_ATTRIBUTES)
+ -> BOOL;
+ pub fn CopyFileW(lpExistingFileName: LPCWSTR,
+ lpNewFileName: LPCWSTR,
+ bFailIfExists: BOOL)
+ -> BOOL;
+ pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+ pub fn GetLastError() -> DWORD;
+ pub fn FindFirstFileW(fileName: *u16, findFileData: HANDLE)
+ -> HANDLE;
+ pub fn FindNextFileW(findFile: HANDLE, findFileData: HANDLE)
+ -> BOOL;
+ pub fn FindClose(findFile: HANDLE) -> BOOL;
+ pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+ hSourceHandle: HANDLE,
+ hTargetProcessHandle: HANDLE,
+ lpTargetHandle: LPHANDLE,
+ dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwOptions: DWORD)
+ -> BOOL;
+ pub fn CloseHandle(hObject: HANDLE) -> BOOL;
+ pub fn OpenProcess(dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwProcessId: DWORD)
+ -> HANDLE;
+ pub fn GetCurrentProcess() -> HANDLE;
+ pub fn CreateProcessA(lpApplicationName: LPCTSTR,
+ lpCommandLine: LPTSTR,
+ lpProcessAttributes:
+ LPSECURITY_ATTRIBUTES,
+ lpThreadAttributes:
+ LPSECURITY_ATTRIBUTES,
+ bInheritHandles: BOOL,
+ dwCreationFlags: DWORD,
+ lpEnvironment: LPVOID,
+ lpCurrentDirectory: LPCTSTR,
+ lpStartupInfo: LPSTARTUPINFO,
+ lpProcessInformation:
+ LPPROCESS_INFORMATION)
+ -> BOOL;
+ pub fn WaitForSingleObject(hHandle: HANDLE,
+ dwMilliseconds: DWORD)
+ -> DWORD;
+ pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint)
+ -> BOOL;
+ pub fn GetExitCodeProcess(hProcess: HANDLE,
+ lpExitCode: LPDWORD)
+ -> BOOL;
+ pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
+ pub fn VirtualAlloc(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ flAllocationType: DWORD,
+ flProtect: DWORD)
+ -> LPVOID;
+ pub fn VirtualFree(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ dwFreeType: DWORD)
+ -> BOOL;
+ pub fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
+ pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T)
+ -> BOOL;
+ pub fn VirtualProtect(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ flNewProtect: DWORD,
+ lpflOldProtect: LPDWORD)
+ -> BOOL;
+ pub fn VirtualQuery(lpAddress: LPCVOID,
+ lpBuffer: LPMEMORY_BASIC_INFORMATION,
+ dwLength: SIZE_T)
+ -> SIZE_T;
+ pub fn CreateFileMappingW(hFile: HANDLE,
+ lpAttributes: LPSECURITY_ATTRIBUTES,
+ flProtect: DWORD,
+ dwMaximumSizeHigh: DWORD,
+ dwMaximumSizeLow: DWORD,
+ lpName: LPCTSTR)
+ -> HANDLE;
+ pub fn MapViewOfFile(hFileMappingObject: HANDLE,
+ dwDesiredAccess: DWORD,
+ dwFileOffsetHigh: DWORD,
+ dwFileOffsetLow: DWORD,
+ dwNumberOfBytesToMap: SIZE_T)
+ -> LPVOID;
+ pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+ }
}
pub mod msvcrt {
*/
+use cast;
+use libc;
use prelude::*;
-
-use task::local_data_priv::*;
-
-#[cfg(test)] use task;
+use rt::task::{Task, LocalStorage};
+use util;
/**
* Indexes a task-local data slot. This pointer is used for comparison to
pub enum KeyValue<T> { Key }
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
- unsafe { local_pop(Handle::new(), key) }
-}
-
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
- unsafe { local_get(Handle::new(), key, f) }
-}
+trait LocalData {}
+impl<T: 'static> LocalData for T {}
-/**
- * Retrieve a mutable borrowed pointer to a task-local data value.
- */
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
- unsafe { local_get_mut(Handle::new(), key, f) }
+// The task-local-map stores all TLS information for the currently running task.
+// It is stored as an owned pointer into the runtime, and it's only allocated
+// when TLS is used for the first time. This map must be very carefully
+// constructed because it has many mutable loans unsoundly handed out on it to
+// the various invocations of TLS requests.
+//
+// One of the most important operations is loaning a value via `get` to a
+// caller. In doing so, the slot that the TLS entry is occupying cannot be
+// invalidated because upon returning it's loan state must be updated. Currently
+// the TLS map is a vector, but this is possibly dangerous because the vector
+// can be reallocated/moved when new values are pushed onto it.
+//
+// This problem currently isn't solved in a very elegant way. Inside the `get`
+// function, it internally "invalidates" all references after the loan is
+// finished and looks up into the vector again. In theory this will prevent
+// pointers from being moved under our feet so long as LLVM doesn't go too crazy
+// with the optimizations.
+//
+// n.b. If TLS is used heavily in future, this could be made more efficient with
+// a proper map.
+#[doc(hidden)]
+pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
+type TLSValue = ~LocalData;
+
+// Gets the map from the runtime. Lazily initialises if not done so already.
+unsafe fn get_local_map() -> &mut Map {
+ use rt::local::Local;
+
+ let task: *mut Task = Local::unsafe_borrow();
+ match &mut (*task).storage {
+ // If the at_exit function is already set, then we just need to take
+ // a loan out on the TLS map stored inside
+ &LocalStorage(Some(ref mut map_ptr)) => {
+ return map_ptr;
+ }
+ // If this is the first time we've accessed TLS, perform similar
+ // actions to the oldsched way of doing things.
+ &LocalStorage(ref mut slot) => {
+ *slot = Some(~[]);
+ match *slot {
+ Some(ref mut map_ptr) => { return map_ptr }
+ None => abort()
+ }
+ }
+ }
}
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-pub fn set<T: 'static>(key: Key<T>, data: T) {
- unsafe { local_set(Handle::new(), key, data) }
+#[deriving(Eq)]
+enum LoanState {
+ NoLoan, ImmLoan, MutLoan
}
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
- unsafe {
- match f(pop(::cast::unsafe_copy(&key))) {
- Some(next) => { set(key, next); }
- None => {}
+impl LoanState {
+ fn describe(&self) -> &'static str {
+ match *self {
+ NoLoan => "no loan",
+ ImmLoan => "immutable",
+ MutLoan => "mutable"
}
}
}
-#[test]
-fn test_tls_multitask() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"parent data");
- do task::spawn {
- // TLS shouldn't carry over.
- assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
- set(my_key, @~"child data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
- ~"child data");
- // should be cleaned up for us
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
+ unsafe { cast::transmute(key) }
+}
+
+/// Removes a task-local value from task-local storage. This will return
+/// Some(value) if the key was present in TLS, otherwise it will return None.
+///
+/// A runtime assertion will be triggered it removal of TLS value is attempted
+/// while the value is still loaned out via `get` or `get_mut`.
+pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
+ let map = unsafe { get_local_map() };
+ let key_value = key_to_key_value(key);
+
+ for entry in map.mut_iter() {
+ match *entry {
+ Some((k, _, loan)) if k == key_value => {
+ if loan != NoLoan {
+ fail!("TLS value cannot be removed because it is currently \
+ borrowed as %s", loan.describe());
+ }
+ // Move the data out of the `entry` slot via util::replace.
+ // This is guaranteed to succeed because we already matched
+ // on `Some` above.
+ let data = match util::replace(entry, None) {
+ Some((_, data, _)) => data,
+ None => abort()
+ };
+
+ // Move `data` into transmute to get out the memory that it
+ // owns, we must free it manually later.
+ let (_vtable, box): (uint, ~~T) = unsafe {
+ cast::transmute(data)
+ };
+
+ // Now that we own `box`, we can just move out of it as we would
+ // with any other data.
+ return Some(**box);
+ }
+ _ => {}
+ }
}
- // Must work multiple times
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ return None;
}
-#[test]
-fn test_tls_overwrite() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"first data");
- set(my_key, @~"next data"); // Shouldn't leak.
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
+/// reference to the value located in TLS if one exists, or `None` if the key
+/// provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via the `get_mut` method provided.
+pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
+ get_with(key, ImmLoan, f)
}
-#[test]
-fn test_tls_pop() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"weasel");
- assert!(*(pop(my_key).unwrap()) == ~"weasel");
- // Pop must remove the data from the map.
- assert!(pop(my_key).is_none());
+/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
+/// of a reference to the mutable value located in TLS if one exists, or `None`
+/// if the key provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via this or the `get` methods. This is similar to how it's a runtime
+/// error to take two mutable loans on an `@mut` box.
+pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
+ do get_with(key, MutLoan) |x| {
+ match x {
+ None => f(None),
+ // We're violating a lot of compiler guarantees with this
+ // invocation of `transmute_mut`, but we're doing runtime checks to
+ // ensure that it's always valid (only one at a time).
+ //
+ // there is no need to be upset!
+ Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
+ }
+ }
}
-#[test]
-fn test_tls_modify() {
- static my_key: Key<@~str> = &Key;
- modify(my_key, |data| {
- match data {
- Some(@ref val) => fail!("unwelcome value: %s", *val),
- None => Some(@~"first data")
+fn get_with<T: 'static, U>(key: Key<T>,
+ state: LoanState,
+ f: &fn(Option<&T>) -> U) -> U {
+ // This function must be extremely careful. Because TLS can store owned
+ // values, and we must have some form of `get` function other than `pop`,
+ // this function has to give a `&` reference back to the caller.
+ //
+ // One option is to return the reference, but this cannot be sound because
+ // the actual lifetime of the object is not known. The slot in TLS could not
+ // be modified until the object goes out of scope, but the TLS code cannot
+ // know when this happens.
+ //
+ // For this reason, the reference is yielded to a specified closure. This
+ // way the TLS code knows exactly what the lifetime of the yielded pointer
+ // is, allowing callers to acquire references to owned data. This is also
+ // sound so long as measures are taken to ensure that while a TLS slot is
+ // loaned out to a caller, it's not modified recursively.
+ let map = unsafe { get_local_map() };
+ let key_value = key_to_key_value(key);
+
+ let pos = map.iter().position(|entry| {
+ match *entry {
+ Some((k, _, _)) if k == key_value => true, _ => false
}
});
- modify(my_key, |data| {
- match data {
- Some(@~"first data") => Some(@~"next data"),
- Some(@ref val) => fail!("wrong value: %s", *val),
- None => fail!("missing value")
+ match pos {
+ None => { return f(None); }
+ Some(i) => {
+ let ret;
+ let mut return_loan = false;
+ match map[i] {
+ Some((_, ref data, ref mut loan)) => {
+ match (state, *loan) {
+ (_, NoLoan) => {
+ *loan = state;
+ return_loan = true;
+ }
+ (ImmLoan, ImmLoan) => {}
+ (want, cur) => {
+ fail!("TLS slot cannot be borrowed as %s because \
+ it is already borrowed as %s",
+ want.describe(), cur.describe());
+ }
+ }
+ // data was created with `~~T as ~LocalData`, so we extract
+ // pointer part of the trait, (as ~~T), and then use
+ // compiler coercions to achieve a '&' pointer.
+ unsafe {
+ match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data){
+ (_vtable, ref box) => {
+ let value: &T = **box;
+ ret = f(Some(value));
+ }
+ }
+ }
+ }
+ _ => abort()
+ }
+
+ // n.b. 'data' and 'loans' are both invalid pointers at the point
+ // 'f' returned because `f` could have appended more TLS items which
+ // in turn relocated the vector. Hence we do another lookup here to
+ // fixup the loans.
+ if return_loan {
+ match map[i] {
+ Some((_, _, ref mut loan)) => { *loan = NoLoan; }
+ None => abort()
+ }
+ }
+ return ret;
}
- });
- assert!(*(pop(my_key).unwrap()) == ~"next data");
+ }
}
-#[test]
-fn test_tls_crust_automorestack_memorial_bug() {
- // This might result in a stack-canary clobber if the runtime fails to
- // set sp_limit to 0 when calling the cleanup extern - it might
- // automatically jump over to the rust stack, which causes next_c_sp
- // to get recorded as something within a rust stack segment. Then a
- // subsequent upcall (esp. for logging, think vsnprintf) would run on
- // a stack smaller than 1 MB.
- static my_key: Key<@~str> = &Key;
- do task::spawn {
- set(my_key, @~"hax");
- }
+fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::abort() }
}
-#[test]
-fn test_tls_multiple_types() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- do task::spawn {
- set(str_key, @~"string data");
- set(box_key, @@());
- set(int_key, @42);
+/// Inserts a value into task local storage. If the key is already present in
+/// TLS, then the previous value is removed and replaced with the provided data.
+///
+/// It is considered a runtime error to attempt to set a key which is currently
+/// on loan via the `get` or `get_mut` methods.
+pub fn set<T: 'static>(key: Key<T>, data: T) {
+ let map = unsafe { get_local_map() };
+ let keyval = key_to_key_value(key);
+
+ // When the task-local map is destroyed, all the data needs to be cleaned
+ // up. For this reason we can't do some clever tricks to store '~T' as a
+ // '*c_void' or something like that. To solve the problem, we cast
+ // everything to a trait (LocalData) which is then stored inside the map.
+ // Upon destruction of the map, all the objects will be destroyed and the
+ // traits have enough information about them to destroy themselves.
+ //
+ // FIXME(#7673): This should be "~data as ~LocalData" (only one sigil)
+ let data = ~~data as ~LocalData:;
+
+ fn insertion_position(map: &mut Map,
+ key: *libc::c_void) -> Option<uint> {
+ // First see if the map contains this key already
+ let curspot = map.iter().position(|entry| {
+ match *entry {
+ Some((ekey, _, loan)) if key == ekey => {
+ if loan != NoLoan {
+ fail!("TLS value cannot be overwritten because it is
+ already borrowed as %s", loan.describe())
+ }
+ true
+ }
+ _ => false,
+ }
+ });
+ // If it doesn't contain the key, just find a slot that's None
+ match curspot {
+ Some(i) => Some(i),
+ None => map.iter().position(|entry| entry.is_none())
+ }
+ }
+
+ // The type of the local data map must ascribe to Send, so we do the
+ // transmute here to add the Send bound back on. This doesn't actually
+ // matter because TLS will always own the data (until its moved out) and
+ // we're not actually sending it to other schedulers or anything.
+ let data: ~LocalData = unsafe { cast::transmute(data) };
+ match insertion_position(map, keyval) {
+ Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
+ None => { map.push(Some((keyval, data, NoLoan))); }
}
}
-#[test]
-fn test_tls_overwrite_multiple_types() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- do task::spawn {
- set(str_key, @~"string data");
- set(int_key, @42);
- // This could cause a segfault if overwriting-destruction is done
- // with the crazy polymorphic transmute rather than the provided
- // finaliser.
- set(int_key, @31337);
+/// Modifies a task-local value by temporarily removing it from task-local
+/// storage and then re-inserting if `Some` is returned from the closure.
+///
+/// This function will have the same runtime errors as generated from `pop` and
+/// `set` (the key must not currently be on loan
+pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
+ match f(pop(key)) {
+ Some(next) => { set(key, next); }
+ None => {}
}
}
-#[test]
-#[should_fail]
-fn test_tls_cleanup_on_failure() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- set(str_key, @~"parent data");
- set(box_key, @@());
- do task::spawn {
- // spawn_linked
- set(str_key, @~"string data");
+#[cfg(test)]
+mod tests {
+ use prelude::*;
+ use super::*;
+ use task;
+
+ #[test]
+ fn test_tls_multitask() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"parent data");
+ do task::spawn {
+ // TLS shouldn't carry over.
+ assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
+ set(my_key, @~"child data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
+ ~"child data");
+ // should be cleaned up for us
+ }
+ // Must work multiple times
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ }
+
+ #[test]
+ fn test_tls_overwrite() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"first data");
+ set(my_key, @~"next data"); // Shouldn't leak.
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+ }
+
+ #[test]
+ fn test_tls_pop() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"weasel");
+ assert!(*(pop(my_key).unwrap()) == ~"weasel");
+ // Pop must remove the data from the map.
+ assert!(pop(my_key).is_none());
+ }
+
+ #[test]
+ fn test_tls_modify() {
+ static my_key: Key<@~str> = &Key;
+ modify(my_key, |data| {
+ match data {
+ Some(@ref val) => fail!("unwelcome value: %s", *val),
+ None => Some(@~"first data")
+ }
+ });
+ modify(my_key, |data| {
+ match data {
+ Some(@~"first data") => Some(@~"next data"),
+ Some(@ref val) => fail!("wrong value: %s", *val),
+ None => fail!("missing value")
+ }
+ });
+ assert!(*(pop(my_key).unwrap()) == ~"next data");
+ }
+
+ #[test]
+ fn test_tls_crust_automorestack_memorial_bug() {
+ // This might result in a stack-canary clobber if the runtime fails to
+ // set sp_limit to 0 when calling the cleanup extern - it might
+ // automatically jump over to the rust stack, which causes next_c_sp
+ // to get recorded as something within a rust stack segment. Then a
+ // subsequent upcall (esp. for logging, think vsnprintf) would run on
+ // a stack smaller than 1 MB.
+ static my_key: Key<@~str> = &Key;
+ do task::spawn {
+ set(my_key, @~"hax");
+ }
+ }
+
+ #[test]
+ fn test_tls_multiple_types() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ do task::spawn {
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
+ }
+ }
+
+ #[test]
+ fn test_tls_overwrite_multiple_types() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ do task::spawn {
+ set(str_key, @~"string data");
+ set(int_key, @42);
+ // This could cause a segfault if overwriting-destruction is done
+ // with the crazy polymorphic transmute rather than the provided
+ // finaliser.
+ set(int_key, @31337);
+ }
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_tls_cleanup_on_failure() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ set(str_key, @~"parent data");
set(box_key, @@());
- set(int_key, @42);
+ do task::spawn {
+ // spawn_linked
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
+ fail!();
+ }
+ // Not quite nondeterministic.
+ set(int_key, @31337);
fail!();
}
- // Not quite nondeterministic.
- set(int_key, @31337);
- fail!();
-}
-#[test]
-fn test_static_pointer() {
- static key: Key<@&'static int> = &Key;
- static VALUE: int = 0;
- let v: @&'static int = @&VALUE;
- set(key, v);
-}
+ #[test]
+ fn test_static_pointer() {
+ static key: Key<@&'static int> = &Key;
+ static VALUE: int = 0;
+ let v: @&'static int = @&VALUE;
+ set(key, v);
+ }
-#[test]
-fn test_owned() {
- static key: Key<~int> = &Key;
- set(key, ~1);
+ #[test]
+ fn test_owned() {
+ static key: Key<~int> = &Key;
+ set(key, ~1);
- do get(key) |v| {
do get(key) |v| {
do get(key) |v| {
+ do get(key) |v| {
+ assert_eq!(**v.unwrap(), 1);
+ }
assert_eq!(**v.unwrap(), 1);
}
assert_eq!(**v.unwrap(), 1);
}
- assert_eq!(**v.unwrap(), 1);
- }
- set(key, ~2);
- do get(key) |v| {
- assert_eq!(**v.unwrap(), 2);
+ set(key, ~2);
+ do get(key) |v| {
+ assert_eq!(**v.unwrap(), 2);
+ }
}
-}
-#[test]
-fn test_get_mut() {
- static key: Key<int> = &Key;
- set(key, 1);
+ #[test]
+ fn test_get_mut() {
+ static key: Key<int> = &Key;
+ set(key, 1);
- do get_mut(key) |v| {
- *v.unwrap() = 2;
- }
+ do get_mut(key) |v| {
+ *v.unwrap() = 2;
+ }
- do get(key) |v| {
- assert_eq!(*v.unwrap(), 2);
+ do get(key) |v| {
+ assert_eq!(*v.unwrap(), 2);
+ }
}
-}
-#[test]
-fn test_same_key_type() {
- static key1: Key<int> = &Key;
- static key2: Key<int> = &Key;
- static key3: Key<int> = &Key;
- static key4: Key<int> = &Key;
- static key5: Key<int> = &Key;
- set(key1, 1);
- set(key2, 2);
- set(key3, 3);
- set(key4, 4);
- set(key5, 5);
-
- get(key1, |x| assert_eq!(*x.unwrap(), 1));
- get(key2, |x| assert_eq!(*x.unwrap(), 2));
- get(key3, |x| assert_eq!(*x.unwrap(), 3));
- get(key4, |x| assert_eq!(*x.unwrap(), 4));
- get(key5, |x| assert_eq!(*x.unwrap(), 5));
-}
+ #[test]
+ fn test_same_key_type() {
+ static key1: Key<int> = &Key;
+ static key2: Key<int> = &Key;
+ static key3: Key<int> = &Key;
+ static key4: Key<int> = &Key;
+ static key5: Key<int> = &Key;
+ set(key1, 1);
+ set(key2, 2);
+ set(key3, 3);
+ set(key4, 4);
+ set(key5, 5);
+
+ get(key1, |x| assert_eq!(*x.unwrap(), 1));
+ get(key2, |x| assert_eq!(*x.unwrap(), 2));
+ get(key3, |x| assert_eq!(*x.unwrap(), 3));
+ get(key4, |x| assert_eq!(*x.unwrap(), 4));
+ get(key5, |x| assert_eq!(*x.unwrap(), 5));
+ }
-#[test]
-#[should_fail]
-fn test_nested_get_set1() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get(key) |_| {
+ #[test]
+ #[should_fail]
+ fn test_nested_get_set1() {
+ static key: Key<int> = &Key;
set(key, 4);
+ do get(key) |_| {
+ set(key, 4);
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut2() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get(key) |_| {
- get_mut(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut2() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get(key) |_| {
+ get_mut(key, |_| {})
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut3() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get_mut(key) |_| {
- get(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut3() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get_mut(key) |_| {
+ get(key, |_| {})
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut4() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get_mut(key) |_| {
- get_mut(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut4() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get_mut(key) |_| {
+ get_mut(key, |_| {})
+ }
}
}
use rt::local::Local;
unsafe {
- match Local::try_unsafe_borrow::<Task>() {
+ let optional_task: Option<*mut Task> = Local::try_unsafe_borrow();
+ match optional_task {
Some(local) => {
// Use the available logger
(*local).logger.log(Left(msg));
macro_rules! rtassert (
( $arg:expr ) => ( {
- if !$arg {
- rtabort!("assertion failed: %s", stringify!($arg));
+ if ::rt::util::ENFORCE_SANITY {
+ if !$arg {
+ rtabort!("assertion failed: %s", stringify!($arg));
+ }
}
} )
)
#[inline]
fn approx_eq(&self, other: &f32) -> bool {
- self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f32, f32>())
+ self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
/// Converts to degrees, assuming the number is in radians
#[inline]
- fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::<f32>()) }
+ fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
- fn to_radians(&self) -> f32 { *self * (Real::pi::<f32>() / 180.0) }
+ fn to_radians(&self) -> f32 {
+ let value: f32 = Real::pi();
+ *self * (value / 180.0f32)
+ }
}
impl Bounded for f32 {
impl Primitive for f32 {
#[inline]
- fn bits() -> uint { 32 }
+ fn bits(_: Option<f32>) -> uint { 32 }
#[inline]
- fn bytes() -> uint { Primitive::bits::<f32>() / 8 }
+ fn bytes(_: Option<f32>) -> uint { Primitive::bits(Some(0f32)) / 8 }
}
impl Float for f32 {
}
#[inline]
- fn mantissa_digits() -> uint { 24 }
+ fn mantissa_digits(_: Option<f32>) -> uint { 24 }
#[inline]
- fn digits() -> uint { 6 }
+ fn digits(_: Option<f32>) -> uint { 6 }
#[inline]
fn epsilon() -> f32 { 1.19209290e-07 }
#[inline]
- fn min_exp() -> int { -125 }
+ fn min_exp(_: Option<f32>) -> int { -125 }
#[inline]
- fn max_exp() -> int { 128 }
+ fn max_exp(_: Option<f32>) -> int { 128 }
#[inline]
- fn min_10_exp() -> int { -37 }
+ fn min_10_exp(_: Option<f32>) -> int { -37 }
#[inline]
- fn max_10_exp() -> int { 38 }
+ fn max_10_exp(_: Option<f32>) -> int { 38 }
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
assert_eq!(1f32.clamp(&2f32, &4f32), 2f32);
assert_eq!(8f32.clamp(&2f32, &4f32), 4f32);
assert_eq!(3f32.clamp(&2f32, &4f32), 3f32);
- assert!(3f32.clamp(&Float::NaN::<f32>(), &4f32).is_NaN());
- assert!(3f32.clamp(&2f32, &Float::NaN::<f32>()).is_NaN());
- assert!(Float::NaN::<f32>().clamp(&2f32, &4f32).is_NaN());
+
+ let nan: f32 = Float::NaN();
+ assert!(3f32.clamp(&nan, &4f32).is_NaN());
+ assert!(3f32.clamp(&2f32, &nan).is_NaN());
+ assert!(nan.clamp(&2f32, &4f32).is_NaN());
}
#[test]
fn test_asinh() {
assert_eq!(0.0f32.asinh(), 0.0f32);
assert_eq!((-0.0f32).asinh(), -0.0f32);
- assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>());
- assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>());
- assert!(Float::NaN::<f32>().asinh().is_NaN());
+
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let nan: f32 = Float::NaN();
+ assert_eq!(inf.asinh(), inf);
+ assert_eq!(neg_inf.asinh(), neg_inf);
+ assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
}
fn test_acosh() {
assert_eq!(1.0f32.acosh(), 0.0f32);
assert!(0.999f32.acosh().is_NaN());
- assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>());
- assert!(Float::neg_infinity::<f32>().acosh().is_NaN());
- assert!(Float::NaN::<f32>().acosh().is_NaN());
+
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let nan: f32 = Float::NaN();
+ assert_eq!(inf.acosh(), inf);
+ assert!(neg_inf.acosh().is_NaN());
+ assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
}
fn test_atanh() {
assert_eq!(0.0f32.atanh(), 0.0f32);
assert_eq!((-0.0f32).atanh(), -0.0f32);
- assert_eq!(1.0f32.atanh(), Float::infinity::<f32>());
- assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>());
+
+ let inf32: f32 = Float::infinity();
+ let neg_inf32: f32 = Float::neg_infinity();
+ assert_eq!(1.0f32.atanh(), inf32);
+ assert_eq!((-1.0f32).atanh(), neg_inf32);
+
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
- assert!(Float::infinity::<f64>().atanh().is_NaN());
- assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
- assert!(Float::NaN::<f32>().atanh().is_NaN());
+
+ let inf64: f32 = Float::infinity();
+ let neg_inf64: f32 = Float::neg_infinity();
+ let nan32: f32 = Float::NaN();
+ assert!(inf64.atanh().is_NaN());
+ assert!(neg_inf64.atanh().is_NaN());
+ assert!(nan32.atanh().is_NaN());
+
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
}
#[test]
fn test_real_consts() {
- assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
- assert_approx_eq!(Real::frac_pi_2::<f32>(), Real::pi::<f32>() / 2f32);
- assert_approx_eq!(Real::frac_pi_3::<f32>(), Real::pi::<f32>() / 3f32);
- assert_approx_eq!(Real::frac_pi_4::<f32>(), Real::pi::<f32>() / 4f32);
- assert_approx_eq!(Real::frac_pi_6::<f32>(), Real::pi::<f32>() / 6f32);
- assert_approx_eq!(Real::frac_pi_8::<f32>(), Real::pi::<f32>() / 8f32);
- assert_approx_eq!(Real::frac_1_pi::<f32>(), 1f32 / Real::pi::<f32>());
- assert_approx_eq!(Real::frac_2_pi::<f32>(), 2f32 / Real::pi::<f32>());
- assert_approx_eq!(Real::frac_2_sqrtpi::<f32>(), 2f32 / Real::pi::<f32>().sqrt());
- assert_approx_eq!(Real::sqrt2::<f32>(), 2f32.sqrt());
- assert_approx_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt());
- assert_approx_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2());
- assert_approx_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10());
- assert_approx_eq!(Real::ln_2::<f32>(), 2f32.ln());
- assert_approx_eq!(Real::ln_10::<f32>(), 10f32.ln());
+ let pi: f32 = Real::pi();
+ let two_pi: f32 = Real::two_pi();
+ let frac_pi_2: f32 = Real::frac_pi_2();
+ let frac_pi_3: f32 = Real::frac_pi_3();
+ let frac_pi_4: f32 = Real::frac_pi_4();
+ let frac_pi_6: f32 = Real::frac_pi_6();
+ let frac_pi_8: f32 = Real::frac_pi_8();
+ let frac_1_pi: f32 = Real::frac_1_pi();
+ let frac_2_pi: f32 = Real::frac_2_pi();
+ let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi();
+ let sqrt2: f32 = Real::sqrt2();
+ let frac_1_sqrt2: f32 = Real::frac_1_sqrt2();
+ let e: f32 = Real::e();
+ let log2_e: f32 = Real::log2_e();
+ let log10_e: f32 = Real::log10_e();
+ let ln_2: f32 = Real::ln_2();
+ let ln_10: f32 = Real::ln_10();
+
+ assert_approx_eq!(two_pi, 2f32 * pi);
+ assert_approx_eq!(frac_pi_2, pi / 2f32);
+ assert_approx_eq!(frac_pi_3, pi / 3f32);
+ assert_approx_eq!(frac_pi_4, pi / 4f32);
+ assert_approx_eq!(frac_pi_6, pi / 6f32);
+ assert_approx_eq!(frac_pi_8, pi / 8f32);
+ assert_approx_eq!(frac_1_pi, 1f32 / pi);
+ assert_approx_eq!(frac_2_pi, 2f32 / pi);
+ assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
+ assert_approx_eq!(sqrt2, 2f32.sqrt());
+ assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
+ assert_approx_eq!(log2_e, e.log2());
+ assert_approx_eq!(log10_e, e.log10());
+ assert_approx_eq!(ln_2, 2f32.ln());
+ assert_approx_eq!(ln_10, 10f32.ln());
}
#[test]
#[test]
fn test_primitive() {
- assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8);
- assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
+ let none: Option<f32> = None;
+ assert_eq!(Primitive::bits(none), sys::size_of::<f32>() * 8);
+ assert_eq!(Primitive::bytes(none), sys::size_of::<f32>());
}
#[test]
fn test_is_normal() {
- assert!(!Float::NaN::<f32>().is_normal());
- assert!(!Float::infinity::<f32>().is_normal());
- assert!(!Float::neg_infinity::<f32>().is_normal());
- assert!(!Zero::zero::<f32>().is_normal());
- assert!(!Float::neg_zero::<f32>().is_normal());
+ let nan: f32 = Float::NaN();
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let zero: f32 = Zero::zero();
+ let neg_zero: f32 = Float::neg_zero();
+ assert!(!nan.is_normal());
+ assert!(!inf.is_normal());
+ assert!(!neg_inf.is_normal());
+ assert!(!zero.is_normal());
+ assert!(!neg_zero.is_normal());
assert!(1f32.is_normal());
assert!(1e-37f32.is_normal());
assert!(!1e-38f32.is_normal());
#[test]
fn test_classify() {
- assert_eq!(Float::NaN::<f32>().classify(), FPNaN);
- assert_eq!(Float::infinity::<f32>().classify(), FPInfinite);
- assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite);
- assert_eq!(Zero::zero::<f32>().classify(), FPZero);
- assert_eq!(Float::neg_zero::<f32>().classify(), FPZero);
+ let nan: f32 = Float::NaN();
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let zero: f32 = Zero::zero();
+ let neg_zero: f32 = Float::neg_zero();
+ assert_eq!(nan.classify(), FPNaN);
+ assert_eq!(inf.classify(), FPInfinite);
+ assert_eq!(neg_inf.classify(), FPInfinite);
+ assert_eq!(zero.classify(), FPZero);
+ assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1f32.classify(), FPNormal);
assert_eq!(1e-37f32.classify(), FPNormal);
assert_eq!(1e-38f32.classify(), FPSubnormal);
assert_eq!(Float::ldexp(0f32, -123), 0f32);
assert_eq!(Float::ldexp(-0f32, -123), -0f32);
- assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123),
- Float::infinity::<f32>());
- assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123),
- Float::neg_infinity::<f32>());
- assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN());
+
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let nan: f32 = Float::NaN();
+ assert_eq!(Float::ldexp(inf, -123), inf);
+ assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+ assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
assert_eq!(0f32.frexp(), (0f32, 0));
assert_eq!((-0f32).frexp(), (-0f32, 0));
- assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x },
- Float::infinity::<f32>())
- assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x },
- Float::neg_infinity::<f32>())
- assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() })
+
+ let inf: f32 = Float::infinity();
+ let neg_inf: f32 = Float::neg_infinity();
+ let nan: f32 = Float::NaN();
+ assert_eq!(match inf.frexp() { (x, _) => x }, inf)
+ assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
+ assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
}
#[inline]
fn approx_eq(&self, other: &f64) -> bool {
- self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f64, f64>())
+ self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
/// Converts to degrees, assuming the number is in radians
#[inline]
- fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::<f64>()) }
+ fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
- fn to_radians(&self) -> f64 { *self * (Real::pi::<f64>() / 180.0) }
+ fn to_radians(&self) -> f64 {
+ let value: f64 = Real::pi();
+ *self * (value / 180.0)
+ }
}
impl RealExt for f64 {
impl Primitive for f64 {
#[inline]
- fn bits() -> uint { 64 }
+ fn bits(_: Option<f64>) -> uint { 64 }
#[inline]
- fn bytes() -> uint { Primitive::bits::<f64>() / 8 }
+ fn bytes(_: Option<f64>) -> uint { Primitive::bits(Some(0f64)) / 8 }
}
impl Float for f64 {
}
#[inline]
- fn mantissa_digits() -> uint { 53 }
+ fn mantissa_digits(_: Option<f64>) -> uint { 53 }
#[inline]
- fn digits() -> uint { 15 }
+ fn digits(_: Option<f64>) -> uint { 15 }
#[inline]
fn epsilon() -> f64 { 2.2204460492503131e-16 }
#[inline]
- fn min_exp() -> int { -1021 }
+ fn min_exp(_: Option<f64>) -> int { -1021 }
#[inline]
- fn max_exp() -> int { 1024 }
+ fn max_exp(_: Option<f64>) -> int { 1024 }
#[inline]
- fn min_10_exp() -> int { -307 }
+ fn min_10_exp(_: Option<f64>) -> int { -307 }
#[inline]
- fn max_10_exp() -> int { 308 }
+ fn max_10_exp(_: Option<f64>) -> int { 308 }
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
fn test_min() {
assert_eq!(1f64.min(&2f64), 1f64);
assert_eq!(2f64.min(&1f64), 1f64);
- assert!(1f64.min(&Float::NaN::<f64>()).is_NaN());
- assert!(Float::NaN::<f64>().min(&1f64).is_NaN());
+
+ let nan: f64 = Float::NaN();
+ assert!(1f64.min(&nan).is_NaN());
+ assert!(nan.min(&1f64).is_NaN());
}
#[test]
fn test_max() {
assert_eq!(1f64.max(&2f64), 2f64);
assert_eq!(2f64.max(&1f64), 2f64);
- assert!(1f64.max(&Float::NaN::<f64>()).is_NaN());
- assert!(Float::NaN::<f64>().max(&1f64).is_NaN());
+
+ let nan: f64 = Float::NaN();
+ assert!(1f64.max(&nan).is_NaN());
+ assert!(nan.max(&1f64).is_NaN());
}
#[test]
assert_eq!(1f64.clamp(&2f64, &4f64), 2f64);
assert_eq!(8f64.clamp(&2f64, &4f64), 4f64);
assert_eq!(3f64.clamp(&2f64, &4f64), 3f64);
- assert!(3f64.clamp(&Float::NaN::<f64>(), &4f64).is_NaN());
- assert!(3f64.clamp(&2f64, &Float::NaN::<f64>()).is_NaN());
- assert!(Float::NaN::<f64>().clamp(&2f64, &4f64).is_NaN());
+
+ let nan: f64 = Float::NaN();
+ assert!(3f64.clamp(&nan, &4f64).is_NaN());
+ assert!(3f64.clamp(&2f64, &nan).is_NaN());
+ assert!(nan.clamp(&2f64, &4f64).is_NaN());
}
#[test]
fn test_asinh() {
assert_eq!(0.0f64.asinh(), 0.0f64);
assert_eq!((-0.0f64).asinh(), -0.0f64);
- assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>());
- assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>());
- assert!(Float::NaN::<f64>().asinh().is_NaN());
+
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let nan: f64 = Float::NaN();
+ assert_eq!(inf.asinh(), inf);
+ assert_eq!(neg_inf.asinh(), neg_inf);
+ assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
}
fn test_acosh() {
assert_eq!(1.0f64.acosh(), 0.0f64);
assert!(0.999f64.acosh().is_NaN());
- assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>());
- assert!(Float::neg_infinity::<f64>().acosh().is_NaN());
- assert!(Float::NaN::<f64>().acosh().is_NaN());
+
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let nan: f64 = Float::NaN();
+ assert_eq!(inf.acosh(), inf);
+ assert!(neg_inf.acosh().is_NaN());
+ assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
}
fn test_atanh() {
assert_eq!(0.0f64.atanh(), 0.0f64);
assert_eq!((-0.0f64).atanh(), -0.0f64);
- assert_eq!(1.0f64.atanh(), Float::infinity::<f64>());
- assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>());
+
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let nan: f64 = Float::NaN();
+ assert_eq!(1.0f64.atanh(), inf);
+ assert_eq!((-1.0f64).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
- assert!(Float::infinity::<f64>().atanh().is_NaN());
- assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
- assert!(Float::NaN::<f64>().atanh().is_NaN());
+ assert!(inf.atanh().is_NaN());
+ assert!(neg_inf.atanh().is_NaN());
+ assert!(nan.atanh().is_NaN());
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
}
#[test]
fn test_real_consts() {
- assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>());
- assert_approx_eq!(Real::frac_pi_2::<f64>(), Real::pi::<f64>() / 2f64);
- assert_approx_eq!(Real::frac_pi_3::<f64>(), Real::pi::<f64>() / 3f64);
- assert_approx_eq!(Real::frac_pi_4::<f64>(), Real::pi::<f64>() / 4f64);
- assert_approx_eq!(Real::frac_pi_6::<f64>(), Real::pi::<f64>() / 6f64);
- assert_approx_eq!(Real::frac_pi_8::<f64>(), Real::pi::<f64>() / 8f64);
- assert_approx_eq!(Real::frac_1_pi::<f64>(), 1f64 / Real::pi::<f64>());
- assert_approx_eq!(Real::frac_2_pi::<f64>(), 2f64 / Real::pi::<f64>());
- assert_approx_eq!(Real::frac_2_sqrtpi::<f64>(), 2f64 / Real::pi::<f64>().sqrt());
- assert_approx_eq!(Real::sqrt2::<f64>(), 2f64.sqrt());
- assert_approx_eq!(Real::frac_1_sqrt2::<f64>(), 1f64 / 2f64.sqrt());
- assert_approx_eq!(Real::log2_e::<f64>(), Real::e::<f64>().log2());
- assert_approx_eq!(Real::log10_e::<f64>(), Real::e::<f64>().log10());
- assert_approx_eq!(Real::ln_2::<f64>(), 2f64.ln());
- assert_approx_eq!(Real::ln_10::<f64>(), 10f64.ln());
+ let pi: f64 = Real::pi();
+ let two_pi: f64 = Real::two_pi();
+ let frac_pi_2: f64 = Real::frac_pi_2();
+ let frac_pi_3: f64 = Real::frac_pi_3();
+ let frac_pi_4: f64 = Real::frac_pi_4();
+ let frac_pi_6: f64 = Real::frac_pi_6();
+ let frac_pi_8: f64 = Real::frac_pi_8();
+ let frac_1_pi: f64 = Real::frac_1_pi();
+ let frac_2_pi: f64 = Real::frac_2_pi();
+ let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi();
+ let sqrt2: f64 = Real::sqrt2();
+ let frac_1_sqrt2: f64 = Real::frac_1_sqrt2();
+ let e: f64 = Real::e();
+ let log2_e: f64 = Real::log2_e();
+ let log10_e: f64 = Real::log10_e();
+ let ln_2: f64 = Real::ln_2();
+ let ln_10: f64 = Real::ln_10();
+
+ assert_approx_eq!(two_pi, 2.0 * pi);
+ assert_approx_eq!(frac_pi_2, pi / 2f64);
+ assert_approx_eq!(frac_pi_3, pi / 3f64);
+ assert_approx_eq!(frac_pi_4, pi / 4f64);
+ assert_approx_eq!(frac_pi_6, pi / 6f64);
+ assert_approx_eq!(frac_pi_8, pi / 8f64);
+ assert_approx_eq!(frac_1_pi, 1f64 / pi);
+ assert_approx_eq!(frac_2_pi, 2f64 / pi);
+ assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
+ assert_approx_eq!(sqrt2, 2f64.sqrt());
+ assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
+ assert_approx_eq!(log2_e, e.log2());
+ assert_approx_eq!(log10_e, e.log10());
+ assert_approx_eq!(ln_2, 2f64.ln());
+ assert_approx_eq!(ln_10, 10f64.ln());
}
#[test]
#[test]
fn test_primitive() {
- assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8);
- assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
+ let none: Option<f64> = None;
+ assert_eq!(Primitive::bits(none), sys::size_of::<f64>() * 8);
+ assert_eq!(Primitive::bytes(none), sys::size_of::<f64>());
}
#[test]
fn test_is_normal() {
- assert!(!Float::NaN::<f64>().is_normal());
- assert!(!Float::infinity::<f64>().is_normal());
- assert!(!Float::neg_infinity::<f64>().is_normal());
- assert!(!Zero::zero::<f64>().is_normal());
- assert!(!Float::neg_zero::<f64>().is_normal());
+ let nan: f64 = Float::NaN();
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let zero: f64 = Zero::zero();
+ let neg_zero: f64 = Float::neg_zero();
+ assert!(!nan.is_normal());
+ assert!(!inf.is_normal());
+ assert!(!neg_inf.is_normal());
+ assert!(!zero.is_normal());
+ assert!(!neg_zero.is_normal());
assert!(1f64.is_normal());
assert!(1e-307f64.is_normal());
assert!(!1e-308f64.is_normal());
#[test]
fn test_classify() {
- assert_eq!(Float::NaN::<f64>().classify(), FPNaN);
- assert_eq!(Float::infinity::<f64>().classify(), FPInfinite);
- assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite);
- assert_eq!(Zero::zero::<f64>().classify(), FPZero);
- assert_eq!(Float::neg_zero::<f64>().classify(), FPZero);
+ let nan: f64 = Float::NaN();
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let zero: f64 = Zero::zero();
+ let neg_zero: f64 = Float::neg_zero();
+ assert_eq!(nan.classify(), FPNaN);
+ assert_eq!(inf.classify(), FPInfinite);
+ assert_eq!(neg_inf.classify(), FPInfinite);
+ assert_eq!(zero.classify(), FPZero);
+ assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1e-307f64.classify(), FPNormal);
assert_eq!(1e-308f64.classify(), FPSubnormal);
}
assert_eq!(Float::ldexp(0f64, -123), 0f64);
assert_eq!(Float::ldexp(-0f64, -123), -0f64);
- assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123),
- Float::infinity::<f64>());
- assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123),
- Float::neg_infinity::<f64>());
- assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN());
+
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let nan: f64 = Float::NaN();
+ assert_eq!(Float::ldexp(inf, -123), inf);
+ assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+ assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
assert_eq!(0f64.frexp(), (0f64, 0));
assert_eq!((-0f64).frexp(), (-0f64, 0));
- assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x },
- Float::infinity::<f64>())
- assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x },
- Float::neg_infinity::<f64>())
- assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() })
+
+ let inf: f64 = Float::infinity();
+ let neg_inf: f64 = Float::neg_infinity();
+ let nan: f64 = Float::NaN();
+ assert_eq!(match inf.frexp() { (x, _) => x }, inf)
+ assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
+ assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
}
#[inline]
fn approx_eq(&self, other: &float) -> bool {
- self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<float, float>())
+ self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
impl Bounded for float {
#[inline]
- fn min_value() -> float { Bounded::min_value::<f64>() as float }
+ fn min_value() -> float {
+ let x: f64 = Bounded::min_value();
+ x as float
+ }
#[inline]
- fn max_value() -> float { Bounded::max_value::<f64>() as float }
+ fn max_value() -> float {
+ let x: f64 = Bounded::max_value();
+ x as float
+ }
}
impl Primitive for float {
#[inline]
- fn bits() -> uint { Primitive::bits::<f64>() }
+ fn bits(_: Option<float>) -> uint {
+ let bits: uint = Primitive::bits(Some(0f64));
+ bits
+ }
#[inline]
- fn bytes() -> uint { Primitive::bytes::<f64>() }
+ fn bytes(_: Option<float>) -> uint {
+ let bytes: uint = Primitive::bytes(Some(0f64));
+ bytes
+ }
}
impl Float for float {
#[inline]
- fn NaN() -> float { Float::NaN::<f64>() as float }
+ fn NaN() -> float {
+ let value: f64 = Float::NaN();
+ value as float
+ }
#[inline]
- fn infinity() -> float { Float::infinity::<f64>() as float }
+ fn infinity() -> float {
+ let value: f64 = Float::infinity();
+ value as float
+ }
#[inline]
- fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float }
+ fn neg_infinity() -> float {
+ let value: f64 = Float::neg_infinity();
+ value as float
+ }
#[inline]
- fn neg_zero() -> float { Float::neg_zero::<f64>() as float }
+ fn neg_zero() -> float {
+ let value: f64 = Float::neg_zero();
+ value as float
+ }
/// Returns `true` if the number is NaN
#[inline]
fn classify(&self) -> FPCategory { (*self as f64).classify() }
#[inline]
- fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() }
+ fn mantissa_digits(_: Option<float>) -> uint {
+ Float::mantissa_digits(Some(0f64))
+ }
#[inline]
- fn digits() -> uint { Float::digits::<f64>() }
+ fn digits(_: Option<float>) -> uint {
+ Float::digits(Some(0f64))
+ }
#[inline]
- fn epsilon() -> float { Float::epsilon::<f64>() as float }
+ fn epsilon() -> float {
+ let value: f64 = Float::epsilon();
+ value as float
+ }
#[inline]
- fn min_exp() -> int { Float::min_exp::<f64>() }
+ fn min_exp(_: Option<float>) -> int {
+ Float::min_exp(Some(0f64))
+ }
#[inline]
- fn max_exp() -> int { Float::max_exp::<f64>() }
+ fn max_exp(_: Option<float>) -> int {
+ Float::max_exp(Some(0f64))
+ }
#[inline]
- fn min_10_exp() -> int { Float::min_10_exp::<f64>() }
+ fn min_10_exp(_: Option<float>) -> int {
+ Float::min_10_exp(Some(0f64))
+ }
#[inline]
- fn max_10_exp() -> int { Float::max_10_exp::<f64>() }
+ fn max_10_exp(_: Option<float>) -> int {
+ Float::max_10_exp(Some(0f64))
+ }
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
fn ldexp(x: float, exp: int) -> float {
- Float::ldexp(x as f64, exp) as float
+ let value: f64 = Float::ldexp(x as f64, exp);
+ value as float
}
///
assert_eq!(1f.clamp(&2f, &4f), 2f);
assert_eq!(8f.clamp(&2f, &4f), 4f);
assert_eq!(3f.clamp(&2f, &4f), 3f);
- assert!(3f.clamp(&Float::NaN::<float>(), &4f).is_NaN());
- assert!(3f.clamp(&2f, &Float::NaN::<float>()).is_NaN());
- assert!(Float::NaN::<float>().clamp(&2f, &4f).is_NaN());
+ let nan: float = Float::NaN();
+ assert!(3f.clamp(&nan, &4f).is_NaN());
+ assert!(3f.clamp(&2f, &nan).is_NaN());
+ assert!(nan.clamp(&2f, &4f).is_NaN());
}
#[test]
fn test_asinh() {
assert_eq!(0.0f.asinh(), 0.0f);
assert_eq!((-0.0f).asinh(), -0.0f);
- assert_eq!(Float::infinity::<float>().asinh(), Float::infinity::<float>());
- assert_eq!(Float::neg_infinity::<float>().asinh(), Float::neg_infinity::<float>());
- assert!(Float::NaN::<float>().asinh().is_NaN());
+
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let nan: float = Float::NaN();
+ assert_eq!(inf.asinh(), inf);
+ assert_eq!(neg_inf.asinh(), neg_inf);
+ assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f);
assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f);
}
fn test_acosh() {
assert_eq!(1.0f.acosh(), 0.0f);
assert!(0.999f.acosh().is_NaN());
- assert_eq!(Float::infinity::<float>().acosh(), Float::infinity::<float>());
- assert!(Float::neg_infinity::<float>().acosh().is_NaN());
- assert!(Float::NaN::<float>().acosh().is_NaN());
+
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let nan: float = Float::NaN();
+ assert_eq!(inf.acosh(), inf);
+ assert!(neg_inf.acosh().is_NaN());
+ assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f);
assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f);
}
fn test_atanh() {
assert_eq!(0.0f.atanh(), 0.0f);
assert_eq!((-0.0f).atanh(), -0.0f);
- assert_eq!(1.0f.atanh(), Float::infinity::<float>());
- assert_eq!((-1.0f).atanh(), Float::neg_infinity::<float>());
+
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let inf64: f64 = Float::infinity();
+ let neg_inf64: f64 = Float::neg_infinity();
+ let nan: float = Float::NaN();
+ assert_eq!(1.0f.atanh(), inf);
+ assert_eq!((-1.0f).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
- assert!(Float::infinity::<f64>().atanh().is_NaN());
- assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
- assert!(Float::NaN::<float>().atanh().is_NaN());
+ assert!(inf64.atanh().is_NaN());
+ assert!(neg_inf64.atanh().is_NaN());
+ assert!(nan.atanh().is_NaN());
assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f);
assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f);
}
#[test]
fn test_real_consts() {
- assert_approx_eq!(Real::two_pi::<float>(), 2f * Real::pi::<float>());
- assert_approx_eq!(Real::frac_pi_2::<float>(), Real::pi::<float>() / 2f);
- assert_approx_eq!(Real::frac_pi_3::<float>(), Real::pi::<float>() / 3f);
- assert_approx_eq!(Real::frac_pi_4::<float>(), Real::pi::<float>() / 4f);
- assert_approx_eq!(Real::frac_pi_6::<float>(), Real::pi::<float>() / 6f);
- assert_approx_eq!(Real::frac_pi_8::<float>(), Real::pi::<float>() / 8f);
- assert_approx_eq!(Real::frac_1_pi::<float>(), 1f / Real::pi::<float>());
- assert_approx_eq!(Real::frac_2_pi::<float>(), 2f / Real::pi::<float>());
- assert_approx_eq!(Real::frac_2_sqrtpi::<float>(), 2f / Real::pi::<float>().sqrt());
- assert_approx_eq!(Real::sqrt2::<float>(), 2f.sqrt());
- assert_approx_eq!(Real::frac_1_sqrt2::<float>(), 1f / 2f.sqrt());
- assert_approx_eq!(Real::log2_e::<float>(), Real::e::<float>().log2());
- assert_approx_eq!(Real::log10_e::<float>(), Real::e::<float>().log10());
- assert_approx_eq!(Real::ln_2::<float>(), 2f.ln());
- assert_approx_eq!(Real::ln_10::<float>(), 10f.ln());
+ let pi: float = Real::pi();
+ let two_pi: float = Real::two_pi();
+ let frac_pi_2: float = Real::frac_pi_2();
+ let frac_pi_3: float = Real::frac_pi_3();
+ let frac_pi_4: float = Real::frac_pi_4();
+ let frac_pi_6: float = Real::frac_pi_6();
+ let frac_pi_8: float = Real::frac_pi_8();
+ let frac_1_pi: float = Real::frac_1_pi();
+ let frac_2_pi: float = Real::frac_2_pi();
+ let frac_2_sqrtpi: float = Real::frac_2_sqrtpi();
+ let sqrt2: float = Real::sqrt2();
+ let frac_1_sqrt2: float = Real::frac_1_sqrt2();
+ let e: float = Real::e();
+ let log2_e: float = Real::log2_e();
+ let log10_e: float = Real::log10_e();
+ let ln_2: float = Real::ln_2();
+ let ln_10: float = Real::ln_10();
+
+ assert_approx_eq!(two_pi, 2f * pi);
+ assert_approx_eq!(frac_pi_2, pi / 2f);
+ assert_approx_eq!(frac_pi_3, pi / 3f);
+ assert_approx_eq!(frac_pi_4, pi / 4f);
+ assert_approx_eq!(frac_pi_6, pi / 6f);
+ assert_approx_eq!(frac_pi_8, pi / 8f);
+ assert_approx_eq!(frac_1_pi, 1f / pi);
+ assert_approx_eq!(frac_2_pi, 2f / pi);
+ assert_approx_eq!(frac_2_sqrtpi, 2f / pi.sqrt());
+ assert_approx_eq!(sqrt2, 2f.sqrt());
+ assert_approx_eq!(frac_1_sqrt2, 1f / 2f.sqrt());
+ assert_approx_eq!(log2_e, e.log2());
+ assert_approx_eq!(log10_e, e.log10());
+ assert_approx_eq!(ln_2, 2f.ln());
+ assert_approx_eq!(ln_10, 10f.ln());
}
#[test]
#[test]
fn test_primitive() {
- assert_eq!(Primitive::bits::<float>(), sys::size_of::<float>() * 8);
- assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>());
+ let none: Option<float> = None;
+ assert_eq!(Primitive::bits(none), sys::size_of::<float>() * 8);
+ assert_eq!(Primitive::bytes(none), sys::size_of::<float>());
}
#[test]
fn test_is_normal() {
- assert!(!Float::NaN::<float>().is_normal());
- assert!(!Float::infinity::<float>().is_normal());
- assert!(!Float::neg_infinity::<float>().is_normal());
- assert!(!Zero::zero::<float>().is_normal());
- assert!(!Float::neg_zero::<float>().is_normal());
+ let nan: float = Float::NaN();
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let zero: float = Zero::zero();
+ let neg_zero: float = Float::neg_zero();
+ assert!(!nan.is_normal());
+ assert!(!inf.is_normal());
+ assert!(!neg_inf.is_normal());
+ assert!(!zero.is_normal());
+ assert!(!neg_zero.is_normal());
assert!(1f.is_normal());
assert!(1e-307f.is_normal());
assert!(!1e-308f.is_normal());
#[test]
fn test_classify() {
- assert_eq!(Float::NaN::<float>().classify(), FPNaN);
- assert_eq!(Float::infinity::<float>().classify(), FPInfinite);
- assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite);
- assert_eq!(Zero::zero::<float>().classify(), FPZero);
- assert_eq!(Float::neg_zero::<float>().classify(), FPZero);
+ let nan: float = Float::NaN();
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let zero: float = Zero::zero();
+ let neg_zero: float = Float::neg_zero();
+ assert_eq!(nan.classify(), FPNaN);
+ assert_eq!(inf.classify(), FPInfinite);
+ assert_eq!(neg_inf.classify(), FPInfinite);
+ assert_eq!(zero.classify(), FPZero);
+ assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1f.classify(), FPNormal);
assert_eq!(1e-307f.classify(), FPNormal);
assert_eq!(1e-308f.classify(), FPSubnormal);
assert_eq!(Float::ldexp(0f, -123), 0f);
assert_eq!(Float::ldexp(-0f, -123), -0f);
- assert_eq!(Float::ldexp(Float::infinity::<float>(), -123),
- Float::infinity::<float>());
- assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123),
- Float::neg_infinity::<float>());
- assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN());
+
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let nan: float = Float::NaN();
+ assert_eq!(Float::ldexp(inf, -123), inf);
+ assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
+ assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
assert_eq!(0f.frexp(), (0f, 0));
assert_eq!((-0f).frexp(), (-0f, 0));
- assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x },
- Float::infinity::<float>())
- assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x },
- Float::neg_infinity::<float>())
- assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() })
+
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ let nan: float = Float::NaN();
+ assert_eq!(match inf.frexp() { (x, _) => x }, inf);
+ assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
+ assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
#[test]
impl Primitive for $T {
#[inline]
- fn bits() -> uint { bits }
+ fn bits(_: Option<$T>) -> uint { bits }
#[inline]
- fn bytes() -> uint { bits / 8 }
+ fn bytes(_: Option<$T>) -> uint { bits / 8 }
}
// String conversion functions and impl str -> num
#[test]
fn test_primitive() {
- assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
- assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
+ let none: Option<$T> = None;
+ assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
+ assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
}
#[test]
+ Div<Self,Self>
+ Rem<Self,Self> {
// FIXME (#5527): These should be associated constants
- fn bits() -> uint;
- fn bytes() -> uint;
+ fn bits(unused_self: Option<Self>) -> uint;
+ fn bytes(unused_self: Option<Self>) -> uint;
}
/// A collection of traits relevant to primitive signed and unsigned integers
fn is_normal(&self) -> bool;
fn classify(&self) -> FPCategory;
- fn mantissa_digits() -> uint;
- fn digits() -> uint;
+ fn mantissa_digits(unused_self: Option<Self>) -> uint;
+ fn digits(unused_self: Option<Self>) -> uint;
fn epsilon() -> Self;
- fn min_exp() -> int;
- fn max_exp() -> int;
- fn min_10_exp() -> int;
- fn max_10_exp() -> int;
+ fn min_exp(unused_self: Option<Self>) -> int;
+ fn max_exp(unused_self: Option<Self>) -> int;
+ fn min_10_exp(unused_self: Option<Self>) -> int;
+ fn max_10_exp(unused_self: Option<Self>) -> int;
fn ldexp(x: Self, exp: int) -> Self;
fn frexp(&self) -> (Self, int);
match self.checked_add(&v) {
Some(x) => x,
None => if v >= Zero::zero() {
- Bounded::max_value::<T>()
+ Bounded::max_value()
} else {
- Bounded::min_value::<T>()
+ Bounded::min_value()
}
}
}
match self.checked_sub(&v) {
Some(x) => x,
None => if v >= Zero::zero() {
- Bounded::min_value::<T>()
+ Bounded::min_value()
} else {
- Bounded::max_value::<T>()
+ Bounded::max_value()
}
}
}
impl Primitive for $T {
#[inline]
- fn bits() -> uint { bits }
+ fn bits(_: Option<$T>) -> uint { bits }
#[inline]
- fn bytes() -> uint { bits / 8 }
+ fn bytes(_: Option<$T>) -> uint { bits / 8 }
}
impl BitCount for $T {
#[test]
fn test_primitive() {
- assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
- assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
+ let none: Option<$T> = None;
+ assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
+ assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
}
#[test]
use clone::Clone;
use cmp::{Eq,Ord};
-use ops::Add;
use util;
use num::Zero;
use iterator;
}
}
-impl<T: Add<T, T>> Add<Option<T>, Option<T>> for Option<T> {
- #[inline]
- fn add(&self, other: &Option<T>) -> Option<T> {
- match (&*self, &*other) {
- (&None, &None) => None,
- (_, &None) => None,
- (&None, _) => None,
- (&Some(ref lhs), &Some(ref rhs)) => Some(*lhs + *rhs)
- }
- }
-}
-
// FIXME: #8242 implementing manually because deriving doesn't work for some reason
impl<T: ToStr> ToStr for Option<T> {
fn to_str(&self) -> ~str {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
+ #[cfg(target_arch = "x86")]
#[link_name = "kernel32"]
#[abi = "stdcall"]
extern "stdcall" {
fn GetLastError() -> DWORD;
}
+ #[cfg(target_arch = "x86_64")]
+ #[link_name = "kernel32"]
+ extern {
+ fn GetLastError() -> DWORD;
+ }
+
unsafe {
GetLastError() as uint
}
use libc::types::os::arch::extra::LPSTR;
use libc::types::os::arch::extra::LPVOID;
+ #[cfg(target_arch = "x86")]
#[link_name = "kernel32"]
#[abi = "stdcall"]
extern "stdcall" {
-> DWORD;
}
+ #[cfg(target_arch = "x86_64")]
+ #[link_name = "kernel32"]
+ extern {
+ fn FormatMessageA(flags: DWORD,
+ lpSrc: LPVOID,
+ msgId: DWORD,
+ langId: DWORD,
+ buf: LPSTR,
+ nsize: DWORD,
+ args: *c_void)
+ -> DWORD;
+ }
+
static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
type LPCWSTR = *u16;
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86")]
#[link_name="kernel32"]
#[abi="stdcall"]
extern "stdcall" {
fn LocalFree(ptr: *c_void);
}
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86_64")]
+#[link_name="kernel32"]
+extern {
+ fn GetCommandLineW() -> LPCWSTR;
+ fn LocalFree(ptr: *c_void);
+}
+
+#[cfg(windows, target_arch = "x86")]
#[link_name="shell32"]
#[abi="stdcall"]
extern "stdcall" {
fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
}
+#[cfg(windows, target_arch = "x86_64")]
+#[link_name="shell32"]
+extern {
+ fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
+}
+
struct OverriddenArgs {
val: ~[~str]
}
let r = unsafe {
libc::mmap(addr, len, prot, flags, fd, offset)
};
- if r == libc::MAP_FAILED {
+ if r.equiv(&libc::MAP_FAILED) {
Err(match errno() as c_int {
libc::EACCES => ErrFdNotAvail,
libc::EBADF => ErrInvalidFd,
pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCopyableVector};
pub use vec::{OwnedVector, OwnedCopyableVector,OwnedEqVector, MutableVector};
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};
+pub use default::Default;
// Reexported runtime types
pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable};
use cast;
use clone::Clone;
+use cmp::Equiv;
use iterator::{range, Iterator};
use option::{Option, Some, None};
+#[cfg(stage0)]
+use sys;
use unstable::intrinsics;
use util::swap;
-#[cfg(not(test))] use ops::{Add,Sub};
-#[cfg(not(test))] use num::Int;
-
#[cfg(not(test))] use cmp::{Eq, Ord};
-/// Calculate the offset from a pointer
+/// Calculate the offset from a pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
#[inline]
-pub fn offset<T>(ptr: *T, count: int) -> *T {
- unsafe { intrinsics::offset(ptr, count) }
+#[cfg(stage0)]
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
+ (ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
}
-/// Calculate the offset from a const pointer
+/// Calculate the offset from a mut pointer
#[inline]
-pub fn const_offset<T>(ptr: *const T, count: int) -> *const T {
- unsafe { intrinsics::offset(ptr as *T, count) }
+#[cfg(stage0)]
+pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+ (ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
}
-/// Calculate the offset from a mut pointer
+/// Calculate the offset from a pointer
+#[inline]
+#[cfg(not(stage0))]
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
+ intrinsics::offset(ptr, count)
+}
+
+/// Calculate the offset from a mut pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
#[inline]
-pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
- unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
+#[cfg(not(stage0))]
+pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+ intrinsics::offset(ptr as *T, count) as *mut T
}
/// Return the offset of the first null pointer in `buf`.
/// Returns true if the pointer is equal to the null pointer.
#[inline]
-pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
+pub fn is_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
-pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
+pub fn is_not_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_not_null() }
/**
* Copies data from one location to another.
*/
#[inline]
#[cfg(target_word_size = "32")]
-pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
- intrinsics::memmove32(dst, src as *T, count as u32);
+pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
+ intrinsics::memmove32(dst,
+ cast::transmute_immut_unsafe(src),
+ count as u32);
}
/**
*/
#[inline]
#[cfg(target_word_size = "64")]
-pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
- intrinsics::memmove64(dst, src as *T, count as u64);
+pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
+ intrinsics::memmove64(dst,
+ cast::transmute_immut_unsafe(src),
+ count as u64);
}
/**
*/
#[inline]
#[cfg(target_word_size = "32")]
-pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
- intrinsics::memcpy32(dst, src as *T, count as u32);
+pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
+ src: P,
+ count: uint) {
+ intrinsics::memcpy32(dst,
+ cast::transmute_immut_unsafe(src),
+ count as u32);
}
/**
*/
#[inline]
#[cfg(target_word_size = "64")]
-pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
- intrinsics::memcpy64(dst, src as *T, count as u64);
+pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
+ src: P,
+ count: uint) {
+ intrinsics::memcpy64(dst,
+ cast::transmute_immut_unsafe(src),
+ count as u64);
}
/**
thing as *T
}
-/// Transform a const region pointer - &const T - to a const unsafe pointer - *const T.
-#[inline]
-pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
- thing as *const T
-}
-
/// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T.
#[inline]
pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
#[allow(missing_doc)]
pub trait RawPtr<T> {
+ fn null() -> Self;
fn is_null(&self) -> bool;
fn is_not_null(&self) -> bool;
+ fn to_uint(&self) -> uint;
unsafe fn to_option(&self) -> Option<&T>;
- fn offset(&self, count: int) -> Self;
- unsafe fn offset_inbounds(self, count: int) -> Self;
+ unsafe fn offset(self, count: int) -> Self;
}
/// Extension methods for immutable pointers
impl<T> RawPtr<T> for *T {
+ /// Returns the null pointer.
+ #[inline]
+ fn null() -> *T { null() }
+
/// Returns true if the pointer is equal to the null pointer.
#[inline]
- fn is_null(&self) -> bool { is_null(*self) }
+ fn is_null(&self) -> bool { *self == RawPtr::null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
- fn is_not_null(&self) -> bool { is_not_null(*self) }
+ fn is_not_null(&self) -> bool { *self != RawPtr::null() }
+
+ /// Returns the address of this pointer.
+ #[inline]
+ fn to_uint(&self) -> uint { *self as uint }
///
/// Returns `None` if the pointer is null, or else returns the value wrapped
}
}
- /// Calculates the offset from a pointer.
- #[inline]
- fn offset(&self, count: int) -> *T { offset(*self, count) }
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end.
#[inline]
- unsafe fn offset_inbounds(self, count: int) -> *T {
- intrinsics::offset_inbounds(self, count)
- }
+ unsafe fn offset(self, count: int) -> *T { offset(self, count) }
}
/// Extension methods for mutable pointers
impl<T> RawPtr<T> for *mut T {
+ /// Returns the null pointer.
+ #[inline]
+ fn null() -> *mut T { mut_null() }
+
/// Returns true if the pointer is equal to the null pointer.
#[inline]
- fn is_null(&self) -> bool { is_null(*self) }
+ fn is_null(&self) -> bool { *self == RawPtr::null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
- fn is_not_null(&self) -> bool { is_not_null(*self) }
+ fn is_not_null(&self) -> bool { *self != RawPtr::null() }
+
+ /// Returns the address of this pointer.
+ #[inline]
+ fn to_uint(&self) -> uint { *self as uint }
///
/// Returns `None` if the pointer is null, or else returns the value wrapped
}
}
- /// Calculates the offset from a mutable pointer.
- #[inline]
- fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end. An arithmetic overflow is also
/// undefined behaviour.
/// This method should be preferred over `offset` when the guarantee can be
/// satisfied, to enable better optimization.
#[inline]
- unsafe fn offset_inbounds(self, count: int) -> *mut T {
- intrinsics::offset_inbounds(self as *T, count) as *mut T
- }
+ unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
}
// Equality for pointers
#[cfg(not(test))]
-impl<T> Eq for *const T {
+impl<T> Eq for *T {
#[inline]
- fn eq(&self, other: &*const T) -> bool {
+ fn eq(&self, other: &*T) -> bool {
(*self as uint) == (*other as uint)
}
#[inline]
- fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
+ fn ne(&self, other: &*T) -> bool { !self.eq(other) }
+}
+
+#[cfg(not(test))]
+impl<T> Eq for *mut T {
+ #[inline]
+ fn eq(&self, other: &*mut T) -> bool {
+ (*self as uint) == (*other as uint)
+ }
+ #[inline]
+ fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
+}
+
+// Equivalence for pointers
+#[cfg(not(test))]
+impl<T> Equiv<*mut T> for *T {
+ fn equiv(&self, other: &*mut T) -> bool {
+ self.to_uint() == other.to_uint()
+ }
+}
+
+#[cfg(not(test))]
+impl<T> Equiv<*T> for *mut T {
+ fn equiv(&self, other: &*T) -> bool {
+ self.to_uint() == other.to_uint()
+ }
}
// Equality for extern "C" fn pointers
// Comparison for pointers
#[cfg(not(test))]
-impl<T> Ord for *const T {
+impl<T> Ord for *T {
#[inline]
- fn lt(&self, other: &*const T) -> bool {
+ fn lt(&self, other: &*T) -> bool {
(*self as uint) < (*other as uint)
}
#[inline]
- fn le(&self, other: &*const T) -> bool {
+ fn le(&self, other: &*T) -> bool {
(*self as uint) <= (*other as uint)
}
#[inline]
- fn ge(&self, other: &*const T) -> bool {
+ fn ge(&self, other: &*T) -> bool {
(*self as uint) >= (*other as uint)
}
#[inline]
- fn gt(&self, other: &*const T) -> bool {
+ fn gt(&self, other: &*T) -> bool {
(*self as uint) > (*other as uint)
}
}
#[cfg(not(test))]
-impl<T, I: Int> Add<I, *T> for *T {
- /// Add an integer value to a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
+impl<T> Ord for *mut T {
#[inline]
- fn add(&self, rhs: &I) -> *T {
- self.offset(rhs.to_int() as int)
+ fn lt(&self, other: &*mut T) -> bool {
+ (*self as uint) < (*other as uint)
}
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *T> for *T {
- /// Subtract an integer value from a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
#[inline]
- fn sub(&self, rhs: &I) -> *T {
- self.offset(-rhs.to_int() as int)
+ fn le(&self, other: &*mut T) -> bool {
+ (*self as uint) <= (*other as uint)
}
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *mut T> for *mut T {
- /// Add an integer value to a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
#[inline]
- fn add(&self, rhs: &I) -> *mut T {
- self.offset(rhs.to_int() as int)
+ fn ge(&self, other: &*mut T) -> bool {
+ (*self as uint) >= (*other as uint)
}
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *mut T> for *mut T {
- /// Subtract an integer value from a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
#[inline]
- fn sub(&self, rhs: &I) -> *mut T {
- self.offset(-rhs.to_int() as int)
+ fn gt(&self, other: &*mut T) -> bool {
+ (*self as uint) > (*other as uint)
}
}
assert!(p.is_null());
assert!(!p.is_not_null());
- let q = offset(p, 1);
+ let q = unsafe { offset(p, 1) };
assert!(!q.is_null());
assert!(q.is_not_null());
assert!(mp.is_null());
assert!(!mp.is_not_null());
- let mq = mp.offset(1);
+ let mq = unsafe { mp.offset(1) };
assert!(!mq.is_null());
assert!(mq.is_not_null());
}
unsafe {
let xs = ~[5, ..16];
let mut ptr = to_ptr(xs);
- let end = ptr + 16;
+ let end = ptr.offset(16);
while ptr < end {
assert_eq!(*ptr, 5);
- ptr = ptr + 1u;
+ ptr = ptr.offset(1);
}
let mut xs_mut = xs.clone();
let mut m_ptr = to_mut_ptr(xs_mut);
- let m_end = m_ptr + 16i16;
+ let m_end = m_ptr.offset(16);
while m_ptr < m_end {
*m_ptr += 5;
- m_ptr = m_ptr + 1u8;
+ m_ptr = m_ptr.offset(1);
}
assert_eq!(xs_mut, ~[10, ..16]);
let ptr = to_ptr(xs);
while idx >= 0i8 {
- assert_eq!(*(ptr + idx), idx as int);
+ assert_eq!(*(ptr.offset(idx as int)), idx as int);
idx = idx - 1i8;
}
let mut xs_mut = xs.clone();
let m_start = to_mut_ptr(xs_mut);
- let mut m_ptr = m_start + 9u32;
+ let mut m_ptr = m_start.offset(9);
while m_ptr >= m_start {
*m_ptr += *m_ptr;
- m_ptr = m_ptr - 1i8;
+ m_ptr = m_ptr.offset(-1);
}
assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
true
}
- fn visit_var(&self) -> bool {
- if ! self.inner.visit_var() { return false; }
- true
- }
-
- fn visit_var_integral(&self) -> bool {
- if ! self.inner.visit_var_integral() { return false; }
- true
- }
-
fn visit_param(&self, i: uint) -> bool {
if ! self.inner.visit_param(i) { return false; }
true
true
}
- fn visit_constr(&self, inner: *TyDesc) -> bool {
- if ! self.inner.visit_constr(inner) { return false; }
- true
- }
-
fn visit_closure_ptr(&self, ck: uint) -> bool {
self.align_to::<@fn()>();
if ! self.inner.visit_closure_ptr(ck) { return false; }
}
}
-macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
+impl Repr for int {
+ fn write_repr(&self, writer: @Writer) {
+ do ::int::to_str_bytes(*self, 10u) |bits| {
+ writer.write(bits);
+ }
+ }
+}
+
+macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
fn write_repr(&self, writer: @Writer) {
do ::$ty::to_str_bytes(*self, 10u) |bits| {
writer.write(bits);
+ writer.write(bytes!($suffix));
}
}
}))
-int_repr!(int)
-int_repr!(i8)
-int_repr!(i16)
-int_repr!(i32)
-int_repr!(i64)
-int_repr!(uint)
-int_repr!(u8)
-int_repr!(u16)
-int_repr!(u32)
-int_repr!(u64)
-
-macro_rules! num_repr(($ty:ident) => (impl Repr for $ty {
+int_repr!(i8, "i8")
+int_repr!(i16, "i16")
+int_repr!(i32, "i32")
+int_repr!(i64, "i64")
+int_repr!(uint, "u")
+int_repr!(u8, "u8")
+int_repr!(u16, "u16")
+int_repr!(u32, "u32")
+int_repr!(u64, "u64")
+
+impl Repr for float {
+ fn write_repr(&self, writer: @Writer) {
+ let s = self.to_str();
+ writer.write(s.as_bytes());
+ }
+}
+
+macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
fn write_repr(&self, writer: @Writer) {
let s = self.to_str();
writer.write(s.as_bytes());
+ writer.write(bytes!($suffix));
}
}))
-num_repr!(float)
-num_repr!(f32)
-num_repr!(f64)
+num_repr!(f32, "f32")
+num_repr!(f64, "f64")
// New implementation using reflect::MovePtr
self.writer.write_str(", ");
}
self.visit_ptr_inner(p as *c_void, inner);
- p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
+ p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
left -= dec;
}
self.writer.write_char(']');
self.write_escaped_slice(*s);
}
}
+
fn visit_estr_uniq(&self) -> bool {
do self.get::<~str> |s| {
self.writer.write_char('~');
self.write_escaped_slice(*s);
}
}
+
fn visit_estr_slice(&self) -> bool {
do self.get::<&str> |s| {
self.write_escaped_slice(*s);
}
}
+ #[cfg(stage0)]
fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
do self.get::<*c_void> |p| {
self.writer.write_str(fmt!("(0x%x as *())",
}
}
+ #[cfg(not(stage0))]
+ fn visit_ptr(&self, mtbl: uint, _inner: *TyDesc) -> bool {
+ do self.get::<*c_void> |p| {
+ self.writer.write_str(fmt!("(0x%x as *", *p as uint));
+ self.write_mut_qualifier(mtbl);
+ self.writer.write_str("())");
+ }
+ }
+
fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write_char('&');
self.write_mut_qualifier(mtbl);
fn visit_trait(&self) -> bool { true }
- fn visit_var(&self) -> bool { true }
- fn visit_var_integral(&self) -> bool { true }
fn visit_param(&self, _i: uint) -> bool { true }
fn visit_self(&self) -> bool { true }
fn visit_type(&self) -> bool { true }
}
}
- // Type no longer exists, vestigial function.
- fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
-
fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
}
exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
exact_test(&(@10), "@10");
- exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
+ exact_test(&(@mut 10), "@mut 10");
exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
exact_test(&(~10), "~10");
exact_test(&(&10), "&10");
exact_test(&(&mut x), "&mut 10");
exact_test(&(@mut [1, 2]), "@mut [1, 2]");
+ exact_test(&(0 as *()), "(0x0 as *())");
+ exact_test(&(0 as *mut ()), "(0x0 as *mut ())");
+
exact_test(&(1,), "(1,)");
exact_test(&(@[1,2,3,4,5,6,7,8]),
"@[1, 2, 3, 4, 5, 6, 7, 8]");
exact_test(&(@[1u8,2u8,3u8,4u8]),
- "@[1, 2, 3, 4]");
+ "@[1u8, 2u8, 3u8, 4u8]");
exact_test(&(@["hi", "there"]),
"@[\"hi\", \"there\"]");
exact_test(&(~["hi", "there"]),
"@{a: 10, b: 1.234}");
exact_test(&(~P{a:10, b:1.234}),
"~{a: 10, b: 1.234}");
- exact_test(&(10_u8, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u16, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u32, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u64, ~"hello"),
- "(10, ~\"hello\")");
+ exact_test(&(10u8, ~"hello"),
+ "(10u8, ~\"hello\")");
+ exact_test(&(10u16, ~"hello"),
+ "(10u16, ~\"hello\")");
+ exact_test(&(10u32, ~"hello"),
+ "(10u32, ~\"hello\")");
+ exact_test(&(10u64, ~"hello"),
+ "(10u64, ~\"hello\")");
struct Foo;
exact_test(&(~[Foo, Foo, Foo]), "~[{}, {}, {}]");
use cell::Cell;
use c_str::ToCStr;
use cast::transmute;
-use libc::{c_char, size_t, STDERR_FILENO};
-use io;
use io::{Writer, WriterUtil};
+use io;
+use libc::{c_char, size_t, STDERR_FILENO};
use option::{Option, None, Some};
-use uint;
+use ptr::RawPtr;
use rt::env;
use rt::local::Local;
use rt::task::Task;
-use str;
use str::{OwnedStr, StrSlice};
+use str;
use sys;
+use uint;
use unstable::raw;
use vec::ImmutableVector;
}
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
- do Local::borrow::<Task, Option<~[BorrowRecord]>> |task| {
+ do Local::borrow |task: &mut Task| {
task.borrow_list.take()
}
}
};
let borrows = f(borrows);
let borrows = Cell::new(borrows);
- do Local::borrow::<Task, ()> |task| {
+ do Local::borrow |task: &mut Task| {
task.borrow_list = Some(borrows.take());
}
}
static ENABLE_DEBUG: bool = false;
#[inline]
-unsafe fn debug_borrow<T>(tag: &'static str,
- p: *const T,
- old_bits: uint,
- new_bits: uint,
- filename: *c_char,
- line: size_t) {
+unsafe fn debug_borrow<T,P:RawPtr<T>>(tag: &'static str,
+ p: P,
+ old_bits: uint,
+ new_bits: uint,
+ filename: *c_char,
+ line: size_t) {
//! A useful debugging function that prints a pointer + tag + newline
//! without allocating memory.
debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);
}
- unsafe fn debug_borrow_slow<T>(tag: &'static str,
- p: *const T,
- old_bits: uint,
- new_bits: uint,
- filename: *c_char,
- line: size_t) {
+ unsafe fn debug_borrow_slow<T,P:RawPtr<T>>(tag: &'static str,
+ p: P,
+ old_bits: uint,
+ new_bits: uint,
+ filename: *c_char,
+ line: size_t) {
let dbg = STDERR_FILENO as io::fd_t;
dbg.write_str(tag);
- dbg.write_hex(p as uint);
+ dbg.write_hex(p.to_uint());
dbg.write_str(" ");
dbg.write_hex(old_bits);
dbg.write_str(" ");
use rt::select::{SelectInner, SelectPortInner};
use select::{Select, SelectPort};
use unstable::atomics::{AtomicUint, AtomicOption, Acquire, Relaxed, SeqCst};
-use unstable::sync::UnsafeAtomicRcBox;
+use unstable::sync::UnsafeArc;
use util::Void;
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
use cell::Cell;
unsafe {
// Install the payload
- assert!((*packet).payload.is_none());
+ rtassert!((*packet).payload.is_none());
(*packet).payload = Some(val);
// Atomically swap out the old state to figure out what
match oldstate {
STATE_BOTH => {
// Port is not waiting yet. Nothing to do
- do Local::borrow::<Scheduler, ()> |sched| {
- rtdebug!("non-rendezvous send");
- sched.metrics.non_rendezvous_sends += 1;
- }
}
STATE_ONE => {
- do Local::borrow::<Scheduler, ()> |sched| {
- rtdebug!("rendezvous send");
- sched.metrics.rendezvous_sends += 1;
- }
// Port has closed. Need to clean up.
let _packet: ~Packet<T> = cast::transmute(this.void_packet);
recvr_active = false;
};
} else {
let recvr = Cell::new(recvr);
- do Local::borrow::<Scheduler, ()> |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_blocked_task(recvr.take());
}
}
if !this.optimistic_check() {
// No data available yet.
// Switch to the scheduler to put the ~Task into the Packet state.
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
this.block_on(sched, task);
}
// The optimistic check is never necessary for correctness. For testing
// purposes, making it randomly return false simulates a racing sender.
use rand::{Rand};
- let actually_check = do Local::borrow::<Scheduler, bool> |sched| {
+ let actually_check = do Local::borrow |sched: &mut Scheduler| {
Rand::rand(&mut sched.rng)
};
if actually_check {
STATE_BOTH => {
// Data has not been sent. Now we're blocked.
rtdebug!("non-rendezvous recv");
- sched.metrics.non_rendezvous_recvs += 1;
false
}
STATE_ONE => {
(*self.packet()).state.store(STATE_ONE, Relaxed);
rtdebug!("rendezvous recv");
- sched.metrics.rendezvous_recvs += 1;
// Channel is closed. Switch back and check the data.
// NB: We have to drop back into the scheduler event loop here
STATE_ONE => true, // Lost the race. Data available.
same_ptr => {
// We successfully unblocked our task pointer.
- assert!(task_as_state == same_ptr);
+ rtassert!(task_as_state == same_ptr);
let handle = BlockedTask::cast_from_uint(task_as_state);
// Because we are already awake, the handle we
// gave to this port shall already be empty.
unsafe {
// See corresponding store() above in block_on for rationale.
// FIXME(#8130) This can happen only in test builds.
- assert!((*packet).state.load(Relaxed) == STATE_ONE);
+ // This load is not required for correctness and may be compiled out.
+ rtassert!((*packet).state.load(Relaxed) == STATE_ONE);
let payload = (*packet).payload.take();
},
task_as_state => {
// The port is blocked waiting for a message we will never send. Wake it.
- assert!((*this.packet()).payload.is_none());
+ rtassert!((*this.packet()).payload.is_none());
let recvr = BlockedTask::cast_from_uint(task_as_state);
do recvr.wake().map_move |woken_task| {
Scheduler::run_task(woken_task);
pub struct SharedChan<T> {
// Just like Chan, but a shared AtomicOption instead of Cell
- priv next: UnsafeAtomicRcBox<AtomicOption<StreamChanOne<T>>>
+ priv next: UnsafeArc<AtomicOption<StreamChanOne<T>>>
}
impl<T> SharedChan<T> {
pub fn new(chan: Chan<T>) -> SharedChan<T> {
let next = chan.next.take();
let next = AtomicOption::new(~next);
- SharedChan { next: UnsafeAtomicRcBox::new(next) }
+ SharedChan { next: UnsafeArc::new(next) }
}
}
pub struct SharedPort<T> {
// The next port on which we will receive the next port on which we will receive T
- priv next_link: UnsafeAtomicRcBox<AtomicOption<PortOne<StreamPortOne<T>>>>
+ priv next_link: UnsafeArc<AtomicOption<PortOne<StreamPortOne<T>>>>
}
impl<T> SharedPort<T> {
let (next_link_port, next_link_chan) = oneshot();
next_link_chan.send(next_data_port);
let next_link = AtomicOption::new(~next_link_port);
- SharedPort { next_link: UnsafeAtomicRcBox::new(next_link) }
+ SharedPort { next_link: UnsafeArc::new(next_link) }
}
}
let fp: *c_void = task_start_wrapper as *c_void;
let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
+ let stack_base: *uint = stack.start();
let sp: *uint = stack.end();
let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
// Save and then immediately load the current context,
swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
};
- initialize_call_frame(&mut *regs, fp, argp, sp);
+ initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
return Context {
start: Some(start),
}
#[cfg(target_arch = "x86")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+ sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
let sp = mut_offset(sp, -4);
regs.ebp = 0;
}
-#[cfg(target_arch = "x86_64")]
+#[cfg(windows, target_arch = "x86_64")]
+type Registers = [uint, ..34];
+#[cfg(not(windows), target_arch = "x86_64")]
type Registers = [uint, ..22];
-#[cfg(target_arch = "x86_64")]
+#[cfg(windows, target_arch = "x86_64")]
+fn new_regs() -> ~Registers { ~([0, .. 34]) }
+#[cfg(not(windows), target_arch = "x86_64")]
fn new_regs() -> ~Registers { ~([0, .. 22]) }
#[cfg(target_arch = "x86_64")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+ sp: *mut uint, stack_base: *uint) {
// Redefinitions from regs.h
static RUSTRT_ARG0: uint = 3;
static RUSTRT_IP: uint = 8;
static RUSTRT_RBP: uint = 2;
+ #[cfg(windows)]
+ fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
+ // Redefinitions from regs.h
+ static RUSTRT_ST1: uint = 11; // stack bottom
+ static RUSTRT_ST2: uint = 12; // stack top
+ regs[RUSTRT_ST1] = sp as uint;
+ regs[RUSTRT_ST2] = stack_base as uint;
+ }
+ #[cfg(not(windows))]
+ fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
+ }
+
+ // Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
+ initialize_tib(regs, sp, stack_base);
+
let sp = align_down(sp);
let sp = mut_offset(sp, -1);
fn new_regs() -> ~Registers { ~([0, .. 32]) }
#[cfg(target_arch = "arm")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+ sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
// sp of arm eabi is 8-byte aligned
let sp = mut_offset(sp, -2);
fn new_regs() -> ~Registers { ~([0, .. 32]) }
#[cfg(target_arch = "mips")]
-fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
+fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
+ sp: *mut uint, _stack_base: *uint) {
let sp = align_down(sp);
// sp of mips o32 is 8-byte aligned
let sp = mut_offset(sp, -2);
/// Reads `n` little-endian unsigned integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
- fn read_le_uint_n(&mut self, nbytes: uint) -> u64;
+ fn read_le_uint_n_(&mut self, nbytes: uint) -> u64;
/// Reads `n` little-endian signed integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
- fn read_le_int_n(&mut self, nbytes: uint) -> i64;
+ fn read_le_int_n_(&mut self, nbytes: uint) -> i64;
/// Reads `n` big-endian unsigned integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
- fn read_be_uint_n(&mut self, nbytes: uint) -> u64;
+ fn read_be_uint_n_(&mut self, nbytes: uint) -> u64;
/// Reads `n` big-endian signed integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
- fn read_be_int_n(&mut self, nbytes: uint) -> i64;
+ fn read_be_int_n_(&mut self, nbytes: uint) -> i64;
/// Reads a little-endian unsigned integer.
///
/// The number of bytes returned is system-dependant.
- fn read_le_uint(&mut self) -> uint;
+ fn read_le_uint_(&mut self) -> uint;
/// Reads a little-endian integer.
///
/// The number of bytes returned is system-dependant.
- fn read_le_int(&mut self) -> int;
+ fn read_le_int_(&mut self) -> int;
/// Reads a big-endian unsigned integer.
///
/// The number of bytes returned is system-dependant.
- fn read_be_uint(&mut self) -> uint;
+ fn read_be_uint_(&mut self) -> uint;
/// Reads a big-endian integer.
///
/// The number of bytes returned is system-dependant.
- fn read_be_int(&mut self) -> int;
+ fn read_be_int_(&mut self) -> int;
/// Reads a big-endian `u64`.
///
/// `u64`s are 8 bytes long.
- fn read_be_u64(&mut self) -> u64;
+ fn read_be_u64_(&mut self) -> u64;
/// Reads a big-endian `u32`.
///
/// `u32`s are 4 bytes long.
- fn read_be_u32(&mut self) -> u32;
+ fn read_be_u32_(&mut self) -> u32;
/// Reads a big-endian `u16`.
///
/// `u16`s are 2 bytes long.
- fn read_be_u16(&mut self) -> u16;
+ fn read_be_u16_(&mut self) -> u16;
/// Reads a big-endian `i64`.
///
/// `i64`s are 8 bytes long.
- fn read_be_i64(&mut self) -> i64;
+ fn read_be_i64_(&mut self) -> i64;
/// Reads a big-endian `i32`.
///
/// `i32`s are 4 bytes long.
- fn read_be_i32(&mut self) -> i32;
+ fn read_be_i32_(&mut self) -> i32;
/// Reads a big-endian `i16`.
///
/// `i16`s are 2 bytes long.
- fn read_be_i16(&mut self) -> i16;
+ fn read_be_i16_(&mut self) -> i16;
/// Reads a big-endian `f64`.
///
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
- fn read_be_f64(&mut self) -> f64;
+ fn read_be_f64_(&mut self) -> f64;
/// Reads a big-endian `f32`.
///
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
- fn read_be_f32(&mut self) -> f32;
+ fn read_be_f32_(&mut self) -> f32;
/// Reads a little-endian `u64`.
///
/// `u64`s are 8 bytes long.
- fn read_le_u64(&mut self) -> u64;
+ fn read_le_u64_(&mut self) -> u64;
/// Reads a little-endian `u32`.
///
/// `u32`s are 4 bytes long.
- fn read_le_u32(&mut self) -> u32;
+ fn read_le_u32_(&mut self) -> u32;
/// Reads a little-endian `u16`.
///
/// `u16`s are 2 bytes long.
- fn read_le_u16(&mut self) -> u16;
+ fn read_le_u16_(&mut self) -> u16;
/// Reads a little-endian `i64`.
///
/// `i64`s are 8 bytes long.
- fn read_le_i64(&mut self) -> i64;
+ fn read_le_i64_(&mut self) -> i64;
/// Reads a little-endian `i32`.
///
/// `i32`s are 4 bytes long.
- fn read_le_i32(&mut self) -> i32;
+ fn read_le_i32_(&mut self) -> i32;
/// Reads a little-endian `i16`.
///
/// `i16`s are 2 bytes long.
- fn read_le_i16(&mut self) -> i16;
+ fn read_le_i16_(&mut self) -> i16;
/// Reads a little-endian `f64`.
///
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
- fn read_le_f64(&mut self) -> f64;
+ fn read_le_f64_(&mut self) -> f64;
/// Reads a little-endian `f32`.
///
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
- fn read_le_f32(&mut self) -> f32;
+ fn read_le_f32_(&mut self) -> f32;
/// Read a u8.
///
/// `u8`s are 1 byte.
- fn read_u8(&mut self) -> u8;
+ fn read_u8_(&mut self) -> u8;
/// Read an i8.
///
/// `i8`s are 1 byte.
- fn read_i8(&mut self) -> i8;
+ fn read_i8_(&mut self) -> i8;
}
pub trait WriterByteConversions {
/// Write the result of passing n through `int::to_str_bytes`.
- fn write_int(&mut self, n: int);
+ fn write_int_(&mut self, n: int);
/// Write the result of passing n through `uint::to_str_bytes`.
- fn write_uint(&mut self, n: uint);
+ fn write_uint_(&mut self, n: uint);
/// Write a little-endian uint (number of bytes depends on system).
- fn write_le_uint(&mut self, n: uint);
+ fn write_le_uint_(&mut self, n: uint);
/// Write a little-endian int (number of bytes depends on system).
- fn write_le_int(&mut self, n: int);
+ fn write_le_int_(&mut self, n: int);
/// Write a big-endian uint (number of bytes depends on system).
- fn write_be_uint(&mut self, n: uint);
+ fn write_be_uint_(&mut self, n: uint);
/// Write a big-endian int (number of bytes depends on system).
- fn write_be_int(&mut self, n: int);
+ fn write_be_int_(&mut self, n: int);
/// Write a big-endian u64 (8 bytes).
fn write_be_u64_(&mut self, n: u64);
/// Write a big-endian u32 (4 bytes).
- fn write_be_u32(&mut self, n: u32);
+ fn write_be_u32_(&mut self, n: u32);
/// Write a big-endian u16 (2 bytes).
- fn write_be_u16(&mut self, n: u16);
+ fn write_be_u16_(&mut self, n: u16);
/// Write a big-endian i64 (8 bytes).
- fn write_be_i64(&mut self, n: i64);
+ fn write_be_i64_(&mut self, n: i64);
/// Write a big-endian i32 (4 bytes).
fn write_be_i32_(&mut self, n: i32);
/// Write a big-endian i16 (2 bytes).
- fn write_be_i16(&mut self, n: i16);
+ fn write_be_i16_(&mut self, n: i16);
/// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
- fn write_be_f64(&mut self, f: f64);
+ fn write_be_f64_(&mut self, f: f64);
/// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
fn write_be_f32_(&mut self, f: f32);
fn write_le_u64_(&mut self, n: u64);
/// Write a little-endian u32 (4 bytes).
- fn write_le_u32(&mut self, n: u32);
+ fn write_le_u32_(&mut self, n: u32);
/// Write a little-endian u16 (2 bytes).
- fn write_le_u16(&mut self, n: u16);
+ fn write_le_u16_(&mut self, n: u16);
/// Write a little-endian i64 (8 bytes).
- fn write_le_i64(&mut self, n: i64);
+ fn write_le_i64_(&mut self, n: i64);
/// Write a little-endian i32 (4 bytes).
- fn write_le_i32(&mut self, n: i32);
+ fn write_le_i32_(&mut self, n: i32);
/// Write a little-endian i16 (2 bytes).
- fn write_le_i16(&mut self, n: i16);
+ fn write_le_i16_(&mut self, n: i16);
/// Write a little-endian IEEE754 double-precision floating-point
/// (8 bytes).
- fn write_le_f64(&mut self, f: f64);
+ fn write_le_f64_(&mut self, f: f64);
/// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32_(&mut self, f: f32);
/// Write a u8 (1 byte).
- fn write_u8(&mut self, n: u8);
+ fn write_u8_(&mut self, n: u8);
/// Write a i8 (1 byte).
- fn write_i8(&mut self, n: i8);
+ fn write_i8_(&mut self, n: i8);
}
impl<T: Reader> ReaderUtil for T {
}
impl<T: Reader> ReaderByteConversions for T {
- fn read_le_uint_n(&mut self, nbytes: uint) -> u64 {
+ fn read_le_uint_n_(&mut self, nbytes: uint) -> u64 {
assert!(nbytes > 0 && nbytes <= 8);
let mut val = 0u64;
let mut pos = 0;
let mut i = nbytes;
while i > 0 {
- val += (self.read_u8() as u64) << pos;
+ val += (self.read_u8_() as u64) << pos;
pos += 8;
i -= 1;
}
val
}
- fn read_le_int_n(&mut self, nbytes: uint) -> i64 {
- extend_sign(self.read_le_uint_n(nbytes), nbytes)
+ fn read_le_int_n_(&mut self, nbytes: uint) -> i64 {
+ extend_sign(self.read_le_uint_n_(nbytes), nbytes)
}
- fn read_be_uint_n(&mut self, nbytes: uint) -> u64 {
+ fn read_be_uint_n_(&mut self, nbytes: uint) -> u64 {
assert!(nbytes > 0 && nbytes <= 8);
let mut val = 0u64;
let mut i = nbytes;
while i > 0 {
i -= 1;
- val += (self.read_u8() as u64) << i * 8;
+ val += (self.read_u8_() as u64) << i * 8;
}
val
}
- fn read_be_int_n(&mut self, nbytes: uint) -> i64 {
- extend_sign(self.read_be_uint_n(nbytes), nbytes)
+ fn read_be_int_n_(&mut self, nbytes: uint) -> i64 {
+ extend_sign(self.read_be_uint_n_(nbytes), nbytes)
}
- fn read_le_uint(&mut self) -> uint {
- self.read_le_uint_n(uint::bytes) as uint
+ fn read_le_uint_(&mut self) -> uint {
+ self.read_le_uint_n_(uint::bytes) as uint
}
- fn read_le_int(&mut self) -> int {
- self.read_le_int_n(int::bytes) as int
+ fn read_le_int_(&mut self) -> int {
+ self.read_le_int_n_(int::bytes) as int
}
- fn read_be_uint(&mut self) -> uint {
- self.read_be_uint_n(uint::bytes) as uint
+ fn read_be_uint_(&mut self) -> uint {
+ self.read_be_uint_n_(uint::bytes) as uint
}
- fn read_be_int(&mut self) -> int {
- self.read_be_int_n(int::bytes) as int
+ fn read_be_int_(&mut self) -> int {
+ self.read_be_int_n_(int::bytes) as int
}
- fn read_be_u64(&mut self) -> u64 {
- self.read_be_uint_n(8) as u64
+ fn read_be_u64_(&mut self) -> u64 {
+ self.read_be_uint_n_(8) as u64
}
- fn read_be_u32(&mut self) -> u32 {
- self.read_be_uint_n(4) as u32
+ fn read_be_u32_(&mut self) -> u32 {
+ self.read_be_uint_n_(4) as u32
}
- fn read_be_u16(&mut self) -> u16 {
- self.read_be_uint_n(2) as u16
+ fn read_be_u16_(&mut self) -> u16 {
+ self.read_be_uint_n_(2) as u16
}
- fn read_be_i64(&mut self) -> i64 {
- self.read_be_int_n(8) as i64
+ fn read_be_i64_(&mut self) -> i64 {
+ self.read_be_int_n_(8) as i64
}
- fn read_be_i32(&mut self) -> i32 {
- self.read_be_int_n(4) as i32
+ fn read_be_i32_(&mut self) -> i32 {
+ self.read_be_int_n_(4) as i32
}
- fn read_be_i16(&mut self) -> i16 {
- self.read_be_int_n(2) as i16
+ fn read_be_i16_(&mut self) -> i16 {
+ self.read_be_int_n_(2) as i16
}
- fn read_be_f64(&mut self) -> f64 {
+ fn read_be_f64_(&mut self) -> f64 {
unsafe {
- cast::transmute::<u64, f64>(self.read_be_u64())
+ cast::transmute::<u64, f64>(self.read_be_u64_())
}
}
- fn read_be_f32(&mut self) -> f32 {
+ fn read_be_f32_(&mut self) -> f32 {
unsafe {
- cast::transmute::<u32, f32>(self.read_be_u32())
+ cast::transmute::<u32, f32>(self.read_be_u32_())
}
}
- fn read_le_u64(&mut self) -> u64 {
- self.read_le_uint_n(8) as u64
+ fn read_le_u64_(&mut self) -> u64 {
+ self.read_le_uint_n_(8) as u64
}
- fn read_le_u32(&mut self) -> u32 {
- self.read_le_uint_n(4) as u32
+ fn read_le_u32_(&mut self) -> u32 {
+ self.read_le_uint_n_(4) as u32
}
- fn read_le_u16(&mut self) -> u16 {
- self.read_le_uint_n(2) as u16
+ fn read_le_u16_(&mut self) -> u16 {
+ self.read_le_uint_n_(2) as u16
}
- fn read_le_i64(&mut self) -> i64 {
- self.read_le_int_n(8) as i64
+ fn read_le_i64_(&mut self) -> i64 {
+ self.read_le_int_n_(8) as i64
}
- fn read_le_i32(&mut self) -> i32 {
- self.read_le_int_n(4) as i32
+ fn read_le_i32_(&mut self) -> i32 {
+ self.read_le_int_n_(4) as i32
}
- fn read_le_i16(&mut self) -> i16 {
- self.read_le_int_n(2) as i16
+ fn read_le_i16_(&mut self) -> i16 {
+ self.read_le_int_n_(2) as i16
}
- fn read_le_f64(&mut self) -> f64 {
+ fn read_le_f64_(&mut self) -> f64 {
unsafe {
- cast::transmute::<u64, f64>(self.read_le_u64())
+ cast::transmute::<u64, f64>(self.read_le_u64_())
}
}
- fn read_le_f32(&mut self) -> f32 {
+ fn read_le_f32_(&mut self) -> f32 {
unsafe {
- cast::transmute::<u32, f32>(self.read_le_u32())
+ cast::transmute::<u32, f32>(self.read_le_u32_())
}
}
- fn read_u8(&mut self) -> u8 {
+ fn read_u8_(&mut self) -> u8 {
match self.read_byte() {
Some(b) => b as u8,
None => 0
}
}
- fn read_i8(&mut self) -> i8 {
+ fn read_i8_(&mut self) -> i8 {
match self.read_byte() {
Some(b) => b as i8,
None => 0
}
impl<T: Writer> WriterByteConversions for T {
- fn write_int(&mut self, n: int) {
+ fn write_int_(&mut self, n: int) {
int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
}
- fn write_uint(&mut self, n: uint) {
+ fn write_uint_(&mut self, n: uint) {
uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
}
- fn write_le_uint(&mut self, n: uint) {
+ fn write_le_uint_(&mut self, n: uint) {
u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
}
- fn write_le_int(&mut self, n: int) {
+ fn write_le_int_(&mut self, n: int) {
u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
}
- fn write_be_uint(&mut self, n: uint) {
+ fn write_be_uint_(&mut self, n: uint) {
u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
}
- fn write_be_int(&mut self, n: int) {
+ fn write_be_int_(&mut self, n: int) {
u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
}
u64_to_be_bytes(n, 8u, |v| self.write(v))
}
- fn write_be_u32(&mut self, n: u32) {
+ fn write_be_u32_(&mut self, n: u32) {
u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
}
- fn write_be_u16(&mut self, n: u16) {
+ fn write_be_u16_(&mut self, n: u16) {
u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
}
- fn write_be_i64(&mut self, n: i64) {
+ fn write_be_i64_(&mut self, n: i64) {
u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
}
u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
}
- fn write_be_i16(&mut self, n: i16) {
+ fn write_be_i16_(&mut self, n: i16) {
u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
}
- fn write_be_f64(&mut self, f: f64) {
+ fn write_be_f64_(&mut self, f: f64) {
unsafe {
self.write_be_u64_(cast::transmute(f))
}
fn write_be_f32_(&mut self, f: f32) {
unsafe {
- self.write_be_u32(cast::transmute(f))
+ self.write_be_u32_(cast::transmute(f))
}
}
u64_to_le_bytes(n, 8u, |v| self.write(v))
}
- fn write_le_u32(&mut self, n: u32) {
+ fn write_le_u32_(&mut self, n: u32) {
u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
}
- fn write_le_u16(&mut self, n: u16) {
+ fn write_le_u16_(&mut self, n: u16) {
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
}
- fn write_le_i64(&mut self, n: i64) {
+ fn write_le_i64_(&mut self, n: i64) {
u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
}
- fn write_le_i32(&mut self, n: i32) {
+ fn write_le_i32_(&mut self, n: i32) {
u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
}
- fn write_le_i16(&mut self, n: i16) {
+ fn write_le_i16_(&mut self, n: i16) {
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
}
- fn write_le_f64(&mut self, f: f64) {
+ fn write_le_f64_(&mut self, f: f64) {
unsafe {
self.write_le_u64_(cast::transmute(f))
}
fn write_le_f32_(&mut self, f: f32) {
unsafe {
- self.write_le_u32(cast::transmute(f))
+ self.write_le_u32_(cast::transmute(f))
}
}
- fn write_u8(&mut self, n: u8) {
+ fn write_u8_(&mut self, n: u8) {
self.write([n])
}
- fn write_i8(&mut self, n: i8) {
+ fn write_i8_(&mut self, n: i8) {
self.write([n as u8])
}
}
assert!(buf == ~[10, 11]);
}
-
#[test]
fn test_read_write_le_mem() {
let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value];
let mut reader = MemReader::new(writer.inner());
for i in uints.iter() {
- assert!(reader.read_le_u64() == *i);
+ assert!(reader.read_le_u64_() == *i);
}
}
let mut reader = MemReader::new(writer.inner());
for i in uints.iter() {
- assert!(reader.read_be_u64() == *i);
+ assert!(reader.read_be_u64_() == *i);
}
}
for i in ints.iter() {
// this tests that the sign extension is working
// (comparing the values as i32 would not test this)
- assert!(reader.read_be_int_n(4) == *i as i64);
+ assert!(reader.read_be_int_n_(4) == *i as i64);
}
}
writer.write(buf);
let mut reader = MemReader::new(writer.inner());
- let f = reader.read_be_f32();
+ let f = reader.read_be_f32_();
assert!(f == 8.1250);
}
writer.write_le_f32_(f);
let mut reader = MemReader::new(writer.inner());
- assert!(reader.read_be_f32() == 8.1250);
- assert!(reader.read_le_f32() == 8.1250);
+ assert!(reader.read_be_f32_() == 8.1250);
+ assert!(reader.read_le_f32_() == 8.1250);
}
}
access: FileAccess
) -> Option<FileStream> {
let open_result = unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).fs_open(path, mode, access)
};
match open_result {
/// by `path`.
pub fn unlink<P: PathLike>(path: &P) {
let unlink_result = unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).fs_unlink(path)
};
match unlink_result {
last_nread: int,
}
-impl FileStream {
-}
-
impl Reader for FileStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.fd.read(buf) {
/// Synchronous, non-blocking file I/O.
pub mod file;
+/// Synchronous, in-memory I/O.
+pub mod pipe;
+
/// Synchronous, non-blocking network I/O.
pub mod net {
pub mod tcp;
mod test {
use super::*;
use from_str::FromStr;
- use option::{Some, None};
+ use option::{Option, Some, None};
#[test]
fn test_from_str_ipv4() {
assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0"));
// out of range
- assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1"));
+ let none: Option<IpAddr> = FromStr::from_str("256.0.0.1");
+ assert_eq!(None, none);
// too short
- assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
+ let none: Option<IpAddr> = FromStr::from_str("255.0.0");
+ assert_eq!(None, none);
// too long
- assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
+ let none: Option<IpAddr> = FromStr::from_str("255.0.0.1.2");
+ assert_eq!(None, none);
// no number between dots
- assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1"));
+ let none: Option<IpAddr> = FromStr::from_str("255.0..1");
+ assert_eq!(None, none);
}
#[test]
FromStr::from_str("2a02:6b8::11:11"));
// too long group
- assert_eq!(None, FromStr::from_str::<IpAddr>("::00000"));
+ let none: Option<IpAddr> = FromStr::from_str("::00000");
+ assert_eq!(None, none);
// too short
- assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
+ let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7");
+ assert_eq!(None, none);
// too long
- assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
+ let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7:8:9");
+ assert_eq!(None, none);
// triple colon
- assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
+ let none: Option<IpAddr> = FromStr::from_str("1:2:::6:7:8");
+ assert_eq!(None, none);
// two double colons
- assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8"));
+ let none: Option<IpAddr> = FromStr::from_str("1:2::6::8");
+ assert_eq!(None, none);
}
#[test]
FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33"));
// colon after v4
- assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:"));
+ let none: Option<IpAddr> = FromStr::from_str("::127.0.0.1:");
+ assert_eq!(None, none);
// not enought groups
- assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
+ let none: Option<IpAddr> = FromStr::from_str("1.2.3.4.5:127.0.0.1");
+ assert_eq!(None, none);
// too many groups
- assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1"));
+ let none: Option<IpAddr> =
+ FromStr::from_str("1.2.3.4.5:6:7:127.0.0.1");
+ assert_eq!(None, none);
}
#[test]
FromStr::from_str("[::127.0.0.1]:22"));
// without port
- assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1"));
+ let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1");
+ assert_eq!(None, none);
// without port
- assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
+ let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:");
+ assert_eq!(None, none);
// wrong brackets around v4
- assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
+ let none: Option<SocketAddr> = FromStr::from_str("[127.0.0.1]:22");
+ assert_eq!(None, none);
// port out of range
- assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
+ let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:123456");
+ assert_eq!(None, none);
}
#[test]
use rt::rtio::{IoFactory, IoFactoryObject,
RtioSocket, RtioTcpListener,
RtioTcpListenerObject, RtioTcpStream,
- RtioTcpStreamObject};
+ RtioTcpStreamObject, RtioStream};
use rt::local::Local;
pub struct TcpStream(~RtioTcpStreamObject);
pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
let stream = unsafe {
rtdebug!("borrowing io to connect");
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
rtdebug!("about to connect");
(*io).tcp_connect(addr)
};
impl Reader for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- match (**self).read(buf) {
+ match (***self).read(buf) {
Ok(read) => Some(read),
Err(ioerr) => {
// EOF is indicated by returning None
impl Writer for TcpStream {
fn write(&mut self, buf: &[u8]) {
- match (**self).write(buf) {
+ match (***self).write(buf) {
Ok(_) => (),
Err(ioerr) => io_error::cond.raise(ioerr),
}
impl TcpListener {
pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
let listener = unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).tcp_bind(addr)
};
match listener {
do run_in_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
- assert!(e.kind == ConnectionRefused);
+ assert_eq!(e.kind, ConnectionRefused);
called = true;
}).inside {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
impl UdpSocket {
pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
- let socket = unsafe { (*Local::unsafe_borrow::<IoFactoryObject>()).udp_bind(addr) };
+ let socket = unsafe {
+ let factory: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*factory).udp_bind(addr)
+ };
match socket {
Ok(s) => Some(UdpSocket(s)),
Err(ioerr) => {
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Synchronous, in-memory pipes.
+//!
+//! Currently these aren't particularly useful, there only exists bindings
+//! enough so that pipes can be created to child processes.
+
+use prelude::*;
+use super::{Reader, Writer};
+use rt::io::{io_error, read_error, EndOfFile};
+use rt::local::Local;
+use rt::rtio::{RtioPipeObject, RtioStream, IoFactoryObject, IoFactory};
+use rt::uv::pipe;
+
+pub struct PipeStream(~RtioPipeObject);
+
+impl PipeStream {
+ /// Creates a new pipe initialized, but not bound to any particular
+ /// source/destination
+ pub fn new() -> Option<PipeStream> {
+ let pipe = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).pipe_init(false)
+ };
+ match pipe {
+ Ok(p) => Some(PipeStream(p)),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+ }
+
+ /// Extracts the underlying libuv pipe to be bound to another source.
+ pub fn uv_pipe(&self) -> pipe::Pipe {
+ // Did someone say multiple layers of indirection?
+ (**self).uv_pipe()
+ }
+}
+
+impl Reader for PipeStream {
+ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ match (***self).read(buf) {
+ Ok(read) => Some(read),
+ Err(ioerr) => {
+ // EOF is indicated by returning None
+ if ioerr.kind != EndOfFile {
+ read_error::cond.raise(ioerr);
+ }
+ return None;
+ }
+ }
+ }
+
+ fn eof(&mut self) -> bool { fail!() }
+}
+
+impl Writer for PipeStream {
+ fn write(&mut self, buf: &[u8]) {
+ match (***self).write(buf) {
+ Ok(_) => (),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ }
+ }
+ }
+
+ fn flush(&mut self) { fail!() }
+}
pub fn new() -> Option<Timer> {
let timer = unsafe {
rtdebug!("Timer::init: borrowing io to init timer");
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
rtdebug!("about to init timer");
(*io).timer_init()
};
(such as any #[test] function). In both cases the data structures live in
KillHandle.
+
I. Task killing.
The model for killing involves two atomic flags, the "kill flag" and the
unkillable flag, which means an unkillable task will see KILL_KILLED and fail
immediately (rendering the subsequent write to the kill flag unnecessary).
+
II. Exit code propagation.
-FIXME(#7544): Decide on the ultimate model for this and document it.
+The basic model for exit code propagation, which is used with the "watched"
+spawn mode (on by default for linked spawns, off for supervised and unlinked
+spawns), is that a parent will wait for all its watched children to exit
+before reporting whether it succeeded or failed. A watching parent will only
+report success if it succeeded and all its children also reported success;
+otherwise, it will report failure. This is most useful for writing test cases:
+
+~~~
+#[test]
+fn test_something_in_another_task {
+ do spawn {
+ assert!(collatz_conjecture_is_false());
+ }
+}
+~~~
+
+Here, as the child task will certainly outlive the parent task, we might miss
+the failure of the child when deciding whether or not the test case passed.
+The watched spawn mode avoids this problem.
+
+In order to propagate exit codes from children to their parents, any
+'watching' parent must wait for all of its children to exit before it can
+report its final exit status. We achieve this by using an UnsafeArc, using the
+reference counting to track how many children are still alive, and using the
+unwrap() operation in the parent's exit path to wait for all children to exit.
+The UnsafeArc referred to here is actually the KillHandle itself.
+
+This also works transitively, as if a "middle" watched child task is itself
+watching a grandchild task, the "middle" task will do unwrap() on its own
+KillHandle (thereby waiting for the grandchild to exit) before dropping its
+reference to its watching parent (which will alert the parent).
+
+While UnsafeArc::unwrap() accomplishes the synchronization, there remains the
+matter of reporting the exit codes themselves. This is easiest when an exiting
+watched task has no watched children of its own:
+
+- If the task with no watched children exits successfully, it need do nothing.
+- If the task with no watched children has failed, it sets a flag in the
+ parent's KillHandle ("any_child_failed") to false. It then stays false forever.
+
+However, if a "middle" watched task with watched children of its own exits
+before its child exits, we need to ensure that the grandparent task may still
+see a failure from the grandchild task. While we could achieve this by having
+each intermediate task block on its handle, this keeps around the other resources
+the task was using. To be more efficient, this is accomplished via "tombstones".
+
+A tombstone is a closure, ~fn() -> bool, which will perform any waiting necessary
+to collect the exit code of descendant tasks. In its environment is captured
+the KillHandle of whichever task created the tombstone, and perhaps also any
+tombstones that that task itself had, and finally also another tombstone,
+effectively creating a lazy-list of heap closures.
+
+When a child wishes to exit early and leave tombstones behind for its parent,
+it must use a LittleLock (pthread mutex) to synchronize with any possible
+sibling tasks which are trying to do the same thing with the same parent.
+However, on the other side, when the parent is ready to pull on the tombstones,
+it need not use this lock, because the unwrap() serves as a barrier that ensures
+no children will remain with references to the handle.
+
+The main logic for creating and assigning tombstones can be found in the
+function reparent_children_to() in the impl for KillHandle.
+
+
+IIA. Issues with exit code propagation.
+
+There are two known issues with the current scheme for exit code propagation.
+
+- As documented in issue #8136, the structure mandates the possibility for stack
+ overflow when collecting tombstones that are very deeply nested. This cannot
+ be avoided with the closure representation, as tombstones end up structured in
+ a sort of tree. However, notably, the tombstones do not actually need to be
+ collected in any particular order, and so a doubly-linked list may be used.
+ However we do not do this yet because DList is in libextra.
+
+- A discussion with Graydon made me realize that if we decoupled the exit code
+ propagation from the parents-waiting action, this could result in a simpler
+ implementation as the exit codes themselves would not have to be propagated,
+ and could instead be propagated implicitly through the taskgroup mechanism
+ that we already have. The tombstoning scheme would still be required. I have
+ not implemented this because currently we can't receive a linked failure kill
+ signal during the task cleanup activity, as that is currently "unkillable",
+ and occurs outside the task's unwinder's "try" block, so would require some
+ restructuring.
*/
use task::spawn::Taskgroup;
use to_bytes::IterBytes;
use unstable::atomics::{AtomicUint, Relaxed};
-use unstable::sync::{UnsafeAtomicRcBox, LittleLock};
+use unstable::sync::{UnsafeArc, LittleLock};
use util;
static KILLED_MSG: &'static str = "killed by linked failure";
static KILL_UNKILLABLE: uint = 2;
struct KillFlag(AtomicUint);
-type KillFlagHandle = UnsafeAtomicRcBox<KillFlag>;
+type KillFlagHandle = UnsafeArc<KillFlag>;
/// A handle to a blocked task. Usually this means having the ~Task pointer by
/// ownership, but if the task is killable, a killer can steal it at any time.
/// State shared between tasks used for task killing during linked failure.
#[deriving(Clone)]
-pub struct KillHandle(UnsafeAtomicRcBox<KillHandleInner>);
+pub struct KillHandle(UnsafeArc<KillHandleInner>);
/// Per-task state related to task death, killing, failure, etc.
pub struct Death {
let handles = match self {
Unkillable(task) => {
let flag = unsafe { KillFlag(AtomicUint::new(cast::transmute(task))) };
- UnsafeAtomicRcBox::newN(flag, num_handles)
+ UnsafeArc::newN(flag, num_handles)
}
Killable(flag_arc) => flag_arc.cloneN(num_handles),
};
impl KillHandle {
pub fn new() -> (KillHandle, KillFlagHandle) {
let (flag, flag_clone) =
- UnsafeAtomicRcBox::new2(KillFlag(AtomicUint::new(KILL_RUNNING)));
- let handle = KillHandle(UnsafeAtomicRcBox::new(KillHandleInner {
+ UnsafeArc::new2(KillFlag(AtomicUint::new(KILL_RUNNING)));
+ let handle = KillHandle(UnsafeArc::new(KillHandleInner {
// Linked failure fields
killed: flag,
unkillable: AtomicUint::new(KILL_RUNNING),
pub fn notify_immediate_failure(&mut self) {
// A benign data race may happen here if there are failing sibling
// tasks that were also spawned-watched. The refcount's write barriers
- // in UnsafeAtomicRcBox ensure that this write will be seen by the
+ // in UnsafeArc ensure that this write will be seen by the
// unwrapper/destructor, whichever task may unwrap it.
unsafe { (*self.get()).any_child_failed = true; }
}
/// All calls must be paired with a preceding call to inhibit_kill.
#[inline]
pub fn allow_kill(&mut self, already_failing: bool) {
- rtassert!(self.unkillable != 0);
+ if self.unkillable == 0 {
+ // we need to decrement the counter before failing.
+ self.unkillable -= 1;
+ fail!("Cannot enter a rekillable() block without a surrounding unkillable()");
+ }
self.unkillable -= 1;
if self.unkillable == 0 {
rtassert!(self.kill_handle.is_some());
pub trait Local {
fn put(value: ~Self);
fn take() -> ~Self;
- fn exists() -> bool;
+ fn exists(unused_value: Option<Self>) -> bool;
fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
+ unsafe fn unsafe_take() -> ~Self;
unsafe fn unsafe_borrow() -> *mut Self;
unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
}
impl Local for Task {
+ #[inline]
fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
+ #[inline]
fn take() -> ~Task { unsafe { local_ptr::take() } }
- fn exists() -> bool { local_ptr::exists() }
+ fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
let mut res: Option<T> = None;
let res_ptr: *mut Option<T> = &mut res;
None => { rtabort!("function failed in local_borrow") }
}
}
+ #[inline]
+ unsafe fn unsafe_take() -> ~Task { local_ptr::unsafe_take() }
+ #[inline]
unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
+ #[inline]
unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
local_ptr::try_unsafe_borrow()
}
impl Local for Scheduler {
fn put(value: ~Scheduler) {
let value = Cell::new(value);
- do Local::borrow::<Task,()> |task| {
+ do Local::borrow |task: &mut Task| {
let task = task;
task.sched = Some(value.take());
};
}
+ #[inline]
fn take() -> ~Scheduler {
- do Local::borrow::<Task,~Scheduler> |task| {
- let sched = task.sched.take_unwrap();
- let task = task;
- task.sched = None;
- sched
+ unsafe {
+ // XXX: Unsafe for speed
+ let task: *mut Task = Local::unsafe_borrow();
+ (*task).sched.take_unwrap()
}
}
- fn exists() -> bool {
- do Local::borrow::<Task,bool> |task| {
+ fn exists(_: Option<Scheduler>) -> bool {
+ do Local::borrow |task: &mut Task| {
match task.sched {
Some(ref _task) => true,
None => false
}
}
fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
- do Local::borrow::<Task, T> |task| {
+ do Local::borrow |task: &mut Task| {
match task.sched {
Some(~ref mut task) => {
f(task)
}
}
}
+ unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut Scheduler {
- match (*Local::unsafe_borrow::<Task>()).sched {
+ let task: *mut Task = Local::unsafe_borrow();
+ match (*task).sched {
Some(~ref mut sched) => {
let s: *mut Scheduler = &mut *sched;
return s;
}
}
unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
- if Local::exists::<Scheduler>() {
- Some(Local::unsafe_borrow())
- } else {
- None
+ let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task_opt {
+ Some(task) => {
+ match (*task).sched {
+ Some(~ref mut sched) => {
+ let s: *mut Scheduler = &mut *sched;
+ Some(s)
+ }
+ None => None
+ }
+ }
+ None => None
}
}
}
impl Local for IoFactoryObject {
fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
- fn exists() -> bool { rtabort!("unimpl") }
+ fn exists(_: Option<IoFactoryObject>) -> bool { rtabort!("unimpl") }
fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
+ unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
- let sched = Local::unsafe_borrow::<Scheduler>();
+ let sched: *mut Scheduler = Local::unsafe_borrow();
let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
return io;
}
- unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
+ unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> {
+ rtabort!("unimpl")
+ }
}
let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
- let res = do Local::borrow::<Task,bool> |_task| {
+ let res = do Local::borrow |_task: &mut Task| {
true
};
assert!(res)
use libc;
use libc::{c_void, uintptr_t, size_t};
use ops::Drop;
-use option::{Some, None};
+use option::{Option, None, Some};
use rt::local::Local;
use rt::task::Task;
use unstable::raw;
#[fixed_stack_segment] #[inline(never)]
pub fn new() -> LocalHeap {
unsafe {
- // Don't need synchronization for the single-threaded local heap
- let synchronized = false as uintptr_t;
// XXX: These usually come from the environment
let detailed_leaks = false as uintptr_t;
let poison_on_free = false as uintptr_t;
- let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free);
+ let region = rust_new_memory_region(detailed_leaks, poison_on_free);
assert!(region.is_not_null());
let boxed = rust_new_boxed_region(region, poison_on_free);
assert!(boxed.is_not_null());
// A little compatibility function
pub unsafe fn local_free(ptr: *libc::c_char) {
// XXX: Unsafe borrow for speed. Lame.
- match Local::try_unsafe_borrow::<Task>() {
+ let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task_ptr {
Some(task) => {
(*task).heap.free(ptr as *libc::c_void);
}
}
pub fn live_allocs() -> *raw::Box<()> {
- let region = do Local::borrow::<Task, *BoxedRegion> |task| {
+ let region = do Local::borrow |task: &mut Task| {
task.heap.boxed_region
};
extern {
#[fast_ffi]
- fn rust_new_memory_region(synchronized: uintptr_t,
- detailed_leaks: uintptr_t,
+ fn rust_new_memory_region(detailed_leaks: uintptr_t,
poison_on_free: uintptr_t) -> *MemoryRegion;
#[fast_ffi]
fn rust_delete_memory_region(region: *MemoryRegion);
use unstable::finally::Finally;
use tls = rt::thread_local_storage;
+static mut RT_TLS_KEY: tls::Key = -1;
+
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
#[fixed_stack_segment]
#[inline(never)]
pub fn init_tls_key() {
unsafe {
- rust_initialize_rt_tls_key();
+ rust_initialize_rt_tls_key(&mut RT_TLS_KEY);
extern {
- fn rust_initialize_rt_tls_key();
+ fn rust_initialize_rt_tls_key(key: *mut tls::Key);
}
}
}
/// # Safety note
///
/// Does not validate the pointer type.
+#[inline]
pub unsafe fn put<T>(sched: ~T) {
let key = tls_key();
let void_ptr: *mut c_void = cast::transmute(sched);
/// # Safety note
///
/// Does not validate the pointer type.
+#[inline]
pub unsafe fn take<T>() -> ~T {
let key = tls_key();
let void_ptr: *mut c_void = tls::get(key);
return ptr;
}
+/// Take ownership of a pointer from thread-local storage.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
+/// Leaves the old pointer in TLS for speed.
+#[inline]
+pub unsafe fn unsafe_take<T>() -> ~T {
+ let key = tls_key();
+ let void_ptr: *mut c_void = tls::get(key);
+ if void_ptr.is_null() {
+ rtabort!("thread-local pointer is null. bogus!");
+ }
+ let ptr: ~T = cast::transmute(void_ptr);
+ return ptr;
+}
+
/// Check whether there is a thread-local pointer installed.
pub fn exists() -> bool {
unsafe {
/// Because this leaves the value in thread-local storage it is possible
/// For the Scheduler pointer to be aliased
pub unsafe fn unsafe_borrow<T>() -> *mut T {
- match try_unsafe_borrow() {
- Some(p) => p,
- None => rtabort!("thread-local pointer is null. bogus!")
+ let key = tls_key();
+ let mut void_ptr: *mut c_void = tls::get(key);
+ if void_ptr.is_null() {
+ rtabort!("thread-local pointer is null. bogus!");
}
+ let ptr: *mut *mut c_void = &mut void_ptr;
+ let ptr: *mut ~T = ptr as *mut ~T;
+ let ptr: *mut T = &mut **ptr;
+ return ptr;
}
pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
}
}
+#[inline]
fn tls_key() -> tls::Key {
match maybe_tls_key() {
Some(key) => key,
}
}
-#[fixed_stack_segment]
-#[inline(never)]
-fn maybe_tls_key() -> Option<tls::Key> {
+#[inline]
+#[cfg(not(test))]
+pub fn maybe_tls_key() -> Option<tls::Key> {
unsafe {
- let key: *mut c_void = rust_get_rt_tls_key();
- let key: &mut tls::Key = cast::transmute(key);
- let key = *key;
- // Check that the key has been initialized.
-
// NB: This is a little racy because, while the key is
// initalized under a mutex and it's assumed to be initalized
// in the Scheduler ctor by any thread that needs to use it,
// another thread. I think this is fine since the only action
// they could take if it was initialized would be to check the
// thread-local value and see that it's not set.
- if key != -1 {
- return Some(key);
+ if RT_TLS_KEY != -1 {
+ return Some(RT_TLS_KEY);
} else {
return None;
}
}
+}
- extern {
- fn rust_get_rt_tls_key() -> *mut c_void;
- }
+// XXX: The boundary between the running runtime and the testing runtime
+// seems to be fuzzy at the moment, and trying to use two different keys
+// results in disaster. This should not be necessary.
+#[inline]
+#[cfg(test)]
+pub fn maybe_tls_key() -> Option<tls::Key> {
+ unsafe { ::cast::transmute(::realstd::rt::local_ptr::maybe_tls_key()) }
}
use vec::OwnedVector;
use cell::Cell;
use option::*;
-use unstable::sync::Exclusive;
+use unstable::sync::{UnsafeArc, LittleLock};
use clone::Clone;
pub struct MessageQueue<T> {
- // XXX: Another mystery bug fixed by boxing this lock
- priv queue: ~Exclusive<~[T]>
+ priv state: UnsafeArc<State<T>>
+}
+
+struct State<T> {
+ count: uint,
+ queue: ~[T],
+ lock: LittleLock
}
impl<T: Send> MessageQueue<T> {
pub fn new() -> MessageQueue<T> {
MessageQueue {
- queue: ~Exclusive::new(~[])
+ state: UnsafeArc::new(State {
+ count: 0,
+ queue: ~[],
+ lock: LittleLock::new()
+ })
}
}
pub fn push(&mut self, value: T) {
unsafe {
let value = Cell::new(value);
- self.queue.with(|q| q.push(value.take()) );
+ let state = self.state.get();
+ do (*state).lock.lock {
+ (*state).count += 1;
+ (*state).queue.push(value.take());
+ }
}
}
pub fn pop(&mut self) -> Option<T> {
unsafe {
- do self.queue.with |q| {
- if !q.is_empty() {
- Some(q.shift())
+ let state = self.state.get();
+ do (*state).lock.lock {
+ if !(*state).queue.is_empty() {
+ (*state).count += 1;
+ Some((*state).queue.shift())
+ } else {
+ None
+ }
+ }
+ }
+ }
+
+ /// A pop that may sometimes miss enqueued elements, but is much faster
+ /// to give up without doing any synchronization
+ pub fn casual_pop(&mut self) -> Option<T> {
+ unsafe {
+ let state = self.state.get();
+ // NB: Unsynchronized check
+ if (*state).count == 0 { return None; }
+ do (*state).lock.lock {
+ if !(*state).queue.is_empty() {
+ (*state).count += 1;
+ Some((*state).queue.shift())
} else {
None
}
}
}
-impl<T> Clone for MessageQueue<T> {
+impl<T: Send> Clone for MessageQueue<T> {
fn clone(&self) -> MessageQueue<T> {
MessageQueue {
- queue: self.queue.clone()
+ state: self.state.clone()
}
}
}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use to_str::ToStr;
-
-pub struct SchedMetrics {
- // The number of times executing `run_sched_once`.
- turns: uint,
- // The number of turns that received a message.
- messages_received: uint,
- // The number of turns that ran a task from the queue.
- tasks_resumed_from_queue: uint,
- // The number of turns that found no work to perform.
- wasted_turns: uint,
- // The number of times the scheduler went to sleep.
- sleepy_times: uint,
- // Context switches from the scheduler into a task.
- context_switches_sched_to_task: uint,
- // Context switches from a task into the scheduler.
- context_switches_task_to_sched: uint,
- // Context switches from a task to a task.
- context_switches_task_to_task: uint,
- // Message sends that unblock the receiver
- rendezvous_sends: uint,
- // Message sends that do not unblock the receiver
- non_rendezvous_sends: uint,
- // Message receives that do not block the receiver
- rendezvous_recvs: uint,
- // Message receives that block the receiver
- non_rendezvous_recvs: uint,
- // JoinLatch releases that create tombstones
- release_tombstone: uint,
- // JoinLatch releases that do not create tombstones
- release_no_tombstone: uint,
-}
-
-impl SchedMetrics {
- pub fn new() -> SchedMetrics {
- SchedMetrics {
- turns: 0,
- messages_received: 0,
- tasks_resumed_from_queue: 0,
- wasted_turns: 0,
- sleepy_times: 0,
- context_switches_sched_to_task: 0,
- context_switches_task_to_sched: 0,
- context_switches_task_to_task: 0,
- rendezvous_sends: 0,
- non_rendezvous_sends: 0,
- rendezvous_recvs: 0,
- non_rendezvous_recvs: 0,
- release_tombstone: 0,
- release_no_tombstone: 0
- }
- }
-}
-
-impl ToStr for SchedMetrics {
- fn to_str(&self) -> ~str {
- fmt!("turns: %u\n\
- messages_received: %u\n\
- tasks_resumed_from_queue: %u\n\
- wasted_turns: %u\n\
- sleepy_times: %u\n\
- context_switches_sched_to_task: %u\n\
- context_switches_task_to_sched: %u\n\
- context_switches_task_to_task: %u\n\
- rendezvous_sends: %u\n\
- non_rendezvous_sends: %u\n\
- rendezvous_recvs: %u\n\
- non_rendezvous_recvs: %u\n\
- release_tombstone: %u\n\
- release_no_tombstone: %u\n\
- ",
- self.turns,
- self.messages_received,
- self.tasks_resumed_from_queue,
- self.wasted_turns,
- self.sleepy_times,
- self.context_switches_sched_to_task,
- self.context_switches_task_to_sched,
- self.context_switches_task_to_task,
- self.rendezvous_sends,
- self.non_rendezvous_sends,
- self.rendezvous_recvs,
- self.non_rendezvous_recvs,
- self.release_tombstone,
- self.release_no_tombstone
- )
- }
-}
\ No newline at end of file
*/
#[doc(hidden)];
-#[deny(unused_imports)];
-#[deny(unused_mut)];
-#[deny(unused_variable)];
-#[deny(unused_unsafe)];
use cell::Cell;
use clone::Clone;
use container::Container;
use iterator::{Iterator, range};
-use option::{Some, None};
+use option::{Option, None, Some};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
use rt::work_queue::WorkQueue;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
-use unstable::sync::UnsafeAtomicRcBox;
+use unstable::sync::UnsafeArc;
use vec::{OwnedVector, MutableVector};
/// The global (exchange) heap.
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;
-pub mod metrics;
-
// FIXME #5248 shouldn't be pub
/// Just stuff
pub mod util;
args::init(argc, argv);
env::init();
logging::init(crate_map);
- rust_update_gc_metadata(crate_map);
}
-
- externfn!(fn rust_update_gc_metadata(crate_map: *u8));
}
/// One-time runtime cleanup.
// Create a shared cell for transmitting the process exit
// code from the main task to this function.
- let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
+ let exit_code = UnsafeArc::new(AtomicInt::new(0));
let exit_code_clone = exit_code.clone();
// When the main task exits, after all the tasks in the main
pub fn in_sched_context() -> bool {
unsafe {
- match Local::try_unsafe_borrow::<Task>() {
+ let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task_ptr {
Some(task) => {
match (*task).task_type {
SchedTask => true,
pub fn in_green_task_context() -> bool {
unsafe {
- match Local::try_unsafe_borrow::<Task>() {
+ let task: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task {
Some(task) => {
match (*task).task_type {
GreenTask(_) => true,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use libc;
use option::*;
use result::*;
use libc::c_int;
use rt::io::IoError;
use super::io::net::ip::{IpAddr, SocketAddr};
+use rt::uv;
use rt::uv::uvio;
use path::Path;
use super::io::support::PathLike;
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
pub type RtioTimerObject = uvio::UvTimer;
pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
+pub type RtioPipeObject = uvio::UvPipeStream;
+pub type RtioProcessObject = uvio::UvProcess;
+pub type RtioProcessConfig<'self> = uv::process::Config<'self>;
pub trait EventLoop {
fn run(&mut self);
fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
-> Result<~RtioFileStream, IoError>;
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+ fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError>;
+ fn spawn(&mut self, config: &RtioProcessConfig) -> Result<~RtioProcessObject, IoError>;
+}
+
+pub trait RtioStream {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>;
}
-pub trait RtioTcpStream : RtioSocket {
- fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+pub trait RtioTcpStream : RtioSocket + RtioStream {
fn peer_name(&mut self) -> Result<SocketAddr, IoError>;
fn control_congestion(&mut self) -> Result<(), IoError>;
fn nodelay(&mut self) -> Result<(), IoError>;
fn tell(&self) -> Result<u64, IoError>;
fn flush(&mut self) -> Result<(), IoError>;
}
+
+pub trait RtioProcess {
+ fn id(&self) -> libc::pid_t;
+ fn kill(&mut self, signal: int) -> Result<(), IoError>;
+ fn wait(&mut self) -> int;
+}
use rt::local_ptr;
use rt::local::Local;
use rt::rtio::{RemoteCallback, PausibleIdleCallback};
-use rt::metrics::SchedMetrics;
use borrow::{to_uint};
use cell::Cell;
use rand::{XorShiftRng, RngUtil};
/// An action performed after a context switch on behalf of the
/// code running before the context switch
cleanup_job: Option<CleanupJob>,
- metrics: SchedMetrics,
/// Should this scheduler run any task, or only pinned tasks?
run_anything: bool,
/// If the scheduler shouldn't run some tasks, a friend to send
idle_callback: Option<~PausibleIdleCallback>
}
+/// An indication of how hard to work on a given operation, the difference
+/// mainly being whether memory is synchronized or not
+#[deriving(Eq)]
+enum EffortLevel {
+ DontTryTooHard,
+ GiveItYourBest
+}
+
impl Scheduler {
// * Initialization Functions
stack_pool: StackPool::new(),
sched_task: None,
cleanup_job: None,
- metrics: SchedMetrics::new(),
run_anything: run_anything,
friend_handle: friend,
rng: XorShiftRng::new(),
// successfully run the input task. Start by running the
// scheduler. Grab it out of TLS - performing the scheduler
// action will have given it away.
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
rtdebug!("starting scheduler %u", sched.sched_id());
sched.run();
// Close the idle callback.
- let mut sched = Local::take::<Scheduler>();
+ let mut sched: ~Scheduler = Local::take();
sched.idle_callback.get_mut_ref().close();
// Make one go through the loop to run the close callback.
sched.run();
// cleaning up the memory it uses. As we didn't actually call
// task.run() on the scheduler task we never get through all
// the cleanup code it runs.
- let mut stask = Local::take::<Task>();
+ let mut stask: ~Task = Local::take();
rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id());
// Should not have any messages
let message = stask.sched.get_mut_ref().message_queue.pop();
- assert!(message.is_none());
+ rtassert!(message.is_none());
stask.destroyed = true;
}
// Our scheduler must be in the task before the event loop
// is started.
let self_sched = Cell::new(self_sched);
- do Local::borrow::<Task,()> |stask| {
+ do Local::borrow |stask: &mut Task| {
stask.sched = Some(self_sched.take());
};
// already have a scheduler stored in our local task, so we
// start off by taking it. This is the only path through the
// scheduler where we get the scheduler this way.
- let mut sched = Local::take::<Scheduler>();
+ let mut sched: ~Scheduler = Local::take();
// Assume that we need to continue idling unless we reach the
// end of this function without performing an action.
// First we check for scheduler messages, these are higher
// priority than regular tasks.
- let sched = match sched.interpret_message_queue() {
+ let sched = match sched.interpret_message_queue(DontTryTooHard) {
Some(sched) => sched,
None => return
};
// This helper will use a randomized work-stealing algorithm
// to find work.
- let mut sched = match sched.do_work() {
+ let sched = match sched.do_work() {
+ Some(sched) => sched,
+ None => return
+ };
+
+ // Now, before sleeping we need to find out if there really
+ // were any messages. Give it your best!
+ let mut sched = match sched.interpret_message_queue(GiveItYourBest) {
Some(sched) => sched,
None => return
};
// If we got here then there was no work to do.
// Generate a SchedHandle and push it to the sleeper list so
// somebody can wake us up later.
- sched.metrics.wasted_turns += 1;
if !sched.sleepy && !sched.no_sleep {
rtdebug!("scheduler has no work to do, going to sleep");
- sched.metrics.sleepy_times += 1;
sched.sleepy = true;
let handle = sched.make_handle();
sched.sleeper_list.push(handle);
// returns the still-available scheduler. At this point all
// message-handling will count as a turn of work, and as a result
// return None.
- fn interpret_message_queue(~self) -> Option<~Scheduler> {
+ fn interpret_message_queue(~self, effort: EffortLevel) -> Option<~Scheduler> {
let mut this = self;
- match this.message_queue.pop() {
+
+ let msg = if effort == DontTryTooHard {
+ // Do a cheap check that may miss messages
+ this.message_queue.casual_pop()
+ } else {
+ this.message_queue.pop()
+ };
+
+ match msg {
Some(PinnedTask(task)) => {
let mut task = task;
task.give_home(Sched(this.make_handle()));
// We've made work available. Notify a
// sleeping scheduler.
- // XXX: perf. Check for a sleeper without
- // synchronizing memory. It's not critical
- // that we always find it.
- match this.sleeper_list.pop() {
+ match this.sleeper_list.casual_pop() {
Some(handle) => {
let mut handle = handle;
handle.send(Wake)
let mut this = self;
// The current task is grabbed from TLS, not taken as an input.
- let current_task: ~Task = Local::take::<Task>();
+ // Doing an unsafe_take to avoid writing back a null pointer -
+ // We're going to call `put` later to do that.
+ let current_task: ~Task = unsafe { Local::unsafe_take() };
// Check that the task is not in an atomically() section (e.g.,
// holding a pthread mutex, which could deadlock the scheduler).
let current_task: &mut Task = match sched.cleanup_job {
Some(CleanupJob { task: ref task, _ }) => {
- transmute_mut_region(*transmute_mut_unsafe(task))
+ let task_ptr: *~Task = task;
+ transmute_mut_region(*transmute_mut_unsafe(task_ptr))
}
None => {
rtabort!("no cleanup job");
// run the cleanup job, as expected by the previously called
// swap_contexts function.
unsafe {
- let sched = Local::unsafe_borrow::<Scheduler>();
- (*sched).run_cleanup_job();
+ let task: *mut Task = Local::unsafe_borrow();
+ (*task).sched.get_mut_ref().run_cleanup_job();
// Must happen after running the cleanup job (of course).
- let task = Local::unsafe_borrow::<Task>();
(*task).death.check_killed((*task).unwinder.unwinding);
}
}
}
pub fn run_task(task: ~Task) {
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
sched.process_task(task, Scheduler::switch_task).map_move(Local::put);
}
pub fn run_task_later(next_task: ~Task) {
let next_task = Cell::new(next_task);
- do Local::borrow::<Scheduler,()> |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_task(next_task.take());
};
}
// exit before emptying the work queue
do run_in_newsched_task {
do spawntask {
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let task = Cell::new(task);
do sched.event_loop.callback_ms(10) {
rtdebug!("in callback");
- let mut sched = Local::take::<Scheduler>();
+ let mut sched: ~Scheduler = Local::take();
sched.enqueue_blocked_task(task.take());
Local::put(sched);
}
pub trait SelectPortInner<T> {
fn recv_ready(self) -> Option<T>;
}
+
use vec::OwnedVector;
use option::{Option, Some, None};
use cell::Cell;
-use unstable::sync::Exclusive;
+use unstable::sync::{UnsafeArc, LittleLock};
use rt::sched::SchedHandle;
use clone::Clone;
pub struct SleeperList {
- priv stack: ~Exclusive<~[SchedHandle]>
+ priv state: UnsafeArc<State>
+}
+
+struct State {
+ count: uint,
+ stack: ~[SchedHandle],
+ lock: LittleLock
}
impl SleeperList {
pub fn new() -> SleeperList {
SleeperList {
- stack: ~Exclusive::new(~[])
+ state: UnsafeArc::new(State {
+ count: 0,
+ stack: ~[],
+ lock: LittleLock::new()
+ })
}
}
pub fn push(&mut self, handle: SchedHandle) {
let handle = Cell::new(handle);
unsafe {
- self.stack.with(|s| s.push(handle.take()));
+ let state = self.state.get();
+ do (*state).lock.lock {
+ (*state).count += 1;
+ (*state).stack.push(handle.take());
+ }
}
}
pub fn pop(&mut self) -> Option<SchedHandle> {
unsafe {
- do self.stack.with |s| {
- if !s.is_empty() {
- Some(s.pop())
+ let state = self.state.get();
+ do (*state).lock.lock {
+ if !(*state).stack.is_empty() {
+ (*state).count -= 1;
+ Some((*state).stack.pop())
+ } else {
+ None
+ }
+ }
+ }
+ }
+
+ /// A pop that may sometimes miss enqueued elements, but is much faster
+ /// to give up without doing any synchronization
+ pub fn casual_pop(&mut self) -> Option<SchedHandle> {
+ unsafe {
+ let state = self.state.get();
+ // NB: Unsynchronized check
+ if (*state).count == 0 { return None; }
+ do (*state).lock.lock {
+ if !(*state).stack.is_empty() {
+ // NB: count is also protected by the lock
+ (*state).count -= 1;
+ Some((*state).stack.pop())
} else {
None
}
impl Clone for SleeperList {
fn clone(&self) -> SleeperList {
SleeperList {
- stack: self.stack.clone()
+ state: self.state.clone()
}
}
-}
\ No newline at end of file
+}
/// Point one word beyond the high end of the allocated stack
pub fn end(&self) -> *uint {
- vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+ unsafe {
+ vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+ }
}
}
use borrow;
use cast::transmute;
use cleanup;
+use local_data;
use libc::{c_void, uintptr_t};
-use ptr;
use prelude::*;
use option::{Option, Some, None};
use rt::borrowck;
}
pub enum TaskType {
- GreenTask(Option<~SchedHome>),
+ GreenTask(Option<SchedHome>),
SchedTask
}
}
pub struct GarbageCollector;
-pub struct LocalStorage(*c_void, Option<extern "Rust" fn(*c_void)>);
+pub struct LocalStorage(Option<local_data::Map>);
pub struct Unwinder {
unwinding: bool,
pub fn build_homed_child(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
- do Local::borrow::<Task, ~Task> |running_task| {
+ do Local::borrow |running_task: &mut Task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
stack_size,
pub fn build_homed_root(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
- do Local::borrow::<Task, ~Task> |running_task| {
+ do Local::borrow |running_task: &mut Task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
stack_size,
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
name: None,
coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
- task_type: GreenTask(Some(~home)),
+ task_type: GreenTask(Some(home)),
borrow_list: None
}
}
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
name: None,
coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
- task_type: GreenTask(Some(~home)),
+ task_type: GreenTask(Some(home)),
borrow_list: None
}
}
pub fn give_home(&mut self, new_home: SchedHome) {
match self.task_type {
GreenTask(ref mut home) => {
- *home = Some(~new_home);
+ *home = Some(new_home);
}
SchedTask => {
rtabort!("type error: used SchedTask as GreenTask");
match self.task_type {
GreenTask(ref mut home) => {
let out = home.take_unwrap();
- return *out;
+ return out;
}
SchedTask => {
rtabort!("type error: used SchedTask as GreenTask");
// Run the task main function, then do some cleanup.
do f.finally {
-
- // Destroy task-local storage. This may run user dtors.
- match self.storage {
- LocalStorage(ptr, Some(ref dtor)) => {
- (*dtor)(ptr)
- }
- _ => ()
- }
-
+ // First, destroy task-local storage. This may run user dtors.
+ //
// FIXME #8302: Dear diary. I'm so tired and confused.
// There's some interaction in rustc between the box
// annihilator and the TLS dtor by which TLS is
// TLS would be reinitialized but never destroyed,
// but somehow this works. I have no idea what's going
// on but this seems to make things magically work. FML.
- self.storage = LocalStorage(ptr::null(), None);
+ //
+ // (added after initial comment) A possible interaction here is
+ // that the destructors for the objects in TLS themselves invoke
+ // TLS, or possibly some destructors for those objects being
+ // annihilated invoke TLS. Sadly these two operations seemed to
+ // be intertwined, and miraculously work for now...
+ self.storage.take();
// Destroy remaining boxes. Also may run user dtors.
unsafe { cleanup::annihilate(); }
pub fn is_home_no_tls(&self, sched: &~Scheduler) -> bool {
match self.task_type {
- GreenTask(Some(~AnySched)) => { false }
- GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _}))) => {
+ GreenTask(Some(AnySched)) => { false }
+ GreenTask(Some(Sched(SchedHandle { sched_id: ref id, _}))) => {
*id == sched.sched_id()
}
GreenTask(None) => {
pub fn homed(&self) -> bool {
match self.task_type {
- GreenTask(Some(~AnySched)) => { false }
- GreenTask(Some(~Sched(SchedHandle { _ }))) => { true }
+ GreenTask(Some(AnySched)) => { false }
+ GreenTask(Some(Sched(SchedHandle { _ }))) => { true }
GreenTask(None) => {
rtabort!("task without home");
}
// Grab both the scheduler and the task from TLS and check if the
// task is executing on an appropriate scheduler.
pub fn on_appropriate_sched() -> bool {
- do Local::borrow::<Task,bool> |task| {
+ do Local::borrow |task: &mut Task| {
let sched_id = task.sched.get_ref().sched_id();
let sched_run_anything = task.sched.get_ref().run_anything;
match task.task_type {
- GreenTask(Some(~AnySched)) => {
+ GreenTask(Some(AnySched)) => {
rtdebug!("anysched task in sched check ****");
sched_run_anything
}
- GreenTask(Some(~Sched(SchedHandle { sched_id: ref id, _ }))) => {
+ GreenTask(Some(Sched(SchedHandle { sched_id: ref id, _ }))) => {
rtdebug!("homed task in sched check ****");
*id == sched_id
}
unsafe {
// Again - might work while safe, or it might not.
- do Local::borrow::<Scheduler,()> |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
sched.run_cleanup_job();
}
// simply unsafe_borrow it to get this reference. We
// need to still have the task in TLS though, so we
// need to unsafe_borrow.
- let task = Local::unsafe_borrow::<Task>();
+ let task: *mut Task = Local::unsafe_borrow();
do (*task).run {
// N.B. Removing `start` from the start wrapper
}
// We remove the sched from the Task in TLS right now.
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
// ... allowing us to give it away when performing a
// scheduling operation.
sched.terminate_current_task()
TlsGetValue(key)
}
-#[cfg(windows)]
+#[cfg(windows, target_arch = "x86")]
#[abi = "stdcall"]
extern "stdcall" {
fn TlsAlloc() -> DWORD;
fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
}
+#[cfg(windows, target_arch = "x86_64")]
+extern {
+ fn TlsAlloc() -> DWORD;
+ fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
+ fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+}
+
#[test]
fn tls_smoke_test() {
use cast::transmute;
// There's a waiting task. Wake it up
rtdebug!("waking blocked tube");
let task = (*state).blocked_task.take_unwrap();
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
sched.resume_blocked_task_immediately(task);
}
}
rtdebug!("blocking on tube recv");
assert!(self.p.refcount() > 1); // There better be somebody to wake us up
assert!((*state).blocked_task.is_none());
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |_, task| {
(*state).blocked_task = Some(task);
}
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone_cell = Cell::new(tube_clone);
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let mut tube_clone = tube_clone_cell.take();
tube_clone.send(1);
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone = Cell::new(tube_clone);
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let tube_clone = Cell::new(tube_clone.take());
do sched.event_loop.callback {
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone = Cell::new(tube_clone);
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
callback_send(tube_clone.take(), 0);
if i == 100 { return; }
let tube = Cell::new(Cell::new(tube));
- do Local::borrow::<Scheduler, ()> |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
let tube = tube.take();
do sched.event_loop.callback {
let mut tube = tube.take();
use option::{Some, None};
use os;
use str::StrSlice;
+use unstable::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
#[cfg(target_os="macos")]
use unstable::running_on_valgrind;
+// Indicates whether we should perform expensive sanity checks, including rtassert!
+// XXX: Once the runtime matures remove the `true` below to turn off rtassert, etc.
+pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert);
+
/// Get the number of cores available
pub fn num_cpus() -> uint {
#[fixed_stack_segment]; #[inline(never)];
}
}
-pub fn set_exit_status(code: int) {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- return rust_set_exit_status_newrt(code as libc::uintptr_t);
- }
+static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
- extern {
- fn rust_set_exit_status_newrt(code: libc::uintptr_t);
- }
+pub fn set_exit_status(code: int) {
+ unsafe { EXIT_STATUS.store(code, SeqCst) }
}
pub fn get_exit_status() -> int {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- return rust_get_exit_status_newrt() as int;
- }
-
- extern {
- fn rust_get_exit_status_newrt() -> libc::uintptr_t;
- }
+ unsafe { EXIT_STATUS.load(SeqCst) }
}
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
- let status = status_to_maybe_uv_error(watcher, status);
+ let status = status_to_maybe_uv_error(status);
let data = watcher.get_watcher_data();
let cb = data.async_cb.get_ref();
(*cb)(watcher, status);
use prelude::*;
use ptr::null;
use libc::c_void;
-use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
- status_to_maybe_uv_error_with_loop, UvError};
+use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, UvError};
+use rt::uv::status_to_maybe_uv_error;
use rt::uv::uvll;
use rt::uv::uvll::*;
use super::super::io::support::PathLike;
pub fn open_sync<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int)
-> Result<int, UvError> {
let result = FsRequest::open_common(loop_, path, flags, mode, None);
- sync_cleanup(loop_, result)
+ sync_cleanup(result)
}
fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
}
pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
let result = FsRequest::unlink_common(loop_, path, Some(cb));
- sync_cleanup(loop_, result);
+ sync_cleanup(result);
}
pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
let result = FsRequest::unlink_common(loop_, path, None);
- sync_cleanup(loop_, result)
+ sync_cleanup(result)
}
pub fn install_req_data(&self, cb: Option<FsCallback>) {
match self { &FsRequest(ptr) => ptr }
}
}
- fn sync_cleanup(loop_: &Loop, result: int)
- -> Result<int, UvError> {
- match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
+ fn sync_cleanup(result: int) -> Result<int, UvError> {
+ match status_to_maybe_uv_error(result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
pub fn write_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
-> Result<int, UvError> {
let result = self.write_common(loop_, buf, offset, None);
- sync_cleanup(loop_, result)
+ sync_cleanup(result)
}
fn read_common(&mut self, loop_: &Loop, buf: Buf,
pub fn read_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
-> Result<int, UvError> {
let result = self.read_common(loop_, buf, offset, None);
- sync_cleanup(loop_, result)
+ sync_cleanup(result)
}
fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
}
pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
let result = self.close_common(loop_, None);
- sync_cleanup(loop_, result)
+ sync_cleanup(result)
}
}
extern fn compl_cb(req: *uv_fs_t) {
let mut req: FsRequest = NativeHandle::from_native_handle(req);
- let loop_ = req.get_loop();
// pull the user cb out of the req data
let cb = {
let data = req.get_req_data();
// in uv_fs_open calls, the result will be the fd in the
// case of success, otherwise it's -1 indicating an error
let result = req.get_result();
- let status = status_to_maybe_uv_error_with_loop(
- loop_.native_handle(), result);
+ let status = status_to_maybe_uv_error(result);
// we have a req and status, call the user cb..
// only giving the user a ref to the FsRequest, as we
// have to clean it up, afterwards (and they aren't really
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
- let status = status_to_maybe_uv_error(idle_watcher, status);
+ let status = status_to_maybe_uv_error(status);
(*cb)(idle_watcher, status);
}
}
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
- let status = status_to_maybe_uv_error(idle_watcher, status);
+ let status = status_to_maybe_uv_error(status);
(*cb)(idle_watcher, status);
}
}
pub use self::idle::IdleWatcher;
pub use self::timer::TimerWatcher;
pub use self::async::AsyncWatcher;
+pub use self::process::Process;
+pub use self::pipe::Pipe;
/// The implementation of `rtio` for libuv
pub mod uvio;
pub mod idle;
pub mod timer;
pub mod async;
+pub mod process;
+pub mod pipe;
/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
+// first int is exit_status, second is term_signal
+pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
timer_cb: Option<TimerCallback>,
async_cb: Option<AsyncCallback>,
udp_recv_cb: Option<UdpReceiveCallback>,
- udp_send_cb: Option<UdpSendCallback>
+ udp_send_cb: Option<UdpSendCallback>,
+ exit_cb: Option<ExitCallback>,
}
pub trait WatcherInterop {
timer_cb: None,
async_cb: None,
udp_recv_cb: None,
- udp_send_cb: None
+ udp_send_cb: None,
+ exit_cb: None,
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
// XXX: Need to define the error constants like EOF so they can be
// compared to the UvError type
-pub struct UvError(uvll::uv_err_t);
+pub struct UvError(c_int);
impl UvError {
pub fn name(&self) -> ~str {
unsafe {
- let inner = match self { &UvError(ref a) => a };
+ let inner = match self { &UvError(a) => a };
let name_str = uvll::err_name(inner);
assert!(name_str.is_not_null());
from_c_str(name_str)
pub fn desc(&self) -> ~str {
unsafe {
- let inner = match self { &UvError(ref a) => a };
+ let inner = match self { &UvError(a) => a };
let desc_str = uvll::strerror(inner);
assert!(desc_str.is_not_null());
from_c_str(desc_str)
}
pub fn is_eof(&self) -> bool {
- self.code == uvll::EOF
+ **self == uvll::EOF
}
}
#[test]
fn error_smoke_test() {
- let err = uvll::uv_err_t { code: 1, sys_errno_: 1 };
- let err: UvError = UvError(err);
+ let err: UvError = UvError(uvll::EOF);
assert_eq!(err.to_str(), ~"EOF: end of file");
}
-pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError {
- unsafe {
- let loop_ = watcher.event_loop();
- UvError(uvll::last_error(loop_.native_handle()))
- }
-}
-
pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
unsafe {
// Importing error constants
use rt::io::*;
// uv error descriptions are static
- let c_desc = uvll::strerror(&*uverr);
+ let c_desc = uvll::strerror(*uverr);
let desc = str::raw::c_str_to_static_slice(c_desc);
- let kind = match uverr.code {
+ let kind = match *uverr {
UNKNOWN => OtherIoError,
OK => OtherIoError,
EOF => EndOfFile,
ECONNREFUSED => ConnectionRefused,
ECONNRESET => ConnectionReset,
EPIPE => BrokenPipe,
- _ => {
- rtdebug!("uverr.code %u", uverr.code as uint);
+ err => {
+ rtdebug!("uverr.code %d", err as int);
// XXX: Need to map remaining uv error types
OtherIoError
}
}
}
-/// Given a uv handle, convert a callback status to a UvError
-pub fn status_to_maybe_uv_error_with_loop(
- loop_: *uvll::uv_loop_t,
- status: c_int) -> Option<UvError> {
- if status != -1 {
- None
- } else {
- unsafe {
- rtdebug!("loop: %x", loop_ as uint);
- let err = uvll::last_error(loop_);
- Some(UvError(err))
- }
- }
-}
-/// Given a uv handle, convert a callback status to a UvError
-pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
- status: c_int) -> Option<UvError> {
- if status != -1 {
+/// Convert a callback status to a UvError
+pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
+ if status >= 0 {
None
} else {
- unsafe {
- rtdebug!("handle: %x", handle.native_handle() as uint);
- let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
- status_to_maybe_uv_error_with_loop(loop_, status)
- }
+ Some(UvError(status))
}
}
use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback,
status_to_maybe_uv_error};
use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
-use rt::uv::last_uv_error;
use vec;
use str;
use from_str::{FromStr};
rtdebug!("buf len: %d", buf.len as int);
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
- let status = status_to_maybe_uv_error(stream_watcher, nread as c_int);
+ let status = status_to_maybe_uv_error(nread as c_int);
(*cb)(stream_watcher, nread as int, buf, status);
}
}
let mut stream_watcher = write_request.stream();
write_request.delete();
let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
- let status = status_to_maybe_uv_error(stream_watcher, status);
+ let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
};
match result {
0 => Ok(()),
- _ => Err(last_uv_error(self)),
+ _ => Err(UvError(result)),
}
}
}
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
- let status = status_to_maybe_uv_error(stream_watcher, status);
+ let status = status_to_maybe_uv_error(status);
cb(stream_watcher, status);
}
}
rtdebug!("connection_cb");
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
- let status = status_to_maybe_uv_error(stream_watcher, status);
+ let status = status_to_maybe_uv_error(status);
(*cb)(stream_watcher, status);
}
}
};
match result {
0 => Ok(()),
- _ => Err(last_uv_error(self)),
+ _ => Err(UvError(result)),
}
}
}
rtdebug!("buf len: %d", buf.len as int);
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
- let status = status_to_maybe_uv_error(udp_watcher, nread as c_int);
+ let status = status_to_maybe_uv_error(nread as c_int);
let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
(*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
}
let mut udp_watcher = send_request.handle();
send_request.delete();
let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
- let status = status_to_maybe_uv_error(udp_watcher, status);
+ let status = status_to_maybe_uv_error(status);
cb(udp_watcher, status);
}
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use libc;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::uvll;
+
+pub struct Pipe(*uvll::uv_pipe_t);
+
+impl uv::Watcher for Pipe {}
+
+impl Pipe {
+ pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
+ unsafe {
+ let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
+ assert!(handle.is_not_null());
+ let ipc = ipc as libc::c_int;
+ assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
+ let mut ret: Pipe =
+ uv::NativeHandle::from_native_handle(handle);
+ ret.install_watcher_data();
+ ret
+ }
+ }
+
+ pub fn as_stream(&self) -> net::StreamWatcher {
+ net::StreamWatcher(**self as *uvll::uv_stream_t)
+ }
+
+ pub fn close(self, cb: uv::NullCallback) {
+ {
+ let mut this = self;
+ let data = this.get_watcher_data();
+ assert!(data.close_cb.is_none());
+ data.close_cb = Some(cb);
+ }
+
+ unsafe { uvll::close(self.native_handle(), close_cb); }
+
+ extern fn close_cb(handle: *uvll::uv_pipe_t) {
+ let mut process: Pipe = uv::NativeHandle::from_native_handle(handle);
+ process.get_watcher_data().close_cb.take_unwrap()();
+ process.drop_watcher_data();
+ unsafe { uvll::free_handle(handle as *libc::c_void) }
+ }
+ }
+}
+
+impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
+ fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
+ Pipe(handle)
+ }
+ fn native_handle(&self) -> *uvll::uv_pipe_t {
+ match self { &Pipe(ptr) => ptr }
+ }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+use libc;
+use ptr;
+use vec;
+use cell::Cell;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::pipe;
+use rt::uv::uvll;
+
+/// A process wraps the handle of the underlying uv_process_t.
+pub struct Process(*uvll::uv_process_t);
+
+/// This configuration describes how a new process should be spawned. This is
+/// translated to libuv's own configuration
+pub struct Config<'self> {
+ /// Path to the program to run
+ program: &'self str,
+
+ /// Arguments to pass to the program (doesn't include the program itself)
+ args: &'self [~str],
+
+ /// Optional environment to specify for the program. If this is None, then
+ /// it will inherit the current process's environment.
+ env: Option<&'self [(~str, ~str)]>,
+
+ /// Optional working directory for the new process. If this is None, then
+ /// the current directory of the running process is inherited.
+ cwd: Option<&'self str>,
+
+ /// Any number of streams/file descriptors/pipes may be attached to this
+ /// process. This list enumerates the file descriptors and such for the
+ /// process to be spawned, and the file descriptors inherited will start at
+ /// 0 and go to the length of this array.
+ ///
+ /// Standard file descriptors are:
+ ///
+ /// 0 - stdin
+ /// 1 - stdout
+ /// 2 - stderr
+ io: &'self [StdioContainer]
+}
+
+/// Describes what to do with a standard io stream for a child process.
+pub enum StdioContainer {
+ /// This stream will be ignored. This is the equivalent of attaching the
+ /// stream to `/dev/null`
+ Ignored,
+
+ /// The specified file descriptor is inherited for the stream which it is
+ /// specified for.
+ InheritFd(libc::c_int),
+
+ /// The specified libuv stream is inherited for the corresponding file
+ /// descriptor it is assigned to.
+ InheritStream(net::StreamWatcher),
+
+ /// Creates a pipe for the specified file descriptor which will be directed
+ /// into the previously-initialized pipe passed in.
+ ///
+ /// The first boolean argument is whether the pipe is readable, and the
+ /// second is whether it is writable. These properties are from the view of
+ /// the *child* process, not the parent process.
+ CreatePipe(pipe::Pipe, bool /* readable */, bool /* writable */),
+}
+
+impl uv::Watcher for Process {}
+
+impl Process {
+ /// Creates a new process, ready to spawn inside an event loop
+ pub fn new() -> Process {
+ let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
+ assert!(handle.is_not_null());
+ let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
+ ret.install_watcher_data();
+ return ret;
+ }
+
+ /// Spawn a new process inside the specified event loop.
+ ///
+ /// The `config` variable will be passed down to libuv, and the `exit_cb`
+ /// will be run only once, when the process exits.
+ ///
+ /// Returns either the corresponding process object or an error which
+ /// occurred.
+ pub fn spawn(&mut self, loop_: &uv::Loop, config: &Config,
+ exit_cb: uv::ExitCallback) -> Result<(), uv::UvError> {
+ let cwd = config.cwd.map_move(|s| s.to_c_str());
+
+ extern fn on_exit(p: *uvll::uv_process_t,
+ exit_status: libc::c_int,
+ term_signal: libc::c_int) {
+ let mut p: Process = uv::NativeHandle::from_native_handle(p);
+ let err = match exit_status {
+ 0 => None,
+ _ => uv::status_to_maybe_uv_error(-1)
+ };
+ p.get_watcher_data().exit_cb.take_unwrap()(p,
+ exit_status as int,
+ term_signal as int,
+ err);
+ }
+
+ let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(
+ config.io.len());
+ unsafe {
+ vec::raw::set_len(&mut stdio, config.io.len());
+ for (slot, &other) in stdio.iter().zip(config.io.iter()) {
+ set_stdio(slot as *uvll::uv_stdio_container_t, other);
+ }
+ }
+
+ let exit_cb = Cell::new(exit_cb);
+ do with_argv(config.program, config.args) |argv| {
+ do with_env(config.env) |envp| {
+ let options = uvll::uv_process_options_t {
+ exit_cb: on_exit,
+ file: unsafe { *argv },
+ args: argv,
+ env: envp,
+ cwd: match cwd {
+ Some(ref cwd) => cwd.with_ref(|p| p),
+ None => ptr::null(),
+ },
+ flags: 0,
+ stdio_count: stdio.len() as libc::c_int,
+ stdio: stdio.as_imm_buf(|p, _| p),
+ uid: 0,
+ gid: 0,
+ };
+
+ match unsafe {
+ uvll::spawn(loop_.native_handle(), **self, options)
+ } {
+ 0 => {
+ (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
+ Ok(())
+ }
+ err => Err(uv::UvError(err))
+ }
+ }
+ }
+ }
+
+ /// Sends a signal to this process.
+ ///
+ /// This is a wrapper around `uv_process_kill`
+ pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
+ match unsafe {
+ uvll::process_kill(self.native_handle(), signum as libc::c_int)
+ } {
+ 0 => Ok(()),
+ err => Err(uv::UvError(err))
+ }
+ }
+
+ /// Returns the process id of a spawned process
+ pub fn pid(&self) -> libc::pid_t {
+ unsafe { uvll::process_pid(**self) as libc::pid_t }
+ }
+
+ /// Closes this handle, invoking the specified callback once closed
+ pub fn close(self, cb: uv::NullCallback) {
+ {
+ let mut this = self;
+ let data = this.get_watcher_data();
+ assert!(data.close_cb.is_none());
+ data.close_cb = Some(cb);
+ }
+
+ unsafe { uvll::close(self.native_handle(), close_cb); }
+
+ extern fn close_cb(handle: *uvll::uv_process_t) {
+ let mut process: Process = uv::NativeHandle::from_native_handle(handle);
+ process.get_watcher_data().close_cb.take_unwrap()();
+ process.drop_watcher_data();
+ unsafe { uvll::free_handle(handle as *libc::c_void) }
+ }
+ }
+}
+
+unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, io: StdioContainer) {
+ match io {
+ Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); }
+ InheritFd(fd) => {
+ uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
+ uvll::set_stdio_container_fd(dst, fd);
+ }
+ InheritStream(stream) => {
+ uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_STREAM);
+ uvll::set_stdio_container_stream(dst, stream.native_handle());
+ }
+ CreatePipe(pipe, readable, writable) => {
+ let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
+ if readable {
+ flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
+ }
+ if writable {
+ flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
+ }
+ uvll::set_stdio_container_flags(dst, flags);
+ uvll::set_stdio_container_stream(dst,
+ pipe.as_stream().native_handle());
+ }
+ }
+}
+
+/// Converts the program and arguments to the argv array expected by libuv
+fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
+ // First, allocation space to put all the C-strings (we need to have
+ // ownership of them somewhere
+ let mut c_strs = vec::with_capacity(args.len() + 1);
+ c_strs.push(prog.to_c_str());
+ for arg in args.iter() {
+ c_strs.push(arg.to_c_str());
+ }
+
+ // Next, create the char** array
+ let mut c_args = vec::with_capacity(c_strs.len() + 1);
+ for s in c_strs.iter() {
+ c_args.push(s.with_ref(|p| p));
+ }
+ c_args.push(ptr::null());
+ c_args.as_imm_buf(|buf, _| f(buf))
+}
+
+/// Converts the environment to the env array expected by libuv
+fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
+ let env = match env {
+ Some(s) => s,
+ None => { return f(ptr::null()); }
+ };
+ // As with argv, create some temporary storage and then the actual array
+ let mut envp = vec::with_capacity(env.len());
+ for &(ref key, ref value) in env.iter() {
+ envp.push(fmt!("%s=%s", *key, *value).to_c_str());
+ }
+ let mut c_envp = vec::with_capacity(envp.len() + 1);
+ for s in envp.iter() {
+ c_envp.push(s.with_ref(|p| p));
+ }
+ c_envp.push(ptr::null());
+ c_envp.as_imm_buf(|buf, _| f(buf))
+}
+
+impl uv::NativeHandle<*uvll::uv_process_t> for Process {
+ fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
+ Process(handle)
+ }
+ fn native_handle(&self) -> *uvll::uv_process_t {
+ match self { &Process(ptr) => ptr }
+ }
+}
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.timer_cb.get_ref();
- let status = status_to_maybe_uv_error(watcher, status);
+ let status = status_to_maybe_uv_error(status);
(*cb)(watcher, status);
}
}
use cast;
use cell::Cell;
use clone::Clone;
-use libc::{c_int, c_uint, c_void};
+use libc::{c_int, c_uint, c_void, pid_t};
use ops::Drop;
use option::*;
use ptr;
use rt::io::IoError;
use rt::io::net::ip::{SocketAddr, IpAddr};
use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
+use rt::kill::BlockedTask;
use rt::local::Local;
use rt::rtio::*;
use rt::sched::{Scheduler, SchedHandle};
S_IRUSR, S_IWUSR};
use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite};
+use task;
#[cfg(test)] use container::Container;
#[cfg(test)] use unstable::run_in_bare_thread;
// go home
let old_home = Cell::new_empty();
let old_home_ptr = &old_home;
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- // get the old home first
- do task.wake().map_move |mut task| {
- old_home_ptr.put_back(task.take_unwrap_home());
- self.home().send(PinnedTask(task));
- };
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ // get the old home first
+ do task.wake().map_move |mut task| {
+ old_home_ptr.put_back(task.take_unwrap_home());
+ self.home().send(PinnedTask(task));
+ };
+ }
}
// do IO
let a = io(self);
// unhome home
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |scheduler, task| {
- do task.wake().map_move |mut task| {
- task.give_home(old_home.take());
- scheduler.make_handle().send(TaskFromFriend(task));
- };
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |scheduler, task| {
+ do task.wake().map_move |mut task| {
+ task.give_home(old_home.take());
+ scheduler.make_handle().send(TaskFromFriend(task));
+ };
+ }
}
// return the result of the IO
a
}
+
+ fn home_for_io_with_sched<A>(&mut self, io_sched: &fn(&mut Self, ~Scheduler) -> A) -> A {
+ use rt::sched::{PinnedTask, TaskFromFriend};
+
+ do task::unkillable { // FIXME(#8674)
+ // go home
+ let old_home = Cell::new_empty();
+ let old_home_ptr = &old_home;
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ // get the old home first
+ do task.wake().map_move |mut task| {
+ old_home_ptr.put_back(task.take_unwrap_home());
+ self.home().send(PinnedTask(task));
+ };
+ }
+
+ // do IO
+ let scheduler: ~Scheduler = Local::take();
+ let a = io_sched(self, scheduler);
+
+ // unhome home
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |scheduler, task| {
+ do task.wake().map_move |mut task| {
+ task.give_home(old_home.take());
+ scheduler.make_handle().send(TaskFromFriend(task));
+ };
+ }
+
+ // return the result of the IO
+ a
+ }
+ }
}
// get a handle for the current scheduler
macro_rules! get_handle_to_current_scheduler(
- () => (do Local::borrow::<Scheduler, SchedHandle> |sched| { sched.make_handle() })
+ () => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
)
enum SocketNameKind {
};
if r != 0 {
- let status = status_to_maybe_uv_error(handle, r);
+ let status = status_to_maybe_uv_error(r);
return Err(uv_error_to_io_error(status.unwrap()));
}
let mut tube = Tube::new();
let tube_clone = tube.clone();
let remote_cell = Cell::new_empty();
- do Local::borrow::<Scheduler, ()>() |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
let tube_clone = tube_clone.clone();
let tube_clone_cell = Cell::new(tube_clone);
let remote = do sched.event_loop.remote_callback {
let result_cell_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell;
// Block this task and take ownership, switch to scheduler context
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
-
- let mut tcp = TcpWatcher::new(self.uv_loop());
- let task_cell = Cell::new(task);
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
- // Wait for a connection
- do tcp.connect(addr) |stream, status| {
- match status {
- None => {
- let tcp = NativeHandle::from_native_handle(stream.native_handle());
- let home = get_handle_to_current_scheduler!();
- let res = Ok(~UvTcpStream { watcher: tcp, home: home });
+ let mut tcp = TcpWatcher::new(self.uv_loop());
+ let task_cell = Cell::new(task);
- // Store the stream in the task's stack
- unsafe { (*result_cell_ptr).put_back(res); }
+ // Wait for a connection
+ do tcp.connect(addr) |stream, status| {
+ match status {
+ None => {
+ let tcp = NativeHandle::from_native_handle(stream.native_handle());
+ let home = get_handle_to_current_scheduler!();
+ let res = Ok(~UvTcpStream { watcher: tcp, home: home });
- // Context switch
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- Some(_) => {
- let task_cell = Cell::new(task_cell.take());
- do stream.close {
- let res = Err(uv_error_to_io_error(status.unwrap()));
+ // Store the stream in the task's stack
unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
+
+ // Context switch
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
+ Some(_) => {
+ let task_cell = Cell::new(task_cell.take());
+ do stream.close {
+ let res = Err(uv_error_to_io_error(status.unwrap()));
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
}
}
}
Ok(~UvTcpListener::new(watcher, home))
}
Err(uverr) => {
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do watcher.as_stream().close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do watcher.as_stream().close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
+ Err(uv_error_to_io_error(uverr))
}
- Err(uv_error_to_io_error(uverr))
}
}
}
Ok(~UvUdpSocket { watcher: watcher, home: home })
}
Err(uverr) => {
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do watcher.close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do watcher.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
}
+ Err(uv_error_to_io_error(uverr))
}
- Err(uv_error_to_io_error(uverr))
}
}
}
let result_cell_ptr: *Cell<Result<~RtioFileStream,
IoError>> = &result_cell;
let path_cell = Cell::new(path);
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int)
- |req,err| {
- if err.is_none() {
- let loop_ = Loop {handle: req.get_loop().native_handle()};
- let home = get_handle_to_current_scheduler!();
- let fd = file::FileDescriptor(req.get_result());
- let fs = ~UvFileStream::new(
- loop_, fd, true, home) as ~RtioFileStream;
- let res = Ok(fs);
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- } else {
- let res = Err(uv_error_to_io_error(err.unwrap()));
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let path = path_cell.take();
+ do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int)
+ |req,err| {
+ if err.is_none() {
+ let loop_ = Loop {handle: req.get_loop().native_handle()};
+ let home = get_handle_to_current_scheduler!();
+ let fd = file::FileDescriptor(req.get_result());
+ let fs = ~UvFileStream::new(
+ loop_, fd, true, home) as ~RtioFileStream;
+ let res = Ok(fs);
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ } else {
+ let res = Err(uv_error_to_io_error(err.unwrap()));
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ };
};
- };
+ }
assert!(!result_cell.is_empty());
return result_cell.take();
}
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
let path_cell = Cell::new(path);
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- do file::FsRequest::unlink(self.uv_loop(), path) |_, err| {
- let res = match err {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err))
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let path = path_cell.take();
+ do file::FsRequest::unlink(self.uv_loop(), path) |_, err| {
+ let res = match err {
+ None => Ok(()),
+ Some(err) => Err(uv_error_to_io_error(err))
+ };
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
};
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
};
- };
+ }
assert!(!result_cell.is_empty());
return result_cell.take();
}
+
+ fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError> {
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvPipeStream { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
+ }
+
+ fn spawn(&mut self,
+ config: &process::Config) -> Result<~RtioProcessObject, IoError> {
+ // Sadly, we must create the UvProcess before we actually call uv_spawn
+ // so that the exit_cb can close over it and notify it when the process
+ // has exited.
+ let mut ret = ~UvProcess {
+ process: Process::new(),
+ home: None,
+ exit_status: None,
+ term_signal: None,
+ exit_error: None,
+ descheduled: None,
+ };
+ let ret_ptr = unsafe {
+ *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
+ };
+
+ // The purpose of this exit callback is to record the data about the
+ // exit and then wake up the task which may be waiting for the process
+ // to exit. This is all performed in the current io-loop, and the
+ // implementation of UvProcess ensures that reading these fields always
+ // occurs on the current io-loop.
+ let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
+ unsafe {
+ assert!((*ret_ptr).exit_status.is_none());
+ (*ret_ptr).exit_status = Some(exit_status);
+ (*ret_ptr).term_signal = Some(term_signal);
+ (*ret_ptr).exit_error = error;
+ match (*ret_ptr).descheduled.take() {
+ Some(task) => {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task);
+ }
+ None => {}
+ }
+ }
+ };
+
+ match ret.process.spawn(self.uv_loop(), config, exit_cb) {
+ Ok(()) => {
+ // Only now do we actually get a handle to this scheduler.
+ ret.home = Some(get_handle_to_current_scheduler!());
+ Ok(ret)
+ }
+ Err(uverr) => {
+ // We still need to close the process handle we created, but
+ // that's taken care for us in the destructor of UvProcess
+ Err(uv_error_to_io_error(uverr))
+ }
+ }
+ }
}
pub struct UvTcpListener {
fn drop(&self) {
// XXX need mutable finalizer
let self_ = unsafe { transmute::<&UvTcpListener, &mut UvTcpListener>(self) };
- do self_.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
+ do self_.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher().as_stream().close {
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher(), r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher(), r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
}
-pub struct UvTcpStream {
- watcher: TcpWatcher,
- home: SchedHandle,
-}
-
-impl HomingIO for UvTcpStream {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTcpStream {
- fn drop(&self) {
- // XXX need mutable finalizer
- let this = unsafe { transmute::<&UvTcpStream, &mut UvTcpStream>(self) };
- do this.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.watcher.as_stream().close {
- let scheduler = Local::take::<Scheduler>();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
+trait UvStream: HomingIO {
+ fn as_stream(&mut self) -> StreamWatcher;
}
-impl RtioSocket for UvTcpStream {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Tcp, self_.watcher)
- }
- }
-}
-
-impl RtioTcpStream for UvTcpStream {
+// FIXME(#3429) I would rather this be `impl<T: UvStream> RtioStream for T` but
+// that has conflicts with other traits that also have methods
+// called `read` and `write`
+macro_rules! rtiostream(($t:ident) => {
+impl RtioStream for $t {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
- do self.home_for_io |self_| {
+ do self.home_for_io_with_sched |self_, scheduler| {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
let buf_ptr: *&mut [u8] = &buf;
do scheduler.deschedule_running_task_and_then |_sched, task| {
let task_cell = Cell::new(task);
let alloc: AllocCallback = |_| unsafe {
slice_to_uv_buf(*buf_ptr)
};
- let mut watcher = self_.watcher.as_stream();
+ let mut watcher = self_.as_stream();
do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
// Stop reading so that no read callbacks are
unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- do self.home_for_io |self_| {
+ do self.home_for_io_with_sched |self_, scheduler| {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
let buf_ptr: *&[u8] = &buf;
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- let mut watcher = self_.watcher.as_stream();
+ let mut watcher = self_.as_stream();
do watcher.write(buf) |_watcher, status| {
let result = if status.is_none() {
Ok(())
unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
result_cell.take()
}
}
+}
+})
+
+rtiostream!(UvPipeStream)
+rtiostream!(UvTcpStream)
+
+pub struct UvPipeStream {
+ pipe: Pipe,
+ home: SchedHandle,
+}
+
+impl UvStream for UvPipeStream {
+ fn as_stream(&mut self) -> StreamWatcher { self.pipe.as_stream() }
+}
+
+impl HomingIO for UvPipeStream {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvPipeStream {
+ fn drop(&self) {
+ // FIXME(#4330): should not need a transmute
+ let this = unsafe { cast::transmute_mut(self) };
+ do this.home_for_io |self_| {
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.pipe.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+ }
+}
+
+impl UvPipeStream {
+ pub fn uv_pipe(&self) -> Pipe { self.pipe }
+}
+
+pub struct UvTcpStream {
+ watcher: TcpWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvTcpStream {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvTcpStream {
+ fn drop(&self) {
+ // FIXME(#4330): should not need a transmute
+ let this = unsafe { cast::transmute_mut(self) };
+ do this.home_for_io |self_| {
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher.as_stream().close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+ }
+}
+
+impl UvStream for UvTcpStream {
+ fn as_stream(&mut self) -> StreamWatcher { self.watcher.as_stream() }
+}
+
+impl RtioSocket for UvTcpStream {
+ fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
+ do self.home_for_io |self_| {
+ socket_name(Tcp, self_.watcher)
+ }
+ }
+}
+impl RtioTcpStream for UvTcpStream {
fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
do self.home_for_io |self_| {
socket_name(TcpPeer, self_.watcher)
do self.home_for_io |self_| {
let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
do self.home_for_io |self_| {
let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
delay_in_seconds as c_uint)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
fn drop(&self) {
// XXX need mutable finalizer
let this = unsafe { transmute::<&UvUdpSocket, &mut UvUdpSocket>(self) };
- do this.home_for_io |_| {
- let scheduler = Local::take::<Scheduler>();
+ do this.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
- do this.watcher.close {
- let scheduler = Local::take::<Scheduler>();
+ do self_.watcher.close {
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
impl RtioUdpSocket for UvUdpSocket {
fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
- do self.home_for_io |self_| {
+ do self.home_for_io_with_sched |self_, scheduler| {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
let buf_ptr: *&mut [u8] = &buf;
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> {
- do self.home_for_io |self_| {
+ do self.home_for_io_with_sched |self_, scheduler| {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let scheduler = Local::take::<Scheduler>();
let buf_ptr: *&[u8] = &buf;
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
unsafe { (*result_cell_ptr).put_back(result); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(self_.watcher, r) {
+ match status_to_maybe_uv_error(r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
impl Drop for UvTimer {
fn drop(&self) {
let self_ = unsafe { transmute::<&UvTimer, &mut UvTimer>(self) };
- do self_.home_for_io |self_| {
+ do self_.home_for_io_with_sched |self_, scheduler| {
rtdebug!("closing UvTimer");
- let scheduler = Local::take::<Scheduler>();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.close {
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
impl RtioTimer for UvTimer {
fn sleep(&mut self, msecs: u64) {
- do self.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_sched, task| {
rtdebug!("sleep: entered scheduler context");
let task_cell = Cell::new(task);
do self_.watcher.start(msecs, 0) |_, status| {
assert!(status.is_none());
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<int, IoError>> = &result_cell;
let buf_ptr: *&mut [u8] = &buf;
- do self.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
let task_cell = Cell::new(task);
Some(err) => Err(uv_error_to_io_error(err))
};
unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
let buf_ptr: *&[u8] = &buf;
- do self.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
let task_cell = Cell::new(task);
Some(err) => Err(uv_error_to_io_error(err))
};
unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
fn drop(&self) {
let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) };
if self.close_on_drop {
- do self_.home_for_io |self_| {
- let scheduler = Local::take::<Scheduler>();
+ do self_.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.fd.close(&self.loop_) |_,_| {
- let scheduler = Local::take::<Scheduler>();
+ let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
}
}
+pub struct UvProcess {
+ process: process::Process,
+
+ // Sadly, this structure must be created before we return it, so in that
+ // brief interim the `home` is None.
+ home: Option<SchedHandle>,
+
+ // All None until the process exits (exit_error may stay None)
+ priv exit_status: Option<int>,
+ priv term_signal: Option<int>,
+ priv exit_error: Option<UvError>,
+
+ // Used to store which task to wake up from the exit_cb
+ priv descheduled: Option<BlockedTask>,
+}
+
+impl HomingIO for UvProcess {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.home.get_mut_ref() }
+}
+
+impl Drop for UvProcess {
+ fn drop(&self) {
+ // FIXME(#4330): should not need a transmute
+ let this = unsafe { cast::transmute_mut(self) };
+
+ let close = |self_: &mut UvProcess| {
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task = Cell::new(task);
+ do self_.process.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task.take());
+ }
+ }
+ };
+
+ // If home is none, then this process never actually successfully
+ // spawned, so there's no need to switch event loops
+ if this.home.is_none() {
+ close(this)
+ } else {
+ this.home_for_io(close)
+ }
+ }
+}
+
+impl RtioProcess for UvProcess {
+ fn id(&self) -> pid_t {
+ self.process.pid()
+ }
+
+ fn kill(&mut self, signal: int) -> Result<(), IoError> {
+ do self.home_for_io |self_| {
+ match self_.process.kill(signal) {
+ Ok(()) => Ok(()),
+ Err(uverr) => Err(uv_error_to_io_error(uverr))
+ }
+ }
+ }
+
+ fn wait(&mut self) -> int {
+ // Make sure (on the home scheduler) that we have an exit status listed
+ do self.home_for_io |self_| {
+ match self_.exit_status {
+ Some(*) => {}
+ None => {
+ // If there's no exit code previously listed, then the
+ // process's exit callback has yet to be invoked. We just
+ // need to deschedule ourselves and wait to be reawoken.
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ assert!(self_.descheduled.is_none());
+ self_.descheduled = Some(task);
+ }
+ assert!(self_.exit_status.is_some());
+ }
+ }
+ }
+
+ self.exit_status.unwrap()
+ }
+}
+
#[test]
fn test_simple_io_no_connect() {
do run_in_newsched_task {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
let maybe_chan = (*io).tcp_connect(addr);
assert!(maybe_chan.is_err());
fn test_simple_udp_io_bind_only() {
do run_in_newsched_task {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
let maybe_socket = (*io).udp_bind(addr);
assert!(maybe_socket.is_ok());
};
let test_function: ~fn() = || {
- let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let io: *mut IoFactoryObject = unsafe {
+ Local::unsafe_borrow()
+ };
let addr = next_test_ip4();
let maybe_socket = unsafe { (*io).udp_bind(addr) };
// this socket is bound to this event loop
assert!(maybe_socket.is_ok());
// block self on sched1
- let scheduler = Local::take::<Scheduler>();
- do scheduler.deschedule_running_task_and_then |_, task| {
- // unblock task
- do task.wake().map_move |task| {
- // send self to sched2
- tasksFriendHandle.take().send(TaskFromFriend(task));
- };
- // sched1 should now sleep since it has nothing else to do
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ // unblock task
+ do task.wake().map_move |task| {
+ // send self to sched2
+ tasksFriendHandle.take().send(TaskFromFriend(task));
+ };
+ // sched1 should now sleep since it has nothing else to do
+ }
}
// sched2 will wake up and get the task
// as we do nothing else, the function ends and the socket goes out of scope
let chan = Cell::new(chan);
let body1: ~fn() = || {
- let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let io: *mut IoFactoryObject = unsafe {
+ Local::unsafe_borrow()
+ };
let addr = next_test_ip4();
let socket = unsafe { (*io).udp_bind(addr) };
assert!(socket.is_ok());
// Start the server first so it's listening when we connect
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut listener = (*io).tcp_bind(addr).unwrap();
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
}
};
let server_fn: ~fn() = || {
- let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let io: *mut IoFactoryObject = unsafe {
+ Local::unsafe_borrow()
+ };
let mut listener = unsafe { (*io).tcp_bind(server_addr).unwrap() };
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
};
let client_fn: ~fn() = || {
- let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let io: *mut IoFactoryObject = unsafe {
+ Local::unsafe_borrow()
+ };
let mut stream = unsafe { (*io).tcp_connect(client_addr) };
while stream.is_err() {
stream = unsafe { (*io).tcp_connect(client_addr) };
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_socket = (*io).udp_bind(server_addr).unwrap();
let mut buf = [0, .. 2048];
let (nread,src) = server_socket.recvfrom(buf).unwrap();
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_socket = (*io).udp_bind(client_addr).unwrap();
client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
}
let addr = next_test_ip4();
do spawntask {
- let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
+ let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() };
let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() };
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
}
reads += 1;
- let scheduler = Local::take::<Scheduler>();
- // Yield to the other task in hopes that it
- // will trigger a read callback while we are
- // not ready for it
- do scheduler.deschedule_running_task_and_then |sched, task| {
- let task = Cell::new(task);
- sched.enqueue_blocked_task(task.take());
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ // Yield to the other task in hopes that it
+ // will trigger a read callback while we are
+ // not ready for it
+ do scheduler.deschedule_running_task_and_then |sched, task| {
+ let task = Cell::new(task);
+ sched.enqueue_blocked_task(task.take());
+ }
}
}
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut listener = (*io).tcp_bind(addr).unwrap();
let mut stream = listener.accept().unwrap();
let buf = [1, .. 2048];
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
let mut buf = [0, .. 2048];
let mut total_bytes_read = 0;
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client = (*io).udp_bind(client_addr).unwrap();
assert!(client.sendto([1], server_addr).is_ok());
assert!(client.sendto([2], server_addr).is_ok());
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server = (*io).udp_bind(server_addr).unwrap();
let mut buf1 = [0];
let mut buf2 = [0];
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_out = (*io).udp_bind(server_out_addr).unwrap();
let mut server_in = (*io).udp_bind(server_in_addr).unwrap();
let msg = [1, .. 2048];
do spawntask {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_out = (*io).udp_bind(client_out_addr).unwrap();
let mut client_in = (*io).udp_bind(client_in_addr).unwrap();
let mut total_bytes_recv = 0;
fn test_timer_sleep_simple() {
do run_in_newsched_task {
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let timer = (*io).timer_init();
do timer.map_move |mut t| { t.sleep(1) };
}
use path::Path;
use rt::io::{Open, Create, ReadWrite, Read};
unsafe {
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
let write_val = "hello uvio!";
let path = "./tmp/file_test_uvio_full.txt";
{
use str::StrSlice;
unsafe {
use libc::{STDOUT_FILENO};
- let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
{
let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false);
let write_buf = input.as_bytes();
use libc;
use prelude::*;
use ptr;
-use str;
use vec;
-pub static UNKNOWN: c_int = -1;
+pub use self::errors::*;
+
pub static OK: c_int = 0;
-pub static EOF: c_int = 1;
-pub static EADDRINFO: c_int = 2;
-pub static EACCES: c_int = 3;
-pub static ECONNREFUSED: c_int = 12;
-pub static ECONNRESET: c_int = 13;
-pub static EPIPE: c_int = 36;
+pub static EOF: c_int = -4095;
+pub static UNKNOWN: c_int = -4094;
+
+// uv-errno.h redefines error codes for windows, but not for unix...
+
+#[cfg(windows)]
+pub mod errors {
+ use libc::c_int;
-pub struct uv_err_t {
- code: c_int,
- sys_errno_: c_int
+ pub static EACCES: c_int = -4093;
+ pub static ECONNREFUSED: c_int = -4079;
+ pub static ECONNRESET: c_int = -4078;
+ pub static EPIPE: c_int = -4048;
}
+#[cfg(not(windows))]
+pub mod errors {
+ use libc;
+ use libc::c_int;
+
+ pub static EACCES: c_int = -libc::EACCES;
+ pub static ECONNREFUSED: c_int = -libc::ECONNREFUSED;
+ pub static ECONNRESET: c_int = -libc::ECONNRESET;
+ pub static EPIPE: c_int = -libc::EPIPE;
+}
+
+pub static PROCESS_SETUID: c_int = 1 << 0;
+pub static PROCESS_SETGID: c_int = 1 << 1;
+pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
+pub static PROCESS_DETACHED: c_int = 1 << 3;
+pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
+
+pub static STDIO_IGNORE: c_int = 0x00;
+pub static STDIO_CREATE_PIPE: c_int = 0x01;
+pub static STDIO_INHERIT_FD: c_int = 0x02;
+pub static STDIO_INHERIT_STREAM: c_int = 0x04;
+pub static STDIO_READABLE_PIPE: c_int = 0x10;
+pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
pub struct uv_buf_t {
base: *u8,
len: libc::size_t,
}
+pub struct uv_process_options_t {
+ exit_cb: uv_exit_cb,
+ file: *libc::c_char,
+ args: **libc::c_char,
+ env: **libc::c_char,
+ cwd: *libc::c_char,
+ flags: libc::c_uint,
+ stdio_count: libc::c_int,
+ stdio: *uv_stdio_container_t,
+ uid: uv_uid_t,
+ gid: uv_gid_t,
+}
+
+// These fields are private because they must be interfaced with through the
+// functions below.
+pub struct uv_stdio_container_t {
+ priv flags: libc::c_int,
+ priv stream: *uv_stream_t,
+}
+
pub type uv_handle_t = c_void;
pub type uv_loop_t = c_void;
pub type uv_idle_t = c_void;
pub type uv_stream_t = c_void;
pub type uv_fs_t = c_void;
pub type uv_udp_send_t = c_void;
+pub type uv_process_t = c_void;
+pub type uv_pipe_t = c_void;
#[cfg(stage0)]
pub type uv_idle_cb = *u8;
pub type uv_timer_cb = *u8;
#[cfg(stage0)]
pub type uv_write_cb = *u8;
+#[cfg(stage0)]
+pub type uv_exit_cb = *u8;
#[cfg(not(stage0))]
pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
#[cfg(not(stage0))]
pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
status: c_int);
+#[cfg(not(stage0))]
+pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
+ exit_status: c_int,
+ term_signal: c_int);
pub type sockaddr = c_void;
pub type sockaddr_in = c_void;
pub type sockaddr_in6 = c_void;
pub type sockaddr_storage = c_void;
+#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
+#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
+#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
+#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
+
#[deriving(Eq)]
pub enum uv_handle_type {
UV_UNKNOWN_HANDLE,
return rust_uv_read_stop(stream as *c_void);
}
-pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+pub unsafe fn strerror(err: c_int) -> *c_char {
#[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_last_error(loop_handle);
-}
-
-pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
- #[fixed_stack_segment]; #[inline(never)];
-
return rust_uv_strerror(err);
}
-pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+pub unsafe fn err_name(err: c_int) -> *c_char {
#[fixed_stack_segment]; #[inline(never)];
-
return rust_uv_err_name(err);
}
rust_uv_fs_req_cleanup(req);
}
+pub unsafe fn spawn(loop_ptr: *c_void, result: *uv_process_t,
+ options: uv_process_options_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_spawn(loop_ptr, result, options);
+}
+
+pub unsafe fn process_kill(p: *uv_process_t, signum: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_process_kill(p, signum);
+}
+
+pub unsafe fn process_pid(p: *uv_process_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_process_pid(p);
+}
+
+pub unsafe fn set_stdio_container_flags(c: *uv_stdio_container_t,
+ flags: libc::c_int) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_flags(c, flags);
+}
+
+pub unsafe fn set_stdio_container_fd(c: *uv_stdio_container_t,
+ fd: libc::c_int) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_fd(c, fd);
+}
+
+pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
+ stream: *uv_stream_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_stream(c, stream);
+}
+
+pub unsafe fn pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_uv_pipe_init(loop_ptr, p, ipc)
+}
+
// data access helpers
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_get_len_from_buf(buf);
}
-pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
- let err = last_error(uv_loop);
- let err_ptr = ptr::to_unsafe_ptr(&err);
- let err_name = str::raw::from_c_str(err_name(err_ptr));
- let err_msg = str::raw::from_c_str(strerror(err_ptr));
- return fmt!("LIBUV ERROR: name: %s msg: %s",
- err_name, err_msg);
-}
-
-pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data {
- let err = last_error(uv_loop);
- let err_ptr = ptr::to_unsafe_ptr(&err);
- let err_name = str::raw::from_c_str(err_name(err_ptr));
- let err_msg = str::raw::from_c_str(strerror(err_ptr));
- uv_err_data { err_name: err_name, err_msg: err_msg }
-}
pub struct uv_err_data {
err_name: ~str,
cb: uv_async_cb) -> c_int;
fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
- fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t;
- fn rust_uv_strerror(err: *uv_err_t) -> *c_char;
- fn rust_uv_err_name(err: *uv_err_t) -> *c_char;
+ fn rust_uv_strerror(err: c_int) -> *c_char;
+ fn rust_uv_err_name(err: c_int) -> *c_char;
fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in;
fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6;
fn rust_uv_free_ip4_addr(addr: *sockaddr_in);
fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
+ fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
+ options: uv_process_options_t) -> c_int;
+ fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
+ fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
+ fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
+ fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
+ fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
+ stream: *uv_stream_t);
+ fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
}
//! Process spawning.
-#[allow(missing_doc)];
-
-use c_str::ToCStr;
use cast;
-use clone::Clone;
+use cell::Cell;
use comm::{stream, SharedChan, GenericChan, GenericPort};
-use io;
-use libc::{pid_t, c_void, c_int};
+#[cfg(not(windows))]
use libc;
-use option::{Some, None};
-use os;
+use libc::{pid_t, c_int};
use prelude::*;
-use ptr;
use task;
use vec::ImmutableVector;
+use rt::io;
+use rt::local::Local;
+use rt::rtio::{IoFactoryObject, RtioProcessObject, RtioProcess, IoFactory};
+use rt::uv::process;
+
/**
* A value representing a child process.
*
* for the process to terminate.
*/
pub struct Process {
-
/// The unique id of the process (this should never be negative).
priv pid: pid_t,
- /**
- * A handle to the process - on unix this will always be NULL, but on
- * windows it will be a HANDLE to the process, which will prevent the
- * pid being re-used until the handle is closed.
- */
- priv handle: *(),
+ /// The internal handle to the underlying libuv process.
+ priv handle: ~RtioProcessObject,
- /// Some(fd), or None when stdin is being redirected from a fd not created by Process::new.
- priv input: Option<c_int>,
+ /// Some(fd), or None when stdin is being redirected from a fd not created
+ /// by Process::new.
+ priv input: Option<~io::Writer>,
- /// Some(file), or None when stdout is being redirected to a fd not created by Process::new.
- priv output: Option<*libc::FILE>,
+ /// Some(file), or None when stdout is being redirected to a fd not created
+ /// by Process::new.
+ priv output: Option<~io::Reader>,
- /// Some(file), or None when stderr is being redirected to a fd not created by Process::new.
- priv error: Option<*libc::FILE>,
-
- /// None until finish() is called.
- priv exit_code: Option<int>,
+ /// Some(file), or None when stderr is being redirected to a fd not created
+ /// by Process::new.
+ priv error: Option<~io::Reader>,
}
/// Options that can be given when starting a Process.
* If this is None then a new pipe will be created for the new program's
* output and Process.output() will provide a Reader to read from this pipe.
*
- * If this is Some(file-descriptor) then the new process will write its output
- * to the given file descriptor, Process.output_redirected() will return
- * true, and Process.output() will fail.
+ * If this is Some(file-descriptor) then the new process will write its
+ * output to the given file descriptor, Process.output_redirected() will
+ * return true, and Process.output() will fail.
*/
out_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new program's
- * error stream and Process.error() will provide a Reader to read from this pipe.
+ * If this is None then a new pipe will be created for the new progam's
+ * error stream and Process.error() will provide a Reader to read from this
+ * pipe.
*
- * If this is Some(file-descriptor) then the new process will write its error output
- * to the given file descriptor, Process.error_redirected() will return true, and
- * and Process.error() will fail.
+ * If this is Some(file-descriptor) then the new process will write its
+ * error output to the given file descriptor, Process.error_redirected()
+ * will return true, and and Process.error() will fail.
*/
err_fd: Option<c_int>,
}
-impl <'self> ProcessOptions<'self> {
+impl<'self> ProcessOptions<'self> {
/// Return a ProcessOptions that has None in every field.
- pub fn new<'a>() -> ProcessOptions<'a> {
+ pub fn new() -> ProcessOptions {
ProcessOptions {
env: None,
dir: None,
/// The output of a finished process.
pub struct ProcessOutput {
-
/// The status (exit code) of the process.
status: int,
* the working directory and the standard IO streams.
*/
pub fn new(prog: &str, args: &[~str],
- options: ProcessOptions)
- -> Process {
- #[fixed_stack_segment]; #[inline(never)];
-
- let (in_pipe, in_fd) = match options.in_fd {
+ options: ProcessOptions) -> Option<Process> {
+ // First, translate all the stdio options into their libuv equivalents
+ let (uv_stdin, stdin) = match options.in_fd {
+ Some(fd) => (process::InheritFd(fd), None),
None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.input)
- },
- Some(fd) => (None, fd)
+ let p = io::pipe::PipeStream::new().expect("need stdin pipe");
+ (process::CreatePipe(p.uv_pipe(), true, false),
+ Some(~p as ~io::Writer))
+ }
};
- let (out_pipe, out_fd) = match options.out_fd {
+ let (uv_stdout, stdout) = match options.out_fd {
+ Some(fd) => (process::InheritFd(fd), None),
None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.out)
- },
- Some(fd) => (None, fd)
+ let p = io::pipe::PipeStream::new().expect("need stdout pipe");
+ (process::CreatePipe(p.uv_pipe(), false, true),
+ Some(~p as ~io::Reader))
+ }
};
- let (err_pipe, err_fd) = match options.err_fd {
+ let (uv_stderr, stderr) = match options.err_fd {
+ Some(fd) => (process::InheritFd(fd), None),
None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.out)
- },
- Some(fd) => (None, fd)
+ let p = io::pipe::PipeStream::new().expect("need stderr pipe");
+ (process::CreatePipe(p.uv_pipe(), false, true),
+ Some(~p as ~io::Reader))
+ }
};
- let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
- in_fd, out_fd, err_fd);
+ // Next, massage our options into the libuv options
+ let dir = options.dir.map(|d| d.to_str());
+ let dir = dir.map(|d| d.as_slice());
+ let config = process::Config {
+ program: prog,
+ args: args,
+ env: options.env.map(|e| e.as_slice()),
+ cwd: dir,
+ io: [uv_stdin, uv_stdout, uv_stderr],
+ };
+ // Finally, actually spawn the process
unsafe {
- for pipe in in_pipe.iter() { libc::close(pipe.input); }
- for pipe in out_pipe.iter() { libc::close(pipe.out); }
- for pipe in err_pipe.iter() { libc::close(pipe.out); }
- }
-
- Process {
- pid: res.pid,
- handle: res.handle,
- input: in_pipe.map(|pipe| pipe.out),
- output: out_pipe.map(|pipe| os::fdopen(pipe.input)),
- error: err_pipe.map(|pipe| os::fdopen(pipe.input)),
- exit_code: None,
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ match (*io).spawn(&config) {
+ Ok(handle) => {
+ Some(Process {
+ pid: handle.id(),
+ handle: handle,
+ input: stdin,
+ output: stdout,
+ error: stderr,
+ })
+ }
+ Err(*) => { None }
+ }
}
}
/// Returns the unique id of the process
pub fn get_id(&self) -> pid_t { self.pid }
- fn input_fd(&mut self) -> c_int {
- match self.input {
- Some(fd) => fd,
- None => fail!("This Process's stdin was redirected to an \
- existing file descriptor.")
- }
- }
-
- fn output_file(&mut self) -> *libc::FILE {
- match self.output {
- Some(file) => file,
- None => fail!("This Process's stdout was redirected to an \
- existing file descriptor.")
- }
- }
-
- fn error_file(&mut self) -> *libc::FILE {
- match self.error {
- Some(file) => file,
- None => fail!("This Process's stderr was redirected to an \
- existing file descriptor.")
- }
- }
-
/**
- * Returns whether this process is reading its stdin from an existing file
- * descriptor rather than a pipe that was created specifically for this
- * process.
+ * Returns a rt::io::Writer that can be used to write to this Process's
+ * stdin.
*
- * If this method returns true then self.input() will fail.
+ * Fails if this Process's stdin was redirected to an existing file
+ * descriptor.
*/
- pub fn input_redirected(&self) -> bool {
- self.input.is_none()
+ pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
+ let ret: &mut io::Writer = *self.input.get_mut_ref();
+ return ret;
}
/**
- * Returns whether this process is writing its stdout to an existing file
- * descriptor rather than a pipe that was created specifically for this
- * process.
+ * Returns a rt::io::Reader that can be used to read from this Process's
+ * stdout.
*
- * If this method returns true then self.output() will fail.
+ * Fails if this Process's stdout was redirected to an existing file
+ * descriptor.
*/
- pub fn output_redirected(&self) -> bool {
- self.output.is_none()
+ pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
+ let ret: &mut io::Reader = *self.output.get_mut_ref();
+ return ret;
}
/**
- * Returns whether this process is writing its stderr to an existing file
- * descriptor rather than a pipe that was created specifically for this
- * process.
+ * Returns a rt::io::Reader that can be used to read from this Process's
+ * stderr.
*
- * If this method returns true then self.error() will fail.
+ * Fails if this Process's stderr was redirected to an existing file
+ * descriptor.
*/
- pub fn error_redirected(&self) -> bool {
- self.error.is_none()
+ pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
+ let ret: &mut io::Reader = *self.error.get_mut_ref();
+ return ret;
}
/**
- * Returns an io::Writer that can be used to write to this Process's stdin.
+ * Closes the handle to stdin, waits for the child process to terminate, and
+ * returns the exit code.
*
- * Fails if this Process's stdin was redirected to an existing file descriptor.
+ * If the child has already been finished then the exit code is returned.
*/
- pub fn input(&mut self) -> @io::Writer {
- // FIXME: the Writer can still be used after self is destroyed: #2625
- io::fd_writer(self.input_fd(), false)
- }
+ pub fn finish(&mut self) -> int {
+ // We're not going to be giving any more input, so close the input by
+ // destroying it. Also, if the output is desired, then
+ // finish_with_output is called so we discard all the outputs here. Note
+ // that the process may not terminate if we don't destroy stdio because
+ // it'll be waiting in a write which we'll just never read.
+ self.input.take();
+ self.output.take();
+ self.error.take();
- /**
- * Returns an io::Reader that can be used to read from this Process's stdout.
- *
- * Fails if this Process's stdout was redirected to an existing file descriptor.
- */
- pub fn output(&mut self) -> @io::Reader {
- // FIXME: the Reader can still be used after self is destroyed: #2625
- io::FILE_reader(self.output_file(), false)
+ self.handle.wait()
}
/**
- * Returns an io::Reader that can be used to read from this Process's stderr.
+ * Closes the handle to stdin, waits for the child process to terminate,
+ * and reads and returns all remaining output of stdout and stderr, along
+ * with the exit code.
*
- * Fails if this Process's stderr was redirected to an existing file descriptor.
- */
- pub fn error(&mut self) -> @io::Reader {
- // FIXME: the Reader can still be used after self is destroyed: #2625
- io::FILE_reader(self.error_file(), false)
- }
-
- /**
- * Closes the handle to the child process's stdin.
+ * If the child has already been finished then the exit code and any
+ * remaining unread output of stdout and stderr will be returned.
*
- * If this process is reading its stdin from an existing file descriptor, then this
- * method does nothing.
+ * This method will fail if the child process's stdout or stderr streams
+ * were redirected to existing file descriptors, or if this method has
+ * already been called.
*/
- pub fn close_input(&mut self) {
- #[fixed_stack_segment]; #[inline(never)];
- match self.input {
- Some(-1) | None => (),
- Some(fd) => {
- unsafe {
- libc::close(fd);
+ pub fn finish_with_output(&mut self) -> ProcessOutput {
+ // This should probably be a helper method in rt::io
+ fn read_everything(input: &mut io::Reader) -> ~[u8] {
+ let mut result = ~[];
+ let mut buf = [0u8, ..1024];
+ loop {
+ match input.read(buf) {
+ Some(i) => { result = result + buf.slice_to(i) }
+ None => break
}
- self.input = Some(-1);
}
+ return result;
}
- }
-
- fn close_outputs(&mut self) {
- #[fixed_stack_segment]; #[inline(never)];
- fclose_and_null(&mut self.output);
- fclose_and_null(&mut self.error);
-
- fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
- #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
- match *f_opt {
- Some(f) if !f.is_null() => {
- unsafe {
- libc::fclose(f);
- *f_opt = Some(0 as *libc::FILE);
- }
- },
- _ => ()
- }
- }
- }
-
- /**
- * Closes the handle to stdin, waits for the child process to terminate,
- * and returns the exit code.
- *
- * If the child has already been finished then the exit code is returned.
- */
- pub fn finish(&mut self) -> int {
- for &code in self.exit_code.iter() {
- return code;
- }
- self.close_input();
- let code = waitpid(self.pid);
- self.exit_code = Some(code);
- return code;
- }
- /**
- * Closes the handle to stdin, waits for the child process to terminate, and reads
- * and returns all remaining output of stdout and stderr, along with the exit code.
- *
- * If the child has already been finished then the exit code and any remaining
- * unread output of stdout and stderr will be returned.
- *
- * This method will fail if the child process's stdout or stderr streams were
- * redirected to existing file descriptors.
- */
- pub fn finish_with_output(&mut self) -> ProcessOutput {
- let output_file = self.output_file();
- let error_file = self.error_file();
-
- // Spawn two entire schedulers to read both stdout and sterr
- // in parallel so we don't deadlock while blocking on one
- // or the other. FIXME (#2625): Surely there's a much more
- // clever way to do this.
let (p, ch) = stream();
let ch = SharedChan::new(ch);
let ch_clone = ch.clone();
- do task::spawn_sched(task::SingleThreaded) {
- let errput = io::FILE_reader(error_file, false);
- ch.send((2, errput.read_whole_stream()));
+
+ let stderr = Cell::new(self.error.take().unwrap());
+ do task::spawn {
+ let output = read_everything(stderr.take());
+ ch.send((2, output));
}
- do task::spawn_sched(task::SingleThreaded) {
- let output = io::FILE_reader(output_file, false);
- ch_clone.send((1, output.read_whole_stream()));
+ let stdout = Cell::new(self.output.take().unwrap());
+ do task::spawn {
+ let output = read_everything(stdout.take());
+ ch_clone.send((1, output));
}
let status = self.finish();
error: errs};
}
- fn destroy_internal(&mut self, force: bool) {
- // if the process has finished, and therefore had waitpid called,
- // and we kill it, then on unix we might ending up killing a
- // newer process that happens to have the same (re-used) id
- if self.exit_code.is_none() {
- killpid(self.pid, force);
- self.finish();
- }
-
- #[cfg(windows)]
- fn killpid(pid: pid_t, _force: bool) {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- libc::funcs::extra::kernel32::TerminateProcess(
- cast::transmute(pid), 1);
- }
- }
-
- #[cfg(unix)]
- fn killpid(pid: pid_t, force: bool) {
- #[fixed_stack_segment]; #[inline(never)];
-
- let signal = if force {
- libc::consts::os::posix88::SIGKILL
- } else {
- libc::consts::os::posix88::SIGTERM
- };
-
- unsafe {
- libc::funcs::posix88::signal::kill(pid, signal as c_int);
- }
- }
- }
-
/**
* Terminates the process, giving it a chance to clean itself up if
* this is supported by the operating system.
* On Posix OSs SIGTERM will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
- pub fn destroy(&mut self) { self.destroy_internal(false); }
+ pub fn destroy(&mut self) {
+ #[cfg(windows)] fn sigterm() -> int { 15 }
+ #[cfg(not(windows))] fn sigterm() -> int { libc::SIGTERM as int }
+ self.handle.kill(sigterm());
+ self.finish();
+ }
/**
* Terminates the process as soon as possible without giving it a
* On Posix OSs SIGKILL will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
- pub fn force_destroy(&mut self) { self.destroy_internal(true); }
+ pub fn force_destroy(&mut self) {
+ #[cfg(windows)] fn sigkill() -> int { 9 }
+ #[cfg(not(windows))] fn sigkill() -> int { libc::SIGKILL as int }
+ self.handle.kill(sigkill());
+ self.finish();
+ }
}
impl Drop for Process {
fn drop(&self) {
// FIXME(#4330) Need self by value to get mutability.
let mut_self: &mut Process = unsafe { cast::transmute(self) };
-
mut_self.finish();
- mut_self.close_outputs();
- free_handle(self.handle);
- }
-}
-
-struct SpawnProcessResult {
- pid: pid_t,
- handle: *(),
-}
-
-#[cfg(windows)]
-fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<~[(~str, ~str)]>,
- dir: Option<&Path>,
- in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
- #[fixed_stack_segment]; #[inline(never)];
-
- use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
- use libc::consts::os::extra::{
- TRUE, FALSE,
- STARTF_USESTDHANDLES,
- INVALID_HANDLE_VALUE,
- DUPLICATE_SAME_ACCESS
- };
- use libc::funcs::extra::kernel32::{
- GetCurrentProcess,
- DuplicateHandle,
- CloseHandle,
- CreateProcessA
- };
- use libc::funcs::extra::msvcrt::get_osfhandle;
-
- use sys;
-
- unsafe {
-
- let mut si = zeroed_startupinfo();
- si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
- si.dwFlags = STARTF_USESTDHANDLES;
-
- let cur_proc = GetCurrentProcess();
-
- let orig_std_in = get_osfhandle(in_fd) as HANDLE;
- if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
- fail!("failure in get_osfhandle: %s", os::last_os_error());
- }
- if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
- 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
- fail!("failure in DuplicateHandle: %s", os::last_os_error());
- }
-
- let orig_std_out = get_osfhandle(out_fd) as HANDLE;
- if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
- fail!("failure in get_osfhandle: %s", os::last_os_error());
- }
- if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
- 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
- fail!("failure in DuplicateHandle: %s", os::last_os_error());
- }
-
- let orig_std_err = get_osfhandle(err_fd) as HANDLE;
- if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
- fail!("failure in get_osfhandle: %s", os::last_os_error());
- }
- if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
- 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
- fail!("failure in DuplicateHandle: %s", os::last_os_error());
- }
-
- let cmd = make_command_line(prog, args);
- let mut pi = zeroed_process_information();
- let mut create_err = None;
-
- do with_envp(env) |envp| {
- do with_dirp(dir) |dirp| {
- do cmd.with_c_str |cmdp| {
- let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
- ptr::mut_null(), ptr::mut_null(), TRUE,
- 0, envp, dirp, &mut si, &mut pi);
- if created == FALSE {
- create_err = Some(os::last_os_error());
- }
- }
- }
- }
-
- CloseHandle(si.hStdInput);
- CloseHandle(si.hStdOutput);
- CloseHandle(si.hStdError);
-
- for msg in create_err.iter() {
- fail!("failure in CreateProcess: %s", *msg);
- }
-
- // We close the thread handle because we don't care about keeping the thread id valid,
- // and we aren't keeping the thread handle around to be able to close it later. We don't
- // close the process handle however because we want the process id to stay valid at least
- // until the calling code closes the process handle.
- CloseHandle(pi.hThread);
-
- SpawnProcessResult {
- pid: pi.dwProcessId as pid_t,
- handle: pi.hProcess as *()
- }
- }
-}
-
-#[cfg(windows)]
-fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
- libc::types::os::arch::extra::STARTUPINFO {
- cb: 0,
- lpReserved: ptr::mut_null(),
- lpDesktop: ptr::mut_null(),
- lpTitle: ptr::mut_null(),
- dwX: 0,
- dwY: 0,
- dwXSize: 0,
- dwYSize: 0,
- dwXCountChars: 0,
- dwYCountCharts: 0,
- dwFillAttribute: 0,
- dwFlags: 0,
- wShowWindow: 0,
- cbReserved2: 0,
- lpReserved2: ptr::mut_null(),
- hStdInput: ptr::mut_null(),
- hStdOutput: ptr::mut_null(),
- hStdError: ptr::mut_null()
- }
-}
-
-#[cfg(windows)]
-fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
- libc::types::os::arch::extra::PROCESS_INFORMATION {
- hProcess: ptr::mut_null(),
- hThread: ptr::mut_null(),
- dwProcessId: 0,
- dwThreadId: 0
- }
-}
-
-// FIXME: this is only pub so it can be tested (see issue #4536)
-#[cfg(windows)]
-pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
- let mut cmd = ~"";
- append_arg(&mut cmd, prog);
- for arg in args.iter() {
- cmd.push_char(' ');
- append_arg(&mut cmd, *arg);
- }
- return cmd;
-
- fn append_arg(cmd: &mut ~str, arg: &str) {
- let quote = arg.iter().any(|c| c == ' ' || c == '\t');
- if quote {
- cmd.push_char('"');
- }
- for i in range(0u, arg.len()) {
- append_char_at(cmd, arg, i);
- }
- if quote {
- cmd.push_char('"');
- }
- }
-
- fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
- match arg[i] as char {
- '"' => {
- // Escape quotes.
- cmd.push_str("\\\"");
- }
- '\\' => {
- if backslash_run_ends_in_quote(arg, i) {
- // Double all backslashes that are in runs before quotes.
- cmd.push_str("\\\\");
- } else {
- // Pass other backslashes through unescaped.
- cmd.push_char('\\');
- }
- }
- c => {
- cmd.push_char(c);
- }
- }
- }
-
- fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
- while i < s.len() && s[i] as char == '\\' {
- i += 1;
- }
- return i < s.len() && s[i] as char == '"';
- }
-}
-
-#[cfg(unix)]
-fn spawn_process_os(prog: &str, args: &[~str],
- env: Option<~[(~str, ~str)]>,
- dir: Option<&Path>,
- in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
- #[fixed_stack_segment]; #[inline(never)];
-
- use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
- use libc::funcs::bsd44::getdtablesize;
-
- mod rustrt {
- use libc::c_void;
-
- #[abi = "cdecl"]
- extern {
- pub fn rust_unset_sigprocmask();
- pub fn rust_set_environ(envp: *c_void);
- }
- }
-
- unsafe {
-
- let pid = fork();
- if pid < 0 {
- fail!("failure in fork: %s", os::last_os_error());
- } else if pid > 0 {
- return SpawnProcessResult {pid: pid, handle: ptr::null()};
- }
-
- rustrt::rust_unset_sigprocmask();
-
- if dup2(in_fd, 0) == -1 {
- fail!("failure in dup2(in_fd, 0): %s", os::last_os_error());
- }
- if dup2(out_fd, 1) == -1 {
- fail!("failure in dup2(out_fd, 1): %s", os::last_os_error());
- }
- if dup2(err_fd, 2) == -1 {
- fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
- }
- // close all other fds
- for fd in range(3, getdtablesize()).invert() {
- close(fd as c_int);
- }
-
- do with_dirp(dir) |dirp| {
- if !dirp.is_null() && chdir(dirp) == -1 {
- fail!("failure in chdir: %s", os::last_os_error());
- }
- }
-
- do with_envp(env) |envp| {
- if !envp.is_null() {
- rustrt::rust_set_environ(envp);
- }
- do with_argv(prog, args) |argv| {
- execvp(*argv, argv);
- // execvp only returns if an error occurred
- fail!("failure in execvp: %s", os::last_os_error());
- }
- }
- }
-}
-
-#[cfg(unix)]
-fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
- use vec;
-
- // We can't directly convert `str`s into `*char`s, as someone needs to hold
- // a reference to the intermediary byte buffers. So first build an array to
- // hold all the ~[u8] byte strings.
- let mut tmps = vec::with_capacity(args.len() + 1);
-
- tmps.push(prog.to_c_str());
-
- for arg in args.iter() {
- tmps.push(arg.to_c_str());
- }
-
- // Next, convert each of the byte strings into a pointer. This is
- // technically unsafe as the caller could leak these pointers out of our
- // scope.
- let mut ptrs = do tmps.map |tmp| {
- tmp.with_ref(|buf| buf)
- };
-
- // Finally, make sure we add a null pointer.
- ptrs.push(ptr::null());
-
- ptrs.as_imm_buf(|buf, _| cb(buf))
-}
-
-#[cfg(unix)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
- use vec;
-
- // On posixy systems we can pass a char** for envp, which is a
- // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
- // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
- match env {
- Some(env) => {
- let mut tmps = vec::with_capacity(env.len());
-
- for pair in env.iter() {
- // Use of match here is just to workaround limitations
- // in the stage0 irrefutable pattern impl.
- let kv = fmt!("%s=%s", pair.first(), pair.second());
- tmps.push(kv.to_c_str());
- }
-
- // Once again, this is unsafe.
- let mut ptrs = do tmps.map |tmp| {
- tmp.with_ref(|buf| buf)
- };
- ptrs.push(ptr::null());
-
- do ptrs.as_imm_buf |buf, _| {
- unsafe { cb(cast::transmute(buf)) }
- }
- }
- _ => cb(ptr::null())
- }
-}
-
-#[cfg(windows)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
- // On win32 we pass an "environment block" which is not a char**, but
- // rather a concatenation of null-terminated k=v\0 sequences, with a final
- // \0 to terminate.
- match env {
- Some(env) => {
- let mut blk = ~[];
-
- for pair in env.iter() {
- let kv = fmt!("%s=%s", pair.first(), pair.second());
- blk.push_all(kv.as_bytes());
- blk.push(0);
- }
-
- blk.push(0);
-
- do blk.as_imm_buf |p, _len| {
- unsafe { cb(cast::transmute(p)) }
- }
- }
- _ => cb(ptr::mut_null())
- }
-}
-
-fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
- match d {
- Some(dir) => dir.with_c_str(|buf| cb(buf)),
- None => cb(ptr::null())
- }
-}
-
-#[cfg(windows)]
-fn free_handle(handle: *()) {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
}
-#[cfg(unix)]
-fn free_handle(_handle: *()) {
- // unix has no process handle object, just a pid
-}
-
/**
* Spawns a process and waits for it to terminate. The process will
* inherit the current stdin/stdout/stderr file descriptors.
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- });
+ }).unwrap();
prog.finish()
}
* The process's stdout/stderr output and exit code.
*/
pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
- let mut prog = Process::new(prog, args, ProcessOptions::new());
+ let mut prog = Process::new(prog, args, ProcessOptions::new()).unwrap();
prog.finish_with_output()
}
-/**
- * Waits for a process to exit and returns the exit code, failing
- * if there is no process with the specified id.
- *
- * Note that this is private to avoid race conditions on unix where if
- * a user calls waitpid(some_process.get_id()) then some_process.finish()
- * and some_process.destroy() and some_process.finalize() will then either
- * operate on a none-existent process or, even worse, on a newer process
- * with the same id.
- */
-fn waitpid(pid: pid_t) -> int {
- return waitpid_os(pid);
-
- #[cfg(windows)]
- fn waitpid_os(pid: pid_t) -> int {
- #[fixed_stack_segment]; #[inline(never)];
-
- use libc::types::os::arch::extra::DWORD;
- use libc::consts::os::extra::{
- SYNCHRONIZE,
- PROCESS_QUERY_INFORMATION,
- FALSE,
- STILL_ACTIVE,
- INFINITE,
- WAIT_FAILED
- };
- use libc::funcs::extra::kernel32::{
- OpenProcess,
- GetExitCodeProcess,
- CloseHandle,
- WaitForSingleObject
- };
-
- unsafe {
-
- let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
- if proc.is_null() {
- fail!("failure in OpenProcess: %s", os::last_os_error());
- }
-
- loop {
- let mut status = 0;
- if GetExitCodeProcess(proc, &mut status) == FALSE {
- CloseHandle(proc);
- fail!("failure in GetExitCodeProcess: %s", os::last_os_error());
- }
- if status != STILL_ACTIVE {
- CloseHandle(proc);
- return status as int;
- }
- if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
- CloseHandle(proc);
- fail!("failure in WaitForSingleObject: %s", os::last_os_error());
- }
- }
- }
- }
-
- #[cfg(unix)]
- fn waitpid_os(pid: pid_t) -> int {
- #[fixed_stack_segment]; #[inline(never)];
-
- use libc::funcs::posix01::wait::*;
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- fn WIFEXITED(status: i32) -> bool {
- (status & 0xffi32) == 0i32
- }
-
- #[cfg(target_os = "macos")]
- #[cfg(target_os = "freebsd")]
- fn WIFEXITED(status: i32) -> bool {
- (status & 0x7fi32) == 0i32
- }
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- fn WEXITSTATUS(status: i32) -> i32 {
- (status >> 8i32) & 0xffi32
- }
-
- #[cfg(target_os = "macos")]
- #[cfg(target_os = "freebsd")]
- fn WEXITSTATUS(status: i32) -> i32 {
- status >> 8i32
- }
-
- let mut status = 0 as c_int;
- if unsafe { waitpid(pid, &mut status, 0) } == -1 {
- fail!("failure in waitpid: %s", os::last_os_error());
- }
-
- return if WIFEXITED(status) {
- WEXITSTATUS(status) as int
- } else {
- 1
- };
- }
-}
-
#[cfg(test)]
mod tests {
- use io;
- use libc::{c_int, uintptr_t};
- use option::{Option, None, Some};
use os;
use path::Path;
- use run;
+ use prelude::*;
use str;
+ use super::*;
use unstable::running_on_valgrind;
- #[test]
- #[cfg(windows)]
- fn test_make_command_line() {
- assert_eq!(
- run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
- ~"prog aaa bbb ccc"
- );
- assert_eq!(
- run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
- ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
- );
- assert_eq!(
- run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
- ~"\"C:\\Program Files\\test\" aa\\\"bb"
- );
- assert_eq!(
- run::make_command_line("echo", [~"a b c"]),
- ~"echo \"a b c\""
- );
- }
-
#[test]
#[cfg(not(target_os="android"))]
fn test_process_status() {
- assert_eq!(run::process_status("false", []), 1);
- assert_eq!(run::process_status("true", []), 0);
+ assert_eq!(process_status("false", []), 1);
+ assert_eq!(process_status("true", []), 0);
}
#[test]
#[cfg(target_os="android")]
fn test_process_status() {
- assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1);
- assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0);
+ assert_eq!(process_status("/system/bin/sh", [~"-c",~"false"]), 1);
+ assert_eq!(process_status("/system/bin/sh", [~"-c",~"true"]), 0);
}
#[test]
#[cfg(not(target_os="android"))]
fn test_process_output_output() {
- let run::ProcessOutput {status, output, error}
- = run::process_output("echo", [~"hello"]);
+ let ProcessOutput {status, output, error}
+ = process_output("echo", [~"hello"]);
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
#[cfg(target_os="android")]
fn test_process_output_output() {
- let run::ProcessOutput {status, output, error}
- = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]);
+ let ProcessOutput {status, output, error}
+ = process_output("/system/bin/sh", [~"-c",~"echo hello"]);
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
#[cfg(not(target_os="android"))]
fn test_process_output_error() {
- let run::ProcessOutput {status, output, error}
- = run::process_output("mkdir", [~"."]);
+ let ProcessOutput {status, output, error}
+ = process_output("mkdir", [~"."]);
assert_eq!(status, 1);
assert_eq!(output, ~[]);
#[cfg(target_os="android")]
fn test_process_output_error() {
- let run::ProcessOutput {status, output, error}
- = run::process_output("/system/bin/mkdir", [~"."]);
+ let ProcessOutput {status, output, error}
+ = process_output("/system/bin/mkdir", [~"."]);
assert_eq!(status, 255);
assert_eq!(output, ~[]);
assert!(!error.is_empty());
}
- #[test]
- fn test_pipes() {
-
- let pipe_in = os::pipe();
- let pipe_out = os::pipe();
- let pipe_err = os::pipe();
-
- let mut proc = run::Process::new("cat", [], run::ProcessOptions {
- dir: None,
- env: None,
- in_fd: Some(pipe_in.input),
- out_fd: Some(pipe_out.out),
- err_fd: Some(pipe_err.out)
- });
-
- assert!(proc.input_redirected());
- assert!(proc.output_redirected());
- assert!(proc.error_redirected());
-
- os::close(pipe_in.input);
- os::close(pipe_out.out);
- os::close(pipe_err.out);
-
- let expected = ~"test";
- writeclose(pipe_in.out, expected);
- let actual = readclose(pipe_out.input);
- readclose(pipe_err.input);
- proc.finish();
-
- assert_eq!(expected, actual);
- }
-
- fn writeclose(fd: c_int, s: &str) {
- let writer = io::fd_writer(fd, false);
- writer.write_str(s);
- os::close(fd);
- }
-
- fn readclose(fd: c_int) -> ~str {
- #[fixed_stack_segment]; #[inline(never)];
-
- unsafe {
- let file = os::fdopen(fd);
- let reader = io::FILE_reader(file, false);
- let buf = reader.read_whole_stream();
- os::fclose(file);
- str::from_bytes(buf)
- }
- }
-
#[test]
#[cfg(not(target_os="android"))]
fn test_finish_once() {
- let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+ let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(target_os="android")]
fn test_finish_once() {
- let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
- run::ProcessOptions::new());
+ let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
+ ProcessOptions::new()).unwrap();
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(not(target_os="android"))]
fn test_finish_twice() {
- let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
+ let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
assert_eq!(prog.finish(), 1);
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(target_os="android")]
fn test_finish_twice() {
- let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
- run::ProcessOptions::new());
+ let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
+ ProcessOptions::new()).unwrap();
assert_eq!(prog.finish(), 1);
assert_eq!(prog.finish(), 1);
}
#[cfg(not(target_os="android"))]
fn test_finish_with_output_once() {
- let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
- let run::ProcessOutput {status, output, error}
+ let prog = Process::new("echo", [~"hello"], ProcessOptions::new());
+ let mut prog = prog.unwrap();
+ let ProcessOutput {status, output, error}
= prog.finish_with_output();
let output_str = str::from_bytes(output);
#[cfg(target_os="android")]
fn test_finish_with_output_once() {
- let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
- run::ProcessOptions::new());
- let run::ProcessOutput {status, output, error}
- = prog.finish_with_output();
- let output_str = str::from_bytes(output);
-
- assert_eq!(status, 0);
- assert_eq!(output_str.trim().to_owned(), ~"hello");
- // FIXME #7224
- if !running_on_valgrind() {
- assert_eq!(error, ~[]);
- }
- }
-
- #[test]
- #[cfg(not(target_os="android"))]
- fn test_finish_with_output_twice() {
-
- let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
- let run::ProcessOutput {status, output, error}
+ let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+ ProcessOptions::new()).unwrap();
+ let ProcessOutput {status, output, error}
= prog.finish_with_output();
-
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
if !running_on_valgrind() {
assert_eq!(error, ~[]);
}
-
- let run::ProcessOutput {status, output, error}
- = prog.finish_with_output();
-
- assert_eq!(status, 0);
- assert_eq!(output, ~[]);
- // FIXME #7224
- if !running_on_valgrind() {
- assert_eq!(error, ~[]);
- }
- }
- #[test]
- #[cfg(target_os="android")]
- fn test_finish_with_output_twice() {
-
- let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
- run::ProcessOptions::new());
- let run::ProcessOutput {status, output, error}
- = prog.finish_with_output();
-
- let output_str = str::from_bytes(output);
-
- assert_eq!(status, 0);
- assert_eq!(output_str.trim().to_owned(), ~"hello");
- // FIXME #7224
- if !running_on_valgrind() {
- assert_eq!(error, ~[]);
- }
-
- let run::ProcessOutput {status, output, error}
- = prog.finish_with_output();
-
- assert_eq!(status, 0);
- assert_eq!(output, ~[]);
- // FIXME #7224
- if !running_on_valgrind() {
- assert_eq!(error, ~[]);
- }
}
#[test]
#[should_fail]
#[cfg(not(windows),not(target_os="android"))]
fn test_finish_with_output_redirected() {
- let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions {
+ let mut prog = Process::new("echo", [~"hello"], ProcessOptions {
env: None,
dir: None,
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- });
- // this should fail because it is not valid to read the output when it was redirected
+ }).unwrap();
+ // this should fail because it is not valid to read the output when it
+ // was redirected
prog.finish_with_output();
}
#[test]
#[should_fail]
#[cfg(not(windows),target_os="android")]
fn test_finish_with_output_redirected() {
- let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
- run::ProcessOptions {
+ let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+ ProcessOptions {
env: None,
dir: None,
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- });
- // this should fail because it is not valid to read the output when it was redirected
+ }).unwrap();
+ // this should fail because it is not valid to read the output when it
+ // was redirected
prog.finish_with_output();
}
#[cfg(unix,not(target_os="android"))]
- fn run_pwd(dir: Option<&Path>) -> run::Process {
- run::Process::new("pwd", [], run::ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> Process {
+ Process::new("pwd", [], ProcessOptions {
dir: dir,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[cfg(unix,target_os="android")]
- fn run_pwd(dir: Option<&Path>) -> run::Process {
- run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> Process {
+ Process::new("/system/bin/sh", [~"-c",~"pwd"], ProcessOptions {
dir: dir,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[cfg(windows)]
- fn run_pwd(dir: Option<&Path>) -> run::Process {
- run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> Process {
+ Process::new("cmd", [~"/c", ~"cd"], ProcessOptions {
dir: dir,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[test]
}
#[cfg(unix,not(target_os="android"))]
- fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
- run::Process::new("env", [], run::ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+ Process::new("env", [], ProcessOptions {
env: env,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[cfg(unix,target_os="android")]
- fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
- run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+ Process::new("/system/bin/sh", [~"-c",~"set"], ProcessOptions {
env: env,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[cfg(windows)]
- fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
- run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
+ Process::new("cmd", [~"/c", ~"set"], ProcessOptions {
env: env,
- .. run::ProcessOptions::new()
- })
+ .. ProcessOptions::new()
+ }).unwrap()
}
#[test]
#[test]
fn test_add_to_env() {
-
let mut new_env = os::env();
new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
do (|| {
let c = Cell::new(c.take());
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let task_handles = task.make_selectable(ports.len());
pub mod io;
pub mod hash;
pub mod container;
-
+pub mod default;
/* Common data structures */
use container::{Container, Mutable};
use iter::Times;
use iterator::{Iterator, FromIterator, Extendable};
-use iterator::{Filter, AdditiveIterator, Map, Enumerate};
+use iterator::{Filter, AdditiveIterator, Map};
use iterator::{Invert, DoubleEndedIterator};
use libc;
-use num::{Saturating, Zero};
+use num::{Saturating};
use option::{None, Option, Some};
use ptr;
use ptr::RawPtr;
use unstable::raw::{Repr, Slice};
use vec;
use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
+use default::Default;
/*
Section: Conditions
pub fn from_bytes(vv: &[u8]) -> ~str {
use str::not_utf8::cond;
- if !is_utf8(vv) {
- let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap();
- cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
- first_bad_byte as uint))
+ match from_bytes_opt(vv) {
+ None => {
+ let first_bad_byte = *vv.iter().find(|&b| !is_utf8([*b])).unwrap();
+ cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
+ first_bad_byte as uint))
+ }
+ Some(s) => s
+ }
+}
+
+/// Convert a vector of bytes to a new UTF-8 string, if possible.
+/// Returns None if the vector contains invalid UTF-8.
+pub fn from_bytes_opt(vv: &[u8]) -> Option<~str> {
+ if is_utf8(vv) {
+ Some(unsafe { raw::from_bytes(vv) })
} else {
- return unsafe { raw::from_bytes(vv) }
+ None
}
}
cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u",
first_bad_byte as uint))
} else {
- return unsafe { raw::from_bytes_owned(vv) }
+ unsafe { raw::from_bytes_owned(vv) }
+ }
+}
+
+/// Consumes a vector of bytes to create a new utf-8 string.
+/// Returns None if the vector contains invalid UTF-8.
+pub fn from_bytes_owned_opt(vv: ~[u8]) -> Option<~str> {
+ if is_utf8(vv) {
+ Some(unsafe { raw::from_bytes_owned(vv) })
+ } else {
+ None
}
}
///
/// Fails if invalid UTF-8
pub fn from_bytes_slice<'a>(v: &'a [u8]) -> &'a str {
- assert!(is_utf8(v));
- unsafe { cast::transmute(v) }
+ from_bytes_slice_opt(v).expect("from_bytes_slice: not utf-8")
+}
+
+/// Converts a vector to a string slice without performing any allocations.
+///
+/// Returns None if the slice is not utf-8.
+pub fn from_bytes_slice_opt<'a>(v: &'a [u8]) -> Option<&'a str> {
+ if is_utf8(v) {
+ Some(unsafe { cast::transmute(v) })
+ } else { None }
}
impl ToStr for ~str {
/// Use with the `std::iterator` module.
pub type ByteRevIterator<'self> = Invert<ByteIterator<'self>>;
-/// An iterator over byte index and either &u8 or char
-#[deriving(Clone)]
-enum OffsetIterator<'self> {
- // use ByteIterator here when it can be cloned
- ByteOffset(Enumerate<vec::VecIterator<'self, u8>>),
- CharOffset(CharOffsetIterator<'self>),
-}
-
/// An iterator over the substrings of a string, separated by `sep`.
#[deriving(Clone)]
-pub struct CharSplitIterator<'self,Sep> {
- priv iter: OffsetIterator<'self>,
+pub struct CharSplitIterator<'self, Sep> {
+ /// The slice remaining to be iterated
priv string: &'self str,
- priv position: uint,
priv sep: Sep,
- /// The number of splits remaining
- priv count: uint,
/// Whether an empty string at the end is allowed
priv allow_trailing_empty: bool,
+ priv only_ascii: bool,
priv finished: bool,
}
+/// An iterator over the substrings of a string, separated by `sep`,
+/// starting from the back of the string.
+pub type CharRSplitIterator<'self, Sep> = Invert<CharSplitIterator<'self, Sep>>;
+
+/// An iterator over the substrings of a string, separated by `sep`,
+/// splitting at most `count` times.
+#[deriving(Clone)]
+pub struct CharSplitNIterator<'self, Sep> {
+ priv iter: CharSplitIterator<'self, Sep>,
+ /// The number of splits remaining
+ priv count: uint,
+ priv invert: bool,
+}
+
/// An iterator over the words of a string, separated by an sequence of whitespace
pub type WordIterator<'self> =
Filter<'self, &'self str, CharSplitIterator<'self, extern "Rust" fn(char) -> bool>>;
pub type AnyLineIterator<'self> =
Map<'self, &'self str, &'self str, CharSplitIterator<'self, char>>;
+impl<'self, Sep> CharSplitIterator<'self, Sep> {
+ #[inline]
+ fn get_end(&mut self) -> Option<&'self str> {
+ if !self.finished && (self.allow_trailing_empty || self.string.len() > 0) {
+ self.finished = true;
+ Some(self.string)
+ } else {
+ None
+ }
+ }
+}
+
impl<'self, Sep: CharEq> Iterator<&'self str> for CharSplitIterator<'self, Sep> {
#[inline]
fn next(&mut self) -> Option<&'self str> {
if self.finished { return None }
- let start = self.position;
- let len = self.string.len();
+ let mut next_split = None;
+ if self.only_ascii {
+ for (idx, byte) in self.string.byte_iter().enumerate() {
+ if self.sep.matches(byte as char) && byte < 128u8 {
+ next_split = Some((idx, idx + 1));
+ break;
+ }
+ }
+ } else {
+ for (idx, ch) in self.string.char_offset_iter() {
+ if self.sep.matches(ch) {
+ next_split = Some((idx, self.string.char_range_at(idx).next));
+ break;
+ }
+ }
+ }
+ match next_split {
+ Some((a, b)) => unsafe {
+ let elt = raw::slice_unchecked(self.string, 0, a);
+ self.string = raw::slice_unchecked(self.string, b, self.string.len());
+ Some(elt)
+ },
+ None => self.get_end(),
+ }
+ }
+}
- if self.count > 0 {
- match self.iter {
- // this gives a *huge* speed up for splitting on ASCII
- // characters (e.g. '\n' or ' ')
- ByteOffset(ref mut iter) =>
- for (idx, &byte) in *iter {
- if self.sep.matches(byte as char) {
- self.position = idx + 1;
- self.count -= 1;
- return Some(unsafe {
- raw::slice_bytes(self.string, start, idx)
- })
- }
- },
- CharOffset(ref mut iter) =>
- for (idx, ch) in *iter {
- if self.sep.matches(ch) {
- // skip over the separator
- self.position = self.string.char_range_at(idx).next;
- self.count -= 1;
- return Some(unsafe {
- raw::slice_bytes(self.string, start, idx)
- })
- }
- },
+impl<'self, Sep: CharEq> DoubleEndedIterator<&'self str>
+for CharSplitIterator<'self, Sep> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'self str> {
+ if self.finished { return None }
+
+ if !self.allow_trailing_empty {
+ self.allow_trailing_empty = true;
+ match self.next_back() {
+ Some(elt) if !elt.is_empty() => return Some(elt),
+ _ => if self.finished { return None }
+ }
+ }
+ let len = self.string.len();
+ let mut next_split = None;
+
+ if self.only_ascii {
+ for (j, byte) in self.string.byte_rev_iter().enumerate() {
+ if self.sep.matches(byte as char) && byte < 128u8 {
+ let idx = len - j - 1;
+ next_split = Some((idx, idx + 1));
+ break;
+ }
+ }
+ } else {
+ for (idx, ch) in self.string.char_offset_rev_iter() {
+ if self.sep.matches(ch) {
+ next_split = Some((idx, self.string.char_range_at(idx).next));
+ break;
+ }
}
}
- self.finished = true;
- if self.allow_trailing_empty || start < len {
- Some(unsafe { raw::slice_bytes(self.string, start, len) })
+ match next_split {
+ Some((a, b)) => unsafe {
+ let elt = raw::slice_unchecked(self.string, b, len);
+ self.string = raw::slice_unchecked(self.string, 0, a);
+ Some(elt)
+ },
+ None => { self.finished = true; Some(self.string) }
+ }
+ }
+}
+
+impl<'self, Sep: CharEq> Iterator<&'self str> for CharSplitNIterator<'self, Sep> {
+ #[inline]
+ fn next(&mut self) -> Option<&'self str> {
+ if self.count != 0 {
+ self.count -= 1;
+ if self.invert { self.iter.next_back() } else { self.iter.next() }
} else {
- None
+ self.iter.get_end()
}
}
}
pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
do s.as_imm_buf |sbuf, _n| {
cast::transmute(Slice {
- data: sbuf.offset_inbounds(begin as int),
+ data: sbuf.offset(begin as int),
len: end - begin,
})
}
fn char_offset_iter(&self) -> CharOffsetIterator<'self>;
fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self>;
fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
- fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitIterator<'self, Sep>;
- fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
- -> CharSplitIterator<'self, Sep>;
+ fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
+ fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
+ fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep>;
+ fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self>;
fn split_str_iter(&self, &'self str) -> StrSplitIterator<'self>;
fn line_iter(&self) -> CharSplitIterator<'self, char>;
/// ~~~
#[inline]
fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep> {
- self.split_options_iter(sep, self.len(), true)
+ CharSplitIterator {
+ string: *self,
+ only_ascii: sep.only_ascii(),
+ sep: sep,
+ allow_trailing_empty: true,
+ finished: false,
+ }
}
/// An iterator over substrings of `self`, separated by characters
/// matched by `sep`, restricted to splitting at most `count`
/// times.
#[inline]
- fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitIterator<'self, Sep> {
- self.split_options_iter(sep, count, true)
+ fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+ -> CharSplitNIterator<'self, Sep> {
+ CharSplitNIterator {
+ iter: self.split_iter(sep),
+ count: count,
+ invert: false,
+ }
}
/// An iterator over substrings of `self`, separated by characters
- /// matched by `sep`, splitting at most `count` times, and
- /// possibly not including the trailing empty substring, if it
- /// exists.
+ /// matched by `sep`.
+ ///
+ /// Equivalent to `split_iter`, except that the trailing substring
+ /// is skipped if empty (terminator semantics).
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let v: ~[&str] = "A.B.".split_terminator_iter('.').collect();
+ /// assert_eq!(v, ~["A", "B"]);
+ /// ~~~
#[inline]
- fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
+ fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
-> CharSplitIterator<'self, Sep> {
- let iter = if sep.only_ascii() {
- ByteOffset(self.as_bytes().iter().enumerate())
- } else {
- CharOffset(self.char_offset_iter())
- };
CharSplitIterator {
- iter: iter,
- string: *self,
- position: 0,
- sep: sep,
+ allow_trailing_empty: false,
+ ..self.split_iter(sep)
+ }
+ }
+
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by `sep`, in reverse order
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let v: ~[&str] = "Mary had a little lamb".rsplit_iter(' ').collect();
+ /// assert_eq!(v, ~["lamb", "little", "a", "had", "Mary"]);
+ /// ~~~
+ #[inline]
+ fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep> {
+ self.split_iter(sep).invert()
+ }
+
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by `sep`, starting from the end of the string.
+ /// Restricted to splitting at most `count` times.
+ #[inline]
+ fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+ -> CharSplitNIterator<'self, Sep> {
+ CharSplitNIterator {
+ iter: self.split_iter(sep),
count: count,
- allow_trailing_empty: allow_trailing_empty,
- finished: false,
+ invert: true,
}
}
+
+
/// An iterator over the start and end indices of each match of
/// `sep` within `self`.
#[inline]
/// by `\n`).
#[inline]
fn line_iter(&self) -> CharSplitIterator<'self, char> {
- self.split_options_iter('\n', self.len(), false)
+ self.split_terminator_iter('\n')
}
/// An iterator over the lines of a string, separated by either
fn reserve(&mut self, n: uint);
fn reserve_at_least(&mut self, n: uint);
fn capacity(&self) -> uint;
+ fn truncate(&mut self, len: uint);
+ fn into_bytes(self) -> ~[u8];
/// Work with the mutable byte buffer and length of a slice.
///
}
}
+ /// Shorten a string to the specified length (which must be <= the current length)
+ #[inline]
+ fn truncate(&mut self, len: uint) {
+ assert!(len <= self.len());
+ assert!(self.is_char_boundary(len));
+ unsafe { raw::set_len(self, len); }
+ }
+
+ /// Consumes the string, returning the underlying byte buffer.
+ ///
+ /// The buffer does not have a null terminator.
+ #[inline]
+ fn into_bytes(self) -> ~[u8] {
+ unsafe { cast::transmute(self) }
+ }
+
#[inline]
fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
let v: &mut ~[u8] = unsafe { cast::transmute(self) };
}
// This works because every lifetime is a sub-lifetime of 'static
-impl<'self> Zero for &'self str {
- fn zero() -> &'self str { "" }
- fn is_zero(&self) -> bool { self.is_empty() }
+impl<'self> Default for &'self str {
+ fn default() -> &'self str { "" }
}
-impl Zero for ~str {
- fn zero() -> ~str { ~"" }
- fn is_zero(&self) -> bool { self.len() == 0 }
+impl Default for ~str {
+ fn default() -> ~str { ~"" }
}
-impl Zero for @str {
- fn zero() -> @str { @"" }
- fn is_zero(&self) -> bool { self.len() == 0 }
+impl Default for @str {
+ fn default() -> @str { @"" }
}
#[cfg(test)]
mod tests {
use container::Container;
- use option::Some;
+ use option::{None, Some};
use libc::c_char;
use libc;
use ptr;
use str::*;
use vec;
- use vec::{ImmutableVector, CopyableVector};
+ use vec::{Vector, ImmutableVector, CopyableVector};
use cmp::{TotalOrd, Less, Equal, Greater};
#[test]
assert_eq!("华", data.as_slice());
}
+ #[test]
+ fn test_into_bytes() {
+ let data = ~"asdf";
+ let buf = data.into_bytes();
+ assert_eq!(bytes!("asdf"), buf.as_slice());
+ }
+
#[test]
fn test_find_str() {
// byte positions
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
let split: ~[&str] = data.split_iter(' ').collect();
- assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!( split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut rsplit: ~[&str] = data.rsplit_iter(' ').collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
let split: ~[&str] = data.split_iter(|c: char| c == ' ').collect();
- assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+ assert_eq!( split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut rsplit: ~[&str] = data.rsplit_iter(|c: char| c == ' ').collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
// Unicode
let split: ~[&str] = data.split_iter('ä').collect();
- assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!( split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut rsplit: ~[&str] = data.rsplit_iter('ä').collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
let split: ~[&str] = data.split_iter(|c: char| c == 'ä').collect();
- assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+ assert_eq!( split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut rsplit: ~[&str] = data.rsplit_iter(|c: char| c == 'ä').collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
}
#[test]
assert_eq!(split, ~["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
}
+ #[test]
+ fn test_rsplitn_char_iterator() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let mut split: ~[&str] = data.rsplitn_iter(' ', 3).collect();
+ split.reverse();
+ assert_eq!(split, ~["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut split: ~[&str] = data.rsplitn_iter(|c: char| c == ' ', 3).collect();
+ split.reverse();
+ assert_eq!(split, ~["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ // Unicode
+ let mut split: ~[&str] = data.rsplitn_iter('ä', 3).collect();
+ split.reverse();
+ assert_eq!(split, ~["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut split: ~[&str] = data.rsplitn_iter(|c: char| c == 'ä', 3).collect();
+ split.reverse();
+ assert_eq!(split, ~["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+ }
+
#[test]
fn test_split_char_iterator_no_trailing() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
- let split: ~[&str] = data.split_options_iter('\n', 1000, true).collect();
+ let split: ~[&str] = data.split_iter('\n').collect();
+ assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]);
+
+ let split: ~[&str] = data.split_terminator_iter('\n').collect();
+ assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]);
+ }
+
+ #[test]
+ fn test_rev_split_char_iterator_no_trailing() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let mut split: ~[&str] = data.split_iter('\n').invert().collect();
+ split.reverse();
assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]);
- let split: ~[&str] = data.split_options_iter('\n', 1000, false).collect();
+ let mut split: ~[&str] = data.split_terminator_iter('\n').invert().collect();
+ split.reverse();
assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]);
}
}
#[test]
- fn test_str_zero() {
- use num::Zero;
- fn t<S: Zero + Str>() {
- let s: S = Zero::zero();
+ fn test_str_default() {
+ use default::Default;
+ fn t<S: Default + Str>() {
+ let s: S = Default::default();
assert_eq!(s.as_slice(), "");
- assert!(s.is_zero());
}
t::<&str>();
assert_eq!(5, sum_len([~"01", ~"2", ~"34", ~""]));
assert_eq!(5, sum_len([s.as_slice()]));
}
+
+ #[test]
+ fn test_str_truncate() {
+ let mut s = ~"12345";
+ s.truncate(5);
+ assert_eq!(s.as_slice(), "12345");
+ s.truncate(3);
+ assert_eq!(s.as_slice(), "123");
+ s.truncate(0);
+ assert_eq!(s.as_slice(), "");
+
+ let mut s = ~"12345";
+ let p = s.as_imm_buf(|p,_| p);
+ s.truncate(3);
+ s.push_str("6");
+ let p_ = s.as_imm_buf(|p,_| p);
+ assert_eq!(p_, p);
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_str_truncate_invalid_len() {
+ let mut s = ~"12345";
+ s.truncate(6);
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_str_truncate_split_codepoint() {
+ let mut s = ~"\u00FC"; // ü
+ s.truncate(1);
+ }
+
+ #[test]
+ fn test_str_from_bytes_slice() {
+ let xs = bytes!("hello");
+ assert_eq!(from_bytes_slice(xs), "hello");
+
+ let xs = bytes!("ศไทย中华Việt Nam");
+ assert_eq!(from_bytes_slice(xs), "ศไทย中华Việt Nam");
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_str_from_bytes_slice_invalid() {
+ let xs = bytes!("hello", 0xff);
+ let _ = from_bytes_slice(xs);
+ }
+
+ #[test]
+ fn test_str_from_bytes_slice_opt() {
+ let xs = bytes!("hello");
+ assert_eq!(from_bytes_slice_opt(xs), Some("hello"));
+
+ let xs = bytes!("ศไทย中华Việt Nam");
+ assert_eq!(from_bytes_slice_opt(xs), Some("ศไทย中华Việt Nam"));
+
+ let xs = bytes!("hello", 0xff);
+ assert_eq!(from_bytes_slice_opt(xs), None);
+ }
+
+ #[test]
+ fn test_str_from_bytes() {
+ let xs = bytes!("hello");
+ assert_eq!(from_bytes(xs), ~"hello");
+
+ let xs = bytes!("ศไทย中华Việt Nam");
+ assert_eq!(from_bytes(xs), ~"ศไทย中华Việt Nam");
+ }
+
+ #[test]
+ fn test_str_from_bytes_opt() {
+ let xs = bytes!("hello").to_owned();
+ assert_eq!(from_bytes_opt(xs), Some(~"hello"));
+
+ let xs = bytes!("ศไทย中华Việt Nam");
+ assert_eq!(from_bytes_opt(xs), Some(~"ศไทย中华Việt Nam"));
+
+ let xs = bytes!("hello", 0xff);
+ assert_eq!(from_bytes_opt(xs), None);
+ }
+
+ #[test]
+ fn test_str_from_bytes_owned() {
+ let xs = bytes!("hello").to_owned();
+ assert_eq!(from_bytes_owned(xs), ~"hello");
+
+ let xs = bytes!("ศไทย中华Việt Nam").to_owned();
+ assert_eq!(from_bytes_owned(xs), ~"ศไทย中华Việt Nam");
+ }
+
+ #[test]
+ fn test_str_from_bytes_owned_opt() {
+ let xs = bytes!("hello").to_owned();
+ assert_eq!(from_bytes_owned_opt(xs), Some(~"hello"));
+
+ let xs = bytes!("ศไทย中华Việt Nam").to_owned();
+ assert_eq!(from_bytes_owned_opt(xs), Some(~"ศไทย中华Việt Nam"));
+
+ let xs = bytes!("hello", 0xff).to_owned();
+ assert_eq!(from_bytes_owned_opt(xs), None);
+ }
}
#[cfg(test)]
}
}
+ #[bench]
+ fn split_iter_unicode_ascii(bh: &mut BenchHarness) {
+ let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
+
+ do bh.iter {
+ assert_eq!(s.split_iter('V').len(), 3);
+ }
+ }
+
+ #[bench]
+ fn split_iter_unicode_not_ascii(bh: &mut BenchHarness) {
+ struct NotAscii(char);
+ impl CharEq for NotAscii {
+ fn matches(&self, c: char) -> bool {
+ **self == c
+ }
+ fn only_ascii(&self) -> bool { false }
+ }
+ let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
+
+ do bh.iter {
+ assert_eq!(s.split_iter(NotAscii('V')).len(), 3);
+ }
+ }
+
+
+ #[bench]
+ fn split_iter_ascii(bh: &mut BenchHarness) {
+ let s = "Mary had a little lamb, Little lamb, little-lamb.";
+ let len = s.split_iter(' ').len();
+
+ do bh.iter {
+ assert_eq!(s.split_iter(' ').len(), len);
+ }
+ }
+
+ #[bench]
+ fn split_iter_not_ascii(bh: &mut BenchHarness) {
+ struct NotAscii(char);
+ impl CharEq for NotAscii {
+ #[inline]
+ fn matches(&self, c: char) -> bool { **self == c }
+ fn only_ascii(&self) -> bool { false }
+ }
+ let s = "Mary had a little lamb, Little lamb, little-lamb.";
+ let len = s.split_iter(' ').len();
+
+ do bh.iter {
+ assert_eq!(s.split_iter(NotAscii(' ')).len(), len);
+ }
+ }
+
+ #[bench]
+ fn split_iter_extern_fn(bh: &mut BenchHarness) {
+ let s = "Mary had a little lamb, Little lamb, little-lamb.";
+ let len = s.split_iter(' ').len();
+ fn pred(c: char) -> bool { c == ' ' }
+
+ do bh.iter {
+ assert_eq!(s.split_iter(pred).len(), len);
+ }
+ }
+
+ #[bench]
+ fn split_iter_closure(bh: &mut BenchHarness) {
+ let s = "Mary had a little lamb, Little lamb, little-lamb.";
+ let len = s.split_iter(' ').len();
+
+ do bh.iter {
+ assert_eq!(s.split_iter(|c: char| c == ' ').len(), len);
+ }
+ }
+
+ #[bench]
+ fn split_iter_slice(bh: &mut BenchHarness) {
+ let s = "Mary had a little lamb, Little lamb, little-lamb.";
+ let len = s.split_iter(' ').len();
+
+ do bh.iter {
+ assert_eq!(s.split_iter(&[' ']).len(), len);
+ }
+ }
+
#[bench]
fn is_utf8_100_ascii(bh: &mut BenchHarness) {
if in_green_task_context() {
// XXX: Logging doesn't work here - the check to call the log
// function never passes - so calling the log function directly.
- do Local::borrow::<Task, ()> |task| {
+ do Local::borrow |task: &mut Task| {
let msg = match task.name {
Some(ref name) =>
fmt!("task '%s' failed at '%s', %s:%i",
msg, file, line as int);
}
- let task = Local::unsafe_borrow::<Task>();
+ let task: *mut Task = Local::unsafe_borrow();
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[allow(missing_doc)];
-
-use cast;
-use libc;
-use local_data;
-use prelude::*;
-use ptr;
-use unstable::raw;
-use util;
-
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
- NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
- pub fn new() -> Handle {
- use rt::local::Local;
- unsafe {
- let task = Local::unsafe_borrow::<Task>();
- NewHandle(&mut (*task).storage)
- }
- }
-}
-
-#[deriving(Eq)]
-enum LoanState {
- NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
- fn describe(&self) -> &'static str {
- match *self {
- NoLoan => "no loan",
- ImmLoan => "immutable",
- MutLoan => "mutable"
- }
- }
-}
-
-trait LocalData {}
-impl<T: 'static> LocalData for T {}
-
-// The task-local-map stores all TLS information for the currently running task.
-// It is stored as an owned pointer into the runtime, and it's only allocated
-// when TLS is used for the first time. This map must be very carefully
-// constructed because it has many mutable loans unsoundly handed out on it to
-// the various invocations of TLS requests.
-//
-// One of the most important operations is loaning a value via `get` to a
-// caller. In doing so, the slot that the TLS entry is occupying cannot be
-// invalidated because upon returning it's loan state must be updated. Currently
-// the TLS map is a vector, but this is possibly dangerous because the vector
-// can be reallocated/moved when new values are pushed onto it.
-//
-// This problem currently isn't solved in a very elegant way. Inside the `get`
-// function, it internally "invalidates" all references after the loan is
-// finished and looks up into the vector again. In theory this will prevent
-// pointers from being moved under our feet so long as LLVM doesn't go too crazy
-// with the optimizations.
-//
-// n.b. Other structures are not sufficient right now:
-// * HashMap uses ~[T] internally (push reallocates/moves)
-// * TreeMap is plausible, but it's in extra
-// * dlist plausible, but not in std
-// * a custom owned linked list was attempted, but difficult to write
-// and involved a lot of extra code bloat
-//
-// n.b. Has to be stored with a pointer at outermost layer; the foreign call
-// returns void *.
-//
-// n.b. If TLS is used heavily in future, this could be made more efficient with
-// a proper map.
-type TaskLocalMap = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
-type TLSValue = ~LocalData:;
-
-fn cleanup_task_local_map(map_ptr: *libc::c_void) {
- unsafe {
- assert!(!map_ptr.is_null());
- // Get and keep the single reference that was created at the
- // beginning.
- let _map: TaskLocalMap = cast::transmute(map_ptr);
- // All local_data will be destroyed along with the map.
- }
-}
-
-// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
-
- unsafe fn newsched_map(local: *mut LocalStorage) -> &mut TaskLocalMap {
- // This is based on the same idea as the oldsched code above.
- match &mut *local {
- // If the at_exit function is already set, then we just need to take
- // a loan out on the TLS map stored inside
- &LocalStorage(ref mut map_ptr, Some(_)) => {
- assert!(map_ptr.is_not_null());
- return cast::transmute(map_ptr);
- }
- // If this is the first time we've accessed TLS, perform similar
- // actions to the oldsched way of doing things.
- &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
- assert!(map_ptr.is_null());
- assert!(at_exit.is_none());
- let map: TaskLocalMap = ~[];
- *map_ptr = cast::transmute(map);
- *at_exit = Some(cleanup_task_local_map);
- return cast::transmute(map_ptr);
- }
- }
- }
-
- match handle {
- NewHandle(local_storage) => newsched_map(local_storage)
- }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
- let pair: raw::Closure = cast::transmute_copy(&key);
- return pair.code as *libc::c_void;
-}
-
-pub unsafe fn local_pop<T: 'static>(handle: Handle,
- key: local_data::Key<T>) -> Option<T> {
- let map = get_local_map(handle);
- let key_value = key_to_key_value(key);
-
- for entry in map.mut_iter() {
- match *entry {
- Some((k, _, loan)) if k == key_value => {
- if loan != NoLoan {
- fail!("TLS value cannot be removed because it is already \
- borrowed as %s", loan.describe());
- }
- // Move the data out of the `entry` slot via util::replace. This
- // is guaranteed to succeed because we already matched on `Some`
- // above.
- let data = match util::replace(entry, None) {
- Some((_, data, _)) => data,
- None => abort(),
- };
-
- // Move `data` into transmute to get out the memory that it
- // owns, we must free it manually later.
- let (_vtable, box): (uint, ~~T) = cast::transmute(data);
-
- // Read the box's value (using the compiler's built-in
- // auto-deref functionality to obtain a pointer to the base)
- let ret = ptr::read_ptr(cast::transmute::<&T, *mut T>(*box));
-
- // Finally free the allocated memory. we don't want this to
- // actually touch the memory inside because it's all duplicated
- // now, so the box is transmuted to a 0-sized type. We also use
- // a type which references `T` because currently the layout
- // could depend on whether T contains managed pointers or not.
- let _: ~~[T, ..0] = cast::transmute(box);
-
- // Everything is now deallocated, and we own the value that was
- // located inside TLS, so we now return it.
- return Some(ret);
- }
- _ => {}
- }
- }
- return None;
-}
-
-pub unsafe fn local_get<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- f: &fn(Option<&T>) -> U) -> U {
- local_get_with(handle, key, ImmLoan, f)
-}
-
-pub unsafe fn local_get_mut<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- f: &fn(Option<&mut T>) -> U) -> U {
- do local_get_with(handle, key, MutLoan) |x| {
- match x {
- None => f(None),
- // We're violating a lot of compiler guarantees with this
- // invocation of `transmute_mut`, but we're doing runtime checks to
- // ensure that it's always valid (only one at a time).
- //
- // there is no need to be upset!
- Some(x) => { f(Some(cast::transmute_mut(x))) }
- }
- }
-}
-
-unsafe fn local_get_with<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- state: LoanState,
- f: &fn(Option<&T>) -> U) -> U {
- // This function must be extremely careful. Because TLS can store owned
- // values, and we must have some form of `get` function other than `pop`,
- // this function has to give a `&` reference back to the caller.
- //
- // One option is to return the reference, but this cannot be sound because
- // the actual lifetime of the object is not known. The slot in TLS could not
- // be modified until the object goes out of scope, but the TLS code cannot
- // know when this happens.
- //
- // For this reason, the reference is yielded to a specified closure. This
- // way the TLS code knows exactly what the lifetime of the yielded pointer
- // is, allowing callers to acquire references to owned data. This is also
- // sound so long as measures are taken to ensure that while a TLS slot is
- // loaned out to a caller, it's not modified recursively.
- let map = get_local_map(handle);
- let key_value = key_to_key_value(key);
-
- let pos = map.iter().position(|entry| {
- match *entry {
- Some((k, _, _)) if k == key_value => true, _ => false
- }
- });
- match pos {
- None => { return f(None); }
- Some(i) => {
- let ret;
- let mut return_loan = false;
- match map[i] {
- Some((_, ref data, ref mut loan)) => {
- match (state, *loan) {
- (_, NoLoan) => {
- *loan = state;
- return_loan = true;
- }
- (ImmLoan, ImmLoan) => {}
- (want, cur) => {
- fail!("TLS slot cannot be borrowed as %s because \
- it is already borrowed as %s",
- want.describe(), cur.describe());
- }
- }
- // data was created with `~~T as ~LocalData`, so we extract
- // pointer part of the trait, (as ~~T), and then use
- // compiler coercions to achieve a '&' pointer.
- match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data) {
- (_vtable, ref box) => {
- let value: &T = **box;
- ret = f(Some(value));
- }
- }
- }
- _ => abort()
- }
-
- // n.b. 'data' and 'loans' are both invalid pointers at the point
- // 'f' returned because `f` could have appended more TLS items which
- // in turn relocated the vector. Hence we do another lookup here to
- // fixup the loans.
- if return_loan {
- match map[i] {
- Some((_, _, ref mut loan)) => { *loan = NoLoan; }
- None => { abort(); }
- }
- }
- return ret;
- }
- }
-}
-
-fn abort() -> ! {
- #[fixed_stack_segment]; #[inline(never)];
-
- unsafe { libc::abort() }
-}
-
-pub unsafe fn local_set<T: 'static>(handle: Handle,
- key: local_data::Key<T>,
- data: T) {
- let map = get_local_map(handle);
- let keyval = key_to_key_value(key);
-
- // When the task-local map is destroyed, all the data needs to be cleaned
- // up. For this reason we can't do some clever tricks to store '~T' as a
- // '*c_void' or something like that. To solve the problem, we cast
- // everything to a trait (LocalData) which is then stored inside the map.
- // Upon destruction of the map, all the objects will be destroyed and the
- // traits have enough information about them to destroy themselves.
- //
- // FIXME(#7673): This should be "~data as ~LocalData" (without the colon at
- // the end, and only one sigil)
- let data = ~~data as ~LocalData:;
-
- fn insertion_position(map: &mut TaskLocalMap,
- key: *libc::c_void) -> Option<uint> {
- // First see if the map contains this key already
- let curspot = map.iter().position(|entry| {
- match *entry {
- Some((ekey, _, loan)) if key == ekey => {
- if loan != NoLoan {
- fail!("TLS value cannot be overwritten because it is
- already borrowed as %s", loan.describe())
- }
- true
- }
- _ => false,
- }
- });
- // If it doesn't contain the key, just find a slot that's None
- match curspot {
- Some(i) => Some(i),
- None => map.iter().position(|entry| entry.is_none())
- }
- }
-
- match insertion_position(map, keyval) {
- Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
- None => { map.push(Some((keyval, data, NoLoan))); }
- }
-}
#[cfg(test)] use ptr;
#[cfg(test)] use task;
-mod local_data_priv;
pub mod spawn;
/**
use rt::task::Task;
if in_green_task_context() {
- do Local::borrow::<Task, U> |task| {
+ do Local::borrow |task: &mut Task| {
match task.name {
Some(ref name) => blk(Some(name.as_slice())),
None => blk(None)
// FIXME #6842: What does yield really mean in newsched?
// FIXME(#7544): Optimize this, since we know we won't block.
- let sched = Local::take::<Scheduler>();
+ let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
sched.enqueue_blocked_task(task);
}
use rt::task::Task;
- do Local::borrow::<Task, bool> |local| {
+ do Local::borrow |local: &mut Task| {
local.unwinder.unwinding
}
}
unsafe {
if in_green_task_context() {
// The inhibits/allows might fail and need to borrow the task.
- let t = Local::unsafe_borrow::<Task>();
+ let t: *mut Task = Local::unsafe_borrow();
do (|| {
(*t).death.inhibit_kill((*t).unwinder.unwinding);
f()
}
}
-/// The inverse of unkillable. Only ever to be used nested in unkillable().
-pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
+/**
+ * Makes killable a task marked as unkillable. This
+ * is meant to be used only nested in unkillable.
+ *
+ * # Example
+ *
+ * ~~~
+ * do task::unkillable {
+ * do task::rekillable {
+ * // Task is killable
+ * }
+ * // Task is unkillable again
+ * }
+ */
+pub fn rekillable<U>(f: &fn() -> U) -> U {
use rt::task::Task;
- if in_green_task_context() {
- let t = Local::unsafe_borrow::<Task>();
- do (|| {
- (*t).death.allow_kill((*t).unwinder.unwinding);
+ unsafe {
+ if in_green_task_context() {
+ let t: *mut Task = Local::unsafe_borrow();
+ do (|| {
+ (*t).death.allow_kill((*t).unwinder.unwinding);
+ f()
+ }).finally {
+ (*t).death.inhibit_kill((*t).unwinder.unwinding);
+ }
+ } else {
+ // FIXME(#3095): As in unkillable().
f()
- }).finally {
- (*t).death.inhibit_kill((*t).unwinder.unwinding);
}
- } else {
- // FIXME(#3095): As in unkillable().
- f()
}
}
}
}
-#[ignore(reason = "linked failure")]
#[test]
+#[ignore(cfg(windows))]
fn test_kill_rekillable_task() {
use rt::test::*;
do run_in_newsched_task {
do task::try {
do task::unkillable {
- unsafe {
- do task::rekillable {
- do task::spawn {
- fail!();
- }
+ do task::rekillable {
+ do task::spawn {
+ fail!();
}
}
}
}
}
-#[test] #[should_fail]
+#[test]
+#[should_fail]
+#[ignore(cfg(windows))]
+fn test_rekillable_not_nested() {
+ do rekillable {
+ // This should fail before
+ // receiving anything since
+ // this block should be nested
+ // into a unkillable block.
+ deschedule();
+ }
+}
+
+
+#[test]
+#[ignore(cfg(windows))]
+fn test_rekillable_nested_failure() {
+
+ let result = do task::try {
+ do unkillable {
+ do rekillable {
+ let (port,chan) = comm::stream();
+ do task::spawn { chan.send(()); fail!(); }
+ port.recv(); // wait for child to exist
+ port.recv(); // block forever, expect to get killed.
+ }
+ }
+ };
+ assert!(result.is_err());
+}
+
+
+#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_cant_dup_task_builder() {
let mut builder = task();
builder.unlinked();
#[cfg(test)]
fn get_sched_id() -> int {
- do Local::borrow::<::rt::sched::Scheduler, int> |sched| {
+ do Local::borrow |sched: &mut ::rt::sched::Scheduler| {
sched.sched_id() as int
}
}
fn kill_task(mut handle: KillHandle) {
do handle.kill().map_move |killed_task| {
let killed_task = Cell::new(killed_task);
- do Local::borrow::<Scheduler, ()> |sched| {
+ do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_task(killed_task.take());
}
};
unsafe {
// Can't use safe borrow, because the taskgroup destructor needs to
// access the scheduler again to send kill signals to other tasks.
- let me = Local::unsafe_borrow::<Task>();
+ let me: *mut Task = Local::unsafe_borrow();
blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding)
}
}
unsafe {
// Can't use safe borrow, because creating new hashmaps for the
// tasksets requires an rng, which needs to borrow the sched.
- let me = Local::unsafe_borrow::<Task>();
+ let me: *mut Task = Local::unsafe_borrow();
blk(match (*me).taskgroup {
None => {
// First task in its (unlinked/unsupervised) taskgroup.
// If child data is 'None', the enlist is vacuously successful.
let enlist_success = do child_data.take().map_move_default(true) |child_data| {
let child_data = Cell::new(child_data); // :(
- do Local::borrow::<Task, bool> |me| {
+ do Local::borrow |me: &mut Task| {
let (child_tg, ancestors) = child_data.take();
let mut ancestors = ancestors;
let handle = me.death.kill_handle.get_ref();
} else {
unsafe {
// Creating a 1:1 task:thread ...
- let sched = Local::unsafe_borrow::<Scheduler>();
+ let sched: *mut Scheduler = Local::unsafe_borrow();
let sched_handle = (*sched).make_handle();
// Since this is a 1:1 scheduler we create a queue not in
// NB: raw-pointer IterBytes does _not_ dereference
// to the target; it just gives you the pointer-bytes.
-impl<A> IterBytes for *const A {
+impl<A> IterBytes for *A {
+ #[inline]
+ fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
+ (*self as uint).iter_bytes(lsb0, f)
+ }
+}
+
+impl<A> IterBytes for *mut A {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
(*self as uint).iter_bytes(lsb0, f)
impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
fn zero() -> ($($T,)+) {
- ($(Zero::zero::<$T>(),)+)
+ ($({ let x: $T = Zero::zero(); x},)+)
}
#[inline]
fn is_zero(&self) -> bool {
#[inline]
fn is_zero(&self) -> bool { true }
}
+
+#[cfg(not(test))]
+impl Default for () {
+ fn default() -> () { () }
+}
#[test]
fn option_empty() {
- assert!(AtomicOption::empty::<()>().is_empty(SeqCst));
+ let mut option: AtomicOption<()> = AtomicOption::empty();
+ assert!(option.is_empty(SeqCst));
}
#[test]
FreeLibrary(handle); ()
}
+ #[cfg(target_arch = "x86")]
#[link_name = "kernel32"]
extern "stdcall" {
fn SetLastError(error: u32);
fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
fn FreeLibrary(handle: *libc::c_void);
}
+
+ #[cfg(target_arch = "x86_64")]
+ #[link_name = "kernel32"]
+ extern {
+ fn SetLastError(error: u32);
+ fn LoadLibraryW(name: *u16) -> *libc::c_void;
+ fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
+ handle: **libc::c_void) -> *libc::c_void;
+ fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
+ fn FreeLibrary(handle: *libc::c_void);
+ }
}
n_inputs: uint, retstyle: uint) -> bool;
fn visit_trait(&self) -> bool;
- fn visit_var(&self) -> bool;
- fn visit_var_integral(&self) -> bool;
fn visit_param(&self, i: uint) -> bool;
fn visit_self(&self) -> bool;
fn visit_type(&self) -> bool;
fn visit_opaque_box(&self) -> bool;
- fn visit_constr(&self, inner: *TyDesc) -> bool;
fn visit_closure_ptr(&self, ck: uint) -> bool;
}
/// Get the address of the `__morestack` stack growth function.
pub fn morestack_addr() -> *();
- /// Calculates the offset from a pointer.
- ///
- /// This is implemented as an intrinsic to avoid converting to and from an
- /// integer, since the conversion would throw away aliasing information.
- pub fn offset<T>(dst: *T, offset: int) -> *T;
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end. An arithmetic overflow is also
/// undefined behaviour.
///
- /// This intrinsic should be preferred over `offset` when the guarantee can
- /// be satisfied, to enable better optimization.
- pub fn offset_inbounds<T>(dst: *T, offset: int) -> *T;
+ /// This is implemented as an intrinsic to avoid converting to and from an
+ /// integer, since the conversion would throw away aliasing information.
+ pub fn offset<T>(dst: *T, offset: int) -> *T;
/// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
use c_str::ToCStr;
use cast::transmute;
use libc::{c_char, c_void, size_t, uintptr_t};
-use option::{Some, None};
+use option::{Option, None, Some};
use sys;
use rt::task::Task;
use rt::local::Local;
#[lang="malloc"]
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
// XXX: Unsafe borrow for speed. Lame.
- match Local::try_unsafe_borrow::<Task>() {
+ let task: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task {
Some(task) => {
(*task).heap.alloc(td as *c_void, size as uint) as *c_char
}
impl<T> Repr<*Box<T>> for @T {}
impl<T> Repr<*Box<Vec<T>>> for @[T] {}
impl Repr<*String> for ~str {}
+impl Repr<*Box<String>> for @str {}
// sure would be nice to have this
// impl<T> Repr<*Vec<T>> for ~[T] {}
/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
-pub struct UnsafeAtomicRcBox<T> {
- data: *mut libc::c_void,
+pub struct UnsafeArc<T> {
+ data: *mut ArcData<T>,
}
-struct AtomicRcBoxData<T> {
+struct ArcData<T> {
count: AtomicUint,
// An unwrapper uses this protocol to communicate with the "other" task that
// drops the last refcount on an arc. Unfortunately this can't be a proper
data: Option<T>,
}
-unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut libc::c_void {
- let data = ~AtomicRcBoxData { count: AtomicUint::new(refcount),
- unwrapper: AtomicOption::empty(),
- data: Some(data) };
+unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
+ let data = ~ArcData { count: AtomicUint::new(refcount),
+ unwrapper: AtomicOption::empty(),
+ data: Some(data) };
cast::transmute(data)
}
-impl<T: Send> UnsafeAtomicRcBox<T> {
- pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
- unsafe { UnsafeAtomicRcBox { data: new_inner(data, 1) } }
+impl<T: Send> UnsafeArc<T> {
+ pub fn new(data: T) -> UnsafeArc<T> {
+ unsafe { UnsafeArc { data: new_inner(data, 1) } }
}
/// As new(), but returns an extra pre-cloned handle.
- pub fn new2(data: T) -> (UnsafeAtomicRcBox<T>, UnsafeAtomicRcBox<T>) {
+ pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
unsafe {
let ptr = new_inner(data, 2);
- (UnsafeAtomicRcBox { data: ptr }, UnsafeAtomicRcBox { data: ptr })
+ (UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
}
}
/// As new(), but returns a vector of as many pre-cloned handles as requested.
- pub fn newN(data: T, num_handles: uint) -> ~[UnsafeAtomicRcBox<T>] {
+ pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
unsafe {
if num_handles == 0 {
~[] // need to free data here
} else {
let ptr = new_inner(data, num_handles);
- vec::from_fn(num_handles, |_| UnsafeAtomicRcBox { data: ptr })
+ vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
}
}
}
/// As newN(), but from an already-existing handle. Uses one xadd.
- pub fn cloneN(self, num_handles: uint) -> ~[UnsafeAtomicRcBox<T>] {
+ pub fn cloneN(self, num_handles: uint) -> ~[UnsafeArc<T>] {
if num_handles == 0 {
~[] // The "num_handles - 1" trick (below) fails in the 0 case.
} else {
unsafe {
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
// Minus one because we are recycling the given handle's refcount.
- let old_count = data.count.fetch_add(num_handles - 1, Acquire);
- // let old_count = data.count.fetch_add(num_handles, Acquire);
+ let old_count = (*self.data).count.fetch_add(num_handles - 1, Acquire);
+ // let old_count = (*self.data).count.fetch_add(num_handles, Acquire);
assert!(old_count >= 1);
- let ptr = cast::transmute(data);
+ let ptr = self.data;
cast::forget(self); // Don't run the destructor on this handle.
- vec::from_fn(num_handles, |_| UnsafeAtomicRcBox { data: ptr })
+ vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
}
}
}
#[inline]
pub fn get(&self) -> *mut T {
unsafe {
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- assert!(data.count.load(Relaxed) > 0);
- let r: *mut T = data.data.get_mut_ref();
- cast::forget(data);
+ assert!((*self.data).count.load(Relaxed) > 0);
+ let r: *mut T = (*self.data).data.get_mut_ref();
return r;
}
}
#[inline]
pub fn get_immut(&self) -> *T {
unsafe {
- let data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- assert!(data.count.load(Relaxed) > 0);
- let r: *T = data.data.get_ref();
- cast::forget(data);
+ assert!((*self.data).count.load(Relaxed) > 0);
+ let r: *T = (*self.data).data.get_ref();
return r;
}
}
do task::unkillable {
unsafe {
let mut this = this.take();
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
+ // The ~ dtor needs to run if this code succeeds.
+ let mut data: ~ArcData<T> = cast::transmute(this.data);
// Set up the unwrap protocol.
let (p1,c1) = comm::oneshot(); // ()
let (p2,c2) = comm::oneshot(); // bool
// We were the last owner. Can unwrap immediately.
// AtomicOption's destructor will free the server endpoint.
// FIXME(#3224): it should be like this
- // let ~AtomicRcBoxData { data: user_data, _ } = data;
+ // let ~ArcData { data: user_data, _ } = data;
// user_data
data.data.take_unwrap()
} else {
let (c2, data) = c2_and_data.take();
c2.send(true);
// FIXME(#3224): it should be like this
- // let ~AtomicRcBoxData { data: user_data, _ } = data;
+ // let ~ArcData { data: user_data, _ } = data;
// user_data
let mut data = data;
data.data.take_unwrap()
/// As unwrap above, but without blocking. Returns 'Left(self)' if this is
/// not the last reference; 'Right(unwrapped_data)' if so.
- pub fn try_unwrap(self) -> Either<UnsafeAtomicRcBox<T>, T> {
+ pub fn try_unwrap(self) -> Either<UnsafeArc<T>, T> {
unsafe {
let mut this = self; // FIXME(#4330) mutable self
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
+ // The ~ dtor needs to run if this code succeeds.
+ let mut data: ~ArcData<T> = cast::transmute(this.data);
// This can of course race with anybody else who has a handle, but in
// such a case, the returned count will always be at least 2. If we
// see 1, no race was possible. All that matters is 1 or not-1.
}
}
-impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
- fn clone(&self) -> UnsafeAtomicRcBox<T> {
+impl<T: Send> Clone for UnsafeArc<T> {
+ fn clone(&self) -> UnsafeArc<T> {
unsafe {
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
// This barrier might be unnecessary, but I'm not sure...
- let old_count = data.count.fetch_add(1, Acquire);
+ let old_count = (*self.data).count.fetch_add(1, Acquire);
assert!(old_count >= 1);
- cast::forget(data);
- return UnsafeAtomicRcBox { data: self.data };
+ return UnsafeArc { data: self.data };
}
}
}
#[unsafe_destructor]
-impl<T> Drop for UnsafeAtomicRcBox<T>{
+impl<T> Drop for UnsafeArc<T>{
fn drop(&self) {
unsafe {
if self.data.is_null() {
return; // Happens when destructing an unwrapper's handle.
}
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+ let mut data: ~ArcData<T> = cast::transmute(self.data);
// Must be acquire+release, not just release, to make sure this
// doesn't get reordered to after the unwrapper pointer load.
let old_count = data.count.fetch_sub(1, SeqCst);
*/
// FIXME(#8140) should not be pub
pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
- use rt::task::Task;
+ use rt::task::{Task, GreenTask, SchedTask};
use rt::local::Local;
- use rt::in_green_task_context;
-
- if in_green_task_context() {
- let t = Local::unsafe_borrow::<Task>();
- do (|| {
- (*t).death.inhibit_deschedule();
- f()
- }).finally {
- (*t).death.allow_deschedule();
+
+ let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task_opt {
+ Some(t) => {
+ match (*t).task_type {
+ GreenTask(_) => {
+ do (|| {
+ (*t).death.inhibit_deschedule();
+ f()
+ }).finally {
+ (*t).death.allow_deschedule();
+ }
+ }
+ SchedTask => f()
+ }
}
- } else {
- f()
+ None => f()
}
}
* need to block or deschedule while accessing shared state, use extra::sync::RWArc.
*/
pub struct Exclusive<T> {
- x: UnsafeAtomicRcBox<ExData<T>>
+ x: UnsafeArc<ExData<T>>
}
impl<T:Send> Clone for Exclusive<T> {
data: user_data
};
Exclusive {
- x: UnsafeAtomicRcBox::new(data)
+ x: UnsafeArc::new(data)
}
}
use comm;
use option::*;
use prelude::*;
- use super::{Exclusive, UnsafeAtomicRcBox, atomically};
+ use super::{Exclusive, UnsafeArc, atomically};
use task;
use util;
#[test]
fn arclike_newN() {
// Tests that the many-refcounts-at-once constructors don't leak.
- let _ = UnsafeAtomicRcBox::new2(~~"hello");
- let x = UnsafeAtomicRcBox::newN(~~"hello", 0);
+ let _ = UnsafeArc::new2(~~"hello");
+ let x = UnsafeArc::newN(~~"hello", 0);
assert_eq!(x.len(), 0)
- let x = UnsafeAtomicRcBox::newN(~~"hello", 1);
+ let x = UnsafeArc::newN(~~"hello", 1);
assert_eq!(x.len(), 1)
- let x = UnsafeAtomicRcBox::newN(~~"hello", 10);
+ let x = UnsafeArc::newN(~~"hello", 10);
assert_eq!(x.len(), 10)
}
#[test]
fn arclike_cloneN() {
// Tests that the many-refcounts-at-once special-clone doesn't leak.
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
let x = x.cloneN(0);
assert_eq!(x.len(), 0);
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
let x = x.cloneN(1);
assert_eq!(x.len(), 1);
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
let x = x.cloneN(10);
assert_eq!(x.len(), 10);
}
#[test]
fn arclike_unwrap_basic() {
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
assert!(x.unwrap() == ~~"hello");
}
#[test]
fn arclike_try_unwrap() {
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
assert!(x.try_unwrap().expect_right("try_unwrap failed") == ~~"hello");
}
#[test]
fn arclike_try_unwrap_fail() {
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
let x2 = x.clone();
let left_x = x.try_unwrap();
assert!(left_x.is_left());
#[test]
fn arclike_try_unwrap_unwrap_race() {
// When an unwrap and a try_unwrap race, the unwrapper should always win.
- let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x = UnsafeArc::new(~~"hello");
let x2 = Cell::new(x.clone());
let (p,c) = comm::stream();
do task::spawn {
let t: *mut T = &mut tmp;
// Perform the swap, `&mut` pointers never alias
- ptr::copy_nonoverlapping_memory(t, x, 1);
- ptr::copy_nonoverlapping_memory(x, y, 1);
+ let x_raw: *mut T = x;
+ let y_raw: *mut T = y;
+ ptr::copy_nonoverlapping_memory(t, x_raw, 1);
+ ptr::copy_nonoverlapping_memory(x, y_raw, 1);
ptr::copy_nonoverlapping_memory(y, t, 1);
// y and t now point to the same thing, but we need to completely forget `tmp`
#[warn(non_camel_case_types)];
use cast;
-use clone::Clone;
+use clone::{Clone, DeepClone};
use container::{Container, Mutable};
use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
use cmp;
use sys;
use sys::size_of;
use uint;
+use unstable::finally::Finally;
use unstable::intrinsics;
use unstable::intrinsics::{get_tydesc, contains_managed};
use unstable::raw::{Box, Repr, Slice, Vec};
let mut v = with_capacity(n_elts);
let p = raw::to_mut_ptr(v);
let mut i: uint = 0u;
- while i < n_elts {
- intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
- i += 1u;
+ do (|| {
+ while i < n_elts {
+ intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
+ i += 1u;
+ }
+ }).finally {
+ raw::set_len(&mut v, i);
}
- raw::set_len(&mut v, n_elts);
v
}
}
let mut v = with_capacity(n_elts);
let p = raw::to_mut_ptr(v);
let mut i = 0u;
- while i < n_elts {
- intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
- i += 1u;
+ do (|| {
+ while i < n_elts {
+ intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
+ i += 1u;
+ }
+ }).finally {
+ raw::set_len(&mut v, i);
}
- raw::set_len(&mut v, n_elts);
v
}
}
lifetime: cast::transmute(p)}
} else {
VecIterator{ptr: p,
- end: p.offset_inbounds(self.len() as int),
+ end: p.offset(self.len() as int),
lifetime: cast::transmute(p)}
}
}
* foreign interop.
*/
#[inline]
- fn as_imm_buf<U>(&self,
- /* NB---this CANNOT be const, see below */
- f: &fn(*T, uint) -> U) -> U {
- // NB---Do not change the type of s to `&const [T]`. This is
- // unsound. The reason is that we are going to create immutable pointers
- // into `s` and pass them to `f()`, but in fact they are potentially
- // pointing at *mutable memory*. Use `as_mut_buf` instead!
-
+ fn as_imm_buf<U>(&self, f: &fn(*T, uint) -> U) -> U {
let s = self.repr();
f(s.data, s.len / sys::nonzero_size_of::<T>())
}
let self_len = self.len();
let rhs_len = rhs.len();
let new_len = self_len + rhs_len;
- self.reserve(new_len);
+ self.reserve_at_least(new_len);
unsafe { // Note: infallible.
let self_p = vec::raw::to_mut_ptr(*self);
let rhs_p = vec::raw::to_ptr(rhs);
lifetime: cast::transmute(p)}
} else {
VecMutIterator{ptr: p,
- end: p.offset_inbounds(self.len() as int),
+ end: p.offset(self.len() as int),
lifetime: cast::transmute(p)}
}
}
}
}
-impl<A:Clone> Clone for ~[A] {
+impl<A: Clone> Clone for ~[A] {
#[inline]
fn clone(&self) -> ~[A] {
self.iter().map(|item| item.clone()).collect()
}
}
+impl<A: DeepClone> DeepClone for ~[A] {
+ #[inline]
+ fn deep_clone(&self) -> ~[A] {
+ self.iter().map(|item| item.deep_clone()).collect()
+ }
+}
+
// This works because every lifetime is a sub-lifetime of 'static
impl<'self, A> Zero for &'self [A] {
fn zero() -> &'self [A] { &'self [] }
// same pointer.
cast::transmute(self.ptr as uint + 1)
} else {
- self.ptr.offset_inbounds(1)
+ self.ptr.offset(1)
};
Some(cast::transmute(old))
// See above for why 'ptr.offset' isn't used
cast::transmute(self.end as uint - 1)
} else {
- self.end.offset_inbounds(-1)
+ self.end.offset(-1)
};
Some(cast::transmute(self.end))
}
};
}
+ #[test]
+ #[should_fail]
+ fn test_from_elem_fail() {
+ use cast;
+
+ struct S {
+ f: int,
+ boxes: (~int, @int)
+ }
+
+ impl Clone for S {
+ fn clone(&self) -> S {
+ let s = unsafe { cast::transmute_mut(self) };
+ s.f += 1;
+ if s.f == 10 { fail!() }
+ S { f: s.f, boxes: s.boxes.clone() }
+ }
+ }
+
+ let s = S { f: 0, boxes: (~0, @0) };
+ let _ = from_elem(100, s);
+ }
+
#[test]
#[should_fail]
fn test_build_fail() {
}
}
- #[ignore] // FIXME #8698
#[test]
#[should_fail]
fn test_map_fail() {
if i == 2 {
fail!()
}
- i += 0;
+ i += 1;
~[(~0, @0)]
};
}
- #[ignore] // FIXME #8698
#[test]
#[should_fail]
fn test_flat_map_fail() {
if i == 2 {
fail!()
}
- i += 0;
+ i += 1;
~[(~0, @0)]
};
}
- #[ignore] // FIXME #8698
#[test]
#[should_fail]
fn test_rposition_fail() {
if i == 2 {
fail!()
}
- i += 0;
+ i += 1;
false
};
}
- #[ignore] // FIXME #8698
#[test]
#[should_fail]
fn test_permute_fail() {
if i == 2 {
fail!()
}
- i += 0;
+ i += 1;
true
};
}
/// A `::foo` path, is relative to the crate root rather than current
/// module (like paths in an import).
global: bool,
- /// The segments in the path (the things separated by ::)
- idents: ~[ident],
- /// "Region parameter", currently only one lifetime is allowed in a path.
- rp: Option<Lifetime>,
- /// These are the type parameters, ie, the `a, b` in `foo::bar::<a, b>`
- types: ~[Ty],
+ /// The segments in the path: the things separated by `::`.
+ segments: ~[PathSegment],
+}
+
+/// A segment of a path: an identifier, an optional lifetime, and a set of
+/// types.
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub struct PathSegment {
+ /// The identifier portion of this path segment.
+ identifier: ident,
+ /// The lifetime parameter for this path segment. Currently only one
+ /// lifetime parameter is allowed.
+ lifetime: Option<Lifetime>,
+ /// The type parameters for this path segment, if present.
+ types: OptVec<Ty>,
}
pub type CrateNum = int;
}
}
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub enum MethodProvenance {
+ FromTrait(def_id),
+ FromImpl(def_id),
+}
+
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum def {
def_fn(def_id, purity),
- def_static_method(/* method */ def_id,
- /* trait */ Option<def_id>,
- purity),
- def_self(NodeId, bool /* is_implicit */),
+ def_static_method(/* method */ def_id, MethodProvenance, purity),
+ def_self(NodeId),
def_self_ty(/* trait id */ NodeId),
def_mod(def_id),
def_foreign_mod(def_id),
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub enum mutability { m_mutbl, m_imm, m_const, }
+pub enum mutability {
+ m_mutbl,
+ m_imm,
+}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum Sigil {
}
// NB Eq method appears below.
-#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct Ty {
id: NodeId,
node: ty_,
idents.map(|i| token::interner_get(i.name)).connect("::")
}
-pub fn path_to_ident(p: &Path) -> ident {
- *p.idents.last()
+pub fn path_to_ident(path: &Path) -> ident {
+ path.segments.last().identifier
}
pub fn local_def(id: NodeId) -> def_id {
def_use(id) | def_struct(id) | def_trait(id) | def_method(id, _) => {
id
}
- def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id)
+ def_arg(id, _) | def_local(id, _) | def_self(id) | def_self_ty(id)
| def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
| def_typaram_binder(id) | def_label(id) => {
local_def(id)
}
}
-pub fn ident_to_path(s: span, i: ident) -> Path {
- ast::Path { span: s,
- global: false,
- idents: ~[i],
- rp: None,
- types: ~[] }
+pub fn ident_to_path(s: span, identifier: ident) -> Path {
+ ast::Path {
+ span: s,
+ global: false,
+ segments: ~[
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ }
}
pub fn ident_to_pat(id: NodeId, s: span, i: ident) -> @pat {
impl Visitor<()> for IdVisitor {
fn visit_mod(&mut self,
module: &_mod,
- _span: span,
+ _: span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
ext::tt::macro_rules::add_new_extension));
syntax_expanders.insert(intern(&"fmt"),
builtin_normal_tt(ext::fmt::expand_syntax_ext));
- syntax_expanders.insert(intern(&"ifmt"),
- builtin_normal_tt(ext::ifmt::expand_syntax_ext));
+ syntax_expanders.insert(intern(&"format"),
+ builtin_normal_tt(ext::ifmt::expand_format));
+ syntax_expanders.insert(intern(&"write"),
+ builtin_normal_tt(ext::ifmt::expand_write));
+ syntax_expanders.insert(intern(&"writeln"),
+ builtin_normal_tt(ext::ifmt::expand_writeln));
syntax_expanders.insert(
intern(&"auto_encode"),
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
}
}
-pub fn expr_to_ident(cx: @ExtCtxt,
- expr: @ast::expr,
- err_msg: &str) -> ast::ident {
- match expr.node {
- ast::expr_path(ref p) => {
- if p.types.len() > 0u || p.idents.len() != 1u {
- cx.span_fatal(expr.span, err_msg);
- }
- return p.idents[0];
- }
- _ => cx.span_fatal(expr.span, err_msg)
- }
-}
-
pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
name: &str) {
if tts.len() != 0 {
pub fn get_single_str_from_tts(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree],
- name: &str) -> @str {
+ name: &str)
+ -> @str {
if tts.len() != 1 {
cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
}
match tts[0] {
ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
- _ =>
- cx.span_fatal(sp, fmt!("%s requires a string.", name))
+ _ => cx.span_fatal(sp, fmt!("%s requires a string.", name)),
}
}
// statements
fn stmt_expr(&self, expr: @ast::expr) -> @ast::stmt;
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt;
+ fn stmt_let_typed(&self,
+ sp: span,
+ mutbl: bool,
+ ident: ast::ident,
+ typ: ast::Ty,
+ ex: @ast::expr)
+ -> @ast::stmt;
// blocks
fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block;
fn path_global(&self, span: span, strs: ~[ast::ident]) -> ast::Path {
self.path_all(span, true, strs, None, ~[])
}
- fn path_all(&self, sp: span,
+ fn path_all(&self,
+ sp: span,
global: bool,
- idents: ~[ast::ident],
+ mut idents: ~[ast::ident],
rp: Option<ast::Lifetime>,
types: ~[ast::Ty])
- -> ast::Path {
+ -> ast::Path {
+ let last_identifier = idents.pop();
+ let mut segments: ~[ast::PathSegment] = idents.move_iter()
+ .map(|ident| {
+ ast::PathSegment {
+ identifier: ident,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect();
+ segments.push(ast::PathSegment {
+ identifier: last_identifier,
+ lifetime: rp,
+ types: opt_vec::from(types),
+ });
ast::Path {
span: sp,
global: global,
- idents: idents,
- rp: rp,
- types: types
+ segments: segments,
}
}
@respan(sp, ast::stmt_decl(@decl, self.next_id()))
}
+ fn stmt_let_typed(&self,
+ sp: span,
+ mutbl: bool,
+ ident: ast::ident,
+ typ: ast::Ty,
+ ex: @ast::expr)
+ -> @ast::stmt {
+ let pat = self.pat_ident(sp, ident);
+ let local = @ast::Local {
+ is_mutbl: mutbl,
+ ty: typ,
+ pat: pat,
+ init: Some(ex),
+ id: self.next_id(),
+ span: sp,
+ };
+ let decl = respan(sp, ast::decl_local(local));
+ @respan(sp, ast::stmt_decl(@decl, self.next_id()))
+ }
+
fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block {
self.block_all(span, ~[], stmts, expr)
}
use codemap::span;
use ext::base::*;
use ext::base;
+use opt_vec;
use parse::token;
use parse::token::{str_to_ident};
ast::Path {
span: sp,
global: false,
- idents: ~[res],
- rp: None,
- types: ~[],
+ segments: ~[
+ ast::PathSegment {
+ identifier: res,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ]
}
),
span: sp,
let variant_count = cx.expr_uint(span, variants.len());
- // need to specify the uint-ness of the random number
- let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
- let r_ty = cx.ty_ident(span, cx.ident_of("R"));
let rand_name = cx.path_all(span,
true,
rand_ident.clone(),
None,
- ~[ uint_ty, r_ty ]);
+ ~[]);
let rand_name = cx.expr_path(rand_name);
- // ::std::rand::Rand::rand::<uint>(rng)
+ // ::std::rand::Rand::rand(rng)
let rv_call = cx.expr_call(span,
rand_name,
~[ rng[0].duplicate(cx) ]);
+ // need to specify the uint-ness of the random number
+ let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
+ let value_ident = cx.ident_of("__value");
+ let let_statement = cx.stmt_let_typed(span,
+ false,
+ value_ident,
+ uint_ty,
+ rv_call);
+
// rand() % variants.len()
- let rand_variant = cx.expr_binary(span, ast::rem,
- rv_call, variant_count);
+ let value_ref = cx.expr_ident(span, value_ident);
+ let rand_variant = cx.expr_binary(span,
+ ast::rem,
+ value_ref,
+ variant_count);
let mut arms = do variants.iter().enumerate().map |(i, id_sum)| {
let i_expr = cx.expr_uint(span, i);
// _ => {} at the end. Should never occur
arms.push(cx.arm_unreachable(span));
- cx.expr_match(span, rand_variant, arms)
+ let match_expr = cx.expr_match(span, rand_variant, arms);
+
+ let block = cx.block(span, ~[ let_statement ], Some(match_expr));
+ cx.expr_block(block)
}
_ => cx.bug("Non-static method in `deriving(Rand)`")
};
use codemap::{span, spanned, ExpnInfo, NameAndSpan};
use ext::base::*;
use fold::*;
+use opt_vec;
use parse;
use parse::{parse_item_from_source_str};
use parse::token;
match (*mac).node {
// Token-tree macros:
mac_invoc_tt(ref pth, ref tts) => {
- if (pth.idents.len() > 1u) {
+ if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
- let extname = &pth.idents[0];
+ let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
// leaving explicit deref here to highlight unbox op:
match (*extsbox).find(&extname.name) {
ast::Path {
span: span,
global: false,
- idents: ~[ident],
- rp: None,
- types: ~[]
+ segments: ~[
+ ast::PathSegment {
+ identifier: ident,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
}
}
_ => cx.span_bug(it.span, "invalid item macro invocation")
};
- let extname = &pth.idents[0];
+ let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let expanded = match (*extsbox).find(&extname.name) {
None => cx.span_fatal(pth.span,
}
_ => return orig(s, sp, fld)
};
- if (pth.idents.len() > 1u) {
+ if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
- let extname = &pth.idents[0];
+ let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
None =>
// a path of length one:
&ast::Path {
global: false,
- idents: [id],
span: _,
- rp: _,
- types: _
+ segments: [
+ ast::PathSegment {
+ identifier: id,
+ lifetime: _,
+ types: _
+ }
+ ]
} => self.ident_accumulator.push(id),
// I believe these must be enums...
_ => ()
)
)
- // conditionally define debug!, but keep it type checking even
- // in non-debug builds.
- macro_rules! __debug (
+ macro_rules! debug (
($arg:expr) => (
- __log(4u32, fmt!( \"%?\", $arg ))
+ if cfg!(debug) { __log(4u32, fmt!( \"%?\", $arg )) }
);
($( $arg:expr ),+) => (
- __log(4u32, fmt!( $($arg),+ ))
+ if cfg!(debug) { __log(4u32, fmt!( $($arg),+ )) }
)
)
- #[cfg(debug)]
- #[macro_escape]
- mod debug_macro {
- macro_rules! debug (($($arg:expr),*) => {
- __debug!($($arg),*)
- })
- }
+ macro_rules! error2 (
+ ($($arg:tt)*) => ( __log(1u32, format!($($arg)*)))
+ )
- #[cfg(not(debug))]
- #[macro_escape]
- mod debug_macro {
- macro_rules! debug (($($arg:expr),*) => {
- if false { __debug!($($arg),*) }
- })
- }
+ macro_rules! warn2 (
+ ($($arg:tt)*) => ( __log(2u32, format!($($arg)*)))
+ )
+
+ macro_rules! info2 (
+ ($($arg:tt)*) => ( __log(3u32, format!($($arg)*)))
+ )
+
+ macro_rules! debug2 (
+ ($($arg:tt)*) => (
+ if cfg!(debug) { __log(4u32, format!($($arg)*)) }
+ )
+ )
macro_rules! fail(
() => (
)
)
+ macro_rules! fail2(
+ () => (
+ fail!(\"explicit failure\")
+ );
+ ($($arg:tt)+) => (
+ ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
+ )
+ )
+
macro_rules! assert(
($cond:expr) => {
if !$cond {
);
)
+ // NOTE(acrichto): start removing this after the next snapshot
macro_rules! printf (
($arg:expr) => (
print(fmt!(\"%?\", $arg))
)
)
+ // NOTE(acrichto): start removing this after the next snapshot
macro_rules! printfln (
($arg:expr) => (
println(fmt!(\"%?\", $arg))
)
)
+ // FIXME(#6846) once stdio is redesigned, this shouldn't perform an
+ // allocation but should rather delegate to an invocation of
+ // write! instead of format!
+ macro_rules! print (
+ ($($arg:tt)+) => ( ::std::io::print(format!($($arg)+)))
+ )
+
+ // FIXME(#6846) once stdio is redesigned, this shouldn't perform an
+ // allocation but should rather delegate to an io::Writer
+ macro_rules! println (
+ ($($arg:tt)+) => ({ print!($($arg)+); ::std::io::println(\"\"); })
+ )
+
// NOTE: use this after a snapshot lands to abstract the details
// of the TLS interface.
macro_rules! local_data_key (
/// Parses the arguments from the given list of tokens, returning None if
/// there's a parse error so we can continue parsing other fmt! expressions.
fn parse_args(&mut self, sp: span,
- tts: &[ast::token_tree]) -> Option<@ast::expr> {
+ leading_expr: bool,
+ tts: &[ast::token_tree]) -> (Option<@ast::expr>,
+ Option<@ast::expr>) {
let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
self.ecx.cfg(),
tts.to_owned());
+ // If we want a leading expression (for ifmtf), parse it here
+ let extra = if leading_expr {
+ let e = Some(p.parse_expr());
+ if !p.eat(&token::COMMA) {
+ self.ecx.span_err(sp, "expected token: `,`");
+ return (e, None);
+ }
+ e
+ } else { None };
+
if *p.token == token::EOF {
- self.ecx.span_err(sp, "ifmt! expects at least one argument");
- return None;
+ self.ecx.span_err(sp, "requires at least a format string argument");
+ return (extra, None);
}
let fmtstr = p.parse_expr();
let mut named = false;
while *p.token != token::EOF {
if !p.eat(&token::COMMA) {
self.ecx.span_err(sp, "expected token: `,`");
- return None;
+ return (extra, None);
}
if named || (token::is_ident(p.token) &&
p.look_ahead(1, |t| *t == token::EQ)) {
self.ecx.span_err(*p.span,
"expected ident, positional arguments \
cannot follow named arguments");
- return None;
+ return (extra, None);
}
_ => {
self.ecx.span_err(*p.span,
fmt!("expected ident for named \
argument, but found `%s`",
p.this_token_to_str()));
- return None;
+ return (extra, None);
}
};
let name = self.ecx.str_of(ident);
self.arg_types.push(None);
}
}
- return Some(fmtstr);
+ return (extra, Some(fmtstr));
}
/// Verifies one piece of a parse string. All errors are not emitted as
/// Actually builds the expression which the ifmt! block will be expanded
/// to
- fn to_expr(&self) -> @ast::expr {
+ fn to_expr(&self, extra: Option<@ast::expr>, f: &str) -> @ast::expr {
let mut lets = ~[];
let mut locals = ~[];
let mut names = vec::from_fn(self.name_positions.len(), |_| None);
let args = names.move_iter().map(|a| a.unwrap());
let mut args = locals.move_iter().chain(args);
- // Next, build up the actual call to the sprintf function.
+ let mut fmt_args = match extra {
+ Some(e) => ~[e], None => ~[]
+ };
+ fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name));
+ fmt_args.push(self.ecx.expr_vec(self.fmtsp, args.collect()));
+
+ // Next, build up the actual call to the {s,f}printf function.
let result = self.ecx.expr_call_global(self.fmtsp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
- self.ecx.ident_of("sprintf"),
- ], ~[
- self.ecx.expr_ident(self.fmtsp, static_name),
- self.ecx.expr_vec(self.fmtsp, args.collect()),
- ]);
+ self.ecx.ident_of(f),
+ ], fmt_args);
// sprintf is unsafe, but we just went through a lot of work to
// validate that our call is save, so inject the unsafe block for the
}
}
-pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
- tts: &[ast::token_tree]) -> base::MacResult {
+pub fn expand_format(ecx: @ExtCtxt, sp: span,
+ tts: &[ast::token_tree]) -> base::MacResult {
+ expand_ifmt(ecx, sp, tts, false, false, "format")
+}
+
+pub fn expand_write(ecx: @ExtCtxt, sp: span,
+ tts: &[ast::token_tree]) -> base::MacResult {
+ expand_ifmt(ecx, sp, tts, true, false, "write")
+}
+
+pub fn expand_writeln(ecx: @ExtCtxt, sp: span,
+ tts: &[ast::token_tree]) -> base::MacResult {
+ expand_ifmt(ecx, sp, tts, true, true, "write")
+}
+
+fn expand_ifmt(ecx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
+ leading_arg: bool, append_newline: bool,
+ function: &str) -> base::MacResult {
let mut cx = Context {
ecx: ecx,
args: ~[],
method_statics: ~[],
fmtsp: sp,
};
- let efmt = match cx.parse_args(sp, tts) {
- Some(e) => e,
- None => { return MRExpr(ecx.expr_uint(sp, 2)); }
+ let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) {
+ (extra, Some(e)) => (extra, e),
+ (_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); }
};
cx.fmtsp = efmt.span;
let fmt = expr_to_str(ecx, efmt,
- "first argument to ifmt! must be a string literal.");
+ "format argument must be a string literal.");
+ let fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() };
let mut err = false;
do parse::parse_error::cond.trap(|m| {
}
}
- MRExpr(cx.to_expr())
+ MRExpr(cx.to_expr(extra, function))
}
use codemap;
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
-use parse::parser::Parser;
use parse::attr::parser_attr;
+use parse::parser::{LifetimeAndTypesWithoutColons, Parser};
use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
use parse::token;
_ => p.fatal(~"expected ident, found "
+ token::to_str(get_ident_interner(), p.token))
},
- "path" => token::nt_path(~p.parse_path_with_tps(false)),
+ "path" => {
+ token::nt_path(~p.parse_path(LifetimeAndTypesWithoutColons).path)
+ }
"attr" => token::nt_attr(@p.parse_attribute(false)),
"tt" => {
*p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
ast::Path {
span: fld.new_span(p.span),
global: p.global,
- idents: p.idents.map(|x| fld.fold_ident(*x)),
- rp: p.rp,
- types: p.types.map(|x| fld.fold_ty(x)),
+ segments: p.segments.map(|segment| ast::PathSegment {
+ identifier: fld.fold_ident(segment.identifier),
+ lifetime: segment.lifetime,
+ types: segment.types.map(|typ| fld.fold_ty(typ)),
+ })
}
}
}
pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
- for tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); }
+ for segment in p.segments.iter() {
+ for typ in segment.types.iter() {
+ (v.visit_ty)(typ, (e.clone(), v))
+ }
+ }
}
pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {
span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
}
- #[test] fn path_exprs_1 () {
+ #[test] fn path_exprs_1() {
assert_eq!(string_to_expr(@"a"),
- @ast::expr{id:1,
- node:ast::expr_path(ast::Path {span:sp(0,1),
- global:false,
- idents:~[str_to_ident("a")],
- rp:None,
- types:~[]}),
- span:sp(0,1)})
+ @ast::expr{
+ id: 1,
+ node: ast::expr_path(ast::Path {
+ span: sp(0, 1),
+ global: false,
+ segments: ~[
+ ast::PathSegment {
+ identifier: str_to_ident("a"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ }),
+ span: sp(0, 1)
+ })
}
#[test] fn path_exprs_2 () {
assert_eq!(string_to_expr(@"::a::b"),
- @ast::expr{id:1,
- node:ast::expr_path(
- ast::Path {span:sp(0,6),
- global:true,
- idents:strs_to_idents(~["a","b"]),
- rp:None,
- types:~[]}),
- span:sp(0,6)})
+ @ast::expr {
+ id:1,
+ node: ast::expr_path(ast::Path {
+ span: sp(0, 6),
+ global: true,
+ segments: ~[
+ ast::PathSegment {
+ identifier: str_to_ident("a"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ },
+ ast::PathSegment {
+ identifier: str_to_ident("b"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ]
+ }),
+ span: sp(0, 6)
+ })
}
#[should_fail]
#[test] fn ret_expr() {
assert_eq!(string_to_expr(@"return d"),
- @ast::expr{id:2,
- node:ast::expr_ret(
- Some(@ast::expr{id:1,
- node:ast::expr_path(
- ast::Path{span:sp(7,8),
- global:false,
- idents:~[str_to_ident("d")],
- rp:None,
- types:~[]
- }),
- span:sp(7,8)})),
- span:sp(0,8)})
+ @ast::expr{
+ id:2,
+ node:ast::expr_ret(Some(@ast::expr{
+ id:1,
+ node:ast::expr_path(ast::Path{
+ span: sp(7, 8),
+ global: false,
+ segments: ~[
+ ast::PathSegment {
+ identifier: str_to_ident("d"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ }),
+ span:sp(7,8)
+ })),
+ span:sp(0,8)
+ })
}
#[test] fn parse_stmt_1 () {
assert_eq!(string_to_stmt(@"b;"),
@spanned{
- node: ast::stmt_expr(@ast::expr{
+ node: ast::stmt_expr(@ast::expr {
id: 1,
- node: ast::expr_path(
- ast::Path{
- span:sp(0,1),
- global:false,
- idents:~[str_to_ident("b")],
- rp:None,
- types: ~[]}),
+ node: ast::expr_path(ast::Path {
+ span:sp(0,1),
+ global:false,
+ segments: ~[
+ ast::PathSegment {
+ identifier: str_to_ident("b"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ }),
span: sp(0,1)},
2), // fixme
span: sp(0,1)})
let parser = string_to_parser(@"b");
assert_eq!(parser.parse_pat(),
@ast::pat{id:1, // fixme
- node: ast::pat_ident(ast::bind_infer,
- ast::Path{
- span:sp(0,1),
- global:false,
- idents:~[str_to_ident("b")],
- rp: None,
- types: ~[]},
- None // no idea
- ),
+ node: ast::pat_ident(
+ ast::bind_infer,
+ ast::Path {
+ span:sp(0,1),
+ global:false,
+ segments: ~[
+ ast::PathSegment {
+ identifier: str_to_ident("b"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ },
+ None /* no idea */),
span: sp(0,1)});
parser_done(parser);
}
- #[test] fn parse_arg () {
- let parser = string_to_parser(@"b : int");
- assert_eq!(parser.parse_arg_general(true),
- ast::arg{
- is_mutbl: false,
- ty: ast::Ty{id:3, // fixme
- node: ast::ty_path(ast::Path{
- span:sp(4,4), // this is bizarre...
- // check this in the original parser?
- global:false,
- idents:~[str_to_ident("int")],
- rp: None,
- types: ~[]},
- None, 2),
- span:sp(4,7)},
- pat: @ast::pat{id:1,
- node: ast::pat_ident(ast::bind_infer,
- ast::Path{
- span:sp(0,1),
- global:false,
- idents:~[str_to_ident("b")],
- rp: None,
- types: ~[]},
- None // no idea
- ),
- span: sp(0,1)},
- id: 4 // fixme
- })
- }
-
// check the contents of the tt manually:
#[test] fn parse_fundecl () {
// this test depends on the intern order of "fn" and "int", and on the
node: ast::ty_path(ast::Path{
span:sp(10,13),
global:false,
- idents:~[str_to_ident("int")],
- rp: None,
- types: ~[]},
- None, 2),
- span:sp(10,13)},
- pat: @ast::pat{id:1, // fixme
- node: ast::pat_ident(
- ast::bind_infer,
- ast::Path{
- span:sp(6,7),
- global:false,
- idents:~[str_to_ident("b")],
- rp: None,
- types: ~[]},
- None // no idea
- ),
- span: sp(6,7)},
+ segments: ~[
+ ast::PathSegment {
+ identifier:
+ str_to_ident("int"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ }, None, 2),
+ span:sp(10,13)
+ },
+ pat: @ast::pat {
+ id:1, // fixme
+ node: ast::pat_ident(
+ ast::bind_infer,
+ ast::Path {
+ span:sp(6,7),
+ global:false,
+ segments: ~[
+ ast::PathSegment {
+ identifier:
+ str_to_ident("b"),
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ ],
+ },
+ None // no idea
+ ),
+ span: sp(6,7)
+ },
id: 4 // fixme
}],
output: ast::Ty{id:5, // fixme
ast::Path{
span:sp(17,18),
global:false,
- idents:~[str_to_ident("b")],
- rp:None,
- types: ~[]}),
+ segments: ~[
+ ast::PathSegment {
+ identifier:
+ str_to_ident(
+ "b"),
+ lifetime:
+ None,
+ types:
+ opt_vec::Empty
+ }
+ ],
+ }),
span: sp(17,18)},
7), // fixme
span: sp(17,18)}],
ObsoleteMode,
ObsoleteImplicitSelf,
ObsoleteLifetimeNotation,
- ObsoleteConstManagedPointer,
ObsoletePurity,
ObsoleteStaticMethod,
ObsoleteConstItem,
ObsoleteUnsafeExternFn,
ObsoletePrivVisibility,
ObsoleteTraitFuncVisibility,
+ ObsoleteConstPointer,
}
impl to_bytes::IterBytes for ObsoleteSyntax {
"instead of `&foo/bar`, write `&'foo bar`; instead of \
`bar/&foo`, write `&bar<'foo>"
),
- ObsoleteConstManagedPointer => (
- "const `@` pointer",
- "instead of `@const Foo`, write `@Foo`"
- ),
ObsoletePurity => (
"pure function",
"remove `pure`"
"visibility not necessary",
"trait functions inherit the visibility of the trait itself"
),
+ ObsoleteConstPointer => (
+ "const pointer",
+ "instead of `&const Foo` or `@const Foo`, write `&Foo` or \
+ `@Foo`"
+ ),
};
self.report(sp, kind, kind_str, desc);
use ast::{item_enum, item_fn, item_foreign_mod, item_impl};
use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_};
use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int};
-use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local, m_const};
+use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local};
use ast::{m_imm, m_mutbl, mac_, mac_invoc_tt, matcher, match_nonterminal};
use ast::{match_seq, match_tok, method, mt, mul, mutability};
use ast::{named_field, neg, NodeId, noreturn, not, pat, pat_box, pat_enum};
type arg_or_capture_item = Either<arg, ()>;
type item_info = (ident, item_, Option<~[Attribute]>);
+/// How to parse a path. There are four different kinds of paths, all of which
+/// are parsed somewhat differently.
+#[deriving(Eq)]
+pub enum PathParsingMode {
+ /// A path with no type parameters; e.g. `foo::bar::Baz`
+ NoTypesAllowed,
+ /// A path with a lifetime and type parameters, with no double colons
+ /// before the type parameters; e.g. `foo::bar<'self>::Baz<T>`
+ LifetimeAndTypesWithoutColons,
+ /// A path with a lifetime and type parameters with double colons before
+ /// the type parameters; e.g. `foo::bar::<'self>::Baz::<T>`
+ LifetimeAndTypesWithColons,
+ /// A path with a lifetime and type parameters with bounds before the last
+ /// set of type parameters only; e.g. `foo::bar<'self>::Baz:X+Y<T>` This
+ /// form does not use extra double colons.
+ LifetimeAndTypesAndBounds,
+}
+
+/// A pair of a path segment and group of type parameter bounds. (See `ast.rs`
+/// for the definition of a path segment.)
+struct PathSegmentAndBoundSet {
+ segment: ast::PathSegment,
+ bound_set: Option<OptVec<TyParamBound>>,
+}
+
+/// A path paired with optional type bounds.
+struct PathAndBounds {
+ path: ast::Path,
+ bounds: Option<OptVec<TyParamBound>>,
+}
+
pub enum item_or_view_item {
// Indicates a failure to parse any kind of item. The attributes are
// returned.
} else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) {
// NAMED TYPE
- let (path, bounds) = self.parse_type_path();
+ let PathAndBounds {
+ path,
+ bounds
+ } = self.parse_path(LifetimeAndTypesAndBounds);
ty_path(path, bounds, self.get_id())
} else {
self.fatal(fmt!("expected type, found token %?",
if mt.mutbl != m_imm && sigil == OwnedSigil {
self.obsolete(*self.last_span, ObsoleteMutOwnedPointer);
}
- if mt.mutbl == m_const && sigil == ManagedSigil {
- self.obsolete(*self.last_span, ObsoleteConstManagedPointer);
- }
ctor(mt)
}
}
}
- // parse a path into a vector of idents, whether the path starts
- // with ::, and a span.
- pub fn parse_path(&self) -> (~[ast::ident],bool,span) {
+ /// Parses a path and optional type parameter bounds, depending on the
+ /// mode. The `mode` parameter determines whether lifetimes, types, and/or
+ /// bounds are permitted and whether `::` must precede type parameter
+ /// groups.
+ pub fn parse_path(&self, mode: PathParsingMode) -> PathAndBounds {
+ // Check for a whole path...
+ let found = match *self.token {
+ INTERPOLATED(token::nt_path(_)) => Some(self.bump_and_get()),
+ _ => None,
+ };
+ match found {
+ Some(INTERPOLATED(token::nt_path(~path))) => {
+ return PathAndBounds {
+ path: path,
+ bounds: None,
+ }
+ }
+ _ => {}
+ }
+
let lo = self.span.lo;
let is_global = self.eat(&token::MOD_SEP);
- let (ids,span{lo:_,hi,expn_info}) = self.parse_path_non_global();
- (ids,is_global,span{lo:lo,hi:hi,expn_info:expn_info})
- }
- // parse a path beginning with an identifier into a vector of idents and a span
- pub fn parse_path_non_global(&self) -> (~[ast::ident],span) {
- let lo = self.span.lo;
- let mut ids = ~[];
- // must be at least one to begin:
- ids.push(self.parse_ident());
+ // Parse any number of segments and bound sets. A segment is an
+ // identifier followed by an optional lifetime and a set of types.
+ // A bound set is a set of type parameter bounds.
+ let mut segments = ~[];
loop {
+ // First, parse an identifier.
match *self.token {
- token::MOD_SEP => {
- let is_ident = do self.look_ahead(1) |t| {
- match *t {
- token::IDENT(*) => true,
- _ => false,
- }
- };
- if is_ident {
- self.bump();
- ids.push(self.parse_ident());
- } else {
- break
- }
- }
- _ => break
+ token::IDENT(*) => {}
+ _ => break,
}
- }
- (ids, mk_sp(lo, self.last_span.hi))
- }
+ let identifier = self.parse_ident();
- // parse a path that doesn't have type parameters attached
- pub fn parse_path_without_tps(&self) -> ast::Path {
- maybe_whole!(deref self, nt_path);
- let (ids,is_global,sp) = self.parse_path();
- ast::Path { span: sp,
- global: is_global,
- idents: ids,
- rp: None,
- types: ~[] }
- }
+ // Next, parse a colon and bounded type parameters, if applicable.
+ let bound_set = if mode == LifetimeAndTypesAndBounds {
+ self.parse_optional_ty_param_bounds()
+ } else {
+ None
+ };
- pub fn parse_bounded_path_with_tps(&self, colons: bool,
- before_tps: Option<&fn()>) -> ast::Path {
- debug!("parse_path_with_tps(colons=%b)", colons);
+ // Parse the '::' before type parameters if it's required. If
+ // it is required and wasn't present, then we're done.
+ if mode == LifetimeAndTypesWithColons &&
+ !self.eat(&token::MOD_SEP) {
+ segments.push(PathSegmentAndBoundSet {
+ segment: ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ },
+ bound_set: bound_set
+ });
+ break
+ }
- maybe_whole!(deref self, nt_path);
- let lo = self.span.lo;
- let path = self.parse_path_without_tps();
- if colons && !self.eat(&token::MOD_SEP) {
- return path;
- }
-
- // If the path might have bounds on it, they should be parsed before
- // the parameters, e.g. module::TraitName:B1+B2<T>
- before_tps.map_move(|callback| callback());
-
- // Parse the (obsolete) trailing region parameter, if any, which will
- // be written "foo/&x"
- let rp_slash = {
- if *self.token == token::BINOP(token::SLASH)
- && self.look_ahead(1, |t| *t == token::BINOP(token::AND))
- {
- self.bump(); self.bump();
- self.obsolete(*self.last_span, ObsoleteLifetimeNotation);
- match *self.token {
- token::IDENT(sid, _) => {
- let span = self.span;
- self.bump();
- Some(ast::Lifetime {
- id: self.get_id(),
- span: *span,
- ident: sid
- })
+ // Parse the `<` before the lifetime and types, if applicable.
+ let (any_lifetime_or_types, optional_lifetime, types) =
+ if mode != NoTypesAllowed && self.eat(&token::LT) {
+ // Parse an optional lifetime.
+ let optional_lifetime = match *self.token {
+ token::LIFETIME(*) => Some(self.parse_lifetime()),
+ _ => None,
+ };
+
+ // Parse type parameters.
+ let mut types = opt_vec::Empty;
+ let mut need_comma = optional_lifetime.is_some();
+ loop {
+ // We're done if we see a `>`.
+ match *self.token {
+ token::GT | token::BINOP(token::SHR) => {
+ self.expect_gt();
+ break
+ }
+ _ => {} // Go on.
}
- _ => {
- self.fatal(fmt!("Expected a lifetime name"));
+
+ if need_comma {
+ self.expect(&token::COMMA)
+ } else {
+ need_comma = true
}
+
+ types.push(self.parse_ty(false))
}
+
+ (true, optional_lifetime, types)
} else {
- None
- }
- };
+ (false, None, opt_vec::Empty)
+ };
- // Parse any lifetime or type parameters which may appear:
- let (lifetimes, tps) = self.parse_generic_values();
- let hi = self.span.lo;
+ // Assemble and push the result.
+ segments.push(PathSegmentAndBoundSet {
+ segment: ast::PathSegment {
+ identifier: identifier,
+ lifetime: optional_lifetime,
+ types: types,
+ },
+ bound_set: bound_set
+ });
- let rp = match (&rp_slash, &lifetimes) {
- (&Some(_), _) => rp_slash,
- (&None, v) => {
- if v.len() == 0 {
- None
- } else if v.len() == 1 {
- Some(*v.get(0))
- } else {
- self.fatal(fmt!("Expected at most one \
- lifetime name (for now)"));
+ // We're done if we don't see a '::', unless the mode required
+ // a double colon to get here in the first place.
+ if !(mode == LifetimeAndTypesWithColons &&
+ !any_lifetime_or_types) {
+ if !self.eat(&token::MOD_SEP) {
+ break
}
}
- };
-
- ast::Path {
- span: mk_sp(lo, hi),
- rp: rp,
- types: tps,
- .. path.clone()
}
- }
- // parse a path optionally with type parameters. If 'colons'
- // is true, then type parameters must be preceded by colons,
- // as in a::t::<t1,t2>
- pub fn parse_path_with_tps(&self, colons: bool) -> ast::Path {
- self.parse_bounded_path_with_tps(colons, None)
- }
+ // Assemble the span.
+ let span = mk_sp(lo, self.last_span.hi);
- // Like the above, but can also parse kind bounds in the case of a
- // path to be used as a type that might be a trait.
- pub fn parse_type_path(&self) -> (ast::Path, Option<OptVec<TyParamBound>>) {
+ // Assemble the path segments.
+ let mut path_segments = ~[];
let mut bounds = None;
- let path = self.parse_bounded_path_with_tps(false, Some(|| {
- // Note: this closure might not even get called in the case of a
- // macro-generated path. But that's the macro parser's job.
- bounds = self.parse_optional_ty_param_bounds();
- }));
- (path, bounds)
+ let last_segment_index = segments.len() - 1;
+ for (i, segment_and_bounds) in segments.move_iter().enumerate() {
+ let PathSegmentAndBoundSet {
+ segment: segment,
+ bound_set: bound_set
+ } = segment_and_bounds;
+ path_segments.push(segment);
+
+ if bound_set.is_some() {
+ if i != last_segment_index {
+ self.span_err(span,
+ "type parameter bounds are allowed only \
+ before the last segment in a path")
+ }
+
+ bounds = bound_set
+ }
+ }
+
+ // Assemble the result.
+ let path_and_bounds = PathAndBounds {
+ path: ast::Path {
+ span: span,
+ global: is_global,
+ segments: path_segments,
+ },
+ bounds: bounds,
+ };
+
+ path_and_bounds
}
/// parses 0 or 1 lifetime
if self.eat_keyword(keywords::Mut) {
m_mutbl
} else if self.eat_keyword(keywords::Const) {
- m_const
+ self.obsolete(*self.last_span, ObsoleteConstPointer);
+ m_imm
} else {
m_imm
}
} else if *self.token == token::LBRACKET {
self.bump();
let mutbl = self.parse_mutability();
- if mutbl == m_mutbl || mutbl == m_const {
+ if mutbl == m_mutbl {
self.obsolete(*self.last_span, ObsoleteMutVector);
}
} else if *self.token == token::MOD_SEP ||
is_ident(&*self.token) && !self.is_keyword(keywords::True) &&
!self.is_keyword(keywords::False) {
- let pth = self.parse_path_with_tps(true);
+ let pth = self.parse_path(LifetimeAndTypesWithColons).path;
// `!`, as an operator, is prefix, so we know this isn't that
if *self.token == token::NOT {
token::AT => {
self.bump();
let m = self.parse_mutability();
- if m == m_const {
- self.obsolete(*self.last_span, ObsoleteConstManagedPointer);
- }
-
let e = self.parse_prefix_expr();
hi = e.span.hi;
// HACK: turn @[...] into a @-evec
let val = self.parse_literal_maybe_minus();
if self.eat(&token::DOTDOT) {
let end = if is_ident_or_path(tok) {
- let path = self.parse_path_with_tps(true);
+ let path = self.parse_path(LifetimeAndTypesWithColons)
+ .path;
let hi = self.span.hi;
self.mk_expr(lo, hi, expr_path(path))
} else {
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
pat = pat_range(start, end);
} else if is_plain_ident(&*self.token) && !can_be_enum_or_struct {
- let name = self.parse_path_without_tps();
+ let name = self.parse_path(NoTypesAllowed).path;
let sub;
if self.eat(&token::AT) {
// parse foo @ pat
pat = pat_ident(bind_infer, name, sub);
} else {
// parse an enum pat
- let enum_path = self.parse_path_with_tps(true);
+ let enum_path = self.parse_path(LifetimeAndTypesWithColons)
+ .path;
match *self.token {
token::LBRACE => {
self.bump();
}
},
_ => {
- if enum_path.idents.len()==1u {
+ if enum_path.segments.len() == 1 {
// it could still be either an enum
// or an identifier pattern, resolve
// will sort it out:
"expected identifier, found path");
}
// why a path here, and not just an identifier?
- let name = self.parse_path_without_tps();
+ let name = self.parse_path(NoTypesAllowed).path;
let sub = if self.eat(&token::AT) {
Some(self.parse_pat())
} else {
// Potential trouble: if we allow macros with paths instead of
// idents, we'd need to look ahead past the whole path here...
- let pth = self.parse_path_without_tps();
+ let pth = self.parse_path(NoTypesAllowed).path;
self.bump();
let id = if *self.token == token::LPAREN {
// parse a::B<~str,int>
fn parse_trait_ref(&self) -> trait_ref {
ast::trait_ref {
- path: self.parse_path_with_tps(false),
+ path: self.parse_path(LifetimeAndTypesWithoutColons).path,
ref_id: self.get_id(),
}
}
}
// item macro.
- let pth = self.parse_path_without_tps();
+ let pth = self.parse_path(NoTypesAllowed).path;
self.expect(&token::NOT);
// a 'special' identifier (like what `macro_rules!` uses)
let id = self.parse_ident();
path.push(id);
}
- let path = ast::Path { span: mk_sp(lo, self.span.hi),
- global: false,
- idents: path,
- rp: None,
- types: ~[] };
+ let path = ast::Path {
+ span: mk_sp(lo, self.span.hi),
+ global: false,
+ segments: path.move_iter().map(|identifier| {
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect()
+ };
return @spanned(lo, self.span.hi,
view_path_simple(first_ident,
path,
seq_sep_trailing_allowed(token::COMMA),
|p| p.parse_path_list_ident()
);
- let path = ast::Path { span: mk_sp(lo, self.span.hi),
- global: false,
- idents: path,
- rp: None,
- types: ~[] };
+ let path = ast::Path {
+ span: mk_sp(lo, self.span.hi),
+ global: false,
+ segments: path.move_iter().map(|identifier| {
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect()
+ };
return @spanned(lo, self.span.hi,
view_path_list(path, idents, self.get_id()));
}
// foo::bar::*
token::BINOP(token::STAR) => {
self.bump();
- let path = ast::Path { span: mk_sp(lo, self.span.hi),
- global: false,
- idents: path,
- rp: None,
- types: ~[] };
+ let path = ast::Path {
+ span: mk_sp(lo, self.span.hi),
+ global: false,
+ segments: path.move_iter().map(|identifier| {
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect()
+ };
return @spanned(lo, self.span.hi,
view_path_glob(path, self.get_id()));
}
_ => ()
}
let last = path[path.len() - 1u];
- let path = ast::Path { span: mk_sp(lo, self.span.hi),
- global: false,
- idents: path,
- rp: None,
- types: ~[] };
+ let path = ast::Path {
+ span: mk_sp(lo, self.span.hi),
+ global: false,
+ segments: path.move_iter().map(|identifier| {
+ ast::PathSegment {
+ identifier: identifier,
+ lifetime: None,
+ types: opt_vec::Empty,
+ }
+ }).collect()
+ };
return @spanned(lo,
self.last_span.hi,
view_path_simple(last, path, self.get_id()));
word(s.s, "[");
match mt.mutbl {
ast::m_mutbl => word_space(s, "mut"),
- ast::m_const => word_space(s, "const"),
ast::m_imm => ()
}
print_type(s, mt.ty);
word(s.s, "[");
match mt.mutbl {
ast::m_mutbl => word_space(s, "mut"),
- ast::m_const => word_space(s, "const"),
ast::m_imm => ()
}
print_type(s, mt.ty);
print_expr(s, coll);
}
-fn print_path_(s: @ps, path: &ast::Path, colons_before_params: bool,
+fn print_path_(s: @ps,
+ path: &ast::Path,
+ colons_before_params: bool,
opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
maybe_print_comment(s, path.span.lo);
- if path.global { word(s.s, "::"); }
- let mut first = true;
- for id in path.idents.iter() {
- if first { first = false; } else { word(s.s, "::"); }
- print_ident(s, *id);
+ if path.global {
+ word(s.s, "::");
}
- do opt_bounds.map |bounds| {
- print_bounds(s, bounds, true);
- };
- if path.rp.is_some() || !path.types.is_empty() {
- if colons_before_params { word(s.s, "::"); }
- if path.rp.is_some() || !path.types.is_empty() {
+ let mut first = true;
+ for (i, segment) in path.segments.iter().enumerate() {
+ if first {
+ first = false
+ } else {
+ word(s.s, "::")
+ }
+
+ print_ident(s, segment.identifier);
+
+ if segment.lifetime.is_some() || !segment.types.is_empty() {
+ // If this is the last segment, print the bounds.
+ if i == path.segments.len() - 1 {
+ match *opt_bounds {
+ None => {}
+ Some(ref bounds) => print_bounds(s, bounds, true),
+ }
+ }
+
+ if colons_before_params {
+ word(s.s, "::")
+ }
word(s.s, "<");
- for r in path.rp.iter() {
- print_lifetime(s, r);
- if !path.types.is_empty() {
- word_space(s, ",");
+ for lifetime in segment.lifetime.iter() {
+ print_lifetime(s, lifetime);
+ if !segment.types.is_empty() {
+ word_space(s, ",")
}
}
- commasep(s, inconsistent, path.types, print_type);
+ commasep(s,
+ inconsistent,
+ segment.types.map_to_vec(|t| (*t).clone()),
+ print_type);
- word(s.s, ">");
+ word(s.s, ">")
}
}
}
pub fn print_view_path(s: @ps, vp: &ast::view_path) {
match vp.node {
ast::view_path_simple(ident, ref path, _) => {
- if path.idents[path.idents.len()-1u] != ident {
+ if path.segments.last().identifier != ident {
print_ident(s, ident);
space(s.s);
word_space(s, "=");
pub fn print_mutability(s: @ps, mutbl: ast::mutability) {
match mutbl {
ast::m_mutbl => word_nbsp(s, "mut"),
- ast::m_const => word_nbsp(s, "const"),
ast::m_imm => {/* nothing */ }
}
}
_ => {
match input.pat.node {
ast::pat_ident(_, ref path, _) if
- path.idents.len() == 1 &&
- path.idents[0] == parse::token::special_idents::invalid => {
+ path.segments.len() == 1 &&
+ path.segments[0].identifier ==
+ parse::token::special_idents::invalid => {
// Do nothing.
}
_ => {
}
pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
- for typ in path.types.iter() {
- visitor.visit_ty(typ, env.clone())
+ for segment in path.segments.iter() {
+ for typ in segment.types.iter() {
+ visitor.visit_ty(typ, env.clone())
+ }
}
}
-Subproject commit dfae9c3e958dc086d9c0ab068cd76d196c95a433
+Subproject commit ef2bcd134164adcaa072dcb56e62b737fdcb075e
anyhow.
*/
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
#define SWAP_REGISTERS _swap_registers
#else
#define SWAP_REGISTERS swap_registers
mov %r14, (RUSTRT_R14*8)(ARG0)
mov %r15, (RUSTRT_R15*8)(ARG0)
+#if defined(__MINGW32__) || defined(_WINDOWS)
+ mov %rdi, (RUSTRT_RDI*8)(ARG0)
+ mov %rsi, (RUSTRT_RSI*8)(ARG0)
+
+ // Save stack range
+ mov %gs:0x08, %r8
+ mov %r8, (RUSTRT_ST1*8)(ARG0)
+ mov %gs:0x10, %r9
+ mov %r9, (RUSTRT_ST2*8)(ARG0)
+#endif
+
// Save 0th argument register:
mov ARG0, (RUSTRT_ARG0*8)(ARG0)
// Save non-volatile XMM registers:
+#if defined(__MINGW32__) || defined(_WINDOWS)
+ movapd %xmm6, (RUSTRT_XMM6*8)(ARG0)
+ movapd %xmm7, (RUSTRT_XMM7*8)(ARG0)
+ movapd %xmm8, (RUSTRT_XMM8*8)(ARG0)
+ movapd %xmm9, (RUSTRT_XMM9*8)(ARG0)
+ movapd %xmm10, (RUSTRT_XMM10*8)(ARG0)
+ movapd %xmm11, (RUSTRT_XMM11*8)(ARG0)
+ movapd %xmm12, (RUSTRT_XMM12*8)(ARG0)
+ movapd %xmm13, (RUSTRT_XMM13*8)(ARG0)
+ movapd %xmm14, (RUSTRT_XMM14*8)(ARG0)
+ movapd %xmm15, (RUSTRT_XMM15*8)(ARG0)
+#else
movapd %xmm0, (RUSTRT_XMM0*8)(ARG0)
movapd %xmm1, (RUSTRT_XMM1*8)(ARG0)
movapd %xmm2, (RUSTRT_XMM2*8)(ARG0)
movapd %xmm3, (RUSTRT_XMM3*8)(ARG0)
movapd %xmm4, (RUSTRT_XMM4*8)(ARG0)
movapd %xmm5, (RUSTRT_XMM5*8)(ARG0)
+#endif
// Restore non-volatile integer registers:
// (including RSP)
mov (RUSTRT_R14*8)(ARG1), %r14
mov (RUSTRT_R15*8)(ARG1), %r15
+#if defined(__MINGW32__) || defined(_WINDOWS)
+ mov (RUSTRT_RDI*8)(ARG1), %rdi
+ mov (RUSTRT_RSI*8)(ARG1), %rsi
+
+ // Restore stack range
+ mov (RUSTRT_ST1*8)(ARG1), %r8
+ mov %r8, %gs:0x08
+ mov (RUSTRT_ST2*8)(ARG1), %r9
+ mov %r9, %gs:0x10
+#endif
+
// Restore 0th argument register:
mov (RUSTRT_ARG0*8)(ARG1), ARG0
// Restore non-volatile XMM registers:
+#if defined(__MINGW32__) || defined(_WINDOWS)
+ movapd (RUSTRT_XMM6*8)(ARG1), %xmm6
+ movapd (RUSTRT_XMM7*8)(ARG1), %xmm7
+ movapd (RUSTRT_XMM8*8)(ARG1), %xmm8
+ movapd (RUSTRT_XMM9*8)(ARG1), %xmm9
+ movapd (RUSTRT_XMM10*8)(ARG1), %xmm10
+ movapd (RUSTRT_XMM11*8)(ARG1), %xmm11
+ movapd (RUSTRT_XMM12*8)(ARG1), %xmm12
+ movapd (RUSTRT_XMM13*8)(ARG1), %xmm13
+ movapd (RUSTRT_XMM14*8)(ARG1), %xmm14
+ movapd (RUSTRT_XMM15*8)(ARG1), %xmm15
+#else
movapd (RUSTRT_XMM0*8)(ARG1), %xmm0
movapd (RUSTRT_XMM1*8)(ARG1), %xmm1
movapd (RUSTRT_XMM2*8)(ARG1), %xmm2
movapd (RUSTRT_XMM3*8)(ARG1), %xmm3
movapd (RUSTRT_XMM4*8)(ARG1), %xmm4
movapd (RUSTRT_XMM5*8)(ARG1), %xmm5
+#endif
// Jump to the instruction pointer
// found in regs:
.text
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
.globl ___morestack
.private_extern MORESTACK
___morestack:
+#elif defined(_WIN32)
+.globl __morestack
+__morestack:
#else
.globl __morestack
.hidden __morestack
.text
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
#define UPCALL_NEW_STACK _upcall_new_stack
#define UPCALL_DEL_STACK _upcall_del_stack
#define MORESTACK ___morestack
#define RUSTRT_R14 6
#define RUSTRT_R15 7
#define RUSTRT_IP 8
-// Not used, just padding
-#define RUSTRT_XXX 9
-#define RUSTRT_XMM0 10
-#define RUSTRT_XMM1 12
-#define RUSTRT_XMM2 14
-#define RUSTRT_XMM3 16
-#define RUSTRT_XMM4 18
-#define RUSTRT_XMM5 20
-#define RUSTRT_MAX 22
+#if defined(__MINGW32__) || defined(_WINDOWS)
+ #define RUSTRT_RDI 9
+ #define RUSTRT_RSI 10
+ #define RUSTRT_ST1 11
+ #define RUSTRT_ST2 12
+ #define RUSTRT_XMM6 14
+ #define RUSTRT_XMM7 16
+ #define RUSTRT_XMM8 18
+ #define RUSTRT_XMM9 20
+ #define RUSTRT_XMM10 22
+ #define RUSTRT_XMM11 24
+ #define RUSTRT_XMM12 26
+ #define RUSTRT_XMM13 28
+ #define RUSTRT_XMM14 30
+ #define RUSTRT_XMM15 32
+ #define RUSTRT_MAX 34
+#else
+ // Not used, just padding
+ #define RUSTRT_XXX 9
+ #define RUSTRT_XMM0 10
+ #define RUSTRT_XMM1 12
+ #define RUSTRT_XMM2 14
+ #define RUSTRT_XMM3 16
+ #define RUSTRT_XMM4 18
+ #define RUSTRT_XMM5 20
+ #define RUSTRT_MAX 22
+#endif
// ARG0 is the register in which the first argument goes.
// Naturally this depends on your operating system.
asm volatile (
"movq %%fs:24, %0"
: "=r"(limit));
+#elif defined(_WIN64)
+ asm volatile (
+ "movq %%gs:0x28, %0"
+ : "=r"(limit));
#endif
return limit;
asm volatile (
"movq %0, %%fs:24"
:: "r"(limit));
+#elif defined(_WIN64)
+ asm volatile (
+ "movq %0, %%gs:0x28"
+ :: "r"(limit));
#endif
}
// except according to those terms.
-#include "sync/sync.h"
#include "memory_region.h"
#if RUSTRT_TRACK_ALLOCATIONS >= 3
# endif
}
-memory_region::memory_region(bool synchronized,
- bool detailed_leaks,
+memory_region::memory_region(bool detailed_leaks,
bool poison_on_free) :
_parent(NULL), _live_allocations(0),
_detailed_leaks(detailed_leaks),
- _poison_on_free(poison_on_free),
- _synchronized(synchronized) {
+ _poison_on_free(poison_on_free) {
}
memory_region::memory_region(memory_region *parent) :
_parent(parent), _live_allocations(0),
_detailed_leaks(parent->_detailed_leaks),
- _poison_on_free(parent->_poison_on_free),
- _synchronized(parent->_synchronized) {
+ _poison_on_free(parent->_poison_on_free) {
}
void memory_region::add_alloc() {
- //_live_allocations++;
- sync::increment(_live_allocations);
+ _live_allocations++;
}
void memory_region::dec_alloc() {
- //_live_allocations--;
- sync::decrement(_live_allocations);
+ _live_allocations--;
}
void memory_region::free(void *mem) {
# endif
# if RUSTRT_TRACK_ALLOCATIONS >= 2
- if (_synchronized) { _lock.lock(); }
if (_allocation_list[newMem->index] != alloc) {
printf("at index %d, found %p, expected %p\n",
alloc->index, _allocation_list[alloc->index], alloc);
// printf("realloc: stored %p at index %d, replacing %p\n",
// newMem, index, mem);
}
- if (_synchronized) { _lock.unlock(); }
# endif
return get_data(newMem);
}
memory_region::~memory_region() {
- if (_synchronized) { _lock.lock(); }
if (_live_allocations == 0 && !_detailed_leaks) {
- if (_synchronized) { _lock.unlock(); }
return;
}
char msg[128];
fprintf(stderr, "%s\n", msg);
assert(false);
}
- if (_synchronized) { _lock.unlock(); }
}
void
# endif
# if RUSTRT_TRACK_ALLOCATIONS >= 2
- if (_synchronized) { _lock.lock(); }
if (((size_t) alloc->index) >= _allocation_list.size()) {
printf("free: ptr 0x%" PRIxPTR " (%s) index %d is beyond allocation_list of size %zu\n",
(uintptr_t) get_data(alloc), alloc->tag, alloc->index, _allocation_list.size());
_allocation_list[alloc->index] = NULL;
alloc->index = -1;
}
- if (_synchronized) { _lock.unlock(); }
# endif
dec_alloc();
# endif
# if RUSTRT_TRACK_ALLOCATIONS >= 2
- if (_synchronized) { _lock.lock(); }
alloc->index = _allocation_list.append(alloc);
- if (_synchronized) { _lock.unlock(); }
# endif
# if RUSTRT_TRACK_ALLOCATIONS >= 3
array_list<alloc_header *> _allocation_list;
const bool _detailed_leaks;
const bool _poison_on_free;
- const bool _synchronized;
lock_and_signal _lock;
void add_alloc();
memory_region& operator=(const memory_region& rhs);
public:
- memory_region(bool synchronized,
- bool detailed_leaks, bool poison_on_free);
+ memory_region(bool detailed_leaks, bool poison_on_free);
memory_region(memory_region *parent);
void *malloc(size_t size, const char *tag);
void *realloc(void *mem, size_t size);
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ABI-specific routines.
-
-#include <sstream>
-#include <string>
-#include <vector>
-#include <cstdlib>
-#include <stdint.h>
-#include "rust_abi.h"
-
-#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__)
-#define HAVE_DLFCN_H
-#include <dlfcn.h>
-#elif defined(_WIN32)
-// Otherwise it's windows.h -- included in rust_abi.h
-#endif
-
-#define END_OF_STACK_RA (void (*)())0xdeadbeef
-
-weak_symbol<uint32_t> abi_version("rust_abi_version");
-
-uint32_t get_abi_version() {
- return (*abi_version == NULL) ? 0 : **abi_version;
-}
-
-namespace stack_walk {
-
-#ifdef HAVE_DLFCN_H
-std::string
-frame::symbol() const {
- std::stringstream ss;
-
- Dl_info info;
- if (!dladdr((void *)ra, &info))
- ss << "??";
- else
- ss << info.dli_sname;
-
- ss << " @ " << std::hex << (uintptr_t)ra;
- return ss.str();
-}
-#else
-std::string
-frame::symbol() const {
- std::stringstream ss;
- ss << std::hex << (uintptr_t)ra;
- return ss.str();
-}
-#endif
-
-std::vector<frame>
-backtrace() {
- std::vector<frame> frames;
-
- // Ideally we would use the current value of EIP here, but there's no
- // portable way to get that and there are never any GC roots in our C++
- // frames anyhow.
- frame f(__builtin_frame_address(0), (void (*)())NULL);
-
- while (f.ra != END_OF_STACK_RA) {
- frames.push_back(f);
- f.next();
- }
- return frames;
-}
-
-std::string
-symbolicate(const std::vector<frame> &frames) {
- std::stringstream ss;
- std::vector<frame>::const_iterator begin(frames.begin()),
- end(frames.end());
- while (begin != end) {
- ss << begin->symbol() << std::endl;
- ++begin;
- }
- return ss.str();
-}
-
-} // end namespace stack_walk
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ABI-specific routines.
-
-#ifndef RUST_ABI_H
-#define RUST_ABI_H
-
-#include <cstdlib>
-#include <string>
-#include <vector>
-#include <stdint.h>
-
-#ifdef __WIN32__
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
-
-template<typename T>
-class weak_symbol {
-private:
- bool init;
- T *data;
- const char *name;
-
- void fill() {
- if (init)
- return;
-
-#ifdef __WIN32__
- data = (T *)GetProcAddress(GetModuleHandle(NULL), name);
-#else
- data = (T *)dlsym(RTLD_DEFAULT, name);
-#endif
-
- init = true;
- }
-
-public:
- weak_symbol(const char *in_name)
- : init(false), data(NULL), name(in_name) {}
-
- T *&operator*() { fill(); return data; }
-};
-
-namespace stack_walk {
-
-struct frame {
- uint8_t *bp; // The frame pointer.
- void (*ra)(); // The return address.
-
- frame(void *in_bp, void (*in_ra)()) : bp((uint8_t *)in_bp), ra(in_ra) {}
-
- inline void next() {
- ra = *(void (**)())(bp + sizeof(void *));
- bp = *(uint8_t **)bp;
- }
-
- std::string symbol() const;
-};
-
-std::vector<frame> backtrace();
-std::string symbolicate(const std::vector<frame> &frames);
-
-} // end namespace stack_walk
-
-
-uint32_t get_abi_version();
-
-#endif
/* Foreign builtins. */
#include "rust_util.h"
-#include "sync/timer.h"
#include "sync/rust_thread.h"
#include "sync/lock_and_signal.h"
#include "memory_region.h"
#include "boxed_region.h"
-#include "rust_abi.h"
#include "rust_rng.h"
#include "vg/valgrind.h"
#include "sp.h"
#ifdef __APPLE__
#include <crt_externs.h>
+#include <mach/mach_time.h>
#endif
#if !defined(__WIN32__)
free(rng);
}
-
-/* Debug helpers strictly to verify ABI conformance.
- *
- * FIXME (#2665): move these into a testcase when the testsuite
- * understands how to have explicit C files included.
- */
-
-struct quad {
- uint64_t a;
- uint64_t b;
- uint64_t c;
- uint64_t d;
-};
-
-struct floats {
- double a;
- uint8_t b;
- double c;
-};
-
-extern "C" quad
-debug_abi_1(quad q) {
- quad qq = { q.c + 1,
- q.d - 1,
- q.a + 1,
- q.b - 1 };
- return qq;
-}
-
-extern "C" floats
-debug_abi_2(floats f) {
- floats ff = { f.c + 1.0,
- 0xff,
- f.a - 1.0 };
- return ff;
-}
-
-extern "C" int
-debug_static_mut;
-
-int debug_static_mut = 3;
-
-extern "C" void
-debug_static_mut_check_four() {
- assert(debug_static_mut == 4);
-}
-
extern "C" CDECL char*
#if defined(__WIN32__)
rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) {
}
#endif
+const uint64_t ns_per_s = 1000000000LL;
+
extern "C" CDECL void
precise_time_ns(uint64_t *ns) {
- timer t;
- *ns = t.time_ns();
+
+#ifdef __APPLE__
+ uint64_t time = mach_absolute_time();
+ mach_timebase_info_data_t info = {0, 0};
+ if (info.denom == 0) {
+ mach_timebase_info(&info);
+ }
+ uint64_t time_nano = time * (info.numer / info.denom);
+ *ns = time_nano;
+#elif __WIN32__
+ uint64_t ticks_per_s;
+ QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_s);
+ if (ticks_per_s == 0LL) {
+ ticks_per_s = 1LL;
+ }
+ uint64_t ticks;
+ QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+ *ns = ((ticks * ns_per_s) / ticks_per_s);
+#else
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ *ns = (ts.tv_sec * ns_per_s + ts.tv_nsec);
+#endif
}
struct rust_tm {
if (zone != NULL) {
size_t size = strlen(zone);
- reserve_vec_exact(&out_tm->tm_zone, size);
+ assert(out_tm->tm_zone->alloc >= size);
memcpy(out_tm->tm_zone->data, zone, size);
out_tm->tm_zone->fill = size;
}
#endif
#ifndef _WIN32
-pthread_key_t rt_key = -1;
+typedef pthread_key_t tls_key;
#else
-DWORD rt_key = -1;
+typedef DWORD tls_key;
#endif
-extern "C" void*
-rust_get_rt_tls_key() {
- return &rt_key;
-}
-
// Initialize the TLS key used by the new scheduler
extern "C" CDECL void
-rust_initialize_rt_tls_key() {
+rust_initialize_rt_tls_key(tls_key *key) {
static lock_and_signal init_lock;
static bool initialized = false;
if (!initialized) {
#ifndef _WIN32
- assert(!pthread_key_create(&rt_key, NULL));
+ assert(!pthread_key_create(key, NULL));
#else
- rt_key = TlsAlloc();
- assert(rt_key != TLS_OUT_OF_INDEXES);
+ *key = TlsAlloc();
+ assert(*key != TLS_OUT_OF_INDEXES);
#endif
initialized = true;
}
extern "C" CDECL memory_region*
-rust_new_memory_region(uintptr_t synchronized,
- uintptr_t detailed_leaks,
+rust_new_memory_region(uintptr_t detailed_leaks,
uintptr_t poison_on_free) {
- return new memory_region((bool)synchronized,
- (bool)detailed_leaks,
+ return new memory_region((bool)detailed_leaks,
(bool)poison_on_free);
}
return &global_args_ptr;
}
-static lock_and_signal exit_status_lock;
-static uintptr_t exit_status = 0;
-
-extern "C" CDECL void
-rust_set_exit_status_newrt(uintptr_t code) {
- scoped_lock with(exit_status_lock);
- exit_status = code;
-}
-
-extern "C" CDECL uintptr_t
-rust_get_exit_status_newrt() {
- scoped_lock with(exit_status_lock);
- return exit_status;
-}
-
static lock_and_signal change_dir_lock;
extern "C" CDECL void
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "rust_exchange_alloc.h"
-#include "sync/sync.h"
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-#include <stdio.h>
-
-void *
-rust_exchange_alloc::malloc(size_t size) {
- void *value = ::malloc(size);
- assert(value);
- return value;
-}
-
-void *
-rust_exchange_alloc::realloc(void *ptr, size_t size) {
- void *new_ptr = ::realloc(ptr, size);
- assert(new_ptr);
- return new_ptr;
-}
-
-void
-rust_exchange_alloc::free(void *ptr) {
- ::free(ptr);
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef RUST_EXCHANGE_ALLOC_H
-#define RUST_EXCHANGE_ALLOC_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-class rust_exchange_alloc {
- public:
- void *malloc(size_t size);
- void *realloc(void *mem, size_t size);
- void free(void *mem);
-};
-
-#endif
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "rust_gc_metadata.h"
-#include "rust_crate_map.h"
-#include "rust_globals.h"
-
-#include <algorithm>
-#include <vector>
-
-struct safe_point {
- uintptr_t safe_point_loc;
- uintptr_t safe_point_meta;
- uintptr_t function_meta;
-};
-
-struct update_gc_entry_args {
- std::vector<safe_point> *safe_points;
-};
-
-static void
-update_gc_entry(const mod_entry *entry, void *cookie) {
- update_gc_entry_args *args = (update_gc_entry_args *)cookie;
- if (!strcmp(entry->name, "_gc_module_metadata")) {
- uintptr_t *next = (uintptr_t *)entry->state;
- uint32_t num_safe_points = *(uint32_t *)next;
- next++;
-
- for (uint32_t i = 0; i < num_safe_points; i++) {
- safe_point sp = { next[0], next[1], next[2] };
- next += 3;
-
- args->safe_points->push_back(sp);
- }
- }
-}
-
-static bool
-cmp_safe_point(safe_point a, safe_point b) {
- return a.safe_point_loc < b.safe_point_loc;
-}
-
-uintptr_t *global_safe_points = 0;
-
-void
-update_gc_metadata(const void* map) {
- std::vector<safe_point> safe_points;
- update_gc_entry_args args = { &safe_points };
-
- // Extract list of safe points from each module.
- iter_crate_map((const cratemap *)map, update_gc_entry, (void *)&args);
- std::sort(safe_points.begin(), safe_points.end(), cmp_safe_point);
-
- // Serialize safe point list into format expected by runtime.
- global_safe_points =
- (uintptr_t *)malloc((safe_points.size()*3 + 1)*sizeof(uintptr_t));
- if (!global_safe_points) return;
-
- uintptr_t *next = global_safe_points;
- *next = safe_points.size();
- next++;
- for (uint32_t i = 0; i < safe_points.size(); i++) {
- next[0] = safe_points[i].safe_point_loc;
- next[1] = safe_points[i].safe_point_meta;
- next[2] = safe_points[i].function_meta;
- next += 3;
- }
-}
-
-extern "C" CDECL void *
-rust_gc_metadata() {
- return (void *)global_safe_points;
-}
-
-extern "C" CDECL void
-rust_update_gc_metadata(const void* map) {
- update_gc_metadata(map);
-}
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef RUST_GC_METADATA_H
-#define RUST_GC_METADATA_H
-
-void update_gc_metadata(const void* map);
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
-
-#endif /* RUST_GC_METADATA_H */
// Helper functions used only in tests
#include "rust_util.h"
-#include "sync/timer.h"
#include "sync/rust_thread.h"
#include "sync/lock_and_signal.h"
-#include "rust_abi.h"
// These functions are used in the unit tests for C ABI calls.
rust_get_test_int() {
return 1;
}
+
+/* Debug helpers strictly to verify ABI conformance.
+ *
+ * FIXME (#2665): move these into a testcase when the testsuite
+ * understands how to have explicit C files included.
+ */
+
+struct quad {
+ uint64_t a;
+ uint64_t b;
+ uint64_t c;
+ uint64_t d;
+};
+
+struct floats {
+ double a;
+ uint8_t b;
+ double c;
+};
+
+extern "C" quad
+rust_dbg_abi_1(quad q) {
+ quad qq = { q.c + 1,
+ q.d - 1,
+ q.a + 1,
+ q.b - 1 };
+ return qq;
+}
+
+extern "C" floats
+rust_dbg_abi_2(floats f) {
+ floats ff = { f.c + 1.0,
+ 0xff,
+ f.a - 1.0 };
+ return ff;
+}
+
+extern "C" int
+rust_dbg_static_mut;
+
+int rust_dbg_static_mut = 3;
+
+extern "C" void
+rust_dbg_static_mut_check_four() {
+ assert(rust_dbg_static_mut == 4);
+}
/**********************************************************************/
+#ifdef __SEH__
+# define PERSONALITY_FUNC __gxx_personality_seh0
+#else
+# ifdef __USING_SJLJ_EXCEPTIONS__
+# define PERSONALITY_FUNC __gxx_personality_sjlj
+# else
+# define PERSONALITY_FUNC __gxx_personality_v0
+# endif
+#endif
+
extern "C" _Unwind_Reason_Code
-__gxx_personality_v0(int version,
+PERSONALITY_FUNC(int version,
_Unwind_Action actions,
uint64_t exception_class,
_Unwind_Exception *ue_header,
extern "C" void
upcall_s_rust_personality(s_rust_personality_args *args) {
- args->retval = __gxx_personality_v0(args->version,
- args->actions,
- args->exception_class,
- args->ue_header,
- args->context);
+ args->retval = PERSONALITY_FUNC(args->version,
+ args->actions,
+ args->exception_class,
+ args->ue_header,
+ args->context);
}
/**
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "rust_type.h"
-
-
-// A hardcoded type descriptor for strings, since the runtime needs to
-// be able to create them.
-
-struct type_desc str_body_tydesc = {
- 1, // size
- 1, // align
- NULL, // take_glue
- NULL, // drop_glue
- NULL, // free_glue
- NULL, // visit_glue
- 0, // borrow_offset
-};
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
#define RUST_UTIL_H
#include <limits.h>
-#include "rust_exchange_alloc.h"
#include "rust_type.h"
-extern struct type_desc str_body_tydesc;
-
// Inline fn used regularly elsewhere.
// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
return reinterpret_cast<T*>(v->data);
}
-inline void reserve_vec_exact(rust_vec** vpp,
- size_t size) {
- if (size > (*vpp)->alloc) {
- rust_exchange_alloc exchange_alloc;
- *vpp = (rust_vec*)exchange_alloc
- .realloc(*vpp, size + sizeof(rust_vec));
- (*vpp)->alloc = size;
- }
-}
-
typedef rust_vec rust_str;
inline size_t get_box_size(size_t body_size, size_t body_align) {
return buf.len;
}
-extern "C" uv_err_t
-rust_uv_last_error(uv_loop_t* loop) {
- return uv_last_error(loop);
-}
-
extern "C" const char*
-rust_uv_strerror(uv_err_t* err_ptr) {
- uv_err_t err = *err_ptr;
+rust_uv_strerror(int err) {
return uv_strerror(err);
}
extern "C" const char*
-rust_uv_err_name(uv_err_t* err_ptr) {
- uv_err_t err = *err_ptr;
+rust_uv_err_name(int err) {
return uv_err_name(err);
}
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
return req->loop;
}
+extern "C" int
+rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
+ return uv_spawn(loop, p, options);
+}
+
+extern "C" int
+rust_uv_process_kill(uv_process_t *p, int signum) {
+ return uv_process_kill(p, signum);
+}
+
+extern "C" void
+rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
+ c->flags = (uv_stdio_flags) flags;
+}
+
+extern "C" void
+rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
+ c->data.fd = fd;
+}
+
+extern "C" void
+rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
+ c->data.stream = stream;
+}
+
+extern "C" int
+rust_uv_process_pid(uv_process_t* p) {
+ return p->pid;
+}
+
+extern "C" int
+rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
+ return uv_pipe_init(loop, p, ipc);
+}
-debug_abi_1
-debug_abi_2
-debug_static_mut
-debug_static_mut_check_four
+rust_dbg_abi_1
+rust_dbg_abi_2
+rust_dbg_static_mut
+rust_dbg_static_mut_check_four
get_time
rust_tzset
rust_gmtime
rust_uv_timer_stop
rust_uv_tcp_init
rust_uv_buf_init
-rust_uv_last_error
rust_uv_strerror
rust_uv_err_name
rust_uv_ip4_addr
rust_unlock_little_lock
tdefl_compress_mem_to_heap
tinfl_decompress_mem_to_heap
-rust_gc_metadata
-rust_update_gc_metadata
rust_uv_ip4_port
rust_uv_ip6_port
rust_uv_tcp_getpeername
rust_raw_thread_start
rust_raw_thread_join
rust_raw_thread_delete
-rust_get_rt_tls_key
swap_registers
rust_readdir
rust_opendir
rust_get_global_args_ptr
rust_take_global_args_lock
rust_drop_global_args_lock
-rust_set_exit_status_newrt
-rust_get_exit_status_newrt
rust_take_change_dir_lock
rust_drop_change_dir_lock
rust_get_test_int
-rust_get_task
\ No newline at end of file
+rust_get_task
+rust_uv_spawn
+rust_uv_process_kill
+rust_set_stdio_container_flags
+rust_set_stdio_container_fd
+rust_set_stdio_container_stream
+rust_uv_process_pid
+rust_uv_pipe_init
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef SYNC_H
-#define SYNC_H
-
-class sync {
-public:
- template <class T>
- static bool compare_and_swap(T *address,
- T oldValue, T newValue) {
- return __sync_bool_compare_and_swap(address, oldValue, newValue);
- }
-
- template <class T>
- static T increment(T *address) {
- return __sync_add_and_fetch(address, 1);
- }
-
- template <class T>
- static T decrement(T *address) {
- return __sync_sub_and_fetch(address, 1);
- }
-
- template <class T>
- static T increment(T &address) {
- return __sync_add_and_fetch(&address, 1);
- }
-
- template <class T>
- static T decrement(T &address) {
- return __sync_sub_and_fetch(&address, 1);
- }
-
- template <class T>
- static T read(T *address) {
- return __sync_add_and_fetch(address, 0);
- }
-
- template <class T>
- static T read(T &address) {
- return __sync_add_and_fetch(&address, 0);
- }
-};
-
-#endif /* SYNC_H */
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "../rust_globals.h"
-#include "timer.h"
-
-#if defined(__APPLE__)
-#include <mach/mach_time.h>
-#endif
-
-uint64_t ns_per_s = 1000000000LL;
-
-timer::timer() {
-#if __WIN32__
- _ticks_per_s = 0LL;
- // FIXME (#2675): assert this works or have a workaround.
- QueryPerformanceFrequency((LARGE_INTEGER *)&_ticks_per_s);
- if (_ticks_per_s == 0LL) {
- _ticks_per_s = 1LL;
- }
-#endif
- reset_us(0);
-}
-
-void
-timer::reset_us(uint64_t timeout_us) {
- _start_us = time_us();
- _timeout_us = timeout_us;
-}
-
-uint64_t
-timer::elapsed_us() {
- return time_us() - _start_us;
-}
-
-double
-timer::elapsed_ms() {
- return (double) elapsed_us() / 1000.0;
-}
-
-int64_t
-timer::remaining_us() {
- return _timeout_us - elapsed_us();
-}
-
-bool
-timer::has_timed_out() {
- return remaining_us() <= 0;
-}
-
-uint64_t
-timer::time_ns() {
-#ifdef __APPLE__
- uint64_t time = mach_absolute_time();
- mach_timebase_info_data_t info = {0, 0};
- if (info.denom == 0) {
- mach_timebase_info(&info);
- }
- uint64_t time_nano = time * (info.numer / info.denom);
- return time_nano;
-#elif __WIN32__
- uint64_t ticks;
- QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
- return ((ticks * ns_per_s) / _ticks_per_s);
-#else
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (ts.tv_sec * ns_per_s + ts.tv_nsec);
-#endif
-}
-
-uint64_t
-timer::time_us() {
- return time_ns() / 1000;
-}
-
-timer::~timer() {
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*
- * Utility class to measure time in a platform independent way.
- */
-
-#ifndef TIMER_H
-#define TIMER_H
-
-class timer {
-private:
- uint64_t _start_us;
- uint64_t _timeout_us;
- uint64_t time_us();
-#if __WIN32__
- uint64_t _ticks_per_s;
-#endif
-public:
- timer();
- void reset_us(uint64_t timeout);
- uint64_t elapsed_us();
- double elapsed_ms();
- int64_t remaining_us();
- bool has_timed_out();
- uint64_t time_ns();
- virtual ~timer();
-};
-
-#endif /* TIMER_H */
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef INDEXED_LIST_H
-#define INDEXED_LIST_H
-
-#include <assert.h>
-#include "array_list.h"
-
-class indexed_list_object {
-public:
- virtual ~indexed_list_object() {}
- int32_t list_index;
-};
-
-template<typename T>
-class indexed_list_element : public indexed_list_object {
-public:
- T value;
- indexed_list_element(T value) : value(value) {
- }
-};
-
-/**
- * An array list of objects that are aware of their position in the list.
- * Normally, objects in this list should derive from the base class
- * "indexed_list_object" however because of nasty Rust compiler dependencies
- * on the layout of runtime objects we cannot always derive from this
- * base class, so instead we just enforce the informal protocol that any
- * object inserted in this list must define a "int32_t list_index" member.
- */
-template<typename T> class indexed_list {
- array_list<T*> list;
-public:
- int32_t append(T *value);
- bool pop(T **value);
- /**
- * Same as pop(), except that it returns NULL if the list is empty.
- */
- T* pop_value();
- size_t length() const {
- return list.size();
- }
- bool is_empty() const {
- return list.is_empty();
- }
- int32_t remove(T* value);
- T * operator[](int32_t index);
- const T * operator[](int32_t index) const;
- ~indexed_list() {}
-};
-
-template<typename T> int32_t
-indexed_list<T>::append(T *value) {
- value->list_index = list.push(value);
- return value->list_index;
-}
-
-/**
- * Swap delete the last object in the list with the specified object.
- */
-template<typename T> int32_t
-indexed_list<T>::remove(T *value) {
- assert (value->list_index >= 0);
- assert (value->list_index < (int32_t)list.size());
- int32_t removeIndex = value->list_index;
- T *last = 0;
- list.pop(&last);
- if (last->list_index == removeIndex) {
- last->list_index = -1;
- return removeIndex;
- } else {
- value->list_index = -1;
- list[removeIndex] = last;
- last->list_index = removeIndex;
- return removeIndex;
- }
-}
-
-template<typename T> bool
-indexed_list<T>::pop(T **value) {
- return list.pop(value);
-}
-
-template<typename T> T*
-indexed_list<T>::pop_value() {
- T *value = NULL;
- if (list.pop(&value)) {
- return value;
- }
- return NULL;
-}
-
-template <typename T> T *
-indexed_list<T>::operator[](int32_t index) {
- T *value = list[index];
- assert(value->list_index == index);
- return value;
-}
-
-template <typename T> const T *
-indexed_list<T>::operator[](int32_t index) const {
- T *value = list[index];
- assert(value->list_index == index);
- return value;
-}
-
-#endif /* INDEXED_LIST_H */
#undef PLAT_x86_darwin
#undef PLAT_amd64_darwin
#undef PLAT_x86_win32
+#undef PLAT_amd64_win64
#undef PLAT_x86_linux
#undef PLAT_amd64_linux
#undef PLAT_ppc32_linux
# define PLAT_amd64_darwin 1
#elif defined(__MINGW32__) || defined(__CYGWIN32__) \
|| (defined(_WIN32) && defined(_M_IX86))
-# define PLAT_x86_win32 1
+# if defined(__x86_64__)
+# define PLAT_amd64_win64 1
+# elif defined(__i386__)
+# define PLAT_x86_win32 1
+# endif
#elif defined(__linux__) && defined(__i386__)
# define PLAT_x86_linux 1
#elif defined(__linux__) && defined(__x86_64__)
/* ------------------------ amd64-{linux,darwin} --------------- */
-#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \
+ || defined(PLAT_amd64_win64)
typedef
struct {
#if defined(NVALGRIND)
return 0;
#else /* NVALGRIND */
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
uintptr_t _qzz_res;
#else
unsigned long _qzz_res;
#endif
va_list vargs;
va_start(vargs, format);
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_VALIST_BY_REF,
(uintptr_t)format,
#if defined(NVALGRIND)
return 0;
#else /* NVALGRIND */
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
uintptr_t _qzz_res;
#else
unsigned long _qzz_res;
#endif
va_list vargs;
va_start(vargs, format);
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) || defined(PLAT_amd64_win64)
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
(uintptr_t)format,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#include <stdio.h>
+
#include "rustllvm.h"
-using namespace llvm;
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-// Pass conversion fns
-typedef struct LLVMOpaquePass *LLVMPassRef;
+#include "llvm-c/Transforms/PassManagerBuilder.h"
-inline Pass *unwrap(LLVMPassRef P) {
- return reinterpret_cast<Pass*>(P);
-}
+using namespace llvm;
-inline LLVMPassRef wrap(const Pass *P) {
- return reinterpret_cast<LLVMPassRef>(const_cast<Pass*>(P));
-}
+extern cl::opt<bool> EnableARMEHABI;
-template<typename T>
-inline T *unwrap(LLVMPassRef P) {
- T *Q = (T*)unwrap(P);
- assert(Q && "Invalid cast!");
- return Q;
-}
+typedef struct LLVMOpaquePass *LLVMPassRef;
+typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
+
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef)
-extern "C" void LLVMInitializePasses() {
+extern "C" void
+LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeCodeGen(Registry);
initializeTarget(Registry);
}
-extern "C" void LLVMAddPass(LLVMPassManagerRef PM, LLVMPassRef P) {
- PassManagerBase * pm = unwrap(PM);
- Pass * p = unwrap(P);
-
- pm->add(p);
-}
+extern "C" bool
+LLVMRustAddPass(LLVMPassManagerRef PM, const char *PassName) {
+ PassManagerBase *pm = unwrap(PM);
-extern "C" LLVMPassRef LLVMCreatePass(const char * PassName) {
StringRef SR(PassName);
- PassRegistry * PR = PassRegistry::getPassRegistry();
+ PassRegistry *PR = PassRegistry::getPassRegistry();
- const PassInfo * PI = PR->getPassInfo(SR);
+ const PassInfo *PI = PR->getPassInfo(SR);
if (PI) {
- return wrap(PI->createPass());
- } else {
- return (LLVMPassRef)0;
+ pm->add(PI->createPass());
+ return true;
+ }
+ return false;
+}
+
+extern "C" LLVMTargetMachineRef
+LLVMRustCreateTargetMachine(const char *triple,
+ const char *cpu,
+ const char *feature,
+ CodeModel::Model CM,
+ Reloc::Model RM,
+ CodeGenOpt::Level OptLevel,
+ bool EnableSegmentedStacks) {
+ std::string Error;
+ Triple Trip(Triple::normalize(triple));
+ const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(),
+ Error);
+ if (TheTarget == NULL) {
+ LLVMRustError = Error.c_str();
+ return NULL;
+ }
+
+ TargetOptions Options;
+ Options.EnableSegmentedStacks = EnableSegmentedStacks;
+ Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
+ Options.FloatABIType =
+ (Trip.getEnvironment() == Triple::GNUEABIHF) ? FloatABI::Hard :
+ FloatABI::Default;
+
+ TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(),
+ cpu,
+ feature,
+ Options,
+ RM,
+ CM,
+ OptLevel);
+ return wrap(TM);
+}
+
+extern "C" void
+LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
+ delete unwrap(TM);
+}
+
+// Unfortunately, LLVM doesn't expose a C API to add the corresponding analysis
+// passes for a target to a pass manager. We export that functionality through
+// this function.
+extern "C" void
+LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
+ LLVMPassManagerRef PMR,
+ LLVMModuleRef M) {
+ PassManagerBase *PM = unwrap(PMR);
+ PM->add(new DataLayout(unwrap(M)));
+ unwrap(TM)->addAnalysisPasses(*PM);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
+// field of a PassManagerBuilder, we expose our own method of doing so.
+extern "C" void
+LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) {
+ Triple TargetTriple(unwrap(M)->getTargetTriple());
+ unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple);
+}
+
+// Unfortunately, the LLVM C API doesn't provide a way to create the
+// TargetLibraryInfo pass, so we use this method to do so.
+extern "C" void
+LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) {
+ Triple TargetTriple(unwrap(M)->getTargetTriple());
+ unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple));
+}
+
+// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
+// all the functions in a module, so we do that manually here. You'll find
+// similar code in clang's BackendUtil.cpp file.
+extern "C" void
+LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) {
+ FunctionPassManager *P = unwrap<FunctionPassManager>(PM);
+ P->doInitialization();
+ for (Module::iterator I = unwrap(M)->begin(),
+ E = unwrap(M)->end(); I != E; ++I)
+ if (!I->isDeclaration())
+ P->run(*I);
+ P->doFinalization();
+}
+
+extern "C" void
+LLVMRustSetLLVMOptions(bool PrintPasses,
+ bool VectorizeLoops,
+ bool VectorizeSLP,
+ bool TimePasses) {
+ // Initializing the command-line options more than once is not allowed. So,
+ // check if they've already been initialized. (This could happen if we're
+ // being called from rustpkg, for example). If the arguments change, then
+ // that's just kinda unfortunate.
+ static bool initialized = false;
+ if (initialized) return;
+
+ int argc = 3;
+ const char *argv[20] = {"rustc",
+ "-arm-enable-ehabi",
+ "-arm-enable-ehabi-descriptors"};
+ if (PrintPasses) {
+ argv[argc++] = "-debug-pass";
+ argv[argc++] = "Structure";
+ }
+ if (VectorizeLoops) {
+ argv[argc++] = "-vectorize-loops";
+ }
+ if (VectorizeSLP) {
+ argv[argc++] = "-vectorize-slp";
}
+ if (TimePasses) {
+ argv[argc++] = "-time-passes";
+ }
+ cl::ParseCommandLineOptions(argc, argv);
+ initialized = true;
+}
+
+extern "C" bool
+LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
+ LLVMPassManagerRef PMR,
+ LLVMModuleRef M,
+ const char *path,
+ TargetMachine::CodeGenFileType FileType) {
+ PassManager *PM = unwrap<PassManager>(PMR);
+
+ std::string ErrorInfo;
+ raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+ if (ErrorInfo != "") {
+ LLVMRustError = ErrorInfo.c_str();
+ return false;
+ }
+ formatted_raw_ostream FOS(OS);
+
+ unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
+ PM->run(*unwrap(M));
+ return true;
+}
+
+extern "C" void
+LLVMRustPrintModule(LLVMPassManagerRef PMR,
+ LLVMModuleRef M,
+ const char* path) {
+ PassManager *PM = unwrap<PassManager>(PMR);
+ std::string ErrorInfo;
+ raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
+ formatted_raw_ostream FOS(OS);
+ PM->add(createPrintModulePass(&FOS));
+ PM->run(*unwrap(M));
+}
+
+extern "C" void
+LLVMRustPrintPasses() {
+ LLVMInitializePasses();
+ struct MyListener : PassRegistrationListener {
+ void passEnumerate(const PassInfo *info) {
+ if (info->getPassArgument() && *info->getPassArgument()) {
+ printf("%15s - %s\n", info->getPassArgument(),
+ info->getPassName());
+ }
+ }
+ } listener;
+
+ PassRegistry *PR = PassRegistry::getPassRegistry();
+ PR->enumerateWith(&listener);
}
-extern "C" void LLVMDestroyPass(LLVMPassRef PassRef) {
- Pass *p = unwrap(PassRef);
- delete p;
+extern "C" void
+LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) {
+ unwrap(PMB)->Inliner = createAlwaysInlinerPass(AddLifetimes);
}
using namespace llvm;
using namespace llvm::sys;
-static const char *LLVMRustError;
-
-extern cl::opt<bool> EnableARMEHABI;
+const char *LLVMRustError;
extern "C" LLVMMemoryBufferRef
LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
return LLVMRustError;
}
-extern "C" void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM);
-
-extern "C" void LLVMRustAddPrintModulePass(LLVMPassManagerRef PMR,
- LLVMModuleRef M,
- const char* path) {
- PassManager *PM = unwrap<PassManager>(PMR);
- std::string ErrorInfo;
- raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
- formatted_raw_ostream FOS(OS);
- PM->add(createPrintModulePass(&FOS));
- PM->run(*unwrap(M));
-}
-
-void LLVMInitializeX86TargetInfo();
-void LLVMInitializeX86Target();
-void LLVMInitializeX86TargetMC();
-void LLVMInitializeX86AsmPrinter();
-void LLVMInitializeX86AsmParser();
-
-
-void LLVMInitializeARMTargetInfo();
-void LLVMInitializeARMTarget();
-void LLVMInitializeARMTargetMC();
-void LLVMInitializeARMAsmPrinter();
-void LLVMInitializeARMAsmParser();
-
-void LLVMInitializeMipsTargetInfo();
-void LLVMInitializeMipsTarget();
-void LLVMInitializeMipsTargetMC();
-void LLVMInitializeMipsAsmPrinter();
-void LLVMInitializeMipsAsmParser();
-// Only initialize the platforms supported by Rust here,
-// because using --llvm-root will have multiple platforms
-// that rustllvm doesn't actually link to and it's pointless to put target info
-// into the registry that Rust can not generate machine code for.
-
-void LLVMRustInitializeTargets() {
- LLVMInitializeX86TargetInfo();
- LLVMInitializeX86Target();
- LLVMInitializeX86TargetMC();
- LLVMInitializeX86AsmPrinter();
- LLVMInitializeX86AsmParser();
-
- LLVMInitializeARMTargetInfo();
- LLVMInitializeARMTarget();
- LLVMInitializeARMTargetMC();
- LLVMInitializeARMAsmPrinter();
- LLVMInitializeARMAsmParser();
-
- LLVMInitializeMipsTargetInfo();
- LLVMInitializeMipsTarget();
- LLVMInitializeMipsTargetMC();
- LLVMInitializeMipsAsmPrinter();
- LLVMInitializeMipsAsmParser();
-}
-
// Custom memory manager for MCJITting. It needs special features
// that the generic JIT memory manager doesn't entail. Based on
// code from LLI, change where needed for Rust.
return wrap(EE);
}
-extern "C" bool
-LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
- LLVMModuleRef M,
- const char *triple,
- const char *cpu,
- const char *feature,
- const char *path,
- TargetMachine::CodeGenFileType FileType,
- CodeGenOpt::Level OptLevel,
- bool EnableSegmentedStacks) {
-
- LLVMRustInitializeTargets();
-
- // Initializing the command-line options more than once is not
- // allowed. So, check if they've already been initialized.
- // (This could happen if we're being called from rustpkg, for
- // example.)
- if (!EnableARMEHABI) {
- int argc = 3;
- const char* argv[] = {"rustc", "-arm-enable-ehabi",
- "-arm-enable-ehabi-descriptors"};
- cl::ParseCommandLineOptions(argc, argv);
- }
-
- TargetOptions Options;
- Options.EnableSegmentedStacks = EnableSegmentedStacks;
- Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
-
- PassManager *PM = unwrap<PassManager>(PMR);
-
- std::string Err;
- std::string Trip(Triple::normalize(triple));
- std::string FeaturesStr(feature);
- std::string CPUStr(cpu);
- const Target *TheTarget = TargetRegistry::lookupTarget(Trip, Err);
- TargetMachine *Target =
- TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr,
- Options, Reloc::PIC_,
- CodeModel::Default, OptLevel);
- Target->addAnalysisPasses(*PM);
-
- bool NoVerify = false;
- std::string ErrorInfo;
- raw_fd_ostream OS(path, ErrorInfo,
- sys::fs::F_Binary);
- if (ErrorInfo != "") {
- LLVMRustError = ErrorInfo.c_str();
- return false;
- }
- formatted_raw_ostream FOS(OS);
-
- bool foo = Target->addPassesToEmitFile(*PM, FOS, FileType, NoVerify);
- assert(!foo);
- (void)foo;
- PM->run(*unwrap(M));
- delete Target;
- return true;
-}
-
-extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(LLVMContextRef C,
- const char *Filename) {
- SMDiagnostic d;
- Module *m = ParseAssemblyFile(Filename, d, *unwrap(C));
- if (m) {
- return wrap(m);
- } else {
- LLVMRustError = d.getMessage().str().c_str();
- return NULL;
- }
-}
-
-extern "C" LLVMModuleRef LLVMRustParseBitcode(LLVMMemoryBufferRef MemBuf) {
- LLVMModuleRef M;
- return LLVMParseBitcode(MemBuf, &M, const_cast<char **>(&LLVMRustError))
- ? NULL : M;
+extern "C" void
+LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) {
+ unwrap(M)->setTargetTriple(Triple::normalize(triple));
}
extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N,
return LLVMConstInt(IntTy, N, SignExtend);
}
-extern bool llvm::TimePassesIsEnabled;
-extern "C" void LLVMRustEnableTimePasses() {
- TimePassesIsEnabled = true;
-}
-
extern "C" void LLVMRustPrintPassTimings() {
raw_fd_ostream OS (2, false); // stderr.
TimerGroup::printAll(OS);
LLVMRustCreateMemoryBufferWithContentsOfFile
-LLVMRustEnableTimePasses
LLVMRustWriteOutputFile
LLVMRustGetLastError
LLVMRustConstSmallInt
LLVMRustLoadCrate
LLVMRustPrepareJIT
LLVMRustBuildJIT
-LLVMRustParseBitcode
-LLVMRustParseAssemblyFile
LLVMRustPrintPassTimings
LLVMRustStartMultithreading
LLVMCreateObjectFile
LLVMAddArgumentPromotionPass
LLVMAddAttribute
LLVMAddBasicAliasAnalysisPass
-LLVMRustAddPrintModulePass
LLVMAddCFGSimplificationPass
LLVMAddCase
LLVMAddClause
LLVMStructSetBody
LLVMInlineAsm
LLVMInitializePasses
-LLVMAddPass
-LLVMCreatePass
-LLVMDestroyPass
LLVMDIBuilderCreate
LLVMDIBuilderDispose
LLVMDIBuilderFinalize
LLVMDIBuilderCreateUnionType
LLVMDIBuilderCreateTemplateTypeParameter
LLVMSetUnnamedAddr
+LLVMRustAddPass
+LLVMRustAddAnalysisPasses
+LLVMRustAddLibraryInfo
+LLVMRustCreateTargetMachine
+LLVMRustRunFunctionPassManager
+LLVMRustPrintModule
+LLVMRustDisposeTargetMachine
+LLVMRustAddBuilderLibraryInfo
+LLVMRustSetLLVMOptions
+LLVMRustPrintPasses
+LLVMRustSetNormalizedTarget
+LLVMRustAddAlwaysInlinePass
#include <fcntl.h>
#include <unistd.h>
#endif
+
+extern const char* LLVMRustError;
io::println("\nTreeMap:");
{
- let mut map = TreeMap::new::<uint, uint>();
+ let mut map: TreeMap<uint,uint> = TreeMap::new();
ascending(&mut map, n_keys);
}
{
- let mut map = TreeMap::new::<uint, uint>();
+ let mut map: TreeMap<uint,uint> = TreeMap::new();
descending(&mut map, n_keys);
}
{
io::println(" Random integers:");
- let mut map = TreeMap::new::<uint, uint>();
+ let mut map: TreeMap<uint,uint> = TreeMap::new();
vector(&mut map, n_keys, rand);
}
io::println("\nHashMap:");
{
- let mut map = HashMap::new::<uint, uint>();
+ let mut map: HashMap<uint,uint> = HashMap::new();
ascending(&mut map, n_keys);
}
{
- let mut map = HashMap::new::<uint, uint>();
+ let mut map: HashMap<uint,uint> = HashMap::new();
descending(&mut map, n_keys);
}
{
io::println(" Random integers:");
- let mut map = HashMap::new::<uint, uint>();
+ let mut map: HashMap<uint,uint> = HashMap::new();
vector(&mut map, n_keys, rand);
}
io::println("\nTrieMap:");
{
- let mut map = TrieMap::new::<uint>();
+ let mut map: TrieMap<uint> = TrieMap::new();
ascending(&mut map, n_keys);
}
{
- let mut map = TrieMap::new::<uint>();
+ let mut map: TrieMap<uint> = TrieMap::new();
descending(&mut map, n_keys);
}
{
io::println(" Random integers:");
- let mut map = TrieMap::new::<uint>();
+ let mut map: TrieMap<uint> = TrieMap::new();
vector(&mut map, n_keys, rand);
}
}
{
let mut rng = rand::IsaacRng::new_seeded(seed);
let mut results = empty_results();
- results.bench_int(&mut rng, num_keys, max, || HashSet::new::<uint>());
- results.bench_str(&mut rng, num_keys, || HashSet::new::<~str>());
+ results.bench_int(&mut rng, num_keys, max, || {
+ let s: HashSet<uint> = HashSet::new();
+ s
+ });
+ results.bench_str(&mut rng, num_keys, || {
+ let s: HashSet<~str> = HashSet::new();
+ s
+ });
write_results("std::hashmap::HashSet", &results);
}
{
let mut rng = rand::IsaacRng::new_seeded(seed);
let mut results = empty_results();
- results.bench_int(&mut rng, num_keys, max, || TreeSet::new::<uint>());
- results.bench_str(&mut rng, num_keys, || TreeSet::new::<~str>());
+ results.bench_int(&mut rng, num_keys, max, || {
+ let s: TreeSet<uint> = TreeSet::new();
+ s
+ });
+ results.bench_str(&mut rng, num_keys, || {
+ let s: TreeSet<~str> = TreeSet::new();
+ s
+ });
write_results("extra::treemap::TreeSet", &results);
}
#[nolink]
extern {
- static mut debug_static_mut: libc::c_int;
- pub fn debug_static_mut_check_four();
+ static mut rust_dbg_static_mut: libc::c_int;
+ pub fn rust_dbg_static_mut_check_four();
#[cfg(stage37)] //~ ERROR expected item after attributes
}
--- /dev/null
+#[no_std];
+
+struct S<T> {
+ contents: T,
+}
+
+impl<T> S<T> {
+ fn new<U>(x: T, _: U) -> S<T> {
+ S {
+ contents: x,
+ }
+ }
+}
+
+trait Trait<T> {
+ fn new<U>(x: T, y: U) -> Self;
+}
+
+struct S2 {
+ contents: int,
+}
+
+impl Trait<int> for S2 {
+ fn new<U>(x: int, _: U) -> S2 {
+ S2 {
+ contents: x,
+ }
+ }
+}
+
+fn main() {
+ let _ = S::new::<int,float>(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _ = S::<'self,int>::new::<float>(1, 1.0); //~ ERROR this impl has no lifetime parameter
+ let _: S2 = Trait::new::<int,float>(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _: S2 = Trait::<'self,int>::new::<float>(1, 1.0); //~ ERROR this trait has no lifetime parameter
+}
+
+++ /dev/null
-// Test that attempt to alias `&mut` pointer while pointee is borrowed
-// yields an error.
-//
-// Example from src/middle/borrowck/doc.rs
-
-use std::util::swap;
-
-fn foo(t0: &mut int) {
- let p: &int = &*t0; // Freezes `*t0`
- let q: &const &mut int = &const t0; //~ ERROR cannot borrow `t0`
- **q = 22; //~ ERROR cannot assign to an `&mut` in a `&const` pointer
-}
-
-fn main() {
-}
\ No newline at end of file
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'self> {
+ pointer: &'self mut int
+}
+
+fn a(s: &S) {
+ *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn b(s: &mut S) {
+ *s.pointer += 1;
+}
+
+fn c(s: & &mut S) {
+ *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn main() {}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'self> {
+ pointer: &'self mut int
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+ S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+ let mut x = 1;
+
+ {
+ let mut y = S { pointer: &mut x };
+ let z = copy_borrowed_ptr(&mut y);
+ *y.pointer += 1; //~ ERROR cannot assign
+ *z.pointer += 1;
+ }
+}
**t1 = 22; //~ ERROR cannot assign
}
-fn foo2(t0: &const &mut int) {
- // Note: reborrowing from an &const actually yields two errors, since it
- // is unsafe in two ways: we can't control the aliasing, and we can't
- // control the mutation.
- let t1 = t0;
- let p: &int = &**t0; //~ ERROR cannot borrow an `&mut` in a `&const` pointer
- //~^ ERROR unsafe borrow of aliasable, const value
- **t1 = 22; //~ ERROR cannot assign
-}
-
fn foo3(t0: &mut &mut int) {
let t1 = &mut *t0;
let p: &int = &**t0; //~ ERROR cannot borrow
}
fn main() {
-}
\ No newline at end of file
+}
use std::hashmap::HashMap;
fn main() {
- let mut buggy_map :HashMap<uint, &uint> =
- HashMap::new::<uint, &uint>();
+ let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
buggy_map.insert(42, &*~1); //~ ERROR borrowed value does not live long enough
// but it is ok if we use a temporary
impl Foo {
pub fn f(&self) {}
- pub fn g(&const self) {}
pub fn h(&mut self) {}
}
fn a(x: &mut Foo) {
x.f();
- x.g();
x.h();
}
fn b(x: &Foo) {
x.f();
- x.g();
x.h(); //~ ERROR cannot borrow
}
-fn c(x: &const Foo) {
- x.f(); //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow
- x.g();
- x.h(); //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow
-}
-
fn main() {
}
borrow_mut(v); //~ ERROR cannot borrow
}
-fn pre_const() {
- // In this instance, the freeze starts before the mut borrow.
-
- let mut v = ~3;
- let _w = &const v;
- borrow_mut(v);
-}
-
fn post_freeze() {
// In this instance, the const alias starts after the borrow.
}
}
-fn takes_const_elt(_v: &const int, f: &fn()) {
- f();
-}
-
-fn has_mut_vec_and_tries_to_change_it() {
- let mut v = ~[1, 2, 3];
- do takes_const_elt(&const v[0]) {
- v[1] = 4;
- }
-}
-
fn main() {
}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn process<T>(_t: T) {}
-
-fn match_const_opt_by_mut_ref(v: &const Option<int>) {
- match *v {
- Some(ref mut i) => process(i), //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow of aliasable, const value
- None => ()
- }
-}
-
-fn match_const_opt_by_const_ref(v: &const Option<int>) {
- match *v {
- Some(ref const i) => process(i),
- //~^ ERROR unsafe borrow of aliasable, const value
- None => ()
- }
-}
-
-fn match_const_opt_by_imm_ref(v: &const Option<int>) {
- match *v {
- Some(ref i) => process(i), //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow of aliasable, const value
- None => ()
- }
-}
-
-fn match_const_opt_by_value(v: &const Option<int>) {
- match *v {
- Some(i) => process(i),
- None => ()
- }
-}
-
-fn main() {
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn match_ref(v: Option<int>) -> int {
- match v {
- Some(ref i) => {
- *i
- }
- None => {0}
- }
-}
-
-fn match_ref_unused(v: Option<int>) {
- match v {
- Some(_) => {}
- None => {}
- }
-}
-
-fn match_const_reg(v: &const Option<int>) -> int {
- match *v {
- Some(ref i) => {*i} //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow
- None => {0}
- }
-}
-
-fn impure(_i: int) {
-}
-
-fn match_const_reg_unused(v: &const Option<int>) {
- match *v {
- Some(_) => {impure(0)} // OK because nothing is captured
- None => {}
- }
-}
-
-fn match_const_reg_impure(v: &const Option<int>) {
- match *v {
- Some(ref i) => {impure(*i)} //~ ERROR cannot borrow
- //~^ ERROR unsafe borrow
- None => {}
- }
-}
-
-fn match_imm_reg(v: &Option<int>) {
- match *v {
- Some(ref i) => {impure(*i)} // OK because immutable
- None => {}
- }
-}
-
-fn match_mut_reg(v: &mut Option<int>) {
- match *v {
- Some(ref i) => {impure(*i)} // OK, frozen
- None => {}
- }
-}
-
-fn main() {
-}
borrow(v);
}
-fn aliased_const() {
- let mut v = ~3;
- let _w = &const v;
- borrow(v);
-}
-
fn aliased_mut() {
let mut v = ~3;
let _w = &mut v;
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct Rec {
- f: ~int,
-}
-
-struct Outer {
- f: Inner
-}
-
-struct Inner {
- g: Innermost
-}
-
-struct Innermost {
- h: ~int,
-}
-
-fn borrow(_v: &int) {}
-fn borrow_const(_v: &const int) {}
-
-fn box_mut(v: &mut ~int) {
- borrow(*v); // OK: &mut -> &imm
-}
-
-fn box_mut_rec(v: &mut Rec) {
- borrow(v.f); // OK: &mut -> &imm
-}
-
-fn box_mut_recs(v: &mut Outer) {
- borrow(v.f.g.h); // OK: &mut -> &imm
-}
-
-fn box_imm(v: &~int) {
- borrow(*v); // OK
-}
-
-fn box_imm_rec(v: &Rec) {
- borrow(v.f); // OK
-}
-
-fn box_imm_recs(v: &Outer) {
- borrow(v.f.g.h); // OK
-}
-
-fn box_const(v: &const ~int) {
- borrow_const(*v); //~ ERROR unsafe borrow
-}
-
-fn box_const_rec(v: &const Rec) {
- borrow_const(v.f); //~ ERROR unsafe borrow
-}
-
-fn box_const_recs(v: &const Outer) {
- borrow_const(v.f.g.h); //~ ERROR unsafe borrow
-}
-
-fn main() {
-}
// @int <: X
//
- // This constraint forces X to be
- // @const int.
- r(@3);
+ // Here the type check fails because @const is gone and there is no
+ // supertype.
+ r(@3); //~ ERROR mismatched types
- // Here the type check succeeds but the
- // mutability check will fail, because the
- // type of r has been inferred to be
- // fn(@const int) -> @const int
- *r(@mut 3) = 4; //~ ERROR cannot assign to const dereference of @ pointer
+ // Here the type check succeeds.
+ *r(@mut 3) = 4;
}
// except according to those terms.
fn main() {
- // bad arguments to the ifmt! call
+ // bad arguments to the format! call
- ifmt!(); //~ ERROR: expects at least one
- ifmt!("{}"); //~ ERROR: invalid reference to argument
+ format!(); //~ ERROR: requires at least a format string
+ format!("{}"); //~ ERROR: invalid reference to argument
- ifmt!("{1}", 1); //~ ERROR: invalid reference to argument `1`
+ format!("{1}", 1); //~ ERROR: invalid reference to argument `1`
//~^ ERROR: argument never used
- ifmt!("{foo}"); //~ ERROR: no argument named `foo`
+ format!("{foo}"); //~ ERROR: no argument named `foo`
- ifmt!("{}", 1, 2); //~ ERROR: argument never used
- ifmt!("{1}", 1, 2); //~ ERROR: argument never used
- ifmt!("{}", 1, foo=2); //~ ERROR: named argument never used
- ifmt!("{foo}", 1, foo=2); //~ ERROR: argument never used
- ifmt!("", foo=2); //~ ERROR: named argument never used
+ format!("{}", 1, 2); //~ ERROR: argument never used
+ format!("{1}", 1, 2); //~ ERROR: argument never used
+ format!("{}", 1, foo=2); //~ ERROR: named argument never used
+ format!("{foo}", 1, foo=2); //~ ERROR: argument never used
+ format!("", foo=2); //~ ERROR: named argument never used
- ifmt!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s`
- ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s`
+ format!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s`
+ format!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s`
- ifmt!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
- ifmt!("#"); //~ ERROR: `#` reference used
- ifmt!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
- ifmt!("" 1); //~ ERROR: expected token: `,`
- ifmt!("", 1 1); //~ ERROR: expected token: `,`
+ format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
+ format!("#"); //~ ERROR: `#` reference used
+ format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
+ format!("" 1); //~ ERROR: expected token: `,`
+ format!("", 1 1); //~ ERROR: expected token: `,`
- ifmt!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector
- ifmt!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector
- ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector
+ format!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector
+ format!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector
+ format!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector
// bad syntax of the format string
- ifmt!("{"); //~ ERROR: unterminated format string
- ifmt!("\\ "); //~ ERROR: invalid escape
- ifmt!("\\"); //~ ERROR: expected an escape
+ format!("{"); //~ ERROR: unterminated format string
+ format!("\\ "); //~ ERROR: invalid escape
+ format!("\\"); //~ ERROR: expected an escape
- ifmt!("{0, }", 1); //~ ERROR: expected method
- ifmt!("{0, foo}", 1); //~ ERROR: unknown method
- ifmt!("{0, select}", "a"); //~ ERROR: must be followed by
- ifmt!("{0, plural}", 1); //~ ERROR: must be followed by
+ format!("{0, }", 1); //~ ERROR: expected method
+ format!("{0, foo}", 1); //~ ERROR: unknown method
+ format!("{0, select}", "a"); //~ ERROR: must be followed by
+ format!("{0, plural}", 1); //~ ERROR: must be followed by
- ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated
- ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
- ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
- ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
- ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
- ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
- ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
- ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`
- ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other`
+ format!("{0, select, a{{}", 1); //~ ERROR: must be terminated
+ format!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
+ format!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
+ format!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
+ format!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
+ format!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
+ format!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
+ format!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`
+ format!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other`
- ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as
- ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to
- ifmt!("{0, select, other{}} \
- {0, plural, other{}}", "a");
+ format!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as
+ format!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to
+ format!("{0, select, other{}} \
+ {0, plural, other{}}", "a");
//~^ ERROR: declared with multiple formats
// It should be illegal to use implicit placement arguments nested inside of
// format strings because otherwise the "internal pointer of which argument
// is next" would be invalidated if different cases had different numbers of
// arguments.
- ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit
- ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit
- ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit
+ format!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit
+ format!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit
+ format!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit
}
// except according to those terms.
fn main() {
- ifmt!("{0, plural, other{}}", "a");
+ format!("{0, plural, other{}}", "a");
//~^ ERROR: expected uint but found
}
// except according to those terms.
fn main() {
- ifmt!("{0, select, other{}}", 2);
+ format!("{0, select, other{}}", 2);
//~^ ERROR: expected &str but found integral
}
// except according to those terms.
fn main() {
- ifmt!("{:d}", "3");
+ format!("{:d}", "3");
//~^ ERROR: failed to find an implementation of trait std::fmt::Signed
}
// except according to those terms.
fn main() {
- ifmt!("{:notimplemented}", "3");
+ format!("{:notimplemented}", "3");
//~^ ERROR: unknown format trait `notimplemented`
}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct Bike {
- name: ~str,
-}
-
-trait BikeMethods {
- fn woops(&const self) -> ~str;
-}
-
-impl BikeMethods for Bike {
- fn woops() -> ~str { ~"foo" }
- //~^ ERROR has a `&const self` declaration in the trait, but not in the impl
-}
-
-pub fn main() {
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub trait Nummy {
- fn from_inty<T>() -> Self;
-}
-
-impl Nummy for float {
- fn from_inty<T>() -> float { 0.0 }
-}
-
-fn main() {
- let _1:float = Nummy::from_inty::<int>(); //~ ERROR not enough type
- //~^ NOTE Static methods have an extra implicit type parameter
-}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py as'
+
+fn main() {
+ let as = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py break'
+
+fn main() {
+ let break = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py do'
+
+fn main() {
+ let do = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py else'
+
+fn main() {
+ let else = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py enum'
+
+fn main() {
+ let enum = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py extern'
+
+fn main() {
+ let extern = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py false'
+
+fn main() {
+ let false = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py fn'
+
+fn main() {
+ let fn = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py for'
+
+fn main() {
+ let for = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py if'
+
+fn main() {
+ let if = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py impl'
+
+fn main() {
+ let impl = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py let'
+
+fn main() {
+ let let = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py loop'
+
+fn main() {
+ let loop = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py match'
+
+fn main() {
+ let match = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py mod'
+
+fn main() {
+ let mod = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py mut'
+
+fn main() {
+ let mut = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py priv'
+
+fn main() {
+ let priv = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py pub'
+
+fn main() {
+ let pub = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py ref'
+
+fn main() {
+ let ref = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py return'
+
+fn main() {
+ let return = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py self'
+
+fn main() {
+ let self = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py static'
+
+fn main() {
+ let static = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py struct'
+
+fn main() {
+ let struct = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py super'
+
+fn main() {
+ let super = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py trait'
+
+fn main() {
+ let trait = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py true'
+
+fn main() {
+ let true = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py type'
+
+fn main() {
+ let type = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py unsafe'
+
+fn main() {
+ let unsafe = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py use'
+
+fn main() {
+ let use = "foo"; //~ error: ident
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-tests.py while'
+
+fn main() {
+ let while = "foo"; //~ error: ident
+}
// Test that trait types printed in error msgs include the type arguments.
fn main() {
- let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as
- @Map<~str, ~str>;
+ let x: @HashMap<~str, ~str> = @HashMap::new();
+ let x: @Map<~str, ~str> = x as @Map<~str, ~str>;
let y: @Map<uint, ~str> = @x;
//~^ ERROR expected trait std::container::Map but found @-ptr
}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-extern mod extra;
-
-fn main() {
- unsafe fn f(v: *const int) {
- *v = 1 //~ ERROR cannot assign
- }
-
- unsafe {
- let mut a = 0;
- let v = &mut a;
- f(v);
- }
-}
let x: float<int>; //~ ERROR type parameters are not allowed on this type
let x: char<int>; //~ ERROR type parameters are not allowed on this type
-let x: int<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i8<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i16<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i32<'static>; //~ ERROR region parameters are not allowed on this type
-let x: i64<'static>; //~ ERROR region parameters are not allowed on this type
-let x: uint<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u8<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u16<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u32<'static>; //~ ERROR region parameters are not allowed on this type
-let x: u64<'static>; //~ ERROR region parameters are not allowed on this type
-let x: float<'static>; //~ ERROR region parameters are not allowed on this type
-let x: char<'static>; //~ ERROR region parameters are not allowed on this type
+let x: int<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i8<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i16<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i32<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: i64<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: uint<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u8<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u16<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u32<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: u64<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: float<'static>; //~ ERROR lifetime parameters are not allowed on this type
+let x: char<'static>; //~ ERROR lifetime parameters are not allowed on this type
}
// aux-build:private_variant_xc.rs
+// xfail-test
extern mod private_variant_xc;
//~^ ERROR cannot infer an appropriate lifetime
}
-fn a_fn4<'a,'b>() {
- let _: int<'a> = 1; //~ ERROR region parameters are not allowed on this type
-}
-
fn main() { }
}
}
-fn matcher3(x: opts) {
- match x {
- a(ref mut i) | b(ref const i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
- c(_) => {}
- }
-}
-
fn matcher4(x: opts) {
match x {
a(ref mut i) | b(ref i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
}
fn main() {
- let _ = a::S::new(); //~ ERROR function `new` is private
+ let _ = a::S::new(); //~ ERROR method `new` is private
}
// normal method on struct
let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private
// static method on struct
- let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR function `static_meth_struct` is private
+ let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR method `static_meth_struct` is private
// normal method on enum
let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private
// static method on enum
- let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR function `static_meth_enum` is private
+ let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR method `static_meth_enum` is private
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values)
// as its numerical value along with its associated ASCII char, there
// doesn't seem to be any way around this. Also, gdb doesn't know
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
// its numerical value.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
// its numerical value.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only
// its numerical value.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break _zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
+// xfail-test
+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z debug-info
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-win32
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
+// xfail-test
+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
-
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
// debugger:break zzz
trait MyIter {
fn test_imm(&self);
- fn test_const(&const self);
}
impl<'self> MyIter for &'self [int] {
fn test_imm(&self) { assert_eq!(self[0], 1) }
- fn test_const(&const self) { assert_eq!(self[0], 1) }
}
impl<'self> MyIter for &'self str {
fn test_imm(&self) { assert_eq!(*self, "test") }
- fn test_const(&const self) { assert_eq!(self[0], 't' as u8) }
}
pub fn main() {
// XXX: Other types of mutable vecs don't currently exist
- ([1]).test_const();
- (~[1]).test_const();
- (@[1]).test_const();
- (&[1]).test_const();
- ("test").test_const();
- (~"test").test_const();
- (@"test").test_const();
- (&"test").test_const();
-
// NB: We don't do this double autoreffing for &mut self because that would
// allow creating a mutable pointer to a temporary, which would be a source
// of confusion
}
impl Foo {
- pub fn f(&const self) {}
+ pub fn f(&self) {}
}
fn g(x: &mut Foo) {
--- /dev/null
+// xfail-pretty
+
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn match_ref(v: Option<int>) -> int {
+ match v {
+ Some(ref i) => {
+ *i
+ }
+ None => {0}
+ }
+}
+
+fn match_ref_unused(v: Option<int>) {
+ match v {
+ Some(_) => {}
+ None => {}
+ }
+}
+
+fn impure(_i: int) {
+}
+
+fn match_imm_reg(v: &Option<int>) {
+ match *v {
+ Some(ref i) => {impure(*i)} // OK because immutable
+ None => {}
+ }
+}
+
+fn match_mut_reg(v: &mut Option<int>) {
+ match *v {
+ Some(ref i) => {impure(*i)} // OK, frozen
+ None => {}
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Rec {
+ f: ~int,
+}
+
+struct Outer {
+ f: Inner
+}
+
+struct Inner {
+ g: Innermost
+}
+
+struct Innermost {
+ h: ~int,
+}
+
+fn borrow(_v: &int) {}
+
+fn box_mut(v: &mut ~int) {
+ borrow(*v); // OK: &mut -> &imm
+}
+
+fn box_mut_rec(v: &mut Rec) {
+ borrow(v.f); // OK: &mut -> &imm
+}
+
+fn box_mut_recs(v: &mut Outer) {
+ borrow(v.f.g.h); // OK: &mut -> &imm
+}
+
+fn box_imm(v: &~int) {
+ borrow(*v); // OK
+}
+
+fn box_imm_rec(v: &Rec) {
+ borrow(v.f); // OK
+}
+
+fn box_imm_recs(v: &Outer) {
+ borrow(v.f.g.h); // OK
+}
+
+fn main() {
+}
}
impl<T> Container for cat<T> {
- fn len(&const self) -> uint { self.meows as uint }
- fn is_empty(&const self) -> bool { self.meows == 0 }
+ fn len(&self) -> uint { self.meows as uint }
+ fn is_empty(&self) -> bool { self.meows == 0 }
}
impl<T> Mutable for cat<T> {
}
impl SpeechMaker {
- pub fn how_many(&const self) -> uint { self.speeches }
+ pub fn how_many(&self) -> uint { self.speeches }
}
-fn foo(speaker: &const SpeechMaker) -> uint {
+fn foo(speaker: &SpeechMaker) -> uint {
speaker.how_many() + 33
}
pub fn main() {
let lincoln = SpeechMaker {speeches: 22};
- assert_eq!(foo(&const lincoln), 55);
+ assert_eq!(foo(&lincoln), 55);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-fn f(_: &const [int]) {}
+fn f(_: &[int]) {}
pub fn main() {
let v = [ 1, 2, 3 ];
#[test]
fn test_destroy_once() {
- let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
+ let p = run::Process::new("echo", [], run::ProcessOptions::new());
+ let mut p = p.unwrap();
p.destroy(); // this shouldn't crash (and nor should the destructor)
}
#[test]
fn test_destroy_twice() {
- let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
+ let p = run::Process::new("echo", [], run::ProcessOptions::new());
+ let mut p = p.unwrap();
p.destroy(); // this shouldnt crash...
p.destroy(); // ...and nor should this (and nor should the destructor)
}
}
// this process will stay alive indefinitely trying to read from stdin
- let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
+ let p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
+ let mut p = p.unwrap();
assert!(process_exists(p.get_id()));
}
pub fn main() {
- use std::hash::HashUtil; // necessary for IterBytes check
-
let a = Foo {bar: 4, baz: -3};
a == a; // check for Eq impl w/o testing its correctness
}
pub fn main() {
- use std::hash::HashUtil; // necessary for IterBytes check
-
let a = Foo {bar: 4, baz: -3};
a == a; // check for Eq impl w/o testing its correctness
#[deriving(Zero)]
struct Lots {
- a: ~str,
- b: @str,
c: Option<util::NonCopyable>,
d: u8,
e: char,
}
fn main() {
- assert!(Zero::zero::<Lots>().is_zero());
+ let lots: Lots = Zero::zero();
+ assert!(lots.is_zero());
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::sys;
+
+pub fn main() {
+ enum E { V = 0x1717171717171717 }
+ static C: E = V;
+ let expected: u64 = if sys::size_of::<uint>() < 8 {
+ 0x17171717
+ } else {
+ 0x1717171717171717
+ };
+ assert_eq!(expected, V as u64);
+ assert_eq!(expected, C as u64);
+ assert_eq!(fmt!("%?", V), ~"V");
+ assert_eq!(fmt!("%?", C), ~"V");
+}
let arr = [1,2,3];
let struc = Struc {a: 13u8, b: arr, c: 42};
let s = sys::log_str(&struc);
- assert_eq!(s, ~"{a: 13, b: [1, 2, 3], c: 42}");
+ assert_eq!(s, ~"{a: 13u8, b: [1, 2, 3], c: 42}");
}
use std::num::Float;
pub fn main() {
- let nan = Float::NaN::<float>();
+ let nan: float = Float::NaN();
assert!((nan).is_NaN());
- let inf = Float::infinity::<float>();
- assert_eq!(-inf, Float::neg_infinity::<float>());
+ let inf: float = Float::infinity();
+ let neg_inf: float = Float::neg_infinity();
+ assert_eq!(-inf, neg_inf);
assert!( nan != nan);
assert!( nan != -nan);
fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); }
}
+macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
+
pub fn main() {
- macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
// Make sure there's a poly formatter that takes anything
- t!(ifmt!("{:?}", 1), "1");
- t!(ifmt!("{:?}", A), "{}");
- t!(ifmt!("{:?}", ()), "()");
- t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
+ t!(format!("{:?}", 1), "1");
+ t!(format!("{:?}", A), "{}");
+ t!(format!("{:?}", ()), "()");
+ t!(format!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
// Various edge cases without formats
- t!(ifmt!(""), "");
- t!(ifmt!("hello"), "hello");
- t!(ifmt!("hello \\{"), "hello {");
+ t!(format!(""), "");
+ t!(format!("hello"), "hello");
+ t!(format!("hello \\{"), "hello {");
// default formatters should work
- t!(ifmt!("{}", 1i), "1");
- t!(ifmt!("{}", 1i8), "1");
- t!(ifmt!("{}", 1i16), "1");
- t!(ifmt!("{}", 1i32), "1");
- t!(ifmt!("{}", 1i64), "1");
- t!(ifmt!("{}", 1u), "1");
- t!(ifmt!("{}", 1u8), "1");
- t!(ifmt!("{}", 1u16), "1");
- t!(ifmt!("{}", 1u32), "1");
- t!(ifmt!("{}", 1u64), "1");
- t!(ifmt!("{}", 1.0f), "1");
- t!(ifmt!("{}", 1.0f32), "1");
- t!(ifmt!("{}", 1.0f64), "1");
- t!(ifmt!("{}", "a"), "a");
- t!(ifmt!("{}", ~"a"), "a");
- t!(ifmt!("{}", @"a"), "a");
- t!(ifmt!("{}", false), "false");
- t!(ifmt!("{}", 'a'), "a");
+ t!(format!("{}", 1i), "1");
+ t!(format!("{}", 1i8), "1");
+ t!(format!("{}", 1i16), "1");
+ t!(format!("{}", 1i32), "1");
+ t!(format!("{}", 1i64), "1");
+ t!(format!("{}", 1u), "1");
+ t!(format!("{}", 1u8), "1");
+ t!(format!("{}", 1u16), "1");
+ t!(format!("{}", 1u32), "1");
+ t!(format!("{}", 1u64), "1");
+ t!(format!("{}", 1.0f), "1");
+ t!(format!("{}", 1.0f32), "1");
+ t!(format!("{}", 1.0f64), "1");
+ t!(format!("{}", "a"), "a");
+ t!(format!("{}", ~"a"), "a");
+ t!(format!("{}", @"a"), "a");
+ t!(format!("{}", false), "false");
+ t!(format!("{}", 'a'), "a");
// At least exercise all the formats
- t!(ifmt!("{:b}", true), "true");
- t!(ifmt!("{:c}", '☃'), "☃");
- t!(ifmt!("{:d}", 10), "10");
- t!(ifmt!("{:i}", 10), "10");
- t!(ifmt!("{:u}", 10u), "10");
- t!(ifmt!("{:o}", 10u), "12");
- t!(ifmt!("{:x}", 10u), "a");
- t!(ifmt!("{:X}", 10u), "A");
- t!(ifmt!("{:s}", "foo"), "foo");
- t!(ifmt!("{:s}", ~"foo"), "foo");
- t!(ifmt!("{:s}", @"foo"), "foo");
- t!(ifmt!("{:p}", 0x1234 as *int), "0x1234");
- t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234");
- t!(ifmt!("{:d}", A), "aloha");
- t!(ifmt!("{:d}", B), "adios");
- t!(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
- t!(ifmt!("{1} {0}", 0, 1), "1 0");
- t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
- t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
- t!(ifmt!("{} {0:s}", "a"), "a a");
- t!(ifmt!("{} {0}", "a"), "a a");
+ t!(format!("{:b}", true), "true");
+ t!(format!("{:c}", '☃'), "☃");
+ t!(format!("{:d}", 10), "10");
+ t!(format!("{:i}", 10), "10");
+ t!(format!("{:u}", 10u), "10");
+ t!(format!("{:o}", 10u), "12");
+ t!(format!("{:x}", 10u), "a");
+ t!(format!("{:X}", 10u), "A");
+ t!(format!("{:s}", "foo"), "foo");
+ t!(format!("{:s}", ~"foo"), "foo");
+ t!(format!("{:s}", @"foo"), "foo");
+ t!(format!("{:p}", 0x1234 as *int), "0x1234");
+ t!(format!("{:p}", 0x1234 as *mut int), "0x1234");
+ t!(format!("{:d}", A), "aloha");
+ t!(format!("{:d}", B), "adios");
+ t!(format!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+ t!(format!("{1} {0}", 0, 1), "1 0");
+ t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
+ t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
+ t!(format!("{} {0:s}", "a"), "a a");
+ t!(format!("{} {0}", "a"), "a a");
// Methods should probably work
- t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
- t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1");
- t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2");
- t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3");
- t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa");
- t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb");
- t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc");
- t!(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd");
- t!(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab");
- t!(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb");
+ t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
+ t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1");
+ t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2");
+ t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3");
+ t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa");
+ t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb");
+ t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc");
+ t!(format!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd");
+ t!(format!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab");
+ t!(format!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb");
// Formatting strings and their arguments
- t!(ifmt!("{:s}", "a"), "a");
- t!(ifmt!("{:4s}", "a"), "a ");
- t!(ifmt!("{:>4s}", "a"), " a");
- t!(ifmt!("{:<4s}", "a"), "a ");
- t!(ifmt!("{:.4s}", "a"), "a");
- t!(ifmt!("{:4.4s}", "a"), "a ");
- t!(ifmt!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
- t!(ifmt!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
- t!(ifmt!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
- t!(ifmt!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
- t!(ifmt!("{:2.4s}", "aaaaa"), "aaaa");
- t!(ifmt!("{:2.4s}", "aaaa"), "aaaa");
- t!(ifmt!("{:2.4s}", "aaa"), "aaa");
- t!(ifmt!("{:2.4s}", "aa"), "aa");
- t!(ifmt!("{:2.4s}", "a"), "a ");
- t!(ifmt!("{:0>2s}", "a"), "0a");
- t!(ifmt!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
- t!(ifmt!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
- t!(ifmt!("{:1$s}", "a", 4), "a ");
- t!(ifmt!("{:-#s}", "a"), "a");
- t!(ifmt!("{:+#s}", "a"), "a");
+ t!(format!("{:s}", "a"), "a");
+ t!(format!("{:4s}", "a"), "a ");
+ t!(format!("{:>4s}", "a"), " a");
+ t!(format!("{:<4s}", "a"), "a ");
+ t!(format!("{:.4s}", "a"), "a");
+ t!(format!("{:4.4s}", "a"), "a ");
+ t!(format!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:2.4s}", "aaaaa"), "aaaa");
+ t!(format!("{:2.4s}", "aaaa"), "aaaa");
+ t!(format!("{:2.4s}", "aaa"), "aaa");
+ t!(format!("{:2.4s}", "aa"), "aa");
+ t!(format!("{:2.4s}", "a"), "a ");
+ t!(format!("{:0>2s}", "a"), "0a");
+ t!(format!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
+ t!(format!("{:1$s}", "a", 4), "a ");
+ t!(format!("{:-#s}", "a"), "a");
+ t!(format!("{:+#s}", "a"), "a");
// Formatting integers should select the right implementation based off the
// type of the argument. Also, hex/octal/binary should be defined for
// integers, but they shouldn't emit the negative sign.
- t!(ifmt!("{:d}", -1i), "-1");
- t!(ifmt!("{:d}", -1i8), "-1");
- t!(ifmt!("{:d}", -1i16), "-1");
- t!(ifmt!("{:d}", -1i32), "-1");
- t!(ifmt!("{:d}", -1i64), "-1");
- t!(ifmt!("{:t}", 1i), "1");
- t!(ifmt!("{:t}", 1i8), "1");
- t!(ifmt!("{:t}", 1i16), "1");
- t!(ifmt!("{:t}", 1i32), "1");
- t!(ifmt!("{:t}", 1i64), "1");
- t!(ifmt!("{:x}", 1i), "1");
- t!(ifmt!("{:x}", 1i8), "1");
- t!(ifmt!("{:x}", 1i16), "1");
- t!(ifmt!("{:x}", 1i32), "1");
- t!(ifmt!("{:x}", 1i64), "1");
- t!(ifmt!("{:X}", 1i), "1");
- t!(ifmt!("{:X}", 1i8), "1");
- t!(ifmt!("{:X}", 1i16), "1");
- t!(ifmt!("{:X}", 1i32), "1");
- t!(ifmt!("{:X}", 1i64), "1");
- t!(ifmt!("{:o}", 1i), "1");
- t!(ifmt!("{:o}", 1i8), "1");
- t!(ifmt!("{:o}", 1i16), "1");
- t!(ifmt!("{:o}", 1i32), "1");
- t!(ifmt!("{:o}", 1i64), "1");
-
- t!(ifmt!("{:u}", 1u), "1");
- t!(ifmt!("{:u}", 1u8), "1");
- t!(ifmt!("{:u}", 1u16), "1");
- t!(ifmt!("{:u}", 1u32), "1");
- t!(ifmt!("{:u}", 1u64), "1");
- t!(ifmt!("{:t}", 1u), "1");
- t!(ifmt!("{:t}", 1u8), "1");
- t!(ifmt!("{:t}", 1u16), "1");
- t!(ifmt!("{:t}", 1u32), "1");
- t!(ifmt!("{:t}", 1u64), "1");
- t!(ifmt!("{:x}", 1u), "1");
- t!(ifmt!("{:x}", 1u8), "1");
- t!(ifmt!("{:x}", 1u16), "1");
- t!(ifmt!("{:x}", 1u32), "1");
- t!(ifmt!("{:x}", 1u64), "1");
- t!(ifmt!("{:X}", 1u), "1");
- t!(ifmt!("{:X}", 1u8), "1");
- t!(ifmt!("{:X}", 1u16), "1");
- t!(ifmt!("{:X}", 1u32), "1");
- t!(ifmt!("{:X}", 1u64), "1");
- t!(ifmt!("{:o}", 1u), "1");
- t!(ifmt!("{:o}", 1u8), "1");
- t!(ifmt!("{:o}", 1u16), "1");
- t!(ifmt!("{:o}", 1u32), "1");
- t!(ifmt!("{:o}", 1u64), "1");
+ t!(format!("{:d}", -1i), "-1");
+ t!(format!("{:d}", -1i8), "-1");
+ t!(format!("{:d}", -1i16), "-1");
+ t!(format!("{:d}", -1i32), "-1");
+ t!(format!("{:d}", -1i64), "-1");
+ t!(format!("{:t}", 1i), "1");
+ t!(format!("{:t}", 1i8), "1");
+ t!(format!("{:t}", 1i16), "1");
+ t!(format!("{:t}", 1i32), "1");
+ t!(format!("{:t}", 1i64), "1");
+ t!(format!("{:x}", 1i), "1");
+ t!(format!("{:x}", 1i8), "1");
+ t!(format!("{:x}", 1i16), "1");
+ t!(format!("{:x}", 1i32), "1");
+ t!(format!("{:x}", 1i64), "1");
+ t!(format!("{:X}", 1i), "1");
+ t!(format!("{:X}", 1i8), "1");
+ t!(format!("{:X}", 1i16), "1");
+ t!(format!("{:X}", 1i32), "1");
+ t!(format!("{:X}", 1i64), "1");
+ t!(format!("{:o}", 1i), "1");
+ t!(format!("{:o}", 1i8), "1");
+ t!(format!("{:o}", 1i16), "1");
+ t!(format!("{:o}", 1i32), "1");
+ t!(format!("{:o}", 1i64), "1");
+
+ t!(format!("{:u}", 1u), "1");
+ t!(format!("{:u}", 1u8), "1");
+ t!(format!("{:u}", 1u16), "1");
+ t!(format!("{:u}", 1u32), "1");
+ t!(format!("{:u}", 1u64), "1");
+ t!(format!("{:t}", 1u), "1");
+ t!(format!("{:t}", 1u8), "1");
+ t!(format!("{:t}", 1u16), "1");
+ t!(format!("{:t}", 1u32), "1");
+ t!(format!("{:t}", 1u64), "1");
+ t!(format!("{:x}", 1u), "1");
+ t!(format!("{:x}", 1u8), "1");
+ t!(format!("{:x}", 1u16), "1");
+ t!(format!("{:x}", 1u32), "1");
+ t!(format!("{:x}", 1u64), "1");
+ t!(format!("{:X}", 1u), "1");
+ t!(format!("{:X}", 1u8), "1");
+ t!(format!("{:X}", 1u16), "1");
+ t!(format!("{:X}", 1u32), "1");
+ t!(format!("{:X}", 1u64), "1");
+ t!(format!("{:o}", 1u), "1");
+ t!(format!("{:o}", 1u8), "1");
+ t!(format!("{:o}", 1u16), "1");
+ t!(format!("{:o}", 1u32), "1");
+ t!(format!("{:o}", 1u64), "1");
// Test the flags for formatting integers
- t!(ifmt!("{:3d}", 1), " 1");
- t!(ifmt!("{:>3d}", 1), " 1");
- t!(ifmt!("{:>+3d}", 1), " +1");
- t!(ifmt!("{:<3d}", 1), "1 ");
- t!(ifmt!("{:#d}", 1), "1");
- t!(ifmt!("{:#x}", 10), "0xa");
- t!(ifmt!("{:#X}", 10), "0xA");
- t!(ifmt!("{:#5x}", 10), " 0xa");
- t!(ifmt!("{:#o}", 10), "0o12");
- t!(ifmt!("{:08x}", 10), "0000000a");
- t!(ifmt!("{:8x}", 10), " a");
- t!(ifmt!("{:<8x}", 10), "a ");
- t!(ifmt!("{:>8x}", 10), " a");
- t!(ifmt!("{:#08x}", 10), "0x00000a");
- t!(ifmt!("{:08d}", -10), "-0000010");
- t!(ifmt!("{:x}", -1u8), "ff");
- t!(ifmt!("{:X}", -1u8), "FF");
- t!(ifmt!("{:t}", -1u8), "11111111");
- t!(ifmt!("{:o}", -1u8), "377");
- t!(ifmt!("{:#x}", -1u8), "0xff");
- t!(ifmt!("{:#X}", -1u8), "0xFF");
- t!(ifmt!("{:#t}", -1u8), "0b11111111");
- t!(ifmt!("{:#o}", -1u8), "0o377");
+ t!(format!("{:3d}", 1), " 1");
+ t!(format!("{:>3d}", 1), " 1");
+ t!(format!("{:>+3d}", 1), " +1");
+ t!(format!("{:<3d}", 1), "1 ");
+ t!(format!("{:#d}", 1), "1");
+ t!(format!("{:#x}", 10), "0xa");
+ t!(format!("{:#X}", 10), "0xA");
+ t!(format!("{:#5x}", 10), " 0xa");
+ t!(format!("{:#o}", 10), "0o12");
+ t!(format!("{:08x}", 10), "0000000a");
+ t!(format!("{:8x}", 10), " a");
+ t!(format!("{:<8x}", 10), "a ");
+ t!(format!("{:>8x}", 10), " a");
+ t!(format!("{:#08x}", 10), "0x00000a");
+ t!(format!("{:08d}", -10), "-0000010");
+ t!(format!("{:x}", -1u8), "ff");
+ t!(format!("{:X}", -1u8), "FF");
+ t!(format!("{:t}", -1u8), "11111111");
+ t!(format!("{:o}", -1u8), "377");
+ t!(format!("{:#x}", -1u8), "0xff");
+ t!(format!("{:#X}", -1u8), "0xFF");
+ t!(format!("{:#t}", -1u8), "0b11111111");
+ t!(format!("{:#o}", -1u8), "0o377");
// Signed combinations
- t!(ifmt!("{:+5d}", 1), " +1");
- t!(ifmt!("{:+5d}", -1), " -1");
- t!(ifmt!("{:05d}", 1), "00001");
- t!(ifmt!("{:05d}", -1), "-0001");
- t!(ifmt!("{:+05d}", 1), "+0001");
- t!(ifmt!("{:+05d}", -1), "-0001");
+ t!(format!("{:+5d}", 1), " +1");
+ t!(format!("{:+5d}", -1), " -1");
+ t!(format!("{:05d}", 1), "00001");
+ t!(format!("{:05d}", -1), "-0001");
+ t!(format!("{:+05d}", 1), "+0001");
+ t!(format!("{:+05d}", -1), "-0001");
// Some float stuff
- t!(ifmt!("{:f}", 1.0f), "1");
- t!(ifmt!("{:f}", 1.0f32), "1");
- t!(ifmt!("{:f}", 1.0f64), "1");
- t!(ifmt!("{:.3f}", 1.0f), "1.000");
- t!(ifmt!("{:10.3f}", 1.0f), " 1.000");
- t!(ifmt!("{:+10.3f}", 1.0f), " +1.000");
- t!(ifmt!("{:+10.3f}", -1.0f), " -1.000");
+ t!(format!("{:f}", 1.0f), "1");
+ t!(format!("{:f}", 1.0f32), "1");
+ t!(format!("{:f}", 1.0f64), "1");
+ t!(format!("{:.3f}", 1.0f), "1.000");
+ t!(format!("{:10.3f}", 1.0f), " 1.000");
+ t!(format!("{:+10.3f}", 1.0f), " +1.000");
+ t!(format!("{:+10.3f}", -1.0f), " -1.000");
+
+ test_write();
+ test_print();
+}
+
+// Basic test to make sure that we can invoke the `write!` macro with an
+// io::Writer instance.
+fn test_write() {
+ use std::rt::io::Decorator;
+ use std::rt::io::mem::MemWriter;
+ use std::rt::io;
+ use std::str;
+
+ let mut buf = MemWriter::new();
+ write!(&mut buf as &mut io::Writer, "{}", 3);
+ {
+ let w = &mut buf as &mut io::Writer;
+ write!(w, "{foo}", foo=4);
+ write!(w, "{:s}", "hello");
+ writeln!(w, "{}", "line");
+ writeln!(w, "{foo}", foo="bar");
+ }
+
+ let s = str::from_bytes_owned(buf.inner());
+ t!(s, "34helloline\nbar\n");
}
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+fn test_print() {
+ print!("hi");
+ print!("{:?}", ~[0u8]);
+ println!("hello");
+ println!("this is a {}", "test");
+ println!("{foo}", foo="bar");
+}
use std::hashmap::HashMap;
pub fn main() {
- let mut buggy_map: HashMap<uint, &uint> = HashMap::new::<uint, &uint>();
+ let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
let x = ~1;
buggy_map.insert(42, &*x);
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #5783
+// Nondeterministic behavior when referencing a closure more than once
+
+fn main() {
+ let a: &fn(int) -> @fn(int) -> int = |x:int| |y:int| -> int x + y;
+ let b = a(2);
+ assert!(a(2)(3) == 5);
+ assert!(b(6) == 8);
+}
+// xfail-test
+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
pub fn main() {
let x = list::from_vec([a(22u), b(~"hi")]);
- let exp = ~"@Cons(a(22), @Cons(b(~\"hi\"), @Nil))";
+ let exp = ~"@Cons(a(22u), @Cons(b(~\"hi\"), @Nil))";
let act = fmt!("%?", x);
assert!(act == exp);
check_log(exp, x);
}
pub fn main() {
- assert_eq!(~"a(22)", fmt!("%?", a(22u)));
+ assert_eq!(~"a(22u)", fmt!("%?", a(22u)));
assert_eq!(~"b(~\"hi\")", fmt!("%?", b(~"hi")));
assert_eq!(~"c", fmt!("%?", c));
assert_eq!(~"d", fmt!("%?", d));
--- /dev/null
+struct S<T> {
+ contents: T,
+}
+
+impl<T> S<T> {
+ fn new<U>(x: T, _: U) -> S<T> {
+ S {
+ contents: x,
+ }
+ }
+}
+
+trait Trait<T> {
+ fn new<U>(x: T, y: U) -> Self;
+}
+
+struct S2 {
+ contents: int,
+}
+
+impl Trait<int> for S2 {
+ fn new<U>(x: int, _: U) -> S2 {
+ S2 {
+ contents: x,
+ }
+ }
+}
+
+fn main() {
+ let _ = S::<int>::new::<float>(1, 1.0);
+ let _: S2 = Trait::<int>::new::<float>(1, 1.0);
+}
+
+// xfail-pretty
+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub fn main() {
- let foo: int = 1;
- let bar: int = 2;
- let foobar = foo + bar;
-
- let nope = None::<int> + None::<int>;
- let somefoo = Some(foo) + None::<int>;
- let somebar = None::<int> + Some(bar);
- let somefoobar = Some(foo) + Some(bar);
-
- assert_eq!(nope, None::<int>);
- assert_eq!(somefoo, None::<int>);
- assert_eq!(somebar, None::<int>);
- assert_eq!(foobar, somefoobar.unwrap());
-}
// because `inner`s alignment was 4.
assert_eq!(sys::size_of::<Outer>(), m::size());
- assert_eq!(y, ~"{c8: 22, t: {c64: 44}}");
+ assert_eq!(y, ~"{c8: 22u8, t: {c64: 44u32}}");
}
}
// because `Inner`s alignment was 4.
assert_eq!(sys::size_of::<Outer>(), m::m::size());
- assert_eq!(y, ~"{c8: 22, t: {c64: 44}}");
+ assert_eq!(y, ~"{c8: 22u8, t: {c64: 44u64}}");
}
}
true
}
- fn visit_var(&self) -> bool {
- if ! self.inner.visit_var() { return false; }
- true
- }
-
- fn visit_var_integral(&self) -> bool {
- if ! self.inner.visit_var_integral() { return false; }
- true
- }
-
fn visit_param(&self, i: uint) -> bool {
if ! self.inner.visit_param(i) { return false; }
true
true
}
- fn visit_constr(&self, inner: *TyDesc) -> bool {
- if ! self.inner.visit_constr(inner) { return false; }
- true
- }
-
fn visit_closure_ptr(&self, ck: uint) -> bool {
self.align_to::<@fn()>();
if ! self.inner.visit_closure_ptr(ck) { return false; }
fn visit_trait(&self) -> bool { true }
- fn visit_var(&self) -> bool { true }
- fn visit_var_integral(&self) -> bool { true }
fn visit_param(&self, _i: uint) -> bool { true }
fn visit_self(&self) -> bool { true }
fn visit_type(&self) -> bool { true }
fn visit_opaque_box(&self) -> bool { true }
- fn visit_constr(&self, _inner: *TyDesc) -> bool { true }
fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
}
fn visit_trait(&self) -> bool { true }
- fn visit_var(&self) -> bool { true }
- fn visit_var_integral(&self) -> bool { true }
fn visit_param(&self, _i: uint) -> bool { true }
fn visit_self(&self) -> bool { true }
fn visit_type(&self) -> bool { true }
fn visit_opaque_box(&self) -> bool { true }
- fn visit_constr(&self, _inner: *TyDesc) -> bool { true }
fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
}
#[nolink]
extern {
- static mut debug_static_mut: libc::c_int;
- pub fn debug_static_mut_check_four();
+ static mut rust_dbg_static_mut: libc::c_int;
+ pub fn rust_dbg_static_mut_check_four();
}
unsafe fn static_bound(_: &'static libc::c_int) {}
#[fixed_stack_segment] #[inline(never)]
unsafe fn run() {
- assert!(debug_static_mut == 3);
- debug_static_mut = 4;
- assert!(debug_static_mut == 4);
- debug_static_mut_check_four();
- debug_static_mut += 1;
- assert!(debug_static_mut == 5);
- debug_static_mut *= 3;
- assert!(debug_static_mut == 15);
- debug_static_mut = -3;
- assert!(debug_static_mut == -3);
- static_bound(&debug_static_mut);
- static_bound_set(&mut debug_static_mut);
+ assert!(rust_dbg_static_mut == 3);
+ rust_dbg_static_mut = 4;
+ assert!(rust_dbg_static_mut == 4);
+ rust_dbg_static_mut_check_four();
+ rust_dbg_static_mut += 1;
+ assert!(rust_dbg_static_mut == 5);
+ rust_dbg_static_mut *= 3;
+ assert!(rust_dbg_static_mut == 15);
+ rust_dbg_static_mut = -3;
+ assert!(rust_dbg_static_mut == -3);
+ static_bound(&rust_dbg_static_mut);
+ static_bound_set(&mut rust_dbg_static_mut);
}
pub fn main() {
#[nolink]
extern {
- pub fn debug_abi_1(q: Quad) -> Quad;
- pub fn debug_abi_2(f: Floats) -> Floats;
+ pub fn rust_dbg_abi_1(q: Quad) -> Quad;
+ pub fn rust_dbg_abi_2(f: Floats) -> Floats;
}
}
b: 0xbbbb_bbbb_bbbb_bbbb_u64,
c: 0xcccc_cccc_cccc_cccc_u64,
d: 0xdddd_dddd_dddd_dddd_u64 };
- let qq = rustrt::debug_abi_1(q);
+ let qq = rustrt::rust_dbg_abi_1(q);
error!("a: %x", qq.a as uint);
error!("b: %x", qq.b as uint);
error!("c: %x", qq.c as uint);
let f = Floats { a: 1.234567890e-15_f64,
b: 0b_1010_1010_u8,
c: 1.0987654321e-15_f64 };
- let ff = rustrt::debug_abi_2(f);
+ let ff = rustrt::rust_dbg_abi_2(f);
error!("a: %f", ff.a as float);
error!("b: %u", ff.b as uint);
error!("c: %f", ff.c as float);
let x = t_rec {c8: 22u8, t: a_tag(44u64)};
let y = fmt!("%?", x);
info!("y = %s", y);
- assert_eq!(y, ~"{c8: 22, t: a_tag(44)}");
+ assert_eq!(y, ~"{c8: 22u8, t: a_tag(44u64)}");
}
+// xfail-pretty
+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
assert_eq!(0i.thing(3.14, 1), (3.14, 1));
assert_eq!(B::staticthing(&0i, 3.14, 1), (3.14, 1));
- assert_eq!(B::staticthing::<float, int, int>(&0i, 3.14, 1), (3.14, 1));
+ assert_eq!(B::<float>::staticthing::<int>(&0i, 3.14, 1), (3.14, 1));
assert_eq!(g(0i, 3.14, 1), (3.14, 1));
assert_eq!(g(false, 3.14, 1), (3.14, 1));
use std::io;
pub trait HasNew<T> {
- fn new() -> T;
+ fn new() -> Self;
}
pub struct Foo {
}
pub fn main() {
- let _f: base::Foo = base::HasNew::new::<base::Foo, base::Foo>();
- let _b: base::Bar = base::HasNew::new::<base::Bar, base::Bar>();
+ let _f: base::Foo = base::HasNew::<base::Foo>::new();
+ let _b: base::Bar = base::HasNew::<base::Bar>::new();
}