See #3994.
# Same interface as above, but deletes rather than just listing the files.
define REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT
- $(Q)MATCHES="$(filter-out %$(3),$(wildcard $(1)/$(2)))"; if [ -n "$$MATCHES" ] ; then echo "Warning: removing previous" \'$(2)\' "libraries:" $$MATCHES; rm -v $$MATCHES ; fi
+ $(Q)MATCHES="$(filter-out %$(3),$(wildcard $(1)/$(2)))"; if [ -n "$$MATCHES" ] ; then echo "Warning: removing previous" \'$(2)\' "libraries:" $$MATCHES; rm $$MATCHES ; fi
endef
# We use a different strategy for LIST_ALL_OLD_GLOB_MATCHES_EXCEPT
This is a compiler for Rust, including standard libraries, tools and
documentation.
+## Quick Start
-## Installation
+### Windows
-The Rust compiler currently must be built from a [tarball], unless you
-are on Windows, in which case using the [installer][win-exe] is
-recommended.
+1. Download and use the [installer][win-exe].
+2. Read the [tutorial].
+2. Enjoy!
-Since the Rust compiler is written in Rust, it must be built by
-a precompiled "snapshot" version of itself (made in an earlier state
-of development). As such, source builds require a connection to
-the Internet, to fetch snapshots, and an OS that can execute the
-available snapshot binaries.
+> ***Note:*** Windows users should read the detailed
+> [getting started][wiki-start] notes on the wiki. Even when using
+> the binary installer the Windows build requires a MinGW installation,
+> the precise details of which are not discussed here.
+
+[tutorial]: http://static.rust-lang.org/doc/tutorial.html
+[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
+[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
+
+### Linux / OS X
+
+1. Install the prerequisites (if not already installed)
+ * g++ 4.4 or clang++ 3.x
+ * python 2.6 or later (but not 3.x)
+ * perl 5.0 or later
+ * gnu make 3.81 or later
+ * curl
+2. Download and build Rust
+ You can either download a [tarball] or build directly from the [repo].
+
+ To build from the [tarball] do:
+
+ $ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
+ $ tar -xzf rust-0.7.tar.gz
+ $ cd rust-0.7
+
+ Or to build from the [repo] do:
+
+ $ git clone https://github.com/mozilla/rust.git
+ $ cd rust
+
+ Now that you have Rust's source code, you can configure and build it:
+
+ $ ./configure
+ $ make && make install
+
+ You may need to use `sudo make install` if you do not normally have
+ permission to modify the destination directory. The install locations can
+ be adjusted by passing a `--prefix` argument to `configure`. Various other
+ options are also supported, pass `--help` for more information on them.
+
+ When complete, `make install` will place several programs into
+ `/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
+ API-documentation tool, and `rustpkg`, the Rust package manager and build
+ system.
+3. Read the [tutorial].
+4. Enjoy!
+
+[repo]: https://github.com/mozilla/rust
+[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
+[tutorial]: http://static.rust-lang.org/doc/tutorial.html
+
+## Notes
+
+Since the Rust compiler is written in Rust, it must be built by a
+precompiled "snapshot" version of itself (made in an earlier state of
+development). As such, source builds require a connection to the Internet, to
+fetch snapshots, and an OS that can execute the available snapshot binaries.
Snapshot binaries are currently built and tested on several platforms:
You may find that other platforms work, but these are our "tier 1"
supported build environments that are most likely to work.
-> ***Note:*** Windows users should read the detailed
-> [getting started][wiki-start] notes on the wiki. Even when using
-> the binary installer the Windows build requires a MinGW installation,
-> the precise details of which are not discussed here.
-
-To build from source you will also need the following prerequisite
-packages:
-
-* g++ 4.4 or clang++ 3.x
-* python 2.6 or later (but not 3.x)
-* perl 5.0 or later
-* gnu make 3.81 or later
-* curl
-
-Assuming you're on a relatively modern *nix system and have met the
-prerequisites, something along these lines should work.
-
- $ curl -O http://static.rust-lang.org/dist/rust-0.7.tar.gz
- $ tar -xzf rust-0.7.tar.gz
- $ cd rust-0.7
- $ ./configure
- $ make && make install
+Rust currently needs about 1.8G of RAM to build without swapping; if it hits
+swap, it will take a very long time to build.
-You may need to use `sudo make install` if you do not normally have
-permission to modify the destination directory. The install locations
-can be adjusted by passing a `--prefix` argument to
-`configure`. Various other options are also supported, pass `--help`
-for more information on them.
+There is lots more documentation in the [wiki].
-When complete, `make install` will place several programs into
-`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
-API-documentation tool, and `rustpkg`, the Rust package manager and build system.
-
-[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
-[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
-[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
+[wiki]: https://github.com/mozilla/rust/wiki
## License
See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.
-## More help
-
-The [tutorial] is a good starting point.
-
-[tutorial]: http://static.rust-lang.org/doc/tutorial.html
cd ${CFG_SRC_DIR}
msg "git: submodule sync"
- "${CFG_GIT}" submodule --quiet sync
+ "${CFG_GIT}" submodule sync
msg "git: submodule update"
- "${CFG_GIT}" submodule --quiet update --init
+ "${CFG_GIT}" submodule update --init
need_ok "git failed"
msg "git: submodule foreach sync"
- "${CFG_GIT}" submodule --quiet foreach --recursive 'if test -e .gitmodules; then git submodule sync; fi'
+ "${CFG_GIT}" submodule foreach --recursive 'if test -e .gitmodules; then git submodule sync; fi'
need_ok "git failed"
msg "git: submodule foreach update"
- "${CFG_GIT}" submodule --quiet update --init --recursive
+ "${CFG_GIT}" submodule update --init --recursive
need_ok "git failed"
# NB: this is just for the sake of getting the submodule SHA1 values
"${CFG_GIT}" submodule status --recursive
msg "git: submodule clobber"
- "${CFG_GIT}" submodule --quiet foreach --recursive git clean -dxf
+ "${CFG_GIT}" submodule foreach --recursive git clean -dxf
need_ok "git failed"
- "${CFG_GIT}" submodule --quiet foreach --recursive git checkout .
+ "${CFG_GIT}" submodule foreach --recursive git checkout .
need_ok "git failed"
cd ${CFG_BUILD_DIR}
esac
need_ok "LLVM configure failed"
- # Hack the tools Makefile to turn off the clang build
- sed -i 's/clang//g' tools/Makefile
-
cd $CFG_BUILD_DIR
fi
The Rust compiler is always invoked with a single source file as input, and always produces a single output crate.
The processing of that source file may result in other source files being loaded as modules.
-Source files typically have the extension `.rs` but, by convention,
-source files that represent crates have the extension `.rc`, called *crate files*.
+Source files have the extension `.rs`.
A Rust source file describes a module, the name and
location of which -- in the module tree of the current crate -- are defined
};
~~~~
+#### Mutable statics
+
+If a static item is declared with the ```mut``` keyword, then it is allowed to
+be modified by the program. One of Rust's goals is to make concurrency bugs hard
+to run into, and this is obviously a very large source of race conditions or
+other bugs. For this reason, an ```unsafe``` block is required when either
+reading or writing a mutable static variable. Care should be taken to ensure
+that modifications to a mutable static are safe with respect to other tasks
+running in the same process.
+
+Mutable statics are still very useful, however. They can be used with C
+libraries and can also be bound from C libraries (in an ```extern``` block).
+
+~~~
+# fn atomic_add(_: &mut uint, _: uint) -> uint { 2 }
+
+static mut LEVELS: uint = 0;
+
+// This violates the idea of no shared state, and this doesn't internally
+// protect against races, so this function is `unsafe`
+unsafe fn bump_levels_unsafe1() -> uint {
+ let ret = LEVELS;
+ LEVELS += 1;
+ return ret;
+}
+
+// Assuming that we have an atomic_add function which returns the old value,
+// this function is "safe" but the meaning of the return value may not be what
+// callers expect, so it's still marked as `unsafe`
+unsafe fn bump_levels_unsafe2() -> uint {
+ return atomic_add(&mut LEVELS, 1);
+}
+
+~~~
+
### Traits
A _trait_ describes a set of method types.
you would set it to `rustc::metadata::creader`. To see just error logging
use `rustc=0`.
-Note that when compiling either `.rs` or `.rc` files that don't specify a
+Note that when compiling source files that don't specify a
crate name the crate is given a default name that matches the source file,
with the extension removed. In that case, to turn on logging for a program
compiled from, e.g. `helloworld.rs`, `RUST_LOG` should be set to `helloworld`.
> know.
[bug-3319]: https://github.com/mozilla/rust/issues/3319
-[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
+[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
To build from source you will also need the following prerequisite
packages:
`rusti`, the Rust REPL; and `rust`, a tool which acts both as a unified
interface for them, and for a few common command line scenarios.
-[wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust
[tarball]: http://static.rust-lang.org/dist/rust-0.7.tar.gz
[win-exe]: http://static.rust-lang.org/dist/rust-0.7-install.exe
You can define your own syntax extensions with the macro system. For details, see the [macro tutorial][macros].
-[macros]: tutorial-macros.html
-
# Control structures
## Conditionals
> items.
~~~~
-# use std::float;
-# use std::num::atan;
+use std::float;
+use std::num::atan;
fn angle(vector: (float, float)) -> float {
let pi = float::consts::pi;
match vector {
`loop` denotes an infinite loop, and is the preferred way of writing `while true`:
~~~~
-# use std::int;
+use std::int;
let mut x = 5;
loop {
x += x - 3;
patterns, as in this definition of `area`:
~~~~
-# use std::float;
+use std::float;
# struct Point {x: float, y: float}
# enum Shape { Circle(Point, float), Rectangle(Point, Point) }
fn area(sh: Shape) -> float {
Enum variants may also be structs. For example:
~~~~
-# use std::float;
+use std::float;
# struct Point { x: float, y: float }
# fn square(x: float) -> float { x * x }
enum Shape {
them. Owned closures are used in concurrent code, particularly
for spawning [tasks][tasks].
-[tasks]: tutorial-tasks.html
-
## Closure compatibility
Rust closures have a convenient subtyping property: you can pass any kind of
may be omitted from `do` expressions.
~~~~
-# use std::task::spawn;
+use std::task::spawn;
+
do spawn {
debug!("Kablam!");
}
To call such a method, just prefix it with the type name and a double colon:
~~~~
-# use std::float::consts::pi;
+use std::float::consts::pi;
struct Circle { radius: float }
impl Circle {
fn new(area: float) -> Circle { Circle { radius: (area / pi).sqrt() } }
Generic `type`, `struct`, and `enum` declarations follow the same pattern:
~~~~
-# use std::hashmap::HashMap;
+use std::hashmap::HashMap;
type Set<T> = HashMap<T, ()>;
struct Stack<T> {
implementation to use.
~~~~
-# use std::float::consts::pi;
+use std::float::consts::pi;
trait Shape { fn new(area: float) -> Self; }
struct Circle { radius: float }
struct Square { length: float }
Now, we can implement `Circle` on a type only if we also implement `Shape`.
~~~~
-# use std::float::consts::pi;
+use std::float::consts::pi;
# trait Shape { fn area(&self) -> float; }
# trait Circle : Shape { fn radius(&self) -> float; }
# struct Point { x: float, y: float }
Likewise, supertrait methods may also be called on trait objects.
~~~ {.xfail-test}
-# use std::float::consts::pi;
+use std::float::consts::pi;
# trait Shape { fn area(&self) -> float; }
# trait Circle : Shape { fn radius(&self) -> float; }
# struct Point { x: float, y: float }
[ffi]: tutorial-ffi.html
[wiki]: https://github.com/mozilla/rust/wiki/Docs
-[unit testing]: https://github.com/mozilla/rust/wiki/Doc-unit-testing
-[rustdoc]: https://github.com/mozilla/rust/wiki/Doc-using-rustdoc
-[cargo]: https://github.com/mozilla/rust/wiki/Doc-using-cargo-to-manage-packages
-[attributes]: https://github.com/mozilla/rust/wiki/Doc-attributes
-[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
# $(1) stage
# $(2) triple
-ifdef CFG_INSTALL_SNAP
-snap-stage$(1)-H-$(2): $$(HSREQ$(1)_H_$(2))
- $(CFG_PYTHON) $(S)src/etc/make-snapshot.py stage$(1) $(2) install
-else
snap-stage$(1)-H-$(2): $$(HSREQ$(1)_H_$(2))
$(CFG_PYTHON) $(S)src/etc/make-snapshot.py stage$(1) $(2)
-endif
endef
# code, make sure that these common warnings are denied by default. These can
# be overridden during development temporarily. For stage0, we allow all these
# to suppress warnings which may be bugs in stage0 (should be fixed in stage1+)
-# NOTE: add "-A warnings" after snapshot to WFLAGS_ST0
-WFLAGS_ST0 = -A unrecognized-lint
+WFLAGS_ST0 = -A warnings
WFLAGS_ST1 = -D warnings
WFLAGS_ST2 = -D warnings
let mut tests = ~[];
let dirs = os::list_dir_path(&config.src_base);
for dirs.iter().advance |file| {
- let file = (*file).clone();
+ let file = file.clone();
debug!("inspecting file %s", file.to_str());
- if is_test(config, file) {
- let t = do make_test(config, file) {
+ if is_test(config, &file) {
+ let t = do make_test(config, &file) {
match config.mode {
- mode_codegen => make_metrics_test_closure(config, file),
- _ => make_test_closure(config, file)
+ mode_codegen => make_metrics_test_closure(config, &file),
+ _ => make_test_closure(config, &file)
}
};
tests.push(t)
if not re.search(r"\bextern mod extra\b", block):
block = "extern mod extra;\n" + block
block = """#[ forbid(ctypes) ];
-#[ forbid(deprecated_pattern) ];
-#[ forbid(implicit_copies) ];
-#[ forbid(non_implicitly_copyable_typarams) ];
#[ forbid(path_statement) ];
#[ forbid(type_limits) ];
#[ forbid(unrecognized_lint) ];
import snapshot, sys
-if len(sys.argv) == 3:
- print(snapshot.make_snapshot(sys.argv[1], sys.argv[2], ""))
-else:
- print(snapshot.make_snapshot(sys.argv[1], sys.argv[2], sys.argv[3]))
+print(snapshot.make_snapshot(sys.argv[1], sys.argv[2]))
return scrub(h.hexdigest())
-def make_snapshot(stage, triple, flag):
+def make_snapshot(stage, triple):
kernel = get_kernel(triple)
platform = get_platform(triple)
rev = local_rev_short_sha()
shutil.move(file0, file1)
- if flag == "install":
- # FIXME (#2664): this is an ugly quick hack; pls make it better
- path = file1
- comps = path.split("-")
- parts = { 'year': comps[2], \
- 'month': comps[3], \
- 'date': comps[4], \
- 'check': comps[5], \
- 'plat': comps[6], \
- 'arch': comps[7], \
- 'sha': comps[8].split(".")[0] }
-
- shutil.move(path, "dl/" + path)
- shutil.move('src/snapshots.txt', 'src/snapshots-old.txt')
-
- newf = open('src/snapshots.txt', 'w')
- newf.write("T %(year)s-%(month)s-%(date)s %(check)s\n" % parts)
- newf.write(" %(plat)s-%(arch)s %(sha)s\n\n" % parts)
-
- oldf = open('src/snapshots-old.txt', 'r')
- for line in oldf:
- newf.write(line)
- oldf.close()
-
- newf.close()
-
- os.remove('src/snapshots-old.txt')
-
-
return file1
--- /dev/null
+" Vim compiler file
+" Compiler: Rust Compiler
+" Maintainer: Chris Morgan <me@chrismorgan.info>
+" Latest Revision: 2013 Jul 12
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "rustc"
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+if exists(":CompilerSet") != 2
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent == 1
+ CompilerSet makeprg=rustc
+else
+ CompilerSet makeprg=rustc\ \%
+endif
+
+CompilerSet errorformat=
+ \%f:%l:%c:\ %t%*[^:]:\ %m,
+ \%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m,
+ \%-G%f:%l\ %s,
+ \%-G%*[\ ]^,
+ \%-G%*[\ ]^%*[~],
+ \%-G%*[\ ]...
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
)
_rustc_opts_lint=(
'path-statement[path statements with no effect]'
- 'deprecated-pattern[warn about deprecated uses of pattern bindings]'
- 'non-implicitly-copyable-typarams[passing non implicitly copyable types as copy type params]'
'missing-trait-doc[detects missing documentation for traits]'
'missing-struct-doc[detects missing documentation for structs]'
'ctypes[proper use of core::libc types in foreign modules]'
- 'implicit-copies[implicit copies of non implicitly copyable data]'
"unused-mut[detect mut variables which don't need to be mutable]"
'unused-imports[imports that are never used]'
'heap-memory[use of any (~ type or @ type) heap memory]'
/// As sync::condvar, a mechanism for unlock-and-descheduling and signaling.
pub struct Condvar<'self> {
- is_mutex: bool,
- failed: &'self mut bool,
- cond: &'self sync::Condvar<'self>
+ priv is_mutex: bool,
+ priv failed: &'self mut bool,
+ priv cond: &'self sync::Condvar<'self>
}
impl<'self> Condvar<'self> {
****************************************************************************/
/// An atomically reference counted wrapper for shared immutable state.
-pub struct ARC<T> { x: UnsafeAtomicRcBox<T> }
+pub struct ARC<T> { priv x: UnsafeAtomicRcBox<T> }
/// Create an atomically reference counted wrapper.
pub fn ARC<T:Freeze + Send>(data: T) -> ARC<T> {
pub fn get<'a>(&'a self) -> &'a T {
unsafe { &*self.x.get_immut() }
}
+
+ /**
+ * Retrieve the data back out of the ARC. This function blocks until the
+ * reference given to it is the last existing one, and then unwrap the data
+ * instead of destroying it.
+ *
+ * If multiple tasks call unwrap, all but the first will fail. Do not call
+ * unwrap from a task that holds another reference to the same ARC; it is
+ * guaranteed to deadlock.
+ */
+ pub fn unwrap(self) -> T {
+ let ARC { x: x } = self;
+ unsafe { x.unwrap() }
+ }
}
/**
****************************************************************************/
#[doc(hidden)]
-struct MutexARCInner<T> { lock: Mutex, failed: bool, data: T }
+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> { x: UnsafeAtomicRcBox<MutexARCInner<T>> }
+struct MutexARC<T> { priv x: UnsafeAtomicRcBox<MutexARCInner<T>> }
/// Create a mutex-protected ARC with the supplied data.
pub fn MutexARC<T:Send>(user_data: T) -> MutexARC<T> {
cond: cond })
}
}
+
+ /**
+ * Retrieves the data, blocking until all other references are dropped,
+ * exactly as arc::unwrap.
+ *
+ * Will additionally fail if another task has failed while accessing the arc.
+ */
+ pub fn unwrap(self) -> T {
+ let MutexARC { x: x } = self;
+ let inner = unsafe { x.unwrap() };
+ let MutexARCInner { failed: failed, data: data, _ } = inner;
+ if failed {
+ fail!(~"Can't unwrap poisoned MutexARC - another task failed inside!");
+ }
+ data
+ }
}
// Common code for {mutex.access,rwlock.write}{,_cond}.
****************************************************************************/
#[doc(hidden)]
-struct RWARCInner<T> { lock: RWlock, failed: bool, data: T }
+struct RWARCInner<T> { priv lock: RWlock, priv failed: bool, priv data: T }
/**
* A dual-mode ARC protected by a reader-writer lock. The data can be accessed
* mutably or immutably, and immutably-accessing tasks may run concurrently.
*
* Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
*/
-#[mutable] // XXX remove after snap
#[no_freeze]
struct RWARC<T> {
- x: UnsafeAtomicRcBox<RWARCInner<T>>,
+ priv x: UnsafeAtomicRcBox<RWARCInner<T>>,
}
/// Create a reader/writer ARC with the supplied data.
}
}
}
+
+ /**
+ * Retrieves the data, blocking until all other references are dropped,
+ * exactly as arc::unwrap.
+ *
+ * Will additionally fail if another task has failed while accessing the arc
+ * in write mode.
+ */
+ pub fn unwrap(self) -> T {
+ let RWARC { x: x, _ } = self;
+ let inner = unsafe { x.unwrap() };
+ let RWARCInner { failed: failed, data: data, _ } = inner;
+ if failed {
+ fail!(~"Can't unwrap poisoned RWARC - another task failed inside!")
+ }
+ data
+ }
}
// Borrowck rightly complains about immutably aliasing the rwlock in order to
}
}
#[test] #[should_fail] #[ignore(cfg(windows))]
+ pub fn test_mutex_arc_unwrap_poison() {
+ let arc = MutexARC(1);
+ let arc2 = ~(&arc).clone();
+ let (p, c) = comm::stream();
+ do task::spawn {
+ unsafe {
+ do arc2.access |one| {
+ c.send(());
+ assert!(*one == 2);
+ }
+ }
+ }
+ let _ = p.recv();
+ let one = arc.unwrap();
+ assert!(one == 1);
+ }
+ #[test] #[should_fail] #[ignore(cfg(windows))]
fn test_rw_arc_poison_wr() {
let arc = ~RWARC(1);
let arc2 = (*arc).clone();
use std::uint;
use std::vec;
use std::unstable::intrinsics;
-use std::unstable::intrinsics::{TyDesc};
-
-#[cfg(not(stage0))]
-use std::unstable::intrinsics::{get_tydesc};
-
-#[cfg(stage0)]
-unsafe fn get_tydesc<T>() -> *TyDesc {
- intrinsics::get_tydesc::<T>() as *TyDesc
-}
+use std::unstable::intrinsics::{TyDesc, get_tydesc};
// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
is_pod: bool,
}
-#[mutable] // XXX remove after snap
#[no_freeze]
pub struct Arena {
// The head is separated out from the list as a unbenchmarked
(base + (align - 1)) & !(align - 1)
}
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: &Chunk) {
//debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
// start, size, align, is_done);
if is_done {
- call_drop_glue(tydesc, ptr::offset(buf, start) as *i8);
+ ((*tydesc).drop_glue)(ptr::offset(buf, start) as *i8);
}
// Find where the next tydesc lives
}
}
-#[test]
-fn test_to_base64_basic() {
- assert_eq!("".to_base64(STANDARD), ~"");
- assert_eq!("f".to_base64(STANDARD), ~"Zg==");
- assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
- assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
- assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
- assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
- assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
-}
+#[cfg(test)]
+mod test {
+ use test::BenchHarness;
+ use base64::*;
+
+ #[test]
+ fn test_to_base64_basic() {
+ assert_eq!("".to_base64(STANDARD), ~"");
+ assert_eq!("f".to_base64(STANDARD), ~"Zg==");
+ assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
+ assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
+ assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
+ assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
+ assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
+ }
-#[test]
-fn test_to_base64_line_break() {
- assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
- .contains("\r\n"));
- assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
- ~"Zm9v\r\nYmFy");
-}
+ #[test]
+ fn test_to_base64_line_break() {
+ assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
+ .contains("\r\n"));
+ assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
+ ~"Zm9v\r\nYmFy");
+ }
-#[test]
-fn test_to_base64_padding() {
- assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
- assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
-}
+ #[test]
+ fn test_to_base64_padding() {
+ assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
+ assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
+ }
-#[test]
-fn test_to_base64_url_safe() {
- assert_eq!([251, 255].to_base64(URL_SAFE), ~"-_8");
- assert_eq!([251, 255].to_base64(STANDARD), ~"+/8=");
-}
+ #[test]
+ fn test_to_base64_url_safe() {
+ assert_eq!([251, 255].to_base64(URL_SAFE), ~"-_8");
+ assert_eq!([251, 255].to_base64(STANDARD), ~"+/8=");
+ }
-#[test]
-fn test_from_base64_basic() {
- assert_eq!("".from_base64().get(), "".as_bytes().to_owned());
- assert_eq!("Zg==".from_base64().get(), "f".as_bytes().to_owned());
- assert_eq!("Zm8=".from_base64().get(), "fo".as_bytes().to_owned());
- assert_eq!("Zm9v".from_base64().get(), "foo".as_bytes().to_owned());
- assert_eq!("Zm9vYg==".from_base64().get(), "foob".as_bytes().to_owned());
- assert_eq!("Zm9vYmE=".from_base64().get(), "fooba".as_bytes().to_owned());
- assert_eq!("Zm9vYmFy".from_base64().get(), "foobar".as_bytes().to_owned());
-}
+ #[test]
+ fn test_from_base64_basic() {
+ assert_eq!("".from_base64().get(), "".as_bytes().to_owned());
+ assert_eq!("Zg==".from_base64().get(), "f".as_bytes().to_owned());
+ assert_eq!("Zm8=".from_base64().get(), "fo".as_bytes().to_owned());
+ assert_eq!("Zm9v".from_base64().get(), "foo".as_bytes().to_owned());
+ assert_eq!("Zm9vYg==".from_base64().get(), "foob".as_bytes().to_owned());
+ assert_eq!("Zm9vYmE=".from_base64().get(), "fooba".as_bytes().to_owned());
+ assert_eq!("Zm9vYmFy".from_base64().get(), "foobar".as_bytes().to_owned());
+ }
-#[test]
-fn test_from_base64_newlines() {
- assert_eq!("Zm9v\r\nYmFy".from_base64().get(),
- "foobar".as_bytes().to_owned());
-}
+ #[test]
+ fn test_from_base64_newlines() {
+ assert_eq!("Zm9v\r\nYmFy".from_base64().get(),
+ "foobar".as_bytes().to_owned());
+ }
-#[test]
-fn test_from_base64_urlsafe() {
- assert_eq!("-_8".from_base64().get(), "+/8=".from_base64().get());
-}
+ #[test]
+ fn test_from_base64_urlsafe() {
+ assert_eq!("-_8".from_base64().get(), "+/8=".from_base64().get());
+ }
-#[test]
-fn test_from_base64_invalid_char() {
- assert!("Zm$=".from_base64().is_err())
- assert!("Zg==$".from_base64().is_err());
-}
+ #[test]
+ fn test_from_base64_invalid_char() {
+ assert!("Zm$=".from_base64().is_err())
+ assert!("Zg==$".from_base64().is_err());
+ }
-#[test]
-fn test_from_base64_invalid_padding() {
- assert!("Z===".from_base64().is_err());
-}
+ #[test]
+ fn test_from_base64_invalid_padding() {
+ assert!("Z===".from_base64().is_err());
+ }
-#[test]
-fn test_base64_random() {
- use std::rand::{task_rng, random, RngUtil};
- use std::vec;
+ #[test]
+ fn test_base64_random() {
+ use std::rand::{task_rng, random, RngUtil};
+ use std::vec;
- for 1000.times {
- let v: ~[u8] = do vec::build |push| {
- for task_rng().gen_uint_range(1, 100).times {
- push(random());
- }
- };
- assert_eq!(v.to_base64(STANDARD).from_base64().get(), v);
+ for 1000.times {
+ let v: ~[u8] = do vec::build |push| {
+ for task_rng().gen_uint_range(1, 100).times {
+ push(random());
+ }
+ };
+ assert_eq!(v.to_base64(STANDARD).from_base64().get(), v);
+ }
}
-}
+
+ #[bench]
+ pub fn to_base64(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ do bh.iter {
+ s.to_base64(STANDARD);
+ }
+ bh.bytes = s.len() as u64;
+ }
+
+ #[bench]
+ pub fn from_base64(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ let b = s.to_base64(STANDARD);
+ do bh.iter {
+ b.from_base64();
+ }
+ bh.bytes = b.len() as u64;
+ }
+
+}
\ No newline at end of file
use std::uint;
use std::vec;
+#[deriving(Clone)]
struct SmallBitv {
/// only the lowest nbits of this value are used. the rest is undefined.
bits: uint
pub fn negate(&mut self) { self.bits = !self.bits; }
}
+#[deriving(Clone)]
struct BigBitv {
storage: ~[uint]
}
}
}
-enum BitvVariant { Big(~BigBitv), Small(~SmallBitv) }
+#[deriving(Clone)]
+enum BitvVariant { Big(BigBitv), Small(SmallBitv) }
enum Op {Union, Intersect, Assign, Difference}
/// The bitvector type
+#[deriving(Clone)]
pub struct Bitv {
/// Internal representation of the bit vector (small or large)
rep: BitvVariant,
match self.rep {
Small(ref mut s) => match other.rep {
Small(ref s1) => match op {
- Union => s.union(*s1, self.nbits),
- Intersect => s.intersect(*s1, self.nbits),
- Assign => s.become(*s1, self.nbits),
- Difference => s.difference(*s1, self.nbits)
+ Union => s.union(s1, self.nbits),
+ Intersect => s.intersect(s1, self.nbits),
+ Assign => s.become(s1, self.nbits),
+ Difference => s.difference(s1, self.nbits)
},
Big(_) => die()
},
Big(ref mut s) => match other.rep {
Small(_) => die(),
Big(ref s1) => match op {
- Union => s.union(*s1, self.nbits),
- Intersect => s.intersect(*s1, self.nbits),
- Assign => s.become(*s1, self.nbits),
- Difference => s.difference(*s1, self.nbits)
+ Union => s.union(s1, self.nbits),
+ Intersect => s.intersect(s1, self.nbits),
+ Assign => s.become(s1, self.nbits),
+ Difference => s.difference(s1, self.nbits)
}
}
}
impl Bitv {
pub fn new(nbits: uint, init: bool) -> Bitv {
let rep = if nbits <= uint::bits {
- Small(~SmallBitv::new(if init {!0} else {0}))
+ Small(SmallBitv::new(if init {!0} else {0}))
}
else {
let nelems = nbits/uint::bits +
if nbits % uint::bits == 0 {0} else {1};
let elem = if init {!0u} else {0u};
let s = vec::from_elem(nelems, elem);
- Big(~BigBitv::new(s))
+ Big(BigBitv::new(s))
};
Bitv {rep: rep, nbits: nbits}
}
if self.nbits != v1.nbits { return false; }
match self.rep {
Small(ref b) => match v1.rep {
- Small(ref b1) => b.equals(*b1, self.nbits),
+ Small(ref b1) => b.equals(b1, self.nbits),
_ => false
},
Big(ref s) => match v1.rep {
- Big(ref s1) => s.equals(*s1, self.nbits),
+ Big(ref s1) => s.equals(s1, self.nbits),
Small(_) => return false
}
}
match self.rep {
Small(ref b) => b.is_true(self.nbits),
_ => {
- for self.each() |i| { if !i { return false; } }
+ for self.iter().advance |i| { if !i { return false; } }
true
}
}
}
#[inline]
- pub fn each(&self, f: &fn(bool) -> bool) -> bool {
- let mut i = 0;
- while i < self.nbits {
- if !f(self.get(i)) { return false; }
- i += 1;
- }
- return true;
+ pub fn iter<'a>(&'a self) -> BitvIterator<'a> {
+ BitvIterator {bitv: self, next_idx: 0}
}
/// Returns true if all bits are 0
match self.rep {
Small(ref b) => b.is_false(self.nbits),
Big(_) => {
- for self.each() |i| { if i { return false; } }
+ for self.iter().advance |i| { if i { return false; } }
true
}
}
*/
pub fn to_str(&self) -> ~str {
let mut rs = ~"";
- for self.each() |i| {
+ for self.iter().advance |i| {
if i {
rs.push_char('1');
} else {
}
-impl Clone for Bitv {
- /// Makes a copy of a bitvector
- #[inline]
- fn clone(&self) -> Bitv {
- match self.rep {
- Small(ref b) => {
- Bitv{nbits: self.nbits, rep: Small(~SmallBitv{bits: b.bits})}
- }
- Big(ref b) => {
- let mut st = vec::from_elem(self.nbits / uint::bits + 1, 0u);
- let len = st.len();
- for uint::range(0, len) |i| { st[i] = b.storage[i]; };
- Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: st})}
- }
- }
- }
-}
-
/**
* Transform a byte-vector into a bitv. Each byte becomes 8 bits,
* with the most significant bits of each byte coming first. Each
return true;
}
+/// An iterator for Bitv
+pub struct BitvIterator<'self> {
+ priv bitv: &'self Bitv,
+ priv next_idx: uint
+}
+
+impl<'self> Iterator<bool> for BitvIterator<'self> {
+ #[inline]
+ fn next(&mut self) -> Option<bool> {
+ if self.next_idx < self.bitv.nbits {
+ let idx = self.next_idx;
+ self.next_idx += 1;
+ Some(self.bitv.get(idx))
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let rem = self.bitv.nbits - self.next_idx;
+ (rem, Some(rem))
+ }
+}
+
/// An implementation of a set using a bit vector as an underlying
/// representation for holding numerical elements.
///
/// It should also be noted that the amount of storage necessary for holding a
/// set of objects is proportional to the maximum of the objects when viewed
/// as a uint.
+#[deriving(Clone)]
pub struct BitvSet {
priv size: uint,
}
let Bitv{rep, _} = bitv;
match rep {
- Big(~b) => BitvSet{ size: size, bitv: b },
- Small(~SmallBitv{bits}) =>
+ Big(b) => BitvSet{ size: size, bitv: b },
+ Small(SmallBitv{bits}) =>
BitvSet{ size: size, bitv: BigBitv{ storage: ~[bits] } },
}
}
pub fn unwrap(self) -> Bitv {
let cap = self.capacity();
let BitvSet{bitv, _} = self;
- return Bitv{ nbits:cap, rep: Big(~bitv) };
+ return Bitv{ nbits:cap, rep: Big(bitv) };
}
#[inline]
self.other_op(other, |w1, w2| w1 ^ w2);
}
- pub fn each(&self, blk: &fn(v: &uint) -> bool) -> bool {
- for self.bitv.storage.iter().enumerate().advance |(i, &w)| {
- if !iterate_bits(i * uint::bits, w, |b| blk(&b)) {
- return false;
- }
- }
- return true;
+ pub fn iter<'a>(&'a self) -> BitvSetIterator<'a> {
+ BitvSetIterator {set: self, next_idx: 0}
}
}
}
}
+pub struct BitvSetIterator<'self> {
+ priv set: &'self BitvSet,
+ priv next_idx: uint
+}
+
+impl<'self> Iterator<uint> for BitvSetIterator<'self> {
+ #[inline]
+ fn next(&mut self) -> Option<uint> {
+ while self.next_idx < self.set.capacity() {
+ let idx = self.next_idx;
+ self.next_idx += 1;
+
+ if self.set.contains(&idx) {
+ return Some(idx);
+ }
+ }
+
+ return None;
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ (0, Some(self.set.capacity() - self.next_idx))
+ }
+}
+
#[cfg(test)]
mod tests {
use extra::test::BenchHarness;
#[test]
fn test_1_element() {
let mut act = Bitv::new(1u, false);
- assert!(act.eq_vec(~[false]));
+ assert!(act.eq_vec([false]));
act = Bitv::new(1u, true);
- assert!(act.eq_vec(~[true]));
+ assert!(act.eq_vec([true]));
}
#[test]
act = Bitv::new(10u, false);
assert!((act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false])));
+ [false, false, false, false, false, false, false, false, false, false])));
// all 1
act = Bitv::new(10u, true);
- assert!((act.eq_vec(~[true, true, true, true, true, true, true, true, true, true])));
+ assert!((act.eq_vec([true, true, true, true, true, true, true, true, true, true])));
// mixed
act = Bitv::new(10u, false);
act.set(2u, true);
act.set(3u, true);
act.set(4u, true);
- assert!((act.eq_vec(~[true, true, true, true, true, false, false, false, false, false])));
+ assert!((act.eq_vec([true, true, true, true, true, false, false, false, false, false])));
// mixed
act = Bitv::new(10u, false);
act.set(7u, true);
act.set(8u, true);
act.set(9u, true);
- assert!((act.eq_vec(~[false, false, false, false, false, true, true, true, true, true])));
+ assert!((act.eq_vec([false, false, false, false, false, true, true, true, true, true])));
// mixed
act = Bitv::new(10u, false);
act.set(3u, true);
act.set(6u, true);
act.set(9u, true);
- assert!((act.eq_vec(~[true, false, false, true, false, false, true, false, false, true])));
+ assert!((act.eq_vec([true, false, false, true, false, false, true, false, false, true])));
}
#[test]
act = Bitv::new(31u, false);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false]));
// all 1
act = Bitv::new(31u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, true, true, true, true, true,
+ [true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true]));
// mixed
act.set(6u, true);
act.set(7u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, false, false, false, false, false,
+ [true, true, true, true, true, true, true, true, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false]));
// mixed
act.set(22u, true);
act.set(23u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, true, true, true, true, true, true, true,
false, false, false, false, false, false, false]));
// mixed
act.set(29u, true);
act.set(30u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, true, true, true, true, true, true, true]));
// mixed
act.set(17u, true);
act.set(30u, true);
assert!(act.eq_vec(
- ~[false, false, false, true, false, false, false, false, false, false, false, false,
+ [false, false, false, true, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, false, false, false, false, false, false,
false, false, false, false, false, false, true]));
}
act = Bitv::new(32u, false);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false]));
// all 1
act = Bitv::new(32u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, true, true, true, true, true,
+ [true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true]));
// mixed
act.set(6u, true);
act.set(7u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, false, false, false, false, false,
+ [true, true, true, true, true, true, true, true, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false]));
// mixed
act.set(22u, true);
act.set(23u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, true, true, true, true, true, true, true,
false, false, false, false, false, false, false, false]));
// mixed
act.set(30u, true);
act.set(31u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, true, true, true, true, true, true, true, true]));
// mixed
act.set(30u, true);
act.set(31u, true);
assert!(act.eq_vec(
- ~[false, false, false, true, false, false, false, false, false, false, false, false,
+ [false, false, false, true, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, false, false, false, false, false, false,
false, false, false, false, false, false, true, true]));
}
act = Bitv::new(33u, false);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false]));
// all 1
act = Bitv::new(33u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, true, true, true, true, true,
+ [true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true]));
// mixed
act.set(6u, true);
act.set(7u, true);
assert!(act.eq_vec(
- ~[true, true, true, true, true, true, true, true, false, false, false, false, false,
+ [true, true, true, true, true, true, true, true, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false]));
// mixed
act.set(22u, true);
act.set(23u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, true, true, true, true, true, true, true,
false, false, false, false, false, false, false, false, false]));
// mixed
act.set(30u, true);
act.set(31u, true);
assert!(act.eq_vec(
- ~[false, false, false, false, false, false, false, false, false, false, false,
+ [false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false,
false, true, true, true, true, true, true, true, true, false]));
// mixed
act.set(31u, true);
act.set(32u, true);
assert!(act.eq_vec(
- ~[false, false, false, true, false, false, false, false, false, false, false, false,
+ [false, false, false, true, false, false, false, false, false, false, false, false,
false, false, false, false, false, true, false, false, false, false, false, false,
false, false, false, false, false, false, true, true, true]));
}
assert_eq!(from_bytes([0b00100110]).to_bools(), bools);
}
+ #[test]
+ fn test_bitv_iterator() {
+ let bools = [true, false, true, true];
+ let bitv = from_bools(bools);
+
+ for bitv.iter().zip(bools.iter()).advance |(act, &ex)| {
+ assert_eq!(ex, act);
+ }
+ }
+
+ #[test]
+ fn test_bitv_set_iterator() {
+ let bools = [true, false, true, true];
+ let bitv = BitvSet::from_bitv(from_bools(bools));
+
+ let idxs: ~[uint] = bitv.iter().collect();
+ assert_eq!(idxs, ~[0, 2, 3]);
+ }
+
#[test]
fn test_small_difference() {
let mut b1 = Bitv::new(3, false);
assert_eq!(a.capacity(), uint::bits);
}
+ #[test]
+ fn test_bitv_clone() {
+ let mut a = BitvSet::new();
+
+ assert!(a.insert(1));
+ assert!(a.insert(100));
+ assert!(a.insert(1000));
+
+ let mut b = a.clone();
+
+ assert_eq!(&a, &b);
+
+ assert!(b.remove(&1));
+ assert!(a.contains(&1));
+
+ assert!(a.remove(&1000));
+ assert!(b.contains(&1000));
+ }
+
fn rng() -> rand::IsaacRng {
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
rand::IsaacRng::new_seeded(seed)
b1.union(&b2);
}
}
+
+ #[bench]
+ fn bench_btv_small_iter(b: &mut BenchHarness) {
+ let bitv = Bitv::new(uint::bits, false);
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |pres| {
+ sum += pres as uint;
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_bitv_big_iter(b: &mut BenchHarness) {
+ let bitv = Bitv::new(BENCH_BITS, false);
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |pres| {
+ sum += pres as uint;
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_bitvset_iter(b: &mut BenchHarness) {
+ let bitv = BitvSet::from_bitv(from_fn(BENCH_BITS,
+ |idx| {idx % 3 == 0}));
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |idx| {
+ sum += idx;
+ }
+ }
+ }
}
/// Remove the first element and return it, or None if the sequence is empty
fn pop_front(&mut self) -> Option<T>;
}
+
+#[cfg(test)]
+mod bench {
+
+ use std::container::MutableMap;
+ use std::{vec,rand,uint};
+ use std::rand::RngUtil;
+ use test::BenchHarness;
+
+ pub fn insert_rand_n<M:MutableMap<uint,uint>>(n: uint,
+ map: &mut M,
+ bh: &mut BenchHarness) {
+ // setup
+ let mut rng = rand::XorShiftRng::new();
+
+ map.clear();
+ for uint::range(0,n) |_i| {
+ map.insert(rng.gen::<uint>() % n, 1);
+ }
+
+ // measure
+ do bh.iter {
+ let k = rng.gen::<uint>() % n;
+ map.insert(k, 1);
+ map.remove(&k);
+ }
+ }
+
+ pub fn insert_seq_n<M:MutableMap<uint,uint>>(n: uint,
+ map: &mut M,
+ bh: &mut BenchHarness) {
+ // setup
+ map.clear();
+ for uint::range(0, n) |i| {
+ map.insert(i*2, 1);
+ }
+
+ // measure
+ let mut i = 1;
+ do bh.iter {
+ map.insert(i, 1);
+ map.remove(&i);
+ i = (i + 2) % n;
+ }
+ }
+
+ pub fn find_rand_n<M:MutableMap<uint,uint>>(n: uint,
+ map: &mut M,
+ bh: &mut BenchHarness) {
+ // setup
+ let mut rng = rand::XorShiftRng::new();
+ let mut keys = vec::from_fn(n, |_| rng.gen::<uint>() % n);
+
+ for keys.iter().advance() |k| {
+ map.insert(*k, 1);
+ }
+
+ rng.shuffle_mut(keys);
+
+ // measure
+ let mut i = 0;
+ do bh.iter {
+ map.find(&(keys[i]));
+ i = (i + 1) % n;
+ }
+ }
+
+ pub fn find_seq_n<M:MutableMap<uint,uint>>(n: uint,
+ map: &mut M,
+ bh: &mut BenchHarness) {
+ // setup
+ for uint::range(0, n) |i| {
+ map.insert(i, 1);
+ }
+
+ // measure
+ let mut i = 0;
+ do bh.iter {
+ map.find(&i);
+ i = (i + 1) % n;
+ }
+ }
+}
\ No newline at end of file
}
}
}
+
+#[cfg(test)]
+mod bench {
+
+ use sha1::Sha1;
+ use test::BenchHarness;
+
+ #[bench]
+ pub fn sha1_10(bh: & mut BenchHarness) {
+ let mut sh = Sha1::new();
+ let bytes = [1u8, ..10];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha1_1k(bh: & mut BenchHarness) {
+ let mut sh = Sha1::new();
+ let bytes = [1u8, ..1024];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha1_64k(bh: & mut BenchHarness) {
+ let mut sh = Sha1::new();
+ let bytes = [1u8, ..65536];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+}
test_hash(sh, tests);
}
}
+
+
+
+#[cfg(test)]
+mod bench {
+
+ use sha2::{Sha256,Sha512};
+ use test::BenchHarness;
+
+ #[bench]
+ pub fn sha256_10(bh: & mut BenchHarness) {
+ let mut sh = Sha256::new();
+ let bytes = [1u8, ..10];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha256_1k(bh: & mut BenchHarness) {
+ let mut sh = Sha256::new();
+ let bytes = [1u8, ..1024];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha256_64k(bh: & mut BenchHarness) {
+ let mut sh = Sha256::new();
+ let bytes = [1u8, ..65536];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+
+
+ #[bench]
+ pub fn sha512_10(bh: & mut BenchHarness) {
+ let mut sh = Sha512::new();
+ let bytes = [1u8, ..10];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha512_1k(bh: & mut BenchHarness) {
+ let mut sh = Sha512::new();
+ let bytes = [1u8, ..1024];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+ #[bench]
+ pub fn sha512_64k(bh: & mut BenchHarness) {
+ let mut sh = Sha512::new();
+ let bytes = [1u8, ..65536];
+ do bh.iter {
+ sh.input(bytes);
+ }
+ bh.bytes = bytes.len() as u64;
+ }
+
+}
#[allow(missing_doc)];
use std::cast::transmute;
-#[cfg(stage0)]
-use intrinsic::{get_tydesc};
-#[cfg(not(stage0))]
use std::unstable::intrinsics::{get_tydesc};
pub mod rustrt {
- #[cfg(stage0)]
- use intrinsic::{TyDesc};
- #[cfg(not(stage0))]
use std::unstable::intrinsics::{TyDesc};
#[abi = "cdecl"]
- pub extern {
+ extern {
pub unsafe fn debug_tydesc(td: *TyDesc);
pub unsafe fn debug_opaque(td: *TyDesc, x: *());
pub unsafe fn debug_box(td: *TyDesc, x: *());
// the reverse direction.
use std::cast;
-use std::cmp;
use std::ptr;
use std::util;
use std::iterator::{FromIterator, InvertIterator};
}
/// Double-ended DList iterator
+#[deriving(Clone)]
pub struct DListIterator<'self, T> {
priv head: &'self Link<T>,
priv tail: Rawlink<Node<T>>,
}
/// DList consuming iterator
+#[deriving(Clone)]
pub struct ConsumeIterator<T> {
priv list: DList<T>
}
}
}
+impl<T> Clone for Rawlink<T> {
+ #[inline]
+ fn clone(&self) -> Rawlink<T> {
+ Rawlink{p: self.p}
+ }
+}
+
+impl<T> Node<T> {
+ fn new(v: T) -> Node<T> {
+ Node{value: v, next: None, prev: Rawlink::none()}
+ }
+}
+
/// Set the .prev field on `next`, then return `Some(next)`
fn link_with_prev<T>(mut next: ~Node<T>, prev: Rawlink<Node<T>>) -> Link<T> {
next.prev = prev;
}
}
+// private methods
+impl<T> DList<T> {
+ /// Add a Node first in the list
+ #[inline]
+ fn push_front_node(&mut self, mut new_head: ~Node<T>) {
+ match self.list_head {
+ None => {
+ self.list_tail = Rawlink::some(new_head);
+ self.list_head = link_with_prev(new_head, Rawlink::none());
+ }
+ Some(ref mut head) => {
+ new_head.prev = Rawlink::none();
+ head.prev = Rawlink::some(new_head);
+ util::swap(head, &mut new_head);
+ head.next = Some(new_head);
+ }
+ }
+ self.length += 1;
+ }
+
+ /// Remove the first Node and return it, or None if the list is empty
+ #[inline]
+ fn pop_front_node(&mut self) -> Option<~Node<T>> {
+ do self.list_head.take().map_consume |mut front_node| {
+ self.length -= 1;
+ match front_node.next.take() {
+ Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
+ None => self.list_tail = Rawlink::none()
+ }
+ front_node
+ }
+ }
+
+ /// Add a Node last in the list
+ #[inline]
+ fn push_back_node(&mut self, mut new_tail: ~Node<T>) {
+ match self.list_tail.resolve() {
+ None => return self.push_front_node(new_tail),
+ Some(tail) => {
+ self.list_tail = Rawlink::some(new_tail);
+ tail.next = link_with_prev(new_tail, Rawlink::some(tail));
+ }
+ }
+ self.length += 1;
+ }
+
+ /// Remove the last Node and return it, or None if the list is empty
+ #[inline]
+ fn pop_back_node(&mut self) -> Option<~Node<T>> {
+ do self.list_tail.resolve().map_consume_default(None) |tail| {
+ self.length -= 1;
+ self.list_tail = tail.prev;
+ match tail.prev.resolve() {
+ None => self.list_head.take(),
+ Some(tail_prev) => tail_prev.next.take()
+ }
+ }
+ }
+}
+
impl<T> Deque<T> for DList<T> {
/// Provide a reference to the front element, or None if the list is empty
#[inline]
self.list_tail.resolve().map_mut(|tail| &mut tail.value)
}
- /// Add an element last in the list
+ /// Add an element first in the list
///
/// O(1)
- fn push_back(&mut self, elt: T) {
- match self.list_tail.resolve() {
- None => return self.push_front(elt),
- Some(tail) => {
- let mut new_tail = ~Node{value: elt, next: None, prev: self.list_tail};
- self.list_tail = Rawlink::some(new_tail);
- tail.next = Some(new_tail);
- }
- }
- self.length += 1;
+ fn push_front(&mut self, elt: T) {
+ self.push_front_node(~Node::new(elt))
}
- /// Remove the last element and return it, or None if the list is empty
+ /// Remove the first element and return it, or None if the list is empty
///
/// O(1)
- fn pop_back(&mut self) -> Option<T> {
- match self.list_tail.resolve() {
- None => None,
- Some(tail) => {
- self.length -= 1;
- let tail_own = match tail.prev.resolve() {
- None => {
- self.list_tail = Rawlink::none();
- self.list_head.take_unwrap()
- },
- Some(tail_prev) => {
- self.list_tail = tail.prev;
- tail_prev.next.take_unwrap()
- }
- };
- Some(tail_own.value)
- }
- }
+ fn pop_front(&mut self) -> Option<T> {
+ self.pop_front_node().map_consume(|~Node{value, _}| value)
}
- /// Add an element first in the list
+ /// Add an element last in the list
///
/// O(1)
- fn push_front(&mut self, elt: T) {
- let mut new_head = ~Node{value: elt, next: None, prev: Rawlink::none()};
- match self.list_head {
- None => {
- self.list_tail = Rawlink::some(new_head);
- self.list_head = Some(new_head);
- }
- Some(ref mut head) => {
- head.prev = Rawlink::some(new_head);
- util::swap(head, &mut new_head);
- head.next = Some(new_head);
- }
- }
- self.length += 1;
+ fn push_back(&mut self, elt: T) {
+ self.push_back_node(~Node::new(elt))
}
- /// Remove the first element and return it, or None if the list is empty
+ /// Remove the last element and return it, or None if the list is empty
///
/// O(1)
- fn pop_front(&mut self) -> Option<T> {
- match util::replace(&mut self.list_head, None) {
- None => None,
- Some(old_head) => {
- self.length -= 1;
- match *old_head {
- Node{value: value, next: Some(next), prev: _} => {
- self.list_head = link_with_prev(next, Rawlink::none());
- Some(value)
- }
- Node{value: value, next: None, prev: _} => {
- self.list_tail = Rawlink::none();
- Some(value)
- }
- }
- }
- }
+ fn pop_back(&mut self) -> Option<T> {
+ self.pop_back_node().map_consume(|~Node{value, _}| value)
}
}
DList{list_head: None, list_tail: Rawlink::none(), length: 0}
}
+ /// Move the last element to the front of the list.
+ ///
+ /// If the list is empty, do nothing.
+ #[inline]
+ pub fn rotate_forward(&mut self) {
+ do self.pop_back_node().map_consume |tail| {
+ self.push_front_node(tail)
+ };
+ }
+
+ /// Move the first element to the back of the list.
+ ///
+ /// If the list is empty, do nothing.
+ #[inline]
+ pub fn rotate_backward(&mut self) {
+ do self.pop_front_node().map_consume |head| {
+ self.push_back_node(head)
+ };
+ }
+
/// Add all elements from `other` to the end of the list
///
/// O(1)
None => *self = other,
Some(tail) => {
match other {
- DList{list_head: None, list_tail: _, length: _} => return,
+ DList{list_head: None, _} => return,
DList{list_head: Some(node), list_tail: o_tail, length: o_length} => {
tail.next = link_with_prev(node, self.list_tail);
self.list_tail = o_tail;
if take_a {
it.next();
} else {
- it.insert_next(other.pop_front().unwrap());
+ it.insert_next_node(other.pop_front_node().unwrap());
}
}
}
}
}
-impl<T: cmp::TotalOrd> DList<T> {
+impl<T: Ord> DList<T> {
/// Insert `elt` sorted in ascending order
///
/// O(N)
#[inline]
pub fn insert_ordered(&mut self, elt: T) {
- self.insert_when(elt, |a, b| a.cmp(b) != cmp::Less);
+ self.insert_when(elt, |a, b| a >= b)
}
}
if self.nelem == 0 {
return None;
}
- match *self.head {
- None => None,
- Some(ref head) => {
- self.nelem -= 1;
- self.head = &head.next;
- Some(&head.value)
- }
+ do self.head.map |head| {
+ self.nelem -= 1;
+ self.head = &head.next;
+ &head.value
}
}
if self.nelem == 0 {
return None;
}
- match self.tail.resolve() {
- None => None,
- Some(prev) => {
- self.nelem -= 1;
- self.tail = prev.prev;
- Some(&prev.value)
- }
+ do self.tail.resolve().map_consume |prev| {
+ self.nelem -= 1;
+ self.tail = prev.prev;
+ &prev.value
}
}
}
if self.nelem == 0 {
return None;
}
- match self.head.resolve() {
- None => None,
- Some(next) => {
- self.nelem -= 1;
- self.head = match next.next {
- Some(ref mut node) => Rawlink::some(&mut **node),
- None => Rawlink::none(),
- };
- Some(&mut next.value)
- }
+ do self.head.resolve().map_consume |next| {
+ self.nelem -= 1;
+ self.head = match next.next {
+ Some(ref mut node) => Rawlink::some(&mut **node),
+ None => Rawlink::none(),
+ };
+ &mut next.value
}
}
if self.nelem == 0 {
return None;
}
- match self.tail.resolve() {
- None => None,
- Some(prev) => {
- self.nelem -= 1;
- self.tail = prev.prev;
- Some(&mut prev.value)
- }
+ do self.tail.resolve().map_consume |prev| {
+ self.nelem -= 1;
+ self.tail = prev.prev;
+ &mut prev.value
}
}
}
/// Allow mutating the DList while iterating
pub trait ListInsertion<A> {
- /// Insert `elt` just after to the most recently yielded element
+ /// Insert `elt` just after to the element most recently returned by `.next()`
+ ///
+ /// The inserted element does not appear in the iteration.
fn insert_next(&mut self, elt: A);
/// Provide a reference to the next element, without changing the iterator
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A>;
}
-impl<'self, A> ListInsertion<A> for MutDListIterator<'self, A> {
- fn insert_next(&mut self, elt: A) {
- // Insert an element before `self.head` so that it is between the
+// private methods for MutDListIterator
+impl<'self, A> MutDListIterator<'self, A> {
+ fn insert_next_node(&mut self, mut ins_node: ~Node<A>) {
+ // Insert before `self.head` so that it is between the
// previously yielded element and self.head.
+ //
+ // The inserted node will not appear in further iteration.
match self.head.resolve() {
- None => { self.list.push_back(elt); }
+ None => { self.list.push_back_node(ins_node); }
Some(node) => {
let prev_node = match node.prev.resolve() {
- None => return self.list.push_front(elt),
+ None => return self.list.push_front_node(ins_node),
Some(prev) => prev,
};
- let mut ins_node = ~Node{value: elt, next: None, prev: Rawlink::none()};
let node_own = prev_node.next.take_unwrap();
ins_node.next = link_with_prev(node_own, Rawlink::some(ins_node));
prev_node.next = link_with_prev(ins_node, Rawlink::some(prev_node));
}
}
}
+}
+
+impl<'self, A> ListInsertion<A> for MutDListIterator<'self, A> {
+ #[inline]
+ fn insert_next(&mut self, elt: A) {
+ self.insert_next_node(~Node::new(elt))
+ }
#[inline]
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A> {
- match self.head.resolve() {
- None => None,
- Some(head) => Some(&mut head.value),
+ if self.nelem == 0 {
+ return None
}
+ self.head.resolve().map_consume(|head| &mut head.value)
}
}
}
}
+ #[test]
+ fn test_rotate() {
+ let mut n = DList::new::<int>();
+ n.rotate_backward(); check_links(&n);
+ assert_eq!(n.len(), 0);
+ n.rotate_forward(); check_links(&n);
+ assert_eq!(n.len(), 0);
+
+ let v = ~[1,2,3,4,5];
+ let mut m = list_from(v);
+ m.rotate_backward(); check_links(&m);
+ m.rotate_forward(); check_links(&m);
+ assert_eq!(v.iter().collect::<~[&int]>(), m.iter().collect());
+ m.rotate_forward(); check_links(&m);
+ m.rotate_forward(); check_links(&m);
+ m.pop_front(); check_links(&m);
+ m.rotate_forward(); check_links(&m);
+ m.rotate_backward(); check_links(&m);
+ m.push_front(9); check_links(&m);
+ m.rotate_forward(); check_links(&m);
+ assert_eq!(~[3,9,5,1,2], m.consume_iter().collect());
+ }
+
#[test]
fn test_iterator() {
let m = generate_test();
assert_eq!(it.next(), None);
}
+ #[test]
+ fn test_iterator_clone() {
+ let mut n = DList::new();
+ n.push_back(2);
+ n.push_back(3);
+ n.push_back(4);
+ let mut it = n.iter();
+ it.next();
+ let mut jt = it.clone();
+ assert_eq!(it.next(), jt.next());
+ assert_eq!(it.next_back(), jt.next_back());
+ assert_eq!(it.next(), jt.next());
+ }
+
#[test]
fn test_iterator_double_end() {
let mut n = DList::new();
let _: DList<int> = v.iter().transform(|x| *x).collect();
}
}
- #[bench]
- fn bench_collect_into_vec(b: &mut test::BenchHarness) {
- let v = &[0, ..64];
- do b.iter {
- let _: ~[int] = v.iter().transform(|&x|x).collect();
- }
- }
#[bench]
fn bench_push_front(b: &mut test::BenchHarness) {
m.push_front(0);
}
}
+
#[bench]
- fn bench_push_front_vec_size10(b: &mut test::BenchHarness) {
- let mut m = ~[0, ..10];
+ fn bench_push_back(b: &mut test::BenchHarness) {
+ let mut m = DList::new::<int>();
do b.iter {
- m.unshift(0);
- m.pop(); // to keep it fair, dont' grow the vec
+ m.push_back(0);
}
}
#[bench]
- fn bench_push_back(b: &mut test::BenchHarness) {
+ fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
do b.iter {
m.push_back(0);
+ m.pop_back();
}
}
+
#[bench]
- fn bench_push_back_vec(b: &mut test::BenchHarness) {
- let mut m = ~[];
+ fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
+ let mut m = DList::new::<int>();
do b.iter {
- m.push(0);
+ m.push_front(0);
+ m.pop_front();
}
}
#[bench]
- fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
+ fn bench_rotate_forward(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
+ m.push_front(0);
+ m.push_front(1);
do b.iter {
- m.push_back(0);
- m.pop_back();
+ m.rotate_forward();
}
}
+
#[bench]
- fn bench_push_back_pop_back_vec(b: &mut test::BenchHarness) {
- let mut m = ~[];
+ fn bench_rotate_backward(b: &mut test::BenchHarness) {
+ let mut m = DList::new::<int>();
+ m.push_front(0);
+ m.push_front(1);
do b.iter {
- m.push(0);
- m.pop();
+ m.rotate_backward();
}
}
assert!(m.mut_rev_iter().len_() == 128);
}
}
- #[bench]
- fn bench_iter_vec(b: &mut test::BenchHarness) {
- let v = &[0, ..128];
- do b.iter {
- for v.iter().advance |_| {}
- }
- }
}
pub use std::os;
-pub mod uv_ll;
-
-// General io and system-services modules
-
-#[path = "net/mod.rs"]
-pub mod net;
-
-// libuv modules
-pub mod uv;
-pub mod uv_iotask;
-pub mod uv_global_loop;
-
-
// Utility modules
pub mod c_vec;
-pub mod timer;
pub mod io_util;
pub mod rc;
// And ... other stuff
+pub mod url;
pub mod ebml;
pub mod dbg;
pub mod getopts;
use std::libc::{c_int, c_void, size_t};
#[link_name = "rustrt"]
- pub extern {
- unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
- src_buf_len: size_t,
- pout_len: *mut size_t,
- flags: c_int)
- -> *c_void;
+ extern {
+ pub unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
+ src_buf_len: size_t,
+ pout_len: *mut size_t,
+ flags: c_int)
+ -> *c_void;
- unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
- src_buf_len: size_t,
- pout_len: *mut size_t,
- flags: c_int)
- -> *c_void;
+ pub unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
+ src_buf_len: size_t,
+ pout_len: *mut size_t,
+ flags: c_int)
+ -> *c_void;
}
}
use flatpipes::serial;
use io_util::BufReader;
use flatpipes::{BytePort, FlatChan, FlatPort};
- use net::tcp::TcpSocketBuf;
use std::comm;
use std::int;
}
// FIXME #2064: Networking doesn't work on x86
- #[test]
+ // XXX Broken until networking support is added back
+ /*#[test]
#[cfg(target_arch = "x86_64")]
fn test_pod_tcp_stream() {
fn reader_port(buf: TcpSocketBuf
#[test]
#[cfg(target_arch = "x86_64")]
fn test_serializing_tcp_stream() {
+ // XXX Broken until networking support is added back
fn reader_port(buf: TcpSocketBuf
) -> serial::ReaderPort<int, TcpSocketBuf> {
serial::reader_port(buf)
}
finish_port.recv();
- }
+ }*/
// Tests that the different backends behave the same when the
// binary streaming protocol is broken
}
/// Create a treemap
-pub fn init<K, V>() -> Treemap<K, V> { @Empty }
+pub fn init<K: 'static, V: 'static>() -> Treemap<K, V> {
+ @Empty
+}
/// Insert a value into the map
-pub fn insert<K:Eq + Ord,V>(m: Treemap<K, V>, k: K, v: V) -> Treemap<K, V> {
+pub fn insert<K:Eq + Ord + 'static,
+ V:'static>(
+ m: Treemap<K, V>,
+ k: K,
+ v: V)
+ -> Treemap<K, V> {
@match m {
@Empty => Node(@k, @v, @Empty, @Empty),
@Node(kk, vv, left, right) => cond!(
}
/// Find a value based on the key
-pub fn find<K:Eq + Ord,V:Clone>(m: Treemap<K, V>, k: K) -> Option<V> {
+pub fn find<K:Eq + Ord + 'static,
+ V:Clone + 'static>(
+ m: Treemap<K, V>,
+ k: K)
+ -> Option<V> {
match *m {
Empty => None,
Node(kk, v, left, right) => cond!(
}
}
+impl<A> Future<A> {
+ /// Gets the value from this future, forcing evaluation.
+ pub fn unwrap(self) -> A {
+ let mut this = self;
+ this.get_ref();
+ let state = replace(&mut this.state, Evaluating);
+ match state {
+ Forced(v) => v,
+ _ => fail!( "Logic error." ),
+ }
+ }
+}
+
impl<A> Future<A> {
pub fn get_ref<'a>(&'a mut self) -> &'a A {
/*!
assert_eq!(f.get(), ~"fail");
}
+ #[test]
+ fn test_interface_unwrap() {
+ let mut f = from_value(~"fail");
+ assert_eq!(f.unwrap(), ~"fail");
+ }
+
#[test]
fn test_get_ref_method() {
let mut f = from_value(22);
debug!("read_map()");
let len = match self.stack.pop() {
Object(obj) => {
- let mut obj = obj;
let len = obj.len();
- do obj.consume |key, value| {
+ for obj.consume().advance |(key, value)| {
self.stack.push(value);
self.stack.push(String(key));
}
}
/// Create a list from a vector
-pub fn from_vec<T:Clone>(v: &[T]) -> @List<T> {
+pub fn from_vec<T:Clone + 'static>(v: &[T]) -> @List<T> {
v.rev_iter().fold(@Nil::<T>, |t, h| @Cons((*h).clone(), t))
}
}
/// Appends one list to another
-pub fn append<T:Clone>(l: @List<T>, m: @List<T>) -> @List<T> {
+pub fn append<T:Clone + 'static>(l: @List<T>, m: @List<T>) -> @List<T> {
match *l {
Nil => return m,
Cons(ref x, xs) => {
+++ /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.
-
-//! Types/fns concerning Internet Protocol (IP), versions 4 & 6
-
-#[allow(missing_doc)];
-
-
-use std::libc;
-use std::comm::{stream, SharedChan};
-use std::ptr;
-use std::result;
-use std::str;
-
-use iotask = uv::iotask::IoTask;
-use interact = uv::iotask::interact;
-
-use sockaddr_in = uv_ll::sockaddr_in;
-use sockaddr_in6 = uv_ll::sockaddr_in6;
-use addrinfo = uv_ll::addrinfo;
-use uv_getaddrinfo_t = uv_ll::uv_getaddrinfo_t;
-use uv_ip4_name = uv_ll::ip4_name;
-use uv_ip4_port = uv_ll::ip4_port;
-use uv_ip6_name = uv_ll::ip6_name;
-use uv_ip6_port = uv_ll::ip6_port;
-use uv_getaddrinfo = uv_ll::getaddrinfo;
-use uv_freeaddrinfo = uv_ll::freeaddrinfo;
-use create_uv_getaddrinfo_t = uv_ll::getaddrinfo_t;
-use set_data_for_req = uv_ll::set_data_for_req;
-use get_data_for_req = uv_ll::get_data_for_req;
-use ll = uv_ll;
-
-/// An IP address
-#[deriving(Clone)]
-pub enum IpAddr {
- /// An IPv4 address
- Ipv4(sockaddr_in),
- Ipv6(sockaddr_in6)
-}
-
-/// Human-friendly feedback on why a parse_addr attempt failed
-pub struct ParseAddrErr {
- err_msg: ~str,
-}
-
-/**
- * Convert a `IpAddr` to a str
- *
- * # Arguments
- *
- * * ip - a `extra::net::ip::IpAddr`
- */
-pub fn format_addr(ip: &IpAddr) -> ~str {
- match *ip {
- Ipv4(ref addr) => unsafe {
- let result = uv_ip4_name(addr);
- if result == ~"" {
- fail!("failed to convert inner sockaddr_in address to str")
- }
- result
- },
- Ipv6(ref addr) => unsafe {
- let result = uv_ip6_name(addr);
- if result == ~"" {
- fail!("failed to convert inner sockaddr_in address to str")
- }
- result
- }
- }
-}
-
-/**
- * Get the associated port
- *
- * # Arguments
- * * ip - a `extra::net::ip::IpAddr`
- */
-pub fn get_port(ip: &IpAddr) -> uint {
- match *ip {
- Ipv4(ref addr) => unsafe {
- uv_ip4_port(addr)
- },
- Ipv6(ref addr) => unsafe {
- uv_ip6_port(addr)
- }
- }
-}
-
-/// Represents errors returned from `net::ip::get_addr()`
-enum IpGetAddrErr {
- GetAddrUnknownError
-}
-
-/**
- * Attempts name resolution on the provided `node` string
- *
- * # Arguments
- *
- * * `node` - a string representing some host address
- * * `iotask` - a `uv::iotask` used to interact with the underlying event loop
- *
- * # Returns
- *
- * A `result<~[ip_addr], ip_get_addr_err>` instance that will contain
- * a vector of `ip_addr` results, in the case of success, or an error
- * object in the case of failure
-*/
-pub fn get_addr(node: &str, iotask: &iotask)
- -> result::Result<~[IpAddr], IpGetAddrErr> {
- let (output_po, output_ch) = stream();
- let mut output_ch = Some(SharedChan::new(output_ch));
- do str::as_buf(node) |node_ptr, len| {
- let output_ch = output_ch.take_unwrap();
- debug!("slice len %?", len);
- let handle = create_uv_getaddrinfo_t();
- let handle_ptr: *uv_getaddrinfo_t = &handle;
- let handle_data = GetAddrData {
- output_ch: output_ch.clone()
- };
- let handle_data_ptr: *GetAddrData = &handle_data;
- do interact(iotask) |loop_ptr| {
- unsafe {
- let result = uv_getaddrinfo(
- loop_ptr,
- handle_ptr,
- get_addr_cb,
- node_ptr,
- ptr::null(),
- ptr::null());
- match result {
- 0i32 => {
- set_data_for_req(handle_ptr, handle_data_ptr);
- }
- _ => {
- output_ch.send(result::Err(GetAddrUnknownError));
- }
- }
- }
- };
- output_po.recv()
- }
-}
-
-pub mod v4 {
-
- use net::ip::{IpAddr, Ipv4, ParseAddrErr};
- use uv::ll;
- use uv_ip4_addr = uv::ll::ip4_addr;
- use uv_ip4_name = uv::ll::ip4_name;
-
- use std::cast::transmute;
- use std::result;
- use std::uint;
-
- /**
- * Convert a str to `ip_addr`
- *
- * # Failure
- *
- * Fails if the string is not a valid IPv4 address
- *
- * # Arguments
- *
- * * ip - a string of the format `x.x.x.x`
- *
- * # Returns
- *
- * * an `ip_addr` of the `ipv4` variant
- */
- pub fn parse_addr(ip: &str) -> IpAddr {
- match try_parse_addr(ip) {
- result::Ok(addr) => addr,
- result::Err(ref err_data) => fail!(err_data.err_msg.clone())
- }
- }
-
- // the simple, old style numberic representation of
- // ipv4
- #[deriving(Clone)]
- pub struct Ipv4Rep {
- a: u8,
- b: u8,
- c: u8,
- d: u8,
- }
-
- pub trait AsUnsafeU32 {
- unsafe fn as_u32(&self) -> u32;
- }
-
- impl AsUnsafeU32 for Ipv4Rep {
- // this is pretty dastardly, i know
- unsafe fn as_u32(&self) -> u32 {
- let this: &mut u32 = transmute(self);
- *this
- }
- }
- pub fn parse_to_ipv4_rep(ip: &str) -> result::Result<Ipv4Rep, ~str> {
- let parts: ~[uint] = ip.split_iter('.').transform(|s| {
- match uint::from_str(s) {
- Some(n) if n <= 255 => n,
- _ => 256
- }
- }).collect();
- if parts.len() != 4 {
- Err(fmt!("'%s' doesn't have 4 parts", ip))
- } else if parts.iter().any(|x| *x == 256u) {
- Err(fmt!("invalid octal in addr '%s'", ip))
- } else {
- Ok(Ipv4Rep {
- a: parts[0] as u8, b: parts[1] as u8,
- c: parts[2] as u8, d: parts[3] as u8,
- })
- }
- }
- pub fn try_parse_addr(ip: &str) -> result::Result<IpAddr,ParseAddrErr> {
- unsafe {
- let INADDR_NONE = ll::get_INADDR_NONE();
- let ip_rep_result = parse_to_ipv4_rep(ip);
- if result::is_err(&ip_rep_result) {
- let err_str = result::get_err(&ip_rep_result);
- return result::Err(ParseAddrErr { err_msg: err_str })
- }
- // ipv4_rep.as_u32 is unsafe :/
- let input_is_inaddr_none =
- result::get(&ip_rep_result).as_u32() == INADDR_NONE;
-
- let new_addr = uv_ip4_addr(ip, 22);
- let reformatted_name = uv_ip4_name(&new_addr);
- debug!("try_parse_addr: input ip: %s reparsed ip: %s",
- ip, reformatted_name);
- let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name);
- if result::is_err(&ref_ip_rep_result) {
- let err_str = result::get_err(&ref_ip_rep_result);
- return Err(ParseAddrErr { err_msg: err_str })
- }
-
- if result::get(&ref_ip_rep_result).as_u32() == INADDR_NONE &&
- !input_is_inaddr_none {
- Err(ParseAddrErr {
- err_msg: ~"uv_ip4_name produced invalid result.",
- })
- } else {
- Ok(Ipv4(new_addr))
- }
- }
- }
-}
-pub mod v6 {
-
- use net::ip::{IpAddr, Ipv6, ParseAddrErr};
- use uv_ip6_addr = uv::ll::ip6_addr;
- use uv_ip6_name = uv::ll::ip6_name;
-
- use std::result;
-
- /**
- * Convert a str to `ip_addr`
- *
- * # Failure
- *
- * Fails if the string is not a valid IPv6 address
- *
- * # Arguments
- *
- * * ip - an ipv6 string. See RFC2460 for spec.
- *
- * # Returns
- *
- * * an `ip_addr` of the `ipv6` variant
- */
- pub fn parse_addr(ip: &str) -> IpAddr {
- match try_parse_addr(ip) {
- result::Ok(addr) => addr,
- result::Err(err_data) => fail!(err_data.err_msg.clone())
- }
- }
- pub fn try_parse_addr(ip: &str) -> result::Result<IpAddr,ParseAddrErr> {
- unsafe {
- // need to figure out how to establish a parse failure..
- let new_addr = uv_ip6_addr(ip, 22);
- let reparsed_name = uv_ip6_name(&new_addr);
- debug!("v6::try_parse_addr ip: '%s' reparsed '%s'",
- ip, reparsed_name);
- // '::' appears to be uv_ip6_name() returns for bogus
- // parses..
- if ip != &"::" && reparsed_name == ~"::" {
- Err(ParseAddrErr { err_msg:fmt!("failed to parse '%s'", ip) })
- }
- else {
- Ok(Ipv6(new_addr))
- }
- }
- }
-}
-
-struct GetAddrData {
- output_ch: SharedChan<result::Result<~[IpAddr],IpGetAddrErr>>
-}
-
-extern fn get_addr_cb(handle: *uv_getaddrinfo_t,
- status: libc::c_int,
- res: *addrinfo) {
- unsafe {
- debug!("in get_addr_cb");
- let handle_data = get_data_for_req(handle) as
- *GetAddrData;
- let output_ch = (*handle_data).output_ch.clone();
- if status == 0i32 {
- if res != (ptr::null::<addrinfo>()) {
- let mut out_vec = ~[];
- debug!("initial addrinfo: %?", res);
- let mut curr_addr = res;
- loop {
- let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) {
- Ipv4(*ll::addrinfo_as_sockaddr_in(curr_addr))
- }
- else if ll::is_ipv6_addrinfo(curr_addr) {
- Ipv6(*ll::addrinfo_as_sockaddr_in6(curr_addr))
- }
- else {
- debug!("curr_addr is not of family AF_INET or \
- AF_INET6. Error.");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- break;
- };
- out_vec.push(new_ip_addr);
-
- let next_addr = ll::get_next_addrinfo(curr_addr);
- if next_addr == ptr::null::<addrinfo>() as *addrinfo {
- debug!("null next_addr encountered. no mas");
- break;
- }
- else {
- curr_addr = next_addr;
- debug!("next_addr addrinfo: %?", curr_addr);
- }
- }
- debug!("successful process addrinfo result, len: %?",
- out_vec.len());
- output_ch.send(result::Ok(out_vec));
- }
- else {
- debug!("addrinfo pointer is NULL");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- }
- }
- else {
- debug!("status != 0 error in get_addr_cb");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- }
- if res != (ptr::null::<addrinfo>()) {
- uv_freeaddrinfo(res);
- }
- debug!("leaving get_addr_cb");
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use net::ip::*;
- use net::ip::v4;
- use net::ip::v6;
- use uv;
-
- use std::result;
-
- #[test]
- fn test_ip_ipv4_parse_and_format_ip() {
- let localhost_str = ~"127.0.0.1";
- assert!(format_addr(&v4::parse_addr(localhost_str))
- == localhost_str)
- }
- #[test]
- fn test_ip_ipv6_parse_and_format_ip() {
- let localhost_str = ~"::1";
- let format_result = format_addr(&v6::parse_addr(localhost_str));
- debug!("results: expected: '%s' actual: '%s'",
- localhost_str, format_result);
- assert_eq!(format_result, localhost_str);
- }
- #[test]
- fn test_ip_ipv4_bad_parse() {
- match v4::try_parse_addr("b4df00d") {
- result::Err(ref err_info) => {
- debug!("got error as expected %?", err_info);
- assert!(true);
- }
- result::Ok(ref addr) => {
- fail!("Expected failure, but got addr %?", addr);
- }
- }
- }
- #[test]
- #[ignore(target_os="win32")]
- fn test_ip_ipv6_bad_parse() {
- match v6::try_parse_addr("::,~2234k;") {
- result::Err(ref err_info) => {
- debug!("got error as expected %?", err_info);
- assert!(true);
- }
- result::Ok(ref addr) => {
- fail!("Expected failure, but got addr %?", addr);
- }
- }
- }
- #[test]
- #[ignore(reason = "valgrind says it's leaky")]
- fn test_ip_get_addr() {
- let localhost_name = ~"localhost";
- let iotask = &uv::global_loop::get();
- let ga_result = get_addr(localhost_name, iotask);
- if result::is_err(&ga_result) {
- fail!("got err result from net::ip::get_addr();")
- }
- // note really sure how to reliably test/assert
- // this.. mostly just wanting to see it work, atm.
- let results = result::unwrap(ga_result);
- debug!("test_get_addr: Number of results for %s: %?",
- localhost_name, results.len());
- for results.iter().advance |r| {
- let ipv_prefix = match *r {
- Ipv4(_) => ~"IPv4",
- Ipv6(_) => ~"IPv6"
- };
- debug!("test_get_addr: result %s: '%s'",
- ipv_prefix, format_addr(r));
- }
- // at least one result.. this is going to vary from system
- // to system, based on stuff like the contents of /etc/hosts
- assert!(!results.is_empty());
- }
- #[test]
- #[ignore(reason = "valgrind says it's leaky")]
- fn test_ip_get_addr_bad_input() {
- let localhost_name = ~"sjkl234m,./sdf";
- let iotask = &uv::global_loop::get();
- let ga_result = get_addr(localhost_name, iotask);
- assert!(result::is_err(&ga_result));
- }
-}
+++ /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.
-
-/*!
-Top-level module for network-related functionality.
-
-Basically, including this module gives you:
-
-* `tcp`
-* `ip`
-* `url`
-
-See each of those three modules for documentation on what they do.
-*/
-
-pub mod tcp;
-pub mod ip;
-pub mod url;
+++ /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.
-
-//! High-level interface to libuv's TCP functionality
-// FIXME #4425: Need FFI fixes
-
-#[allow(missing_doc)];
-
-
-use future;
-use future_spawn = future::spawn;
-use ip = net::ip;
-use uv;
-use uv::iotask;
-use uv::iotask::IoTask;
-
-use std::io;
-use std::libc::size_t;
-use std::libc;
-use std::comm::{stream, Port, SharedChan};
-use std::ptr;
-use std::result::{Result};
-use std::result;
-use std::num;
-use std::vec;
-
-pub mod rustrt {
- use std::libc;
-
- #[nolink]
- pub extern {
- unsafe fn rust_uv_current_kernel_malloc(size: libc::c_uint)
- -> *libc::c_void;
- unsafe fn rust_uv_current_kernel_free(mem: *libc::c_void);
- unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint;
- }
-}
-
-/**
- * Encapsulates an open TCP/IP connection through libuv
- *
- * `TcpSocket` is non-copyable/sendable and automagically handles closing the
- * underlying libuv data structures when it goes out of scope. This is the
- * data structure that is used for read/write operations over a TCP stream.
- */
-pub struct TcpSocket {
- socket_data: @TcpSocketData,
-}
-
-#[unsafe_destructor]
-impl Drop for TcpSocket {
- fn drop(&self) {
- tear_down_socket_data(self.socket_data)
- }
-}
-
-pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket {
- TcpSocket {
- socket_data: socket_data
- }
-}
-
-/**
- * A buffered wrapper for `net::tcp::TcpSocket`
- *
- * It is created with a call to `net::tcp::socket_buf()` and has impls that
- * satisfy both the `io::Reader` and `io::Writer` traits.
- */
-pub struct TcpSocketBuf {
- data: @mut TcpBufferedSocketData,
- end_of_stream: @mut bool
-}
-
-pub fn TcpSocketBuf(data: @mut TcpBufferedSocketData) -> TcpSocketBuf {
- TcpSocketBuf {
- data: data,
- end_of_stream: @mut false
- }
-}
-
-/// Contains raw, string-based, error information returned from libuv
-#[deriving(Clone)]
-pub struct TcpErrData {
- err_name: ~str,
- err_msg: ~str,
-}
-
-/// Details returned as part of a `Result::Err` result from `tcp::listen`
-#[deriving(Clone)]
-pub enum TcpListenErrData {
- /**
- * Some unplanned-for error. The first and second fields correspond
- * to libuv's `err_name` and `err_msg` fields, respectively.
- */
- GenericListenErr(~str, ~str),
- /**
- * Failed to bind to the requested IP/Port, because it is already in use.
- *
- * # Possible Causes
- *
- * * Attempting to bind to a port already bound to another listener
- */
- AddressInUse,
- /**
- * Request to bind to an IP/Port was denied by the system.
- *
- * # Possible Causes
- *
- * * Attemping to binding to an IP/Port as a non-Administrator
- * on Windows Vista+
- * * Attempting to bind, as a non-priv'd
- * user, to 'privileged' ports (< 1024) on *nix
- */
- AccessDenied
-}
-/// Details returned as part of a `Result::Err` result from `tcp::connect`
-#[deriving(Clone)]
-pub enum TcpConnectErrData {
- /**
- * Some unplanned-for error. The first and second fields correspond
- * to libuv's `err_name` and `err_msg` fields, respectively.
- */
- GenericConnectErr(~str, ~str),
- /// Invalid IP or invalid port
- ConnectionRefused
-}
-
-/**
- * Initiate a client connection over TCP/IP
- *
- * # Arguments
- *
- * * `input_ip` - The IP address (versions 4 or 6) of the remote host
- * * `port` - the unsigned integer of the desired remote host port
- * * `iotask` - a `uv::iotask` that the tcp request will run on
- *
- * # Returns
- *
- * A `result` that, if the operation succeeds, contains a
- * `net::net::TcpSocket` that can be used to send and receive data to/from
- * the remote host. In the event of failure, a
- * `net::tcp::TcpConnectErrData` instance will be returned
- */
-pub fn connect(input_ip: ip::IpAddr, port: uint,
- iotask: &IoTask)
- -> result::Result<TcpSocket, TcpConnectErrData> {
- unsafe {
- let (result_po, result_ch) = stream::<ConnAttempt>();
- let result_ch = SharedChan::new(result_ch);
- let (closed_signal_po, closed_signal_ch) = stream::<()>();
- let closed_signal_ch = SharedChan::new(closed_signal_ch);
- let conn_data = ConnectReqData {
- result_ch: result_ch,
- closed_signal_ch: closed_signal_ch
- };
- let conn_data_ptr: *ConnectReqData = &conn_data;
- let (reader_po, reader_ch) = stream::<Result<~[u8], TcpErrData>>();
- let reader_ch = SharedChan::new(reader_ch);
- let stream_handle_ptr = malloc_uv_tcp_t();
- *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = uv::ll::tcp_t();
- let socket_data = @TcpSocketData {
- reader_po: @reader_po,
- reader_ch: reader_ch,
- stream_handle_ptr: stream_handle_ptr,
- connect_req: uv::ll::connect_t(),
- write_req: uv::ll::write_t(),
- ipv6: match input_ip {
- ip::Ipv4(_) => { false }
- ip::Ipv6(_) => { true }
- },
- iotask: iotask.clone()
- };
- let socket_data_ptr: *TcpSocketData = &*socket_data;
- // get an unsafe representation of our stream_handle_ptr that
- // we can send into the interact cb to be handled in libuv..
- debug!("stream_handle_ptr outside interact %?",
- stream_handle_ptr);
- do iotask::interact(iotask) |loop_ptr| {
- debug!("in interact cb for tcp client connect..");
- debug!("stream_handle_ptr in interact %?",
- stream_handle_ptr);
- match uv::ll::tcp_init( loop_ptr, stream_handle_ptr) {
- 0i32 => {
- debug!("tcp_init successful");
- debug!("dealing w/ ipv4 connection..");
- let connect_req_ptr: *uv::ll::uv_connect_t =
- &(*socket_data_ptr).connect_req;
- let addr_str = ip::format_addr(&input_ip);
- let connect_result = match input_ip {
- ip::Ipv4(ref addr) => {
- // have to "recreate" the
- // sockaddr_in/6 since the ip_addr
- // discards the port info.. should
- // probably add an additional rust
- // type that actually is closer to
- // what the libuv API expects (ip str
- // + port num)
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip4_addr(addr_str,
- port as int);
- uv::ll::tcp_connect(
- connect_req_ptr,
- stream_handle_ptr,
- &in_addr,
- tcp_connect_on_connect_cb)
- }
- ip::Ipv6(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip6_addr(addr_str,
- port as int);
- uv::ll::tcp_connect6(
- connect_req_ptr,
- stream_handle_ptr,
- &in_addr,
- tcp_connect_on_connect_cb)
- }
- };
- match connect_result {
- 0i32 => {
- debug!("tcp_connect successful: \
- stream %x,
- socket data %x",
- stream_handle_ptr as uint,
- socket_data_ptr as uint);
- // reusable data that we'll have for the
- // duration..
- uv::ll::set_data_for_uv_handle(
- stream_handle_ptr,
- socket_data_ptr as
- *libc::c_void);
- // just so the connect_cb can send the
- // outcome..
- uv::ll::set_data_for_req(connect_req_ptr,
- conn_data_ptr);
- debug!("leaving tcp_connect interact cb...");
- // let tcp_connect_on_connect_cb send on
- // the result_ch, now..
- }
- _ => {
- // immediate connect
- // failure.. probably a garbage ip or
- // somesuch
- let err_data =
- uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*conn_data_ptr)
- .result_ch.clone();
- result_ch.send(ConnFailure(err_data));
- uv::ll::set_data_for_uv_handle(
- stream_handle_ptr,
- conn_data_ptr);
- uv::ll::close(stream_handle_ptr,
- stream_error_close_cb);
- }
- }
- }
- _ => {
- // failure to create a tcp handle
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*conn_data_ptr).result_ch.clone();
- result_ch.send(ConnFailure(err_data));
- }
- }
- }
- match result_po.recv() {
- ConnSuccess => {
- debug!("tcp::connect - received success on result_po");
- result::Ok(TcpSocket(socket_data))
- }
- ConnFailure(ref err_data) => {
- closed_signal_po.recv();
- debug!("tcp::connect - received failure on result_po");
- // still have to free the malloc'd stream handle..
- rustrt::rust_uv_current_kernel_free(stream_handle_ptr
- as *libc::c_void);
- let tcp_conn_err = match err_data.err_name {
- ~"ECONNREFUSED" => ConnectionRefused,
- _ => GenericConnectErr(err_data.err_name.clone(),
- err_data.err_msg.clone())
- };
- result::Err(tcp_conn_err)
- }
- }
- }
-}
-
-/**
- * Write binary data to a tcp stream; Blocks until operation completes
- *
- * # Arguments
- *
- * * sock - a `TcpSocket` to write to
- * * raw_write_data - a vector of `~[u8]` that will be written to the stream.
- * This value must remain valid for the duration of the `write` call
- *
- * # Returns
- *
- * A `Result` object with a `()` value as the `Ok` variant, or a
- * `TcpErrData` value as the `Err` variant
- */
-pub fn write(sock: &TcpSocket, raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- let socket_data_ptr: *TcpSocketData = &*sock.socket_data;
- write_common_impl(socket_data_ptr, raw_write_data)
-}
-
-/**
- * Write binary data to tcp stream; Returns a `future::Future` value
- * immediately
- *
- * # Safety
- *
- * This function can produce unsafe results if:
- *
- * 1. the call to `write_future` is made
- * 2. the `future::Future` value returned is never resolved via
- * `Future::get`
- * 3. and then the `TcpSocket` passed in to `write_future` leaves
- * scope and is destructed before the task that runs the libuv write
- * operation completes.
- *
- * As such: If using `write_future`, always be sure to resolve the returned
- * `Future` so as to ensure libuv doesn't try to access a released write
- * handle. Otherwise, use the blocking `tcp::write` function instead.
- *
- * # Arguments
- *
- * * sock - a `TcpSocket` to write to
- * * raw_write_data - a vector of `~[u8]` that will be written to the stream.
- * This value must remain valid for the duration of the `write` call
- *
- * # Returns
- *
- * A `Future` value that, once the `write` operation completes, resolves to a
- * `Result` object with a `nil` value as the `Ok` variant, or a `TcpErrData`
- * value as the `Err` variant
- */
-pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8])
- -> future::Future<result::Result<(), TcpErrData>>
-{
- let socket_data_ptr: *TcpSocketData = &*sock.socket_data;
- do future_spawn {
- let data_copy = raw_write_data.clone();
- write_common_impl(socket_data_ptr, data_copy)
- }
-}
-
-/**
- * Begin reading binary data from an open TCP connection; used with
- * `read_stop`
- *
- * # Arguments
- *
- * * sock -- a `net::tcp::TcpSocket` for the connection to read from
- *
- * # Returns
- *
- * * A `Result` instance that will either contain a
- * `std::comm::Port<Result<~[u8], TcpErrData>>` that the user can read
- * (and * optionally, loop on) from until `read_stop` is called, or a
- * `TcpErrData` record
- */
-pub fn read_start(sock: &TcpSocket)
- -> result::Result<@Port<result::Result<~[u8],
- TcpErrData>>,
- TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_start_common_impl(socket_data)
-}
-
-/**
- * Stop reading from an open TCP connection; used with `read_start`
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on
- */
-pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_stop_common_impl(socket_data)
-}
-
-/**
- * Reads a single chunk of data from `TcpSocket`; block until data/error
- * recv'd
- *
- * Does a blocking read operation for a single chunk of data from a
- * `TcpSocket` until a data arrives or an error is received. The provided
- * `timeout_msecs` value is used to raise an error if the timeout period
- * passes without any data received.
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to read from
- * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the
- * read attempt. Pass `0u` to wait indefinitely
- */
-pub fn read(sock: &TcpSocket, timeout_msecs: uint)
- -> result::Result<~[u8],TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_common_impl(socket_data, timeout_msecs)
-}
-
-/**
- * Reads a single chunk of data; returns a `future::Future<~[u8]>`
- * immediately
- *
- * Does a non-blocking read operation for a single chunk of data from a
- * `TcpSocket` and immediately returns a `Future` value representing the
- * result. When resolving the returned `Future`, it will block until data
- * arrives or an error is received. The provided `timeout_msecs`
- * value is used to raise an error if the timeout period passes without any
- * data received.
- *
- * # Safety
- *
- * This function can produce unsafe results if the call to `read_future` is
- * made, the `future::Future` value returned is never resolved via
- * `Future::get`, and then the `TcpSocket` passed in to `read_future` leaves
- * scope and is destructed before the task that runs the libuv read
- * operation completes.
- *
- * As such: If using `read_future`, always be sure to resolve the returned
- * `Future` so as to ensure libuv doesn't try to access a released read
- * handle. Otherwise, use the blocking `tcp::read` function instead.
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to read from
- * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the
- * read attempt. Pass `0u` to wait indefinitely
- */
-fn read_future(sock: &TcpSocket, timeout_msecs: uint)
- -> future::Future<result::Result<~[u8],TcpErrData>> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- do future_spawn {
- read_common_impl(socket_data, timeout_msecs)
- }
-}
-
-/**
- * Bind an incoming client connection to a `net::tcp::TcpSocket`
- *
- * # Notes
- *
- * It is safe to call `net::tcp::accept` _only_ within the context of the
- * `new_connect_cb` callback provided as the final argument to the
- * `net::tcp::listen` function.
- *
- * The `new_conn` opaque value is provided _only_ as the first argument to the
- * `new_connect_cb` provided as a part of `net::tcp::listen`.
- * It can be safely sent to another task but it _must_ be
- * used (via `net::tcp::accept`) before the `new_connect_cb` call it was
- * provided to returns.
- *
- * This implies that a port/chan pair must be used to make sure that the
- * `new_connect_cb` call blocks until an attempt to create a
- * `net::tcp::TcpSocket` is completed.
- *
- * # Example
- *
- * Here, the `new_conn` is used in conjunction with `accept` from within
- * a task spawned by the `new_connect_cb` passed into `listen`
- *
- * ~~~ {.rust}
- * do net::tcp::listen(remote_ip, remote_port, backlog, iotask,
- * // this callback is ran once after the connection is successfully
- * // set up
- * |kill_ch| {
- * // pass the kill_ch to your main loop or wherever you want
- * // to be able to externally kill the server from
- * })
- * // this callback is ran when a new connection arrives
- * |new_conn, kill_ch| {
- * let (cont_po, cont_ch) = comm::stream::<option::Option<TcpErrData>>();
- * do task::spawn {
- * let accept_result = net::tcp::accept(new_conn);
- * match accept_result {
- * Err(accept_error) => {
- * cont_ch.send(Some(accept_error));
- * // fail?
- * },
- * Ok(sock) => {
- * cont_ch.send(None);
- * // do work here
- * }
- * }
- * };
- * match cont_po.recv() {
- * // shut down listen()
- * Some(err_data) => kill_ch.send(Some(err_data)),
- * // wait for next connection
- * None => ()
- * }
- * };
- * ~~~
- *
- * # Arguments
- *
- * * `new_conn` - an opaque value used to create a new `TcpSocket`
- *
- * # Returns
- *
- * On success, this function will return a `net::tcp::TcpSocket` as the
- * `Ok` variant of a `Result`. The `net::tcp::TcpSocket` is anchored within
- * the task that `accept` was called within for its lifetime. On failure,
- * this function will return a `net::tcp::TcpErrData` record
- * as the `Err` variant of a `Result`.
- */
-pub fn accept(new_conn: TcpNewConnection)
- -> result::Result<TcpSocket, TcpErrData> {
- unsafe {
- match new_conn{
- NewTcpConn(server_handle_ptr) => {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(
- server_handle_ptr) as *TcpListenFcData;
- let (reader_po, reader_ch) = stream::<
- Result<~[u8], TcpErrData>>();
- let reader_ch = SharedChan::new(reader_ch);
- let iotask = &(*server_data_ptr).iotask;
- let stream_handle_ptr = malloc_uv_tcp_t();
- *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) =
- uv::ll::tcp_t();
- let client_socket_data: @TcpSocketData = @TcpSocketData {
- reader_po: @reader_po,
- reader_ch: reader_ch,
- stream_handle_ptr : stream_handle_ptr,
- connect_req : uv::ll::connect_t(),
- write_req : uv::ll::write_t(),
- ipv6: (*server_data_ptr).ipv6,
- iotask : iotask.clone()
- };
- let client_socket_data_ptr: *TcpSocketData =
- &*client_socket_data;
- let client_stream_handle_ptr =
- (*client_socket_data_ptr).stream_handle_ptr;
-
- let (result_po, result_ch) = stream::<Option<TcpErrData>>();
- let result_ch = SharedChan::new(result_ch);
-
- // UNSAFE LIBUV INTERACTION BEGIN
- // .. normally this happens within the context of
- // a call to uv::hl::interact.. but we're breaking
- // the rules here because this always has to be
- // called within the context of a listen() new_connect_cb
- // callback (or it will likely fail and drown your cat)
- debug!("in interact cb for tcp::accept");
- let loop_ptr = uv::ll::get_loop_for_uv_handle(
- server_handle_ptr);
- match uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) {
- 0i32 => {
- debug!("uv_tcp_init successful for \
- client stream");
- match uv::ll::accept(
- server_handle_ptr as *libc::c_void,
- client_stream_handle_ptr as *libc::c_void) {
- 0i32 => {
- debug!("successfully accepted client \
- connection: \
- stream %x, \
- socket data %x",
- client_stream_handle_ptr as uint,
- client_socket_data_ptr as uint);
- uv::ll::set_data_for_uv_handle(
- client_stream_handle_ptr,
- client_socket_data_ptr
- as *libc::c_void);
- let ptr = uv::ll::get_data_for_uv_handle(
- client_stream_handle_ptr);
- debug!("ptrs: %x %x",
- client_socket_data_ptr as uint,
- ptr as uint);
- result_ch.send(None);
- }
- _ => {
- debug!("failed to accept client conn");
- result_ch.send(Some(
- uv::ll::get_last_err_data(
- loop_ptr).to_tcp_err()));
- }
- }
- }
- _ => {
- debug!("failed to accept client stream");
- result_ch.send(Some(
- uv::ll::get_last_err_data(
- loop_ptr).to_tcp_err()));
- }
- }
- // UNSAFE LIBUV INTERACTION END
- match result_po.recv() {
- Some(err_data) => result::Err(err_data),
- None => result::Ok(TcpSocket(client_socket_data))
- }
- }
- }
- }
-}
-
-/**
- * Bind to a given IP/port and listen for new connections
- *
- * # Arguments
- *
- * * `host_ip` - a `net::ip::IpAddr` representing a unique IP
- * (versions 4 or 6)
- * * `port` - a uint representing the port to listen on
- * * `backlog` - a uint representing the number of incoming connections
- * to cache in memory
- * * `hl_loop` - a `uv_iotask::IoTask` that the tcp request will run on
- * * `on_establish_cb` - a callback that is evaluated if/when the listener
- * is successfully established. it takes no parameters
- * * `new_connect_cb` - a callback to be evaluated, on the libuv thread,
- * whenever a client attempts to conect on the provided ip/port. the
- * callback's arguments are:
- * * `new_conn` - an opaque type that can be passed to
- * `net::tcp::accept` in order to be converted to a `TcpSocket`.
- * * `kill_ch` - channel of type `std::comm::Chan<Option<tcp_err_data>>`.
- * this channel can be used to send a message to cause `listen` to begin
- * closing the underlying libuv data structures.
- *
- * # returns
- *
- * a `Result` instance containing empty data of type `()` on a
- * successful/normal shutdown, and a `TcpListenErrData` enum in the event
- * of listen exiting because of an error
- */
-pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint,
- iotask: &IoTask,
- on_establish_cb: ~fn(SharedChan<Option<TcpErrData>>),
- new_connect_cb: ~fn(TcpNewConnection,
- SharedChan<Option<TcpErrData>>))
- -> result::Result<(), TcpListenErrData> {
- do listen_common(host_ip, port, backlog, iotask,
- on_establish_cb)
- // on_connect_cb
- |handle| {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(handle)
- as *TcpListenFcData;
- let new_conn = NewTcpConn(handle);
- let kill_ch = (*server_data_ptr).kill_ch.clone();
- new_connect_cb(new_conn, kill_ch);
- }
- }
-}
-
-fn listen_common(host_ip: ip::IpAddr,
- port: uint,
- backlog: uint,
- iotask: &IoTask,
- on_establish_cb: ~fn(SharedChan<Option<TcpErrData>>),
- on_connect_cb: ~fn(*uv::ll::uv_tcp_t))
- -> result::Result<(), TcpListenErrData> {
- let (stream_closed_po, stream_closed_ch) = stream::<()>();
- let stream_closed_ch = SharedChan::new(stream_closed_ch);
- let (kill_po, kill_ch) = stream::<Option<TcpErrData>>();
- let kill_ch = SharedChan::new(kill_ch);
- let server_stream = uv::ll::tcp_t();
- let server_stream_ptr: *uv::ll::uv_tcp_t = &server_stream;
- let server_data: TcpListenFcData = TcpListenFcData {
- server_stream_ptr: server_stream_ptr,
- stream_closed_ch: stream_closed_ch,
- kill_ch: kill_ch.clone(),
- on_connect_cb: on_connect_cb,
- iotask: iotask.clone(),
- ipv6: match &host_ip {
- &ip::Ipv4(_) => { false }
- &ip::Ipv6(_) => { true }
- },
- active: @mut true
- };
- let server_data_ptr: *TcpListenFcData = &server_data;
-
- let (setup_po, setup_ch) = stream();
-
- // this is to address a compiler warning about
- // an implicit copy.. it seems that double nested
- // will defeat a move sigil, as is done to the host_ip
- // arg above.. this same pattern works w/o complaint in
- // tcp::connect (because the iotask::interact cb isn't
- // nested within a core::comm::listen block)
- let loc_ip = host_ip;
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- match uv::ll::tcp_init(loop_ptr, server_stream_ptr) {
- 0i32 => {
- uv::ll::set_data_for_uv_handle(
- server_stream_ptr,
- server_data_ptr);
- let addr_str = ip::format_addr(&loc_ip);
- let bind_result = match loc_ip {
- ip::Ipv4(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip4_addr(
- addr_str,
- port as int);
- uv::ll::tcp_bind(server_stream_ptr, &in_addr)
- }
- ip::Ipv6(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip6_addr(
- addr_str,
- port as int);
- uv::ll::tcp_bind6(server_stream_ptr, &in_addr)
- }
- };
- match bind_result {
- 0i32 => {
- match uv::ll::listen(
- server_stream_ptr,
- backlog as libc::c_int,
- tcp_lfc_on_connection_cb) {
- 0i32 => setup_ch.send(None),
- _ => {
- debug!(
- "failure to uv_tcp_init");
- let err_data =
- uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- _ => {
- debug!("failure to uv_tcp_bind");
- let err_data = uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- _ => {
- debug!("failure to uv_tcp_bind");
- let err_data = uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- }
-
- let setup_result = setup_po.recv();
-
- match setup_result {
- Some(ref err_data) => {
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- debug!(
- "tcp::listen post-kill recv hl interact %?",
- loop_ptr);
- *(*server_data_ptr).active = false;
- uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
- }
- };
- stream_closed_po.recv();
- match err_data.err_name {
- ~"EACCES" => {
- debug!("Got EACCES error");
- result::Err(AccessDenied)
- }
- ~"EADDRINUSE" => {
- debug!("Got EADDRINUSE error");
- result::Err(AddressInUse)
- }
- _ => {
- debug!("Got '%s' '%s' libuv error",
- err_data.err_name, err_data.err_msg);
- result::Err(
- GenericListenErr(err_data.err_name.clone(),
- err_data.err_msg.clone()))
- }
- }
- }
- None => {
- on_establish_cb(kill_ch.clone());
- let kill_result = kill_po.recv();
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- debug!(
- "tcp::listen post-kill recv hl interact %?",
- loop_ptr);
- *(*server_data_ptr).active = false;
- uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
- }
- };
- stream_closed_po.recv();
- match kill_result {
- // some failure post bind/listen
- Some(ref err_data) => result::Err(GenericListenErr(
- err_data.err_name.clone(),
- err_data.err_msg.clone())),
- // clean exit
- None => result::Ok(())
- }
- }
- }
-}
-
-
-/**
- * Convert a `net::tcp::TcpSocket` to a `net::tcp::TcpSocketBuf`.
- *
- * This function takes ownership of a `net::tcp::TcpSocket`, returning it
- * stored within a buffered wrapper, which can be converted to a `io::Reader`
- * or `io::Writer`
- *
- * # Arguments
- *
- * * `sock` -- a `net::tcp::TcpSocket` that you want to buffer
- *
- * # Returns
- *
- * A buffered wrapper that you can cast as an `io::Reader` or `io::Writer`
- */
-pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf {
- TcpSocketBuf(@mut TcpBufferedSocketData {
- sock: sock, buf: ~[], buf_off: 0
- })
-}
-
-/// Convenience methods extending `net::tcp::TcpSocket`
-impl TcpSocket {
- pub fn read_start(&self) -> result::Result<@Port<
- result::Result<~[u8], TcpErrData>>, TcpErrData> {
- read_start(self)
- }
- pub fn read_stop(&self) ->
- result::Result<(), TcpErrData> {
- read_stop(self)
- }
- pub fn read(&self, timeout_msecs: uint) ->
- result::Result<~[u8], TcpErrData> {
- read(self, timeout_msecs)
- }
- pub fn read_future(&self, timeout_msecs: uint) ->
- future::Future<result::Result<~[u8], TcpErrData>> {
- read_future(self, timeout_msecs)
- }
- pub fn write(&self, raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- write(self, raw_write_data)
- }
- pub fn write_future(&self, raw_write_data: ~[u8])
- -> future::Future<result::Result<(), TcpErrData>> {
- write_future(self, raw_write_data)
- }
- pub fn get_peer_addr(&self) -> ip::IpAddr {
- unsafe {
- if self.socket_data.ipv6 {
- let addr = uv::ll::ip6_addr("", 0);
- uv::ll::tcp_getpeername6(self.socket_data.stream_handle_ptr,
- &addr);
- ip::Ipv6(addr)
- } else {
- let addr = uv::ll::ip4_addr("", 0);
- uv::ll::tcp_getpeername(self.socket_data.stream_handle_ptr,
- &addr);
- ip::Ipv4(addr)
- }
- }
- }
-}
-
-/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket`
-impl io::Reader for TcpSocketBuf {
- fn read(&self, buf: &mut [u8], len: uint) -> uint {
- if len == 0 { return 0 }
- let mut count: uint = 0;
-
- loop {
- assert!(count < len);
-
- // If possible, copy up to `len` bytes from the internal
- // `data.buf` into `buf`
- let nbuffered = self.data.buf.len() - self.data.buf_off;
- let needed = len - count;
- if nbuffered > 0 {
- unsafe {
- let ncopy = num::min(nbuffered, needed);
- let dst = ptr::mut_offset(
- vec::raw::to_mut_ptr(buf), count);
- let src = ptr::offset(
- vec::raw::to_ptr(self.data.buf),
- self.data.buf_off);
- ptr::copy_memory(dst, src, ncopy);
- self.data.buf_off += ncopy;
- count += ncopy;
- }
- }
-
- assert!(count <= len);
- if count == len {
- break;
- }
-
- // We copied all the bytes we had in the internal buffer into
- // the result buffer, but the caller wants more bytes, so we
- // need to read in data from the socket. Note that the internal
- // buffer is of no use anymore as we read all bytes from it,
- // so we can throw it away.
- let read_result = {
- let data = &*self.data;
- read(&data.sock, 0)
- };
- if read_result.is_err() {
- let err_data = read_result.get_err();
-
- if err_data.err_name == ~"EOF" {
- *self.end_of_stream = true;
- break;
- } else {
- debug!("ERROR sock_buf as io::reader.read err %? %?",
- err_data.err_name, err_data.err_msg);
- // As we have already copied data into result buffer,
- // we cannot simply return 0 here. Instead the error
- // should show up in a later call to read().
- break;
- }
- } else {
- self.data.buf = result::unwrap(read_result);
- self.data.buf_off = 0;
- }
- }
-
- count
- }
- fn read_byte(&self) -> int {
- loop {
- if self.data.buf.len() > self.data.buf_off {
- let c = self.data.buf[self.data.buf_off];
- self.data.buf_off += 1;
- return c as int
- }
-
- let read_result = {
- let data = &*self.data;
- read(&data.sock, 0)
- };
- if read_result.is_err() {
- let err_data = read_result.get_err();
-
- if err_data.err_name == ~"EOF" {
- *self.end_of_stream = true;
- return -1
- } else {
- debug!("ERROR sock_buf as io::reader.read err %? %?",
- err_data.err_name, err_data.err_msg);
- fail!()
- }
- } else {
- self.data.buf = result::unwrap(read_result);
- self.data.buf_off = 0;
- }
- }
- }
- fn eof(&self) -> bool {
- *self.end_of_stream
- }
- fn seek(&self, dist: int, seek: io::SeekStyle) {
- debug!("tcp_socket_buf seek stub %? %?", dist, seek);
- // noop
- }
- fn tell(&self) -> uint {
- 0u // noop
- }
-}
-
-/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket`
-impl io::Writer for TcpSocketBuf {
- pub fn write(&self, data: &[u8]) {
- let socket_data_ptr: *TcpSocketData =
- &(*((*(self.data)).sock).socket_data);
- let w_result = write_common_impl(socket_data_ptr,
- data.slice(0, data.len()).to_owned());
- if w_result.is_err() {
- let err_data = w_result.get_err();
- debug!(
- "ERROR sock_buf as io::writer.writer err: %? %?",
- err_data.err_name, err_data.err_msg);
- }
- }
- fn seek(&self, dist: int, seek: io::SeekStyle) {
- debug!("tcp_socket_buf seek stub %? %?", dist, seek);
- // noop
- }
- fn tell(&self) -> uint {
- 0u
- }
- fn flush(&self) -> int {
- 0
- }
- fn get_type(&self) -> io::WriterType {
- io::File
- }
-}
-
-// INTERNAL API
-
-fn tear_down_socket_data(socket_data: @TcpSocketData) {
- unsafe {
- let (closed_po, closed_ch) = stream::<()>();
- let closed_ch = SharedChan::new(closed_ch);
- let close_data = TcpSocketCloseData {
- closed_ch: closed_ch
- };
- let close_data_ptr: *TcpSocketCloseData = &close_data;
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!(
- "interact dtor for tcp_socket stream %? loop %?",
- stream_handle_ptr, loop_ptr);
- uv::ll::set_data_for_uv_handle(stream_handle_ptr,
- close_data_ptr);
- uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb);
- };
- closed_po.recv();
- //the line below will most likely crash
- //log(debug, fmt!("about to free socket_data at %?", socket_data));
- rustrt::rust_uv_current_kernel_free(stream_handle_ptr
- as *libc::c_void);
- debug!("exiting dtor for tcp_socket");
- }
-}
-
-// shared implementation for tcp::read
-fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint)
- -> result::Result<~[u8],TcpErrData> {
- unsafe {
- use timer;
-
- debug!("starting tcp::read");
- let iotask = &(*socket_data).iotask;
- let rs_result = read_start_common_impl(socket_data);
- if result::is_err(&rs_result) {
- let err_data = result::get_err(&rs_result);
- result::Err(err_data)
- }
- else {
- debug!("tcp::read before recv_timeout");
- let read_result = if timeout_msecs > 0u {
- timer::recv_timeout(
- iotask, timeout_msecs, result::unwrap(rs_result))
- } else {
- Some(result::get(&rs_result).recv())
- };
- debug!("tcp::read after recv_timeout");
- match read_result {
- None => {
- debug!("tcp::read: timed out..");
- let err_data = TcpErrData {
- err_name: ~"TIMEOUT",
- err_msg: ~"req timed out"
- };
- read_stop_common_impl(socket_data);
- result::Err(err_data)
- }
- Some(data_result) => {
- debug!("tcp::read got data");
- read_stop_common_impl(socket_data);
- data_result
- }
- }
- }
- }
-}
-
-// shared impl for read_stop
-fn read_stop_common_impl(socket_data: *TcpSocketData) ->
- result::Result<(), TcpErrData> {
- unsafe {
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- let (stop_po, stop_ch) = stream::<Option<TcpErrData>>();
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!("in interact cb for tcp::read_stop");
- match uv::ll::read_stop(stream_handle_ptr
- as *uv::ll::uv_stream_t) {
- 0i32 => {
- debug!("successfully called uv_read_stop");
- stop_ch.send(None);
- }
- _ => {
- debug!("failure in calling uv_read_stop");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- stop_ch.send(Some(err_data.to_tcp_err()));
- }
- }
- }
- match stop_po.recv() {
- Some(err_data) => Err(err_data),
- None => Ok(())
- }
- }
-}
-
-// shared impl for read_start
-fn read_start_common_impl(socket_data: *TcpSocketData)
- -> result::Result<@Port<
- result::Result<~[u8], TcpErrData>>, TcpErrData> {
- unsafe {
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- let (start_po, start_ch) = stream::<Option<uv::ll::uv_err_data>>();
- debug!("in tcp::read_start before interact loop");
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!("in tcp::read_start interact cb %?",
- loop_ptr);
- match uv::ll::read_start(stream_handle_ptr
- as *uv::ll::uv_stream_t,
- on_alloc_cb,
- on_tcp_read_cb) {
- 0i32 => {
- debug!("success doing uv_read_start");
- start_ch.send(None);
- }
- _ => {
- debug!("error attempting uv_read_start");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- start_ch.send(Some(err_data));
- }
- }
- }
- match start_po.recv() {
- Some(ref err_data) => result::Err(
- err_data.to_tcp_err()),
- None => {
- result::Ok((*socket_data).reader_po)
- }
- }
- }
-}
-
-// helper to convert a "class" vector of [u8] to a *[uv::ll::uv_buf_t]
-
-// shared implementation used by write and write_future
-fn write_common_impl(socket_data_ptr: *TcpSocketData,
- raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- unsafe {
- let write_req_ptr: *uv::ll::uv_write_t =
- &(*socket_data_ptr).write_req;
- let stream_handle_ptr =
- (*socket_data_ptr).stream_handle_ptr;
- let write_buf_vec = ~[
- uv::ll::buf_init(vec::raw::to_ptr(raw_write_data),
- raw_write_data.len())
- ];
- let write_buf_vec_ptr: *~[uv::ll::uv_buf_t] = &write_buf_vec;
- let (result_po, result_ch) = stream::<TcpWriteResult>();
- let result_ch = SharedChan::new(result_ch);
- let write_data = WriteReqData {
- result_ch: result_ch
- };
- let write_data_ptr: *WriteReqData = &write_data;
- do iotask::interact(&(*socket_data_ptr).iotask) |loop_ptr| {
- debug!("in interact cb for tcp::write %?",
- loop_ptr);
- match uv::ll::write(write_req_ptr,
- stream_handle_ptr,
- write_buf_vec_ptr,
- tcp_write_complete_cb) {
- 0i32 => {
- debug!("uv_write() invoked successfully");
- uv::ll::set_data_for_req(write_req_ptr,
- write_data_ptr);
- }
- _ => {
- debug!("error invoking uv_write()");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteError(err_data.to_tcp_err()));
- }
- }
- }
- // FIXME (#2656): Instead of passing unsafe pointers to local data,
- // and waiting here for the write to complete, we should transfer
- // ownership of everything to the I/O task and let it deal with the
- // aftermath, so we don't have to sit here blocking.
- match result_po.recv() {
- TcpWriteSuccess => Ok(()),
- TcpWriteError(err_data) => Err(err_data)
- }
- }
-}
-
-enum TcpNewConnection {
- NewTcpConn(*uv::ll::uv_tcp_t)
-}
-
-struct TcpListenFcData {
- server_stream_ptr: *uv::ll::uv_tcp_t,
- stream_closed_ch: SharedChan<()>,
- kill_ch: SharedChan<Option<TcpErrData>>,
- on_connect_cb: ~fn(*uv::ll::uv_tcp_t),
- iotask: IoTask,
- ipv6: bool,
- active: @mut bool,
-}
-
-extern fn tcp_lfc_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(
- handle) as *TcpListenFcData;
- let stream_closed_ch = (*server_data_ptr).stream_closed_ch.clone();
- stream_closed_ch.send(());
- }
-}
-
-extern fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t,
- status: libc::c_int) {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(handle)
- as *TcpListenFcData;
- let kill_ch = (*server_data_ptr).kill_ch.clone();
- if *(*server_data_ptr).active {
- match status {
- 0i32 => ((*server_data_ptr).on_connect_cb)(handle),
- _ => {
- let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
- kill_ch.send(
- Some(uv::ll::get_last_err_data(loop_ptr)
- .to_tcp_err()));
- *(*server_data_ptr).active = false;
- }
- }
- }
- }
-}
-
-fn malloc_uv_tcp_t() -> *uv::ll::uv_tcp_t {
- unsafe {
- rustrt::rust_uv_current_kernel_malloc(
- rustrt::rust_uv_helper_uv_tcp_t_size()) as *uv::ll::uv_tcp_t
- }
-}
-
-enum TcpConnectResult {
- TcpConnected(TcpSocket),
- TcpConnectError(TcpErrData)
-}
-
-enum TcpWriteResult {
- TcpWriteSuccess,
- TcpWriteError(TcpErrData)
-}
-
-enum TcpReadStartResult {
- TcpReadStartSuccess(Port<TcpReadResult>),
- TcpReadStartError(TcpErrData)
-}
-
-enum TcpReadResult {
- TcpReadData(~[u8]),
- TcpReadDone,
- TcpReadErr(TcpErrData)
-}
-
-trait ToTcpErr {
- fn to_tcp_err(&self) -> TcpErrData;
-}
-
-impl ToTcpErr for uv::ll::uv_err_data {
- fn to_tcp_err(&self) -> TcpErrData {
- TcpErrData {
- err_name: self.err_name.clone(),
- err_msg: self.err_msg.clone(),
- }
- }
-}
-
-extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t,
- nread: libc::ssize_t,
- buf: uv::ll::uv_buf_t) {
- unsafe {
- debug!("entering on_tcp_read_cb stream: %x nread: %?",
- stream as uint, nread);
- let loop_ptr = uv::ll::get_loop_for_uv_handle(stream);
- let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream)
- as *TcpSocketData;
- debug!("socket data is %x", socket_data_ptr as uint);
- match nread as int {
- // incoming err.. probably eof
- -1 => {
- let err_data = uv::ll::get_last_err_data(loop_ptr).to_tcp_err();
- debug!("on_tcp_read_cb: incoming err.. name %? msg %?",
- err_data.err_name, err_data.err_msg);
- let reader_ch = &(*socket_data_ptr).reader_ch;
- reader_ch.send(result::Err(err_data));
- }
- // do nothing .. unneeded buf
- 0 => (),
- // have data
- _ => {
- // we have data
- debug!("tcp on_read_cb nread: %d", nread as int);
- let reader_ch = &(*socket_data_ptr).reader_ch;
- let buf_base = uv::ll::get_base_from_buf(buf);
- let new_bytes = vec::from_buf(buf_base, nread as uint);
- reader_ch.send(result::Ok(new_bytes));
- }
- }
- uv::ll::free_base_of_buf(buf);
- debug!("exiting on_tcp_read_cb");
- }
-}
-
-extern fn on_alloc_cb(handle: *libc::c_void,
- suggested_size: size_t)
- -> uv::ll::uv_buf_t {
- unsafe {
- debug!("tcp read on_alloc_cb!");
- let char_ptr = uv::ll::malloc_buf_base_of(suggested_size);
- debug!("tcp read on_alloc_cb h: %? char_ptr: %u sugsize: %u",
- handle,
- char_ptr as uint,
- suggested_size as uint);
- uv::ll::buf_init(char_ptr, suggested_size as uint)
- }
-}
-
-struct TcpSocketCloseData {
- closed_ch: SharedChan<()>,
-}
-
-extern fn tcp_socket_dtor_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let data = uv::ll::get_data_for_uv_handle(handle)
- as *TcpSocketCloseData;
- let closed_ch = (*data).closed_ch.clone();
- closed_ch.send(());
- debug!("tcp_socket_dtor_close_cb exiting..");
- }
-}
-
-extern fn tcp_write_complete_cb(write_req: *uv::ll::uv_write_t,
- status: libc::c_int) {
- unsafe {
- let write_data_ptr = uv::ll::get_data_for_req(write_req)
- as *WriteReqData;
- if status == 0i32 {
- debug!("successful write complete");
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteSuccess);
- } else {
- let stream_handle_ptr = uv::ll::get_stream_handle_from_write_req(
- write_req);
- let loop_ptr = uv::ll::get_loop_for_uv_handle(stream_handle_ptr);
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- debug!("failure to write");
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteError(err_data.to_tcp_err()));
- }
- }
-}
-
-struct WriteReqData {
- result_ch: SharedChan<TcpWriteResult>,
-}
-
-struct ConnectReqData {
- result_ch: SharedChan<ConnAttempt>,
- closed_signal_ch: SharedChan<()>,
-}
-
-extern fn stream_error_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let data = uv::ll::get_data_for_uv_handle(handle) as
- *ConnectReqData;
- let closed_signal_ch = (*data).closed_signal_ch.clone();
- closed_signal_ch.send(());
- debug!("exiting steam_error_close_cb for %?", handle);
- }
-}
-
-extern fn tcp_connect_close_cb(handle: *uv::ll::uv_tcp_t) {
- debug!("closed client tcp handle %?", handle);
-}
-
-extern fn tcp_connect_on_connect_cb(connect_req_ptr: *uv::ll::uv_connect_t,
- status: libc::c_int) {
- unsafe {
- let conn_data_ptr = (uv::ll::get_data_for_req(connect_req_ptr)
- as *ConnectReqData);
- let result_ch = (*conn_data_ptr).result_ch.clone();
- debug!("tcp_connect result_ch %?", result_ch);
- let tcp_stream_ptr =
- uv::ll::get_stream_handle_from_connect_req(connect_req_ptr);
- match status {
- 0i32 => {
- debug!("successful tcp connection!");
- result_ch.send(ConnSuccess);
- }
- _ => {
- debug!("error in tcp_connect_on_connect_cb");
- let loop_ptr = uv::ll::get_loop_for_uv_handle(tcp_stream_ptr);
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- debug!("err_data %? %?", err_data.err_name,
- err_data.err_msg);
- result_ch.send(ConnFailure(err_data));
- uv::ll::set_data_for_uv_handle(tcp_stream_ptr,
- conn_data_ptr);
- uv::ll::close(tcp_stream_ptr, stream_error_close_cb);
- }
- }
- debug!("leaving tcp_connect_on_connect_cb");
- }
-}
-
-enum ConnAttempt {
- ConnSuccess,
- ConnFailure(uv::ll::uv_err_data)
-}
-
-struct TcpSocketData {
- reader_po: @Port<result::Result<~[u8], TcpErrData>>,
- reader_ch: SharedChan<result::Result<~[u8], TcpErrData>>,
- stream_handle_ptr: *uv::ll::uv_tcp_t,
- connect_req: uv::ll::uv_connect_t,
- write_req: uv::ll::uv_write_t,
- ipv6: bool,
- iotask: IoTask,
-}
-
-struct TcpBufferedSocketData {
- sock: TcpSocket,
- buf: ~[u8],
- buf_off: uint
-}
-
-#[cfg(test)]
-mod test {
-
- use net::ip;
- use net::tcp::{GenericListenErr, TcpConnectErrData, TcpListenErrData};
- use net::tcp::{connect, accept, read, listen, TcpSocket, socket_buf};
- use net;
- use uv::iotask::IoTask;
- use uv;
-
- use std::cell::Cell;
- use std::comm::{stream, SharedChan};
- use std::io;
- use std::result;
- use std::str;
- use std::task;
-
- // FIXME don't run on fbsd or linux 32 bit (#2064)
- #[cfg(target_os="win32")]
- #[cfg(target_os="darwin")]
- #[cfg(target_os="linux")]
- #[cfg(target_os="android")]
- mod tcp_ipv4_server_and_client_test {
- #[cfg(target_arch="x86_64")]
- mod impl64 {
- use net::tcp::test::*;
-
- #[test]
- fn test_gl_tcp_server_and_client_ipv4() {
- impl_gl_tcp_ipv4_server_and_client();
- }
- #[test]
- fn test_gl_tcp_get_peer_addr() {
- impl_gl_tcp_ipv4_get_peer_addr();
- }
- #[test]
- fn test_gl_tcp_ipv4_client_error_connection_refused() {
- impl_gl_tcp_ipv4_client_error_connection_refused();
- }
- #[test]
- fn test_gl_tcp_server_address_in_use() {
- impl_gl_tcp_ipv4_server_address_in_use();
- }
- #[test]
- fn test_gl_tcp_server_access_denied() {
- impl_gl_tcp_ipv4_server_access_denied();
- }
- // Strange failure on Windows. --pcwalton
- #[test]
- #[ignore(cfg(target_os = "win32"))]
- fn test_gl_tcp_ipv4_server_client_reader_writer() {
- impl_gl_tcp_ipv4_server_client_reader_writer();
- }
- #[test]
- fn test_tcp_socket_impl_reader_handles_eof() {
- impl_tcp_socket_impl_reader_handles_eof();
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- mod impl32 {
- use net::tcp::test::*;
-
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_server_and_client_ipv4() {
- unsafe {
- impl_gl_tcp_ipv4_server_and_client();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_get_peer_addr() {
- unsafe {
- impl_gl_tcp_ipv4_get_peer_addr();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_ipv4_client_error_connection_refused() {
- unsafe {
- impl_gl_tcp_ipv4_client_error_connection_refused();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_server_address_in_use() {
- unsafe {
- impl_gl_tcp_ipv4_server_address_in_use();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- #[ignore(cfg(windows), reason = "deadlocking bots")]
- fn test_gl_tcp_server_access_denied() {
- unsafe {
- impl_gl_tcp_ipv4_server_access_denied();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- #[ignore(cfg(target_os = "win32"))]
- fn test_gl_tcp_ipv4_server_client_reader_writer() {
- impl_gl_tcp_ipv4_server_client_reader_writer();
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_and_client() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8888u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (server_result_po, server_result_ch) = stream::<~str>();
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- let actual_req = run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- server_result_ch.send(actual_req);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let actual_resp_result = run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- assert!(actual_resp_result.is_ok());
- let actual_resp = actual_resp_result.get();
- let actual_req = server_result_po.recv();
- debug!("REQ: expected: '%s' actual: '%s'",
- expected_req, actual_req);
- debug!("RESP: expected: '%s' actual: '%s'",
- expected_resp, actual_resp);
- assert!(actual_req.contains(expected_req));
- assert!(actual_resp.contains(expected_resp));
- }
- pub fn impl_gl_tcp_ipv4_get_peer_addr() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8887u;
- let expected_resp = "pong";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let iotask = uv::global_loop::get();
- let connect_result = connect(server_ip_addr, server_port,
- &iotask);
-
- let sock = result::unwrap(connect_result);
-
- debug!("testing peer address");
- // This is what we are actually testing!
- assert!(net::ip::format_addr(&sock.get_peer_addr()) ==
- ~"127.0.0.1");
- assert_eq!(net::ip::get_port(&sock.get_peer_addr()), 8887);
-
- // Fulfill the protocol the test server expects
- let resp_bytes = "ping".as_bytes().to_owned();
- tcp_write_single(&sock, resp_bytes);
- debug!("message sent");
- sock.read(0u);
- debug!("result read");
- }
- pub fn impl_gl_tcp_ipv4_client_error_connection_refused() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8889u;
- let expected_req = ~"ping";
- // client
- debug!("firing up client..");
- let actual_resp_result = run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- match actual_resp_result.get_err() {
- ConnectionRefused => (),
- _ => fail!("unknown error.. expected connection_refused")
- }
- }
- pub fn impl_gl_tcp_ipv4_server_address_in_use() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8890u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- }
- cont_po.recv();
- // this one should fail..
- let listen_err = run_tcp_test_server_fail(
- server_ip,
- server_port,
- hl_loop);
- // client.. just doing this so that the first server tears down
- debug!("server started, firing up client..");
- run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- match listen_err {
- AddressInUse => {
- assert!(true);
- }
- _ => {
- fail!("expected address_in_use listen error, \
- but got a different error varient. check logs.");
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_access_denied() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 80u;
- // this one should fail..
- let listen_err = run_tcp_test_server_fail(
- server_ip,
- server_port,
- hl_loop);
- match listen_err {
- AccessDenied => {
- assert!(true);
- }
- _ => {
- fail!("expected address_in_use listen error, \
- but got a different error varient. check logs.");
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_client_reader_writer() {
-
- let iotask = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8891u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (server_result_po, server_result_ch) = stream::<~str>();
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let iotask_clone = iotask.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- let actual_req = run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &iotask_clone);
- server_result_ch.send(actual_req);
- };
- cont_po.recv();
- // client
- let server_addr = ip::v4::parse_addr(server_ip);
- let conn_result = connect(server_addr, server_port, iotask);
- if result::is_err(&conn_result) {
- assert!(false);
- }
- let sock_buf = @socket_buf(result::unwrap(conn_result));
- buf_write(sock_buf, expected_req);
-
- // so contrived!
- let actual_resp = buf_read(sock_buf, expected_resp.as_bytes().len());
-
- let actual_req = server_result_po.recv();
- debug!("REQ: expected: '%s' actual: '%s'",
- expected_req, actual_req);
- debug!("RESP: expected: '%s' actual: '%s'",
- expected_resp, actual_resp);
- assert!(actual_req.contains(expected_req));
- assert!(actual_resp.contains(expected_resp));
- }
-
- pub fn impl_tcp_socket_impl_reader_handles_eof() {
- use std::io::{Reader,ReaderUtil};
-
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 10041u;
- let expected_req = ~"GET /";
- let expected_resp = "A string\nwith multiple lines\n";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let server_addr = ip::v4::parse_addr(server_ip);
- let conn_result = connect(server_addr, server_port, hl_loop);
- if result::is_err(&conn_result) {
- assert!(false);
- }
- let sock_buf = @socket_buf(result::unwrap(conn_result));
- buf_write(sock_buf, expected_req);
-
- let buf_reader = sock_buf as @Reader;
- let actual_response = str::from_bytes(buf_reader.read_whole_stream());
- debug!("Actual response: %s", actual_response);
- assert!(expected_resp == actual_response);
- }
-
- fn buf_write<W:io::Writer>(w: &W, val: &str) {
- debug!("BUF_WRITE: val len %?", val.len());
- let b_slice = val.as_bytes();
- debug!("BUF_WRITE: b_slice len %?",
- b_slice.len());
- w.write(b_slice)
- }
-
- fn buf_read<R:io::Reader>(r: &R, len: uint) -> ~str {
- let new_bytes = (*r).read_bytes(len);
- debug!("in buf_read.. new_bytes len: %?",
- new_bytes.len());
- str::from_bytes(new_bytes)
- }
-
- fn run_tcp_test_server(server_ip: &str, server_port: uint, resp: ~str,
- cont_ch: SharedChan<()>,
- iotask: &IoTask) -> ~str {
- let (server_po, server_ch) = stream::<~str>();
- let server_ch = SharedChan::new(server_ch);
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let resp_cell = Cell::new(resp);
- let listen_result = listen(server_ip_addr, server_port, 128,
- iotask,
- // on_establish_cb -- called when listener is set up
- |kill_ch| {
- debug!("establish_cb %?",
- kill_ch);
- cont_ch.send(());
- },
- // risky to run this on the loop, but some users
- // will want the POWER
- |new_conn, kill_ch| {
- let resp_cell2 = Cell::new(resp_cell.take());
- debug!("SERVER: new connection!");
- let (cont_po, cont_ch) = stream();
- let server_ch = server_ch.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("SERVER: starting worker for new req");
-
- let accept_result = accept(new_conn);
- debug!("SERVER: after accept()");
- if result::is_err(&accept_result) {
- debug!("SERVER: error accept connection");
- let err_data = result::get_err(&accept_result);
- kill_ch.send(Some(err_data));
- debug!(
- "SERVER/WORKER: send on err cont ch");
- cont_ch.send(());
- }
- else {
- debug!("SERVER/WORKER: send on cont ch");
- cont_ch.send(());
- let sock = result::unwrap(accept_result);
- let peer_addr = sock.get_peer_addr();
- debug!("SERVER: successfully accepted \
- connection from %s:%u",
- ip::format_addr(&peer_addr),
- ip::get_port(&peer_addr));
- let received_req_bytes = read(&sock, 0u);
- match received_req_bytes {
- result::Ok(data) => {
- debug!("SERVER: got REQ str::from_bytes..");
- debug!("SERVER: REQ data len: %?",
- data.len());
- server_ch.send(
- str::from_bytes(data));
- debug!("SERVER: before write");
- let s = resp_cell2.take();
- tcp_write_single(&sock, s.as_bytes().to_owned());
- debug!("SERVER: after write.. die");
- kill_ch.send(None);
- }
- result::Err(err_data) => {
- debug!("SERVER: error recvd: %s %s",
- err_data.err_name, err_data.err_msg);
- kill_ch.send(Some(err_data));
- server_ch.send(~"");
- }
- }
- debug!("SERVER: worker spinning down");
- }
- }
- debug!("SERVER: waiting to recv on cont_ch");
- cont_po.recv();
- });
- // err check on listen_result
- if result::is_err(&listen_result) {
- match result::get_err(&listen_result) {
- GenericListenErr(ref name, ref msg) => {
- fail!("SERVER: exited abnormally name %s msg %s", *name, *msg);
- }
- AccessDenied => {
- fail!("SERVER: exited abnormally, got access denied..");
- }
- AddressInUse => {
- fail!("SERVER: exited abnormally, got address in use...");
- }
- }
- }
- let ret_val = server_po.recv();
- debug!("SERVER: exited and got return val: '%s'", ret_val);
- ret_val
- }
-
- fn run_tcp_test_server_fail(server_ip: &str, server_port: uint,
- iotask: &IoTask) -> TcpListenErrData {
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let listen_result = listen(server_ip_addr, server_port, 128,
- iotask,
- // on_establish_cb -- called when listener is set up
- |kill_ch| {
- debug!("establish_cb %?", kill_ch);
- },
- |new_conn, kill_ch| {
- fail!("SERVER: shouldn't be called.. %? %?", new_conn, kill_ch);
- });
- // err check on listen_result
- if result::is_err(&listen_result) {
- result::get_err(&listen_result)
- }
- else {
- fail!("SERVER: did not fail as expected")
- }
- }
-
- fn run_tcp_test_client(server_ip: &str, server_port: uint, resp: &str,
- iotask: &IoTask) -> result::Result<~str,
- TcpConnectErrData> {
- let server_ip_addr = ip::v4::parse_addr(server_ip);
-
- debug!("CLIENT: starting..");
- let connect_result = connect(server_ip_addr, server_port,
- iotask);
- if result::is_err(&connect_result) {
- debug!("CLIENT: failed to connect");
- let err_data = result::get_err(&connect_result);
- Err(err_data)
- }
- else {
- let sock = result::unwrap(connect_result);
- let resp_bytes = resp.as_bytes().to_owned();
- tcp_write_single(&sock, resp_bytes);
- let read_result = sock.read(0u);
- if read_result.is_err() {
- debug!("CLIENT: failure to read");
- Ok(~"")
- }
- else {
- let ret_val = str::from_bytes(read_result.get());
- debug!("CLIENT: after client_ch recv ret: '%s'",
- ret_val);
- Ok(ret_val)
- }
- }
- }
-
- fn tcp_write_single(sock: &TcpSocket, val: ~[u8]) {
- let mut write_result_future = sock.write_future(val);
- let write_result = write_result_future.get();
- if result::is_err(&write_result) {
- debug!("tcp_write_single: write failed!");
- let err_data = result::get_err(&write_result);
- debug!("tcp_write_single err name: %s msg: %s",
- err_data.err_name, err_data.err_msg);
- // meh. torn on what to do here.
- fail!("tcp_write_single failed");
- }
- }
-}
+++ /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.
-
-//! Types/fns concerning URLs (see RFC 3986)
-
-#[allow(missing_doc)];
-
-
-use std::cmp::Eq;
-use std::io::{Reader, ReaderUtil};
-use std::io;
-use std::hashmap::HashMap;
-use std::to_bytes;
-use std::uint;
-
-#[deriving(Clone, Eq)]
-struct Url {
- scheme: ~str,
- user: Option<UserInfo>,
- host: ~str,
- port: Option<~str>,
- path: ~str,
- query: Query,
- fragment: Option<~str>
-}
-
-#[deriving(Clone, Eq)]
-struct UserInfo {
- user: ~str,
- pass: Option<~str>
-}
-
-pub type Query = ~[(~str, ~str)];
-
-impl Url {
- pub fn new(scheme: ~str,
- user: Option<UserInfo>,
- host: ~str,
- port: Option<~str>,
- path: ~str,
- query: Query,
- fragment: Option<~str>)
- -> Url {
- Url {
- scheme: scheme,
- user: user,
- host: host,
- port: port,
- path: path,
- query: query,
- fragment: fragment,
- }
- }
-}
-
-impl UserInfo {
- pub fn new(user: ~str, pass: Option<~str>) -> UserInfo {
- UserInfo { user: user, pass: pass }
- }
-}
-
-fn encode_inner(s: &str, full_url: bool) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- let ch = rdr.read_byte() as char;
- match ch {
- // unreserved:
- 'A' .. 'Z' |
- 'a' .. 'z' |
- '0' .. '9' |
- '-' | '.' | '_' | '~' => {
- out.push_char(ch);
- }
- _ => {
- if full_url {
- match ch {
- // gen-delims:
- ':' | '/' | '?' | '#' | '[' | ']' | '@' |
-
- // sub-delims:
- '!' | '$' | '&' | '"' | '(' | ')' | '*' |
- '+' | ',' | ';' | '=' => {
- out.push_char(ch);
- }
-
- _ => out.push_str(fmt!("%%%X", ch as uint))
- }
- } else {
- out.push_str(fmt!("%%%X", ch as uint));
- }
- }
- }
- }
-
- out
- }
-}
-
-/**
- * Encodes a URI by replacing reserved characters with percent encoded
- * character sequences.
- *
- * This function is compliant with RFC 3986.
- */
-pub fn encode(s: &str) -> ~str {
- encode_inner(s, true)
-}
-
-/**
- * Encodes a URI component by replacing reserved characters with percent
- * encoded character sequences.
- *
- * This function is compliant with RFC 3986.
- */
-
-pub fn encode_component(s: &str) -> ~str {
- encode_inner(s, false)
-}
-
-fn decode_inner(s: &str, full_url: bool) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- match rdr.read_char() {
- '%' => {
- let bytes = rdr.read_bytes(2u);
- let ch = uint::parse_bytes(bytes, 16u).get() as char;
-
- if full_url {
- // Only decode some characters:
- match ch {
- // gen-delims:
- ':' | '/' | '?' | '#' | '[' | ']' | '@' |
-
- // sub-delims:
- '!' | '$' | '&' | '"' | '(' | ')' | '*' |
- '+' | ',' | ';' | '=' => {
- out.push_char('%');
- out.push_char(bytes[0u] as char);
- out.push_char(bytes[1u] as char);
- }
-
- ch => out.push_char(ch)
- }
- } else {
- out.push_char(ch);
- }
- }
- ch => out.push_char(ch)
- }
- }
-
- out
- }
-}
-
-/**
- * Decode a string encoded with percent encoding.
- *
- * This will only decode escape sequences generated by encode.
- */
-pub fn decode(s: &str) -> ~str {
- decode_inner(s, true)
-}
-
-/**
- * Decode a string encoded with percent encoding.
- */
-pub fn decode_component(s: &str) -> ~str {
- decode_inner(s, false)
-}
-
-fn encode_plus(s: &str) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- let ch = rdr.read_byte() as char;
- match ch {
- 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => {
- out.push_char(ch);
- }
- ' ' => out.push_char('+'),
- _ => out.push_str(fmt!("%%%X", ch as uint))
- }
- }
-
- out
- }
-}
-
-/**
- * Encode a hashmap to the 'application/x-www-form-urlencoded' media type.
- */
-pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str {
- let mut out = ~"";
- let mut first = true;
-
- for m.iter().advance |(key, values)| {
- let key = encode_plus(*key);
-
- for values.iter().advance |value| {
- if first {
- first = false;
- } else {
- out.push_char('&');
- first = false;
- }
-
- out.push_str(fmt!("%s=%s", key, encode_plus(*value)));
- }
- }
-
- out
-}
-
-/**
- * Decode a string encoded with the 'application/x-www-form-urlencoded' media
- * type into a hashmap.
- */
-pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
- do io::with_bytes_reader(s) |rdr| {
- let mut m = HashMap::new();
- let mut key = ~"";
- let mut value = ~"";
- let mut parsing_key = true;
-
- while !rdr.eof() {
- match rdr.read_char() {
- '&' | ';' => {
- if key != ~"" && value != ~"" {
- let mut values = match m.pop(&key) {
- Some(values) => values,
- None => ~[],
- };
-
- values.push(value);
- m.insert(key, values);
- }
-
- parsing_key = true;
- key = ~"";
- value = ~"";
- }
- '=' => parsing_key = false,
- ch => {
- let ch = match ch {
- '%' => {
- let bytes = rdr.read_bytes(2u);
- uint::parse_bytes(bytes, 16u).get() as char
- }
- '+' => ' ',
- ch => ch
- };
-
- if parsing_key {
- key.push_char(ch)
- } else {
- value.push_char(ch)
- }
- }
- }
- }
-
- if key != ~"" && value != ~"" {
- let mut values = match m.pop(&key) {
- Some(values) => values,
- None => ~[],
- };
-
- values.push(value);
- m.insert(key, values);
- }
-
- m
- }
-}
-
-
-fn split_char_first(s: &str, c: char) -> (~str, ~str) {
- let len = s.len();
- let mut index = len;
- let mut mat = 0;
- do io::with_str_reader(s) |rdr| {
- let mut ch;
- while !rdr.eof() {
- ch = rdr.read_byte() as char;
- if ch == c {
- // found a match, adjust markers
- index = rdr.tell()-1;
- mat = 1;
- break;
- }
- }
- }
- if index+mat == len {
- return (s.slice(0, index).to_owned(), ~"");
- } else {
- return (s.slice(0, index).to_owned(),
- s.slice(index + mat, s.len()).to_owned());
- }
-}
-
-fn userinfo_from_str(uinfo: &str) -> UserInfo {
- let (user, p) = split_char_first(uinfo, ':');
- let pass = if p.is_empty() {
- None
- } else {
- Some(p)
- };
- return UserInfo::new(user, pass);
-}
-
-fn userinfo_to_str(userinfo: &UserInfo) -> ~str {
- match userinfo.pass {
- Some(ref pass) => fmt!("%s:%s@", userinfo.user, *pass),
- None => fmt!("%s@", userinfo.user),
- }
-}
-
-fn query_from_str(rawquery: &str) -> Query {
- let mut query: Query = ~[];
- if !rawquery.is_empty() {
- for rawquery.split_iter('&').advance |p| {
- let (k, v) = split_char_first(p, '=');
- query.push((decode_component(k), decode_component(v)));
- };
- }
- return query;
-}
-
-pub fn query_to_str(query: &Query) -> ~str {
- let mut strvec = ~[];
- for query.iter().advance |kv| {
- match kv {
- &(ref k, ref v) => {
- strvec.push(fmt!("%s=%s",
- encode_component(*k),
- encode_component(*v))
- );
- }
- }
- }
- return strvec.connect("&");
-}
-
-// returns the scheme and the rest of the url, or a parsing error
-pub fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> {
- for rawurl.iter().enumerate().advance |(i,c)| {
- match c {
- 'A' .. 'Z' | 'a' .. 'z' => loop,
- '0' .. '9' | '+' | '-' | '.' => {
- if i == 0 {
- return Err(~"url: Scheme must begin with a letter.");
- }
- loop;
- }
- ':' => {
- if i == 0 {
- return Err(~"url: Scheme cannot be empty.");
- } else {
- return Ok((rawurl.slice(0,i).to_owned(),
- rawurl.slice(i+1,rawurl.len()).to_owned()));
- }
- }
- _ => {
- return Err(~"url: Invalid character in scheme.");
- }
- }
- };
- return Err(~"url: Scheme must be terminated with a colon.");
-}
-
-#[deriving(Clone, Eq)]
-enum Input {
- Digit, // all digits
- Hex, // digits and letters a-f
- Unreserved // all other legal characters
-}
-
-// returns userinfo, host, port, and unparsed part, or an error
-fn get_authority(rawurl: &str) ->
- Result<(Option<UserInfo>, ~str, Option<~str>, ~str), ~str> {
- if !rawurl.starts_with("//") {
- // there is no authority.
- return Ok((None, ~"", None, rawurl.to_str()));
- }
-
- enum State {
- Start, // starting state
- PassHostPort, // could be in user or port
- Ip6Port, // either in ipv6 host or port
- Ip6Host, // are in an ipv6 host
- InHost, // are in a host - may be ipv6, but don't know yet
- InPort // are in port
- }
-
- let len = rawurl.len();
- let mut st = Start;
- let mut in = Digit; // most restricted, start here.
-
- let mut userinfo = None;
- let mut host = ~"";
- let mut port = None;
-
- let mut colon_count = 0;
- let mut pos = 0;
- let mut begin = 2;
- let mut end = len;
-
- for rawurl.iter().enumerate().advance |(i,c)| {
- if i < 2 { loop; } // ignore the leading //
-
- // deal with input class first
- match c {
- '0' .. '9' => (),
- 'A' .. 'F' | 'a' .. 'f' => {
- if in == Digit {
- in = Hex;
- }
- }
- 'G' .. 'Z' | 'g' .. 'z' | '-' | '.' | '_' | '~' | '%' |
- '&' |'\'' | '(' | ')' | '+' | '!' | '*' | ',' | ';' | '=' => {
- in = Unreserved;
- }
- ':' | '@' | '?' | '#' | '/' => {
- // separators, don't change anything
- }
- _ => {
- return Err(~"Illegal character in authority");
- }
- }
-
- // now process states
- match c {
- ':' => {
- colon_count += 1;
- match st {
- Start => {
- pos = i;
- st = PassHostPort;
- }
- PassHostPort => {
- // multiple colons means ipv6 address.
- if in == Unreserved {
- return Err(
- ~"Illegal characters in IPv6 address.");
- }
- st = Ip6Host;
- }
- InHost => {
- pos = i;
- // can't be sure whether this is an ipv6 address or a port
- if in == Unreserved {
- return Err(~"Illegal characters in authority.");
- }
- st = Ip6Port;
- }
- Ip6Port => {
- if in == Unreserved {
- return Err(~"Illegal characters in authority.");
- }
- st = Ip6Host;
- }
- Ip6Host => {
- if colon_count > 7 {
- host = rawurl.slice(begin, i).to_owned();
- pos = i;
- st = InPort;
- }
- }
- _ => {
- return Err(~"Invalid ':' in authority.");
- }
- }
- in = Digit; // reset input class
- }
-
- '@' => {
- in = Digit; // reset input class
- colon_count = 0; // reset count
- match st {
- Start => {
- let user = rawurl.slice(begin, i).to_owned();
- userinfo = Some(UserInfo::new(user, None));
- st = InHost;
- }
- PassHostPort => {
- let user = rawurl.slice(begin, pos).to_owned();
- let pass = rawurl.slice(pos+1, i).to_owned();
- userinfo = Some(UserInfo::new(user, Some(pass)));
- st = InHost;
- }
- _ => {
- return Err(~"Invalid '@' in authority.");
- }
- }
- begin = i+1;
- }
-
- '?' | '#' | '/' => {
- end = i;
- break;
- }
- _ => ()
- }
- end = i;
- }
-
- let end = end; // make end immutable so it can be captured
-
- let host_is_end_plus_one: &fn() -> bool = || {
- let xs = ['?', '#', '/'];
- end+1 == len
- && !xs.iter().any(|x| *x == (rawurl[end] as char))
- };
-
- // finish up
- match st {
- Start => {
- if host_is_end_plus_one() {
- host = rawurl.slice(begin, end+1).to_owned();
- } else {
- host = rawurl.slice(begin, end).to_owned();
- }
- }
- PassHostPort | Ip6Port => {
- if in != Digit {
- return Err(~"Non-digit characters in port.");
- }
- host = rawurl.slice(begin, pos).to_owned();
- port = Some(rawurl.slice(pos+1, end).to_owned());
- }
- Ip6Host | InHost => {
- host = rawurl.slice(begin, end).to_owned();
- }
- InPort => {
- if in != Digit {
- return Err(~"Non-digit characters in port.");
- }
- port = Some(rawurl.slice(pos+1, end).to_owned());
- }
- }
-
- let rest = if host_is_end_plus_one() { ~"" }
- else { rawurl.slice(end, len).to_owned() };
- return Ok((userinfo, host, port, rest));
-}
-
-
-// returns the path and unparsed part of url, or an error
-fn get_path(rawurl: &str, authority: bool) ->
- Result<(~str, ~str), ~str> {
- let len = rawurl.len();
- let mut end = len;
- for rawurl.iter().enumerate().advance |(i,c)| {
- match c {
- 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '&' |'\'' | '(' | ')' | '.'
- | '@' | ':' | '%' | '/' | '+' | '!' | '*' | ',' | ';' | '='
- | '_' | '-' => {
- loop;
- }
- '?' | '#' => {
- end = i;
- break;
- }
- _ => return Err(~"Invalid character in path.")
- }
- }
-
- if authority {
- if end != 0 && !rawurl.starts_with("/") {
- return Err(~"Non-empty path must begin with\
- '/' in presence of authority.");
- }
- }
-
- return Ok((decode_component(rawurl.slice(0, end)),
- rawurl.slice(end, len).to_owned()));
-}
-
-// returns the parsed query and the fragment, if present
-fn get_query_fragment(rawurl: &str) ->
- Result<(Query, Option<~str>), ~str> {
- if !rawurl.starts_with("?") {
- if rawurl.starts_with("#") {
- let f = decode_component(rawurl.slice(
- 1,
- rawurl.len()));
- return Ok((~[], Some(f)));
- } else {
- return Ok((~[], None));
- }
- }
- let (q, r) = split_char_first(rawurl.slice(1, rawurl.len()), '#');
- let f = if r.len() != 0 {
- Some(decode_component(r)) } else { None };
- return Ok((query_from_str(q), f));
-}
-
-/**
- * Parse a `str` to a `url`
- *
- * # Arguments
- *
- * `rawurl` - a string representing a full url, including scheme.
- *
- * # Returns
- *
- * a `url` that contains the parsed representation of the url.
- *
- */
-
-pub fn from_str(rawurl: &str) -> Result<Url, ~str> {
- // scheme
- let (scheme, rest) = match get_scheme(rawurl) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // authority
- let (userinfo, host, port, rest) = match get_authority(rest) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // path
- let has_authority = if host == ~"" { false } else { true };
- let (path, rest) = match get_path(rest, has_authority) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // query and fragment
- let (query, fragment) = match get_query_fragment(rest) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- Ok(Url::new(scheme, userinfo, host, port, path, query, fragment))
-}
-
-impl FromStr for Url {
- fn from_str(s: &str) -> Option<Url> {
- match from_str(s) {
- Ok(url) => Some(url),
- Err(_) => None
- }
- }
-}
-
-/**
- * Format a `url` as a string
- *
- * # Arguments
- *
- * `url` - a url.
- *
- * # Returns
- *
- * a `str` that contains the formatted url. Note that this will usually
- * be an inverse of `from_str` but might strip out unneeded separators.
- * for example, "http://somehost.com?", when parsed and formatted, will
- * result in just "http://somehost.com".
- *
- */
-pub fn to_str(url: &Url) -> ~str {
- let user = match url.user {
- Some(ref user) => userinfo_to_str(user),
- None => ~"",
- };
-
- let authority = if url.host.is_empty() {
- ~""
- } else {
- fmt!("//%s%s", user, url.host)
- };
-
- let query = if url.query.is_empty() {
- ~""
- } else {
- fmt!("?%s", query_to_str(&url.query))
- };
-
- let fragment = match url.fragment {
- Some(ref fragment) => fmt!("#%s", encode_component(*fragment)),
- None => ~"",
- };
-
- fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment)
-}
-
-impl ToStr for Url {
- pub fn to_str(&self) -> ~str {
- to_str(self)
- }
-}
-
-impl IterBytes for Url {
- fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
- self.to_str().iter_bytes(lsb0, f)
- }
-}
-
-// Put a few tests outside of the 'test' module so they can test the internal
-// functions and those functions don't need 'pub'
-
-#[test]
-fn test_split_char_first() {
- let (u,v) = split_char_first("hello, sweet world", ',');
- assert_eq!(u, ~"hello");
- assert_eq!(v, ~" sweet world");
-
- let (u,v) = split_char_first("hello sweet world", ',');
- assert_eq!(u, ~"hello sweet world");
- assert_eq!(v, ~"");
-}
-
-#[test]
-fn test_get_authority() {
- let (u, h, p, r) = get_authority(
- "//user:pass@rust-lang.org/something").unwrap();
- assert_eq!(u, Some(UserInfo::new(~"user", Some(~"pass"))));
- assert_eq!(h, ~"rust-lang.org");
- assert!(p.is_none());
- assert_eq!(r, ~"/something");
-
- let (u, h, p, r) = get_authority(
- "//rust-lang.org:8000?something").unwrap();
- assert!(u.is_none());
- assert_eq!(h, ~"rust-lang.org");
- assert_eq!(p, Some(~"8000"));
- assert_eq!(r, ~"?something");
-
- let (u, h, p, r) = get_authority(
- "//rust-lang.org#blah").unwrap();
- assert!(u.is_none());
- assert_eq!(h, ~"rust-lang.org");
- assert!(p.is_none());
- assert_eq!(r, ~"#blah");
-
- // ipv6 tests
- let (_, h, _, _) = get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah").unwrap();
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
-
- let (_, h, p, _) = get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah").unwrap();
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
- assert_eq!(p, Some(~"8000"));
-
- let (u, h, p, _) = get_authority(
- "//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah"
- ).unwrap();
- assert_eq!(u, Some(UserInfo::new(~"us", Some(~"p"))));
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
- assert_eq!(p, Some(~"8000"));
-
- // invalid authorities;
- assert!(get_authority("//user:pass@rust-lang:something").is_err());
- assert!(get_authority("//user@rust-lang:something:/path").is_err());
- assert!(get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a").is_err());
- assert!(get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00").is_err());
-
- // these parse as empty, because they don't start with '//'
- let (_, h, _, _) = get_authority("user:pass@rust-lang").unwrap();
- assert_eq!(h, ~"");
- let (_, h, _, _) = get_authority("rust-lang.org").unwrap();
- assert_eq!(h, ~"");
-}
-
-#[test]
-fn test_get_path() {
- let (p, r) = get_path("/something+%20orother", true).unwrap();
- assert_eq!(p, ~"/something+ orother");
- assert_eq!(r, ~"");
- let (p, r) = get_path("test@email.com#fragment", false).unwrap();
- assert_eq!(p, ~"test@email.com");
- assert_eq!(r, ~"#fragment");
- let (p, r) = get_path("/gen/:addr=?q=v", false).unwrap();
- assert_eq!(p, ~"/gen/:addr=");
- assert_eq!(r, ~"?q=v");
-
- //failure cases
- assert!(get_path("something?q", true).is_err());
-}
-
-#[cfg(test)]
-mod tests {
-
- use net::url::*;
-
- use std::hashmap::HashMap;
-
- #[test]
- fn test_url_parse() {
- let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
-
- let up = from_str(url);
- let u = up.unwrap();
- assert!(u.scheme == ~"http");
- let userinfo = u.user.get_ref();
- assert!(userinfo.user == ~"user");
- assert!(userinfo.pass.get_ref() == &~"pass");
- assert!(u.host == ~"rust-lang.org");
- assert!(u.path == ~"/doc");
- assert!(u.query == ~[(~"s", ~"v")]);
- assert!(u.fragment.get_ref() == &~"something");
- }
-
- #[test]
- fn test_url_parse_host_slash() {
- let urlstr = ~"http://0.42.42.42/";
- let url = from_str(urlstr).unwrap();
- assert!(url.host == ~"0.42.42.42");
- assert!(url.path == ~"/");
- }
-
- #[test]
- fn test_url_with_underscores() {
- let urlstr = ~"http://dotcom.com/file_name.html";
- let url = from_str(urlstr).unwrap();
- assert!(url.path == ~"/file_name.html");
- }
-
- #[test]
- fn test_url_with_dashes() {
- let urlstr = ~"http://dotcom.com/file-name.html";
- let url = from_str(urlstr).unwrap();
- assert!(url.path == ~"/file-name.html");
- }
-
- #[test]
- fn test_no_scheme() {
- assert!(get_scheme("noschemehere.html").is_err());
- }
-
- #[test]
- fn test_invalid_scheme_errors() {
- assert!(from_str("99://something").is_err());
- assert!(from_str("://something").is_err());
- }
-
- #[test]
- fn test_full_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_userless_url_parse_and_format() {
- let url = ~"http://rust-lang.org/doc?s=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_queryless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_empty_query_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?#something";
- let should_be = ~"http://user:pass@rust-lang.org/doc#something";
- assert_eq!(from_str(url).unwrap().to_str(), should_be);
- }
-
- #[test]
- fn test_fragmentless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?q=v";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_minimal_url_parse_and_format() {
- let url = ~"http://rust-lang.org/doc";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_scheme_host_only_url_parse_and_format() {
- let url = ~"http://rust-lang.org";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_pathless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org?q=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_scheme_host_fragment_only_url_parse_and_format() {
- let url = ~"http://rust-lang.org#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_url_component_encoding() {
- let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B";
- let u = from_str(url).unwrap();
- assert!(u.path == ~"/doc uments");
- assert!(u.query == ~[(~"ba%d ", ~"#&+")]);
- }
-
- #[test]
- fn test_url_without_authority() {
- let url = ~"mailto:test@email.com";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_encode() {
- assert_eq!(encode(""), ~"");
- assert_eq!(encode("http://example.com"), ~"http://example.com");
- assert_eq!(encode("foo bar% baz"), ~"foo%20bar%25%20baz");
- assert_eq!(encode(" "), ~"%20");
- assert_eq!(encode("!"), ~"!");
- assert_eq!(encode("\""), ~"\"");
- assert_eq!(encode("#"), ~"#");
- assert_eq!(encode("$"), ~"$");
- assert_eq!(encode("%"), ~"%25");
- assert_eq!(encode("&"), ~"&");
- assert_eq!(encode("'"), ~"%27");
- assert_eq!(encode("("), ~"(");
- assert_eq!(encode(")"), ~")");
- assert_eq!(encode("*"), ~"*");
- assert_eq!(encode("+"), ~"+");
- assert_eq!(encode(","), ~",");
- assert_eq!(encode("/"), ~"/");
- assert_eq!(encode(":"), ~":");
- assert_eq!(encode(";"), ~";");
- assert_eq!(encode("="), ~"=");
- assert_eq!(encode("?"), ~"?");
- assert_eq!(encode("@"), ~"@");
- assert_eq!(encode("["), ~"[");
- assert_eq!(encode("]"), ~"]");
- }
-
- #[test]
- fn test_encode_component() {
- assert_eq!(encode_component(""), ~"");
- assert!(encode_component("http://example.com") ==
- ~"http%3A%2F%2Fexample.com");
- assert!(encode_component("foo bar% baz") ==
- ~"foo%20bar%25%20baz");
- assert_eq!(encode_component(" "), ~"%20");
- assert_eq!(encode_component("!"), ~"%21");
- assert_eq!(encode_component("#"), ~"%23");
- assert_eq!(encode_component("$"), ~"%24");
- assert_eq!(encode_component("%"), ~"%25");
- assert_eq!(encode_component("&"), ~"%26");
- assert_eq!(encode_component("'"), ~"%27");
- assert_eq!(encode_component("("), ~"%28");
- assert_eq!(encode_component(")"), ~"%29");
- assert_eq!(encode_component("*"), ~"%2A");
- assert_eq!(encode_component("+"), ~"%2B");
- assert_eq!(encode_component(","), ~"%2C");
- assert_eq!(encode_component("/"), ~"%2F");
- assert_eq!(encode_component(":"), ~"%3A");
- assert_eq!(encode_component(";"), ~"%3B");
- assert_eq!(encode_component("="), ~"%3D");
- assert_eq!(encode_component("?"), ~"%3F");
- assert_eq!(encode_component("@"), ~"%40");
- assert_eq!(encode_component("["), ~"%5B");
- assert_eq!(encode_component("]"), ~"%5D");
- }
-
- #[test]
- fn test_decode() {
- assert_eq!(decode(""), ~"");
- assert_eq!(decode("abc/def 123"), ~"abc/def 123");
- assert_eq!(decode("abc%2Fdef%20123"), ~"abc%2Fdef 123");
- assert_eq!(decode("%20"), ~" ");
- assert_eq!(decode("%21"), ~"%21");
- assert_eq!(decode("%22"), ~"%22");
- assert_eq!(decode("%23"), ~"%23");
- assert_eq!(decode("%24"), ~"%24");
- assert_eq!(decode("%25"), ~"%");
- assert_eq!(decode("%26"), ~"%26");
- assert_eq!(decode("%27"), ~"'");
- assert_eq!(decode("%28"), ~"%28");
- assert_eq!(decode("%29"), ~"%29");
- assert_eq!(decode("%2A"), ~"%2A");
- assert_eq!(decode("%2B"), ~"%2B");
- assert_eq!(decode("%2C"), ~"%2C");
- assert_eq!(decode("%2F"), ~"%2F");
- assert_eq!(decode("%3A"), ~"%3A");
- assert_eq!(decode("%3B"), ~"%3B");
- assert_eq!(decode("%3D"), ~"%3D");
- assert_eq!(decode("%3F"), ~"%3F");
- assert_eq!(decode("%40"), ~"%40");
- assert_eq!(decode("%5B"), ~"%5B");
- assert_eq!(decode("%5D"), ~"%5D");
- }
-
- #[test]
- fn test_decode_component() {
- assert_eq!(decode_component(""), ~"");
- assert_eq!(decode_component("abc/def 123"), ~"abc/def 123");
- assert_eq!(decode_component("abc%2Fdef%20123"), ~"abc/def 123");
- assert_eq!(decode_component("%20"), ~" ");
- assert_eq!(decode_component("%21"), ~"!");
- assert_eq!(decode_component("%22"), ~"\"");
- assert_eq!(decode_component("%23"), ~"#");
- assert_eq!(decode_component("%24"), ~"$");
- assert_eq!(decode_component("%25"), ~"%");
- assert_eq!(decode_component("%26"), ~"&");
- assert_eq!(decode_component("%27"), ~"'");
- assert_eq!(decode_component("%28"), ~"(");
- assert_eq!(decode_component("%29"), ~")");
- assert_eq!(decode_component("%2A"), ~"*");
- assert_eq!(decode_component("%2B"), ~"+");
- assert_eq!(decode_component("%2C"), ~",");
- assert_eq!(decode_component("%2F"), ~"/");
- assert_eq!(decode_component("%3A"), ~":");
- assert_eq!(decode_component("%3B"), ~";");
- assert_eq!(decode_component("%3D"), ~"=");
- assert_eq!(decode_component("%3F"), ~"?");
- assert_eq!(decode_component("%40"), ~"@");
- assert_eq!(decode_component("%5B"), ~"[");
- assert_eq!(decode_component("%5D"), ~"]");
- }
-
- #[test]
- fn test_encode_form_urlencoded() {
- let mut m = HashMap::new();
- assert_eq!(encode_form_urlencoded(&m), ~"");
-
- m.insert(~"", ~[]);
- m.insert(~"foo", ~[]);
- assert_eq!(encode_form_urlencoded(&m), ~"");
-
- let mut m = HashMap::new();
- m.insert(~"foo", ~[~"bar", ~"123"]);
- assert_eq!(encode_form_urlencoded(&m), ~"foo=bar&foo=123");
-
- let mut m = HashMap::new();
- m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]);
- assert!(encode_form_urlencoded(&m) ==
- ~"foo+bar=abc&foo+bar=12+%3D+34");
- }
-
- #[test]
- fn test_decode_form_urlencoded() {
- // FIXME #4449: Commented out because this causes an ICE, but only
- // on FreeBSD
- /*
- assert_eq!(decode_form_urlencoded([]).len(), 0);
-
- let s = "a=1&foo+bar=abc&foo+bar=12+%3D+34".as_bytes();
- let form = decode_form_urlencoded(s);
- assert_eq!(form.len(), 2);
- assert_eq!(form.get_ref(&~"a"), &~[~"1"]);
- assert_eq!(form.get_ref(&~"foo bar"), &~[~"abc", ~"12 = 34"]);
- */
- }
-}
}
/// Mutable reference counted pointer type
-#[non_owned]
#[no_send]
-#[mutable] // XXX remove after snap
#[no_freeze]
#[unsafe_no_drop_flag]
pub struct RcMut<T> {
//! extra::container::Deque`.
use std::num;
-use std::util;
use std::uint;
use std::vec;
use std::iterator::{FromIterator, InvertIterator};
/// Remove and return the first element in the RingBuf, or None if it is empty
fn pop_front(&mut self) -> Option<T> {
- let result = util::replace(&mut self.elts[self.lo], None);
+ let result = self.elts[self.lo].take();
if result.is_some() {
self.lo = (self.lo + 1u) % self.elts.len();
self.nelts -= 1u;
if self.nelts > 0 {
self.nelts -= 1;
let hi = self.raw_index(self.nelts);
- util::replace(&mut self.elts[hi], None)
+ self.elts[hi].take()
} else {
None
}
pub mod rustrt {
use std::libc::{c_char, c_int};
- pub extern {
+ extern {
pub unsafe fn linenoise(prompt: *c_char) -> *c_char;
pub unsafe fn linenoiseHistoryAdd(line: *c_char) -> c_int;
pub unsafe fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
pub type CompletionCb = @fn(~str, @fn(~str));
-#[cfg(not(stage0))]
static complete_key: local_data::Key<@CompletionCb> = &local_data::Key;
-#[cfg(stage0)]
-fn complete_key(_: @CompletionCb) {}
/// Bind to the main completion callback
pub unsafe fn complete(cb: CompletionCb) {
}
}
-impl<D:Decoder,T:Decodable<D>> Decodable<D> for @T {
+impl<D:Decoder,T:Decodable<D> + 'static> Decodable<D> for @T {
fn decode(d: &mut D) -> @T {
@Decodable::decode(d)
}
}
}
-impl<D:Decoder,T:Decodable<D>> Decodable<D> for @mut T {
+impl<D:Decoder,T:Decodable<D> + 'static> Decodable<D> for @mut T {
fn decode(d: &mut D) -> @mut T {
@mut Decodable::decode(d)
}
}
}
+impl<
+ S: Encoder,
+ T: Encodable<S>
+> Encodable<S> for DList<T> {
+ fn encode(&self, s: &mut S) {
+ do s.emit_seq(self.len()) |s| {
+ for self.iter().enumerate().advance |(i, e)| {
+ s.emit_seq_elt(i, |s| e.encode(s));
+ }
+ }
+ }
+}
+
impl<D:Decoder,T:Decodable<D>> Decodable<D> for DList<T> {
fn decode(d: &mut D) -> DList<T> {
let mut list = DList::new();
#[allow(missing_doc)];
-
-use std::cmp;
-use std::iterator::{Iterator,IteratorUtil,ZipIterator,Counter,EnumerateIterator,FilterMapIterator};
+use std::iterator::{Iterator, IteratorUtil, EnumerateIterator, FilterMapIterator, InvertIterator};
use std::uint;
use std::util::replace;
-use std::vec::{VecIterator,VecMutIterator,VecRevIterator,VecMutRevIterator};
-use std::vec::VecConsumeIterator;
+use std::vec::{VecIterator, VecMutIterator, VecConsumeIterator};
#[allow(missing_doc)]
pub struct SmallIntMap<T> {
if *key >= self.v.len() {
return None;
}
- replace(&mut self.v[*key], None)
+ self.v[*key].take()
}
}
/// Iterator element type is (uint, &'r V)
pub fn iter<'r>(&'r self) -> SmallIntMapIterator<'r, V> {
SmallIntMapIterator {
- iter: Counter::new(0,1).zip(self.v.iter())
+ front: 0,
+ back: self.v.len(),
+ iter: self.v.iter()
}
}
/// Iterator element type is (uint, &'r mut V)
pub fn mut_iter<'r>(&'r mut self) -> SmallIntMapMutIterator<'r, V> {
SmallIntMapMutIterator {
- iter: Counter::new(0,1).zip(self.v.mut_iter())
+ front: 0,
+ back: self.v.len(),
+ iter: self.v.mut_iter()
}
}
/// An iterator visiting all key-value pairs in descending order by the keys.
/// Iterator element type is (uint, &'r V)
pub fn rev_iter<'r>(&'r self) -> SmallIntMapRevIterator<'r, V> {
- SmallIntMapRevIterator {
- iter: Counter::new(self.len() as int - 1, -1).zip(self.v.rev_iter())
- }
+ self.iter().invert()
}
/// An iterator visiting all key-value pairs in descending order by the keys,
/// with mutable references to the values
/// Iterator element type is (uint, &'r mut V)
pub fn mut_rev_iter<'r>(&'r mut self) -> SmallIntMapMutRevIterator <'r, V> {
- SmallIntMapMutRevIterator {
- iter: Counter::new(self.len() as int - 1, -1).zip(self.v.mut_rev_iter())
- }
+ self.mut_iter().invert()
}
/// Empties the hash map, moving all values into the specified closure
macro_rules! iterator {
- /* FIXME: #4375 Cannot attach documentation/attributes to a macro generated struct.
- (struct $name:ident -> $ptr:ty, $elem:ty) => {
- pub struct $name<'self, T> {
- priv ptr: $ptr,
- priv end: $ptr,
- priv lifetime: $elem // FIXME: #5922
- }
- };*/
- (impl $name:ident -> $elem:ty) => {
- impl<'self, T> Iterator<(uint, $elem)> for $name<'self, T> {
+ (impl $name:ident -> $elem:ty, $getter:ident) => {
+ impl<'self, T> Iterator<$elem> for $name<'self, T> {
#[inline]
- pub fn next(&mut self) -> Option<(uint, $elem)> {
- for self.iter.advance |(idx, elem)| {
- match elem {
- &None => {}
- &Some(ref e) => { return Some((idx as uint, e)) }
+ fn next(&mut self) -> Option<$elem> {
+ while self.front < self.back {
+ match self.iter.next() {
+ Some(elem) => {
+ if elem.is_some() {
+ let index = self.front;
+ self.front += 1;
+ return Some((index, elem. $getter ()));
+ }
+ }
+ _ => ()
}
+ self.front += 1;
}
-
None
}
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ (0, Some(self.back - self.front))
+ }
}
}
}
-macro_rules! mut_iterator {
- /* FIXME: #4375 Cannot attach documentation/attributes to a macro generated struct.
- (struct $name:ident -> $ptr:ty, $elem:ty) => {
- pub struct $name<'self, T> {
- priv ptr: $ptr,
- priv end: $ptr,
- priv lifetime: $elem // FIXME: #5922
- }
- };*/
- (impl $name:ident -> $elem:ty) => {
- impl<'self, T> Iterator<(uint, $elem)> for $name<'self, T> {
+macro_rules! double_ended_iterator {
+ (impl $name:ident -> $elem:ty, $getter:ident) => {
+ impl<'self, T> DoubleEndedIterator<$elem> for $name<'self, T> {
#[inline]
- pub fn next(&mut self) -> Option<(uint, $elem)> {
- for self.iter.advance |(idx, elem)| {
- match elem {
- &None => {}
- &Some(ref mut e) => { return Some((idx as uint, e)) }
+ fn next_back(&mut self) -> Option<$elem> {
+ while self.front < self.back {
+ match self.iter.next_back() {
+ Some(elem) => {
+ if elem.is_some() {
+ self.back -= 1;
+ return Some((self.back, elem. $getter ()));
+ }
+ }
+ _ => ()
}
+ self.back -= 1;
}
-
None
}
}
}
pub struct SmallIntMapIterator<'self, T> {
- priv iter: ZipIterator<int,
- Counter<int>,
- &'self Option<T>,
- VecIterator<'self, Option<T> > >
+ priv front: uint,
+ priv back: uint,
+ priv iter: VecIterator<'self, Option<T>>
}
-iterator!{impl SmallIntMapIterator -> &'self T}
+iterator!(impl SmallIntMapIterator -> (uint, &'self T), get_ref)
+double_ended_iterator!(impl SmallIntMapIterator -> (uint, &'self T), get_ref)
+pub type SmallIntMapRevIterator<'self, T> = InvertIterator<(uint, &'self T),
+ SmallIntMapIterator<'self, T>>;
pub struct SmallIntMapMutIterator<'self, T> {
- priv iter: ZipIterator<int,
- Counter<int>,
- &'self mut Option<T>,
- VecMutIterator<'self, Option<T> > >
-}
-
-mut_iterator!{impl SmallIntMapMutIterator -> &'self mut T}
-
-pub struct SmallIntMapRevIterator<'self, T> {
- priv iter: ZipIterator<int,
- Counter<int>,
- &'self Option<T>,
- VecRevIterator<'self, Option<T> > >
-}
-
-iterator!{impl SmallIntMapRevIterator -> &'self T}
-
-pub struct SmallIntMapMutRevIterator<'self, T> {
- priv iter: ZipIterator<int,
- Counter<int>,
- &'self mut Option<T>,
- VecMutRevIterator<'self, Option<T> > >
-}
-
-mut_iterator!{impl SmallIntMapMutRevIterator -> &'self mut T}
-
-/// A set implemented on top of the SmallIntMap type. This set is always a set
-/// of integers, and the space requirements are on the order of the highest
-/// valued integer in the set.
-pub struct SmallIntSet {
- priv map: SmallIntMap<()>
-}
-
-impl Container for SmallIntSet {
- /// Return the number of elements in the map
- fn len(&self) -> uint {
- self.map.len()
- }
-
- /// Return true if the map contains no elements
- fn is_empty(&self) -> bool { self.len() == 0 }
-}
-
-impl Mutable for SmallIntSet {
- /// Clear the map, removing all key-value pairs.
- fn clear(&mut self) { self.map.clear() }
-}
-
-impl Set<uint> for SmallIntSet {
- /// Return true if the set contains a value
- fn contains(&self, value: &uint) -> bool { self.map.contains_key(value) }
-
- /// Return true if the set has no elements in common with `other`.
- /// This is equivalent to checking for an empty uintersection.
- fn is_disjoint(&self, other: &SmallIntSet) -> bool {
- for self.each |v| { if other.contains(v) { return false } }
- true
- }
-
- /// Return true if the set is a subset of another
- fn is_subset(&self, other: &SmallIntSet) -> bool {
- for self.each |v| { if !other.contains(v) { return false } }
- true
- }
-
- /// Return true if the set is a superset of another
- fn is_superset(&self, other: &SmallIntSet) -> bool {
- other.is_subset(self)
- }
-
- /// Visit the values representing the difference
- fn difference(&self, other: &SmallIntSet, f: &fn(&uint) -> bool) -> bool {
- self.each(|v| other.contains(v) || f(v))
- }
-
- /// Visit the values representing the symmetric difference
- fn symmetric_difference(&self,
- other: &SmallIntSet,
- f: &fn(&uint) -> bool) -> bool {
- let len = cmp::max(self.map.v.len() ,other.map.v.len());
-
- for uint::range(0, len) |i| {
- if self.contains(&i) ^ other.contains(&i) {
- if !f(&i) { return false; }
- }
- }
- return true;
- }
-
- /// Visit the values representing the uintersection
- fn intersection(&self, other: &SmallIntSet, f: &fn(&uint) -> bool) -> bool {
- self.each(|v| !other.contains(v) || f(v))
- }
-
- /// Visit the values representing the union
- fn union(&self, other: &SmallIntSet, f: &fn(&uint) -> bool) -> bool {
- let len = cmp::max(self.map.v.len() ,other.map.v.len());
-
- for uint::range(0, len) |i| {
- if self.contains(&i) || other.contains(&i) {
- if !f(&i) { return false; }
- }
- }
- return true;
- }
-}
-
-impl MutableSet<uint> for SmallIntSet {
- /// Add a value to the set. Return true if the value was not already
- /// present in the set.
- fn insert(&mut self, value: uint) -> bool { self.map.insert(value, ()) }
-
- /// Remove a value from the set. Return true if the value was
- /// present in the set.
- fn remove(&mut self, value: &uint) -> bool { self.map.remove(value) }
-}
-
-impl SmallIntSet {
- /// Create an empty SmallIntSet
- pub fn new() -> SmallIntSet { SmallIntSet{map: SmallIntMap::new()} }
-
- /// Visit all values in order
- pub fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) }
-
- /// An iterator visiting all set members in ascending order.
- /// Iterator element type is uint
- pub fn iter<'r>(&'r self) -> SmallIntSetIterator<'r> {
- SmallIntSetIterator {
- iter: self.map.iter()
- }
- }
-
- /// An iterator visiting all set members in descending order.
- /// Iterator element type is uint
- pub fn rev_iter<'r>(&'r mut self) -> SmallIntSetRevIterator<'r> {
- SmallIntSetRevIterator {
- iter: self.map.rev_iter()
- }
- }
-
-}
-
-pub struct SmallIntSetIterator<'self> {
- priv iter: SmallIntMapIterator<'self, ()>
-}
-
-pub struct SmallIntSetRevIterator<'self> {
- priv iter: SmallIntMapRevIterator<'self,()>
-}
-
-impl<'self> Iterator<uint> for SmallIntSetIterator<'self> {
- #[inline]
- pub fn next(&mut self) -> Option<uint> {
- let next_opt = self.iter.next();
- match next_opt {
- None => { None }
- Some((idx, _)) => { Some(idx) }
- }
- }
-}
-
-impl<'self> Iterator<uint> for SmallIntSetRevIterator<'self> {
- #[inline]
- pub fn next(&mut self) -> Option<uint> {
- let next_opt = self.iter.next();
- match next_opt {
- None => { None }
- Some((idx, _)) => { Some(idx) }
- }
- }
+ priv front: uint,
+ priv back: uint,
+ priv iter: VecMutIterator<'self, Option<T>>
}
-
+iterator!(impl SmallIntMapMutIterator -> (uint, &'self mut T), get_mut_ref)
+double_ended_iterator!(impl SmallIntMapMutIterator -> (uint, &'self mut T), get_mut_ref)
+pub type SmallIntMapMutRevIterator<'self, T> = InvertIterator<(uint, &'self mut T),
+ SmallIntMapMutIterator<'self, T>>;
#[cfg(test)]
-mod tests {
+mod test_map {
use super::SmallIntMap;
#[test]
fn test_iterator() {
- let mut a = SmallIntMap::new();
+ let mut m = SmallIntMap::new();
- assert!(a.insert(0,1));
- assert!(a.insert(1,2));
- assert!(a.insert(2,5));
- assert!(a.insert(3,10));
- assert!(a.insert(4,11));
+ assert!(m.insert(0, 1));
+ assert!(m.insert(1, 2));
+ assert!(m.insert(3, 5));
+ assert!(m.insert(6, 10));
+ assert!(m.insert(10, 11));
- let mut it = a.iter();
+ let mut it = m.iter();
+ assert_eq!(it.size_hint(), (0, Some(11)));
assert_eq!(it.next().unwrap(), (0, &1));
+ assert_eq!(it.size_hint(), (0, Some(10)));
assert_eq!(it.next().unwrap(), (1, &2));
- assert_eq!(it.next().unwrap(), (2, &5));
- assert_eq!(it.next().unwrap(), (3, &10));
- assert_eq!(it.next().unwrap(), (4, &11));
+ assert_eq!(it.size_hint(), (0, Some(9)));
+ assert_eq!(it.next().unwrap(), (3, &5));
+ assert_eq!(it.size_hint(), (0, Some(7)));
+ assert_eq!(it.next().unwrap(), (6, &10));
+ assert_eq!(it.size_hint(), (0, Some(4)));
+ assert_eq!(it.next().unwrap(), (10, &11));
+ assert_eq!(it.size_hint(), (0, Some(0)));
assert!(it.next().is_none());
}
+ #[test]
+ fn test_iterator_size_hints() {
+ let mut m = SmallIntMap::new();
+
+ assert!(m.insert(0, 1));
+ assert!(m.insert(1, 2));
+ assert!(m.insert(3, 5));
+ assert!(m.insert(6, 10));
+ assert!(m.insert(10, 11));
+
+ assert_eq!(m.iter().size_hint(), (0, Some(11)));
+ assert_eq!(m.rev_iter().size_hint(), (0, Some(11)));
+ assert_eq!(m.mut_iter().size_hint(), (0, Some(11)));
+ assert_eq!(m.mut_rev_iter().size_hint(), (0, Some(11)));
+ }
+
#[test]
fn test_mut_iterator() {
- let mut a = SmallIntMap::new();
+ let mut m = SmallIntMap::new();
- assert!(a.insert(0,1));
- assert!(a.insert(1,1));
- assert!(a.insert(2,1));
- assert!(a.insert(3,1));
- assert!(a.insert(4,1));
+ assert!(m.insert(0, 1));
+ assert!(m.insert(1, 2));
+ assert!(m.insert(3, 5));
+ assert!(m.insert(6, 10));
+ assert!(m.insert(10, 11));
- for a.mut_iter().advance |(_,v)| {
- *v += 1;
+ for m.mut_iter().advance |(k, v)| {
+ *v += k as int;
}
- assert!(a.iter().all(|(_,v)| *v == 2));
+ let mut it = m.iter();
+ assert_eq!(it.next().unwrap(), (0, &1));
+ assert_eq!(it.next().unwrap(), (1, &3));
+ assert_eq!(it.next().unwrap(), (3, &8));
+ assert_eq!(it.next().unwrap(), (6, &16));
+ assert_eq!(it.next().unwrap(), (10, &21));
+ assert!(it.next().is_none());
}
#[test]
fn test_rev_iterator() {
- let mut a = SmallIntMap::new();
-
- assert!(a.insert(0,1));
- assert!(a.insert(1,2));
- assert!(a.insert(2,5));
- assert!(a.insert(3,10));
- assert!(a.insert(4,11));
-
- let mut b = SmallIntMap::new();
-
- assert!(b.insert(0,11));
- assert!(b.insert(1,10));
- assert!(b.insert(2,5));
- assert!(b.insert(3,2));
- assert!(b.insert(4,1));
+ let mut m = SmallIntMap::new();
- let (a_it, b_it) = (a.iter(), b.rev_iter());
+ assert!(m.insert(0, 1));
+ assert!(m.insert(1, 2));
+ assert!(m.insert(3, 5));
+ assert!(m.insert(6, 10));
+ assert!(m.insert(10, 11));
- assert!(a_it.zip(b_it).all(|( (_ ,v1), (_, v2) )| *v1 == *v2));
+ let mut it = m.rev_iter();
+ assert_eq!(it.next().unwrap(), (10, &11));
+ assert_eq!(it.next().unwrap(), (6, &10));
+ assert_eq!(it.next().unwrap(), (3, &5));
+ assert_eq!(it.next().unwrap(), (1, &2));
+ assert_eq!(it.next().unwrap(), (0, &1));
+ assert!(it.next().is_none());
}
#[test]
fn test_mut_rev_iterator() {
- let mut a = SmallIntMap::new();
+ let mut m = SmallIntMap::new();
- assert!(a.insert(0,5));
- assert!(a.insert(1,4));
- assert!(a.insert(2,3));
- assert!(a.insert(3,2));
- assert!(a.insert(4,1));
+ assert!(m.insert(0, 1));
+ assert!(m.insert(1, 2));
+ assert!(m.insert(3, 5));
+ assert!(m.insert(6, 10));
+ assert!(m.insert(10, 11));
- for a.mut_rev_iter().advance |(i,v)| {
- *v += i as int;
+ for m.mut_rev_iter().advance |(k, v)| {
+ *v += k as int;
}
- assert!(a.iter().all(|(_,v)| *v == 5 ));
+ let mut it = m.iter();
+ assert_eq!(it.next().unwrap(), (0, &1));
+ assert_eq!(it.next().unwrap(), (1, &3));
+ assert_eq!(it.next().unwrap(), (3, &8));
+ assert_eq!(it.next().unwrap(), (6, &16));
+ assert_eq!(it.next().unwrap(), (10, &21));
+ assert!(it.next().is_none());
}
#[test]
}
#[cfg(test)]
-mod test_set {
+mod bench {
- use super::SmallIntSet;
+ use super::*;
+ use test::BenchHarness;
+ use container::bench::*;
- #[test]
- fn test_disjoint() {
- let mut xs = SmallIntSet::new();
- let mut ys = SmallIntSet::new();
- assert!(xs.is_disjoint(&ys));
- assert!(ys.is_disjoint(&xs));
- assert!(xs.insert(5));
- assert!(ys.insert(11));
- assert!(xs.is_disjoint(&ys));
- assert!(ys.is_disjoint(&xs));
- assert!(xs.insert(7));
- assert!(xs.insert(19));
- assert!(xs.insert(4));
- assert!(ys.insert(2));
- assert!(xs.is_disjoint(&ys));
- assert!(ys.is_disjoint(&xs));
- assert!(ys.insert(7));
- assert!(!xs.is_disjoint(&ys));
- assert!(!ys.is_disjoint(&xs));
+ // Find seq
+ #[bench]
+ pub fn insert_rand_100(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ insert_rand_n(100, &mut m, bh);
}
- #[test]
- fn test_subset_and_superset() {
- let mut a = SmallIntSet::new();
- assert!(a.insert(0));
- assert!(a.insert(5));
- assert!(a.insert(11));
- assert!(a.insert(7));
-
- let mut b = SmallIntSet::new();
- assert!(b.insert(0));
- assert!(b.insert(7));
- assert!(b.insert(19));
- assert!(b.insert(250));
- assert!(b.insert(11));
- assert!(b.insert(200));
-
- assert!(!a.is_subset(&b));
- assert!(!a.is_superset(&b));
- assert!(!b.is_subset(&a));
- assert!(!b.is_superset(&a));
-
- assert!(b.insert(5));
-
- assert!(a.is_subset(&b));
- assert!(!a.is_superset(&b));
- assert!(!b.is_subset(&a));
- assert!(b.is_superset(&a));
+ #[bench]
+ pub fn insert_rand_10_000(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ insert_rand_n(10_000, &mut m, bh);
}
- #[test]
- fn test_intersection() {
- let mut a = SmallIntSet::new();
- let mut b = SmallIntSet::new();
-
- assert!(a.insert(11));
- assert!(a.insert(1));
- assert!(a.insert(3));
- assert!(a.insert(77));
- assert!(a.insert(103));
- assert!(a.insert(5));
-
- assert!(b.insert(2));
- assert!(b.insert(11));
- assert!(b.insert(77));
- assert!(b.insert(5));
- assert!(b.insert(3));
-
- let mut i = 0;
- let expected = [3, 5, 11, 77];
- for a.intersection(&b) |x| {
- assert!(expected.contains(x));
- i += 1
- }
- assert_eq!(i, expected.len());
+ // Insert seq
+ #[bench]
+ pub fn insert_seq_100(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ insert_seq_n(100, &mut m, bh);
}
- #[test]
- fn test_difference() {
- let mut a = SmallIntSet::new();
- let mut b = SmallIntSet::new();
-
- assert!(a.insert(1));
- assert!(a.insert(3));
- assert!(a.insert(5));
- assert!(a.insert(9));
- assert!(a.insert(11));
-
- assert!(b.insert(3));
- assert!(b.insert(9));
-
- let mut i = 0;
- let expected = [1, 5, 11];
- for a.difference(&b) |x| {
- assert!(expected.contains(x));
- i += 1
- }
- assert_eq!(i, expected.len());
+ #[bench]
+ pub fn insert_seq_10_000(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ insert_seq_n(10_000, &mut m, bh);
}
- #[test]
- fn test_symmetric_difference() {
- let mut a = SmallIntSet::new();
- let mut b = SmallIntSet::new();
-
- assert!(a.insert(1));
- assert!(a.insert(3));
- assert!(a.insert(5));
- assert!(a.insert(9));
- assert!(a.insert(11));
-
- assert!(b.insert(3));
- assert!(b.insert(9));
- assert!(b.insert(14));
- assert!(b.insert(22));
-
- let mut i = 0;
- let expected = [1, 5, 11, 14, 22];
- for a.symmetric_difference(&b) |x| {
- assert!(expected.contains(x));
- i += 1
- }
- assert_eq!(i, expected.len());
+ // Find rand
+ #[bench]
+ pub fn find_rand_100(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ find_rand_n(100, &mut m, bh);
}
- #[test]
- fn test_union() {
- let mut a = SmallIntSet::new();
- let mut b = SmallIntSet::new();
-
- assert!(a.insert(1));
- assert!(a.insert(3));
- assert!(a.insert(5));
- assert!(a.insert(9));
- assert!(a.insert(11));
- assert!(a.insert(16));
- assert!(a.insert(19));
- assert!(a.insert(24));
-
- assert!(b.insert(1));
- assert!(b.insert(5));
- assert!(b.insert(9));
- assert!(b.insert(13));
- assert!(b.insert(19));
-
- let mut i = 0;
- let expected = [1, 3, 5, 9, 11, 13, 16, 19, 24];
- for a.union(&b) |x| {
- assert!(expected.contains(x));
- i += 1
- }
- assert_eq!(i, expected.len());
+ #[bench]
+ pub fn find_rand_10_000(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ find_rand_n(10_000, &mut m, bh);
}
- #[test]
- fn test_iterator() {
- let mut a = SmallIntSet::new();
-
- assert!(a.insert(0));
- assert!(a.insert(1));
- assert!(a.insert(2));
- assert!(a.insert(3));
- assert!(a.insert(4));
-
- let mut it = a.iter();
- assert_eq!(it.next().unwrap(), 0);
- assert_eq!(it.next().unwrap(), 1);
- assert_eq!(it.next().unwrap(), 2);
- assert_eq!(it.next().unwrap(), 3);
- assert_eq!(it.next().unwrap(), 4);
- assert!(it.next().is_none());
+ // Find seq
+ #[bench]
+ pub fn find_seq_100(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ find_seq_n(100, &mut m, bh);
}
- #[test]
- fn test_rev_iterator() {
- let mut a = SmallIntSet::new();
-
- assert!(a.insert(0));
- assert!(a.insert(1));
- assert!(a.insert(2));
- assert!(a.insert(3));
- assert!(a.insert(4));
-
- let a_it = a.rev_iter();
-
- assert!(do a_it.enumerate().all |( i, v2 )| {
- i + v2 == 4
- });
+ #[bench]
+ pub fn find_seq_10_000(bh: &mut BenchHarness) {
+ let mut m : SmallIntMap<uint> = SmallIntMap::new();
+ find_seq_n(10_000, &mut m, bh);
}
-
}
use sort::*;
- use std::int;
use std::vec;
fn check_sort(v1: &mut [int], v2: &mut [int]) {
use sort::*;
- use std::cast::unsafe_copy;
- use std::local_data;
use std::rand::RngUtil;
use std::rand;
use std::uint;
fn recursive_mkdir_rel() {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os;
+ use std::unstable::change_dir_locked;
let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel").
expect("recursive_mkdir_rel");
- assert!(do os::change_dir_locked(&root) {
+ assert!(do change_dir_locked(&root) {
let path = Path("frob");
debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
os::getcwd().to_str(),
fn recursive_mkdir_rel_2() {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os;
+ use std::unstable::change_dir_locked;
let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2").
expect("recursive_mkdir_rel_2");
- assert!(do os::change_dir_locked(&root) {
+ assert!(do change_dir_locked(&root) {
let path = Path("./frob/baz");
debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
os::getcwd().to_str(), os::path_exists(&path));
use getopts;
+use getopts::groups;
use json::ToJson;
use json;
use serialize::Decodable;
use std::clone::Clone;
use std::comm::{stream, SharedChan};
+use std::libc;
use std::either;
use std::io;
use std::result;
type OptRes = Either<TestOpts, ~str>;
+fn optgroups() -> ~[getopts::groups::OptGroup] {
+ ~[groups::optflag("", "ignored", "Run ignored tests"),
+ groups::optflag("", "test", "Run tests and not benchmarks"),
+ groups::optflag("", "bench", "Run benchmarks instead of tests"),
+ groups::optflag("h", "help", "Display this message (longer with --help)"),
+ groups::optopt("", "save-metrics", "Location to save bench metrics",
+ "PATH"),
+ groups::optopt("", "ratchet-metrics",
+ "Location to load and save metrics from. The metrics \
+ loaded are cause benchmarks to fail if they run too \
+ slowly", "PATH"),
+ groups::optopt("", "ratchet-noise-percent",
+ "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")]
+}
+
+fn usage(binary: &str, helpstr: &str) -> ! {
+ let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
+ println(groups::usage(message, optgroups()));
+ if helpstr == "help" {
+ println("\
+The FILTER is matched against the name of all tests to run, and if any tests
+have a substring match, only those tests are run.
+
+By default, all tests are run in parallel. This can be altered with the
+RUST_THREADS environment variable when running tests (set it to 1).
+
+Test Attributes:
+
+ #[test] - Indicates a function is a test to be run. This function
+ takes no arguments.
+ #[bench] - Indicates a function is a benchmark to be run. This
+ function takes one argument (extra::test::BenchHarness).
+ #[should_fail] - This function (also labeled with #[test]) will only pass if
+ the code causes a failure (an assertion failure or fail!)
+ #[ignore] - When applied to a function which is already attributed as a
+ test, then the test runner will ignore these tests during
+ normal test runs. Running with --ignored will run these
+ tests. This may also be written as #[ignore(cfg(...))] to
+ ignore the test on certain configurations.");
+ }
+ unsafe { libc::exit(0) }
+}
+
// Parses command line arguments into test options
pub fn parse_opts(args: &[~str]) -> OptRes {
let args_ = args.tail();
- let opts = ~[getopts::optflag("ignored"),
- getopts::optflag("test"),
- getopts::optflag("bench"),
- getopts::optopt("save-metrics"),
- getopts::optopt("ratchet-metrics"),
- getopts::optopt("ratchet-noise-percent"),
- getopts::optopt("logfile")];
let matches =
- match getopts::getopts(args_, opts) {
+ match groups::getopts(args_, optgroups()) {
Ok(m) => m,
Err(f) => return either::Right(getopts::fail_str(f))
};
+ if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
+ if getopts::opt_present(&matches, "help") { usage(args[0], "help"); }
+
let filter =
if matches.free.len() > 0 {
Some((matches).free[0].clone())
use super::Tm;
#[abi = "cdecl"]
- pub extern {
+ extern {
pub unsafe fn get_time(sec: &mut i64, nsec: &mut i32);
pub unsafe fn precise_time_ns(ns: &mut u64);
+++ /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.
-
-//! Utilities that leverage libuv's `uv_timer_*` API
-
-
-use uv;
-use uv::iotask;
-use uv::iotask::IoTask;
-
-use std::cast::transmute;
-use std::cast;
-use std::comm::{stream, Chan, SharedChan, Port, select2i};
-use std::either;
-use std::libc::c_void;
-use std::libc;
-
-/**
- * Wait for timeout period then send provided value over a channel
- *
- * This call returns immediately. Useful as the building block for a number
- * of higher-level timer functions.
- *
- * Is not guaranteed to wait for exactly the specified time, but will wait
- * for *at least* that period of time.
- *
- * # Arguments
- *
- * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
- * * msecs - a timeout period, in milliseconds, to wait
- * * ch - a channel of type T to send a `val` on
- * * val - a value of type T to send over the provided `ch`
- */
-pub fn delayed_send<T:Send>(iotask: &IoTask,
- msecs: uint,
- ch: &Chan<T>,
- val: T) {
- let (timer_done_po, timer_done_ch) = stream::<()>();
- let timer_done_ch = SharedChan::new(timer_done_ch);
- let timer = uv::ll::timer_t();
- let timer_ptr: *uv::ll::uv_timer_t = &timer;
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
- if (init_result == 0i32) {
- let start_result = uv::ll::timer_start(
- timer_ptr, delayed_send_cb, msecs, 0u);
- if (start_result == 0i32) {
- // Note: putting the channel into a ~
- // to cast to *c_void
- let timer_done_ch_clone = ~timer_done_ch.clone();
- let timer_done_ch_ptr = transmute::<
- ~SharedChan<()>, *c_void>(
- timer_done_ch_clone);
- uv::ll::set_data_for_uv_handle(
- timer_ptr,
- timer_done_ch_ptr);
- } else {
- let error_msg = uv::ll::get_last_err_info(
- loop_ptr);
- fail!("timer::delayed_send() start failed: %s", error_msg);
- }
- } else {
- let error_msg = uv::ll::get_last_err_info(loop_ptr);
- fail!("timer::delayed_send() init failed: %s", error_msg);
- }
- }
- };
- // delayed_send_cb has been processed by libuv
- timer_done_po.recv();
- // notify the caller immediately
- ch.send(val);
- // uv_close for this timer has been processed
- timer_done_po.recv();
-}
-
-/**
- * Blocks the current task for (at least) the specified time period.
- *
- * Is not guaranteed to sleep for exactly the specified time, but will sleep
- * for *at least* that period of time.
- *
- * # Arguments
- *
- * * `iotask` - a `uv::iotask` that the tcp request will run on
- * * msecs - an amount of time, in milliseconds, for the current task to block
- */
-pub fn sleep(iotask: &IoTask, msecs: uint) {
- let (exit_po, exit_ch) = stream::<()>();
- delayed_send(iotask, msecs, &exit_ch, ());
- exit_po.recv();
-}
-
-/**
- * Receive on a port for (up to) a specified time, then return an `Option<T>`
- *
- * This call will block to receive on the provided port for up to the
- * specified timeout. Depending on whether the provided port receives in that
- * time period, `recv_timeout` will return an `Option<T>` representing the
- * result.
- *
- * # Arguments
- *
- * * `iotask' - `uv::iotask` that the tcp request will run on
- * * msecs - an mount of time, in milliseconds, to wait to receive
- * * wait_port - a `std::comm::port<T>` to receive on
- *
- * # Returns
- *
- * An `Option<T>` representing the outcome of the call. If the call `recv`'d
- * on the provided port in the allotted timeout period, then the result will
- * be a `Some(T)`. If not, then `None` will be returned.
- */
-pub fn recv_timeout<T:Send>(iotask: &IoTask, msecs: uint, wait_po: &Port<T>)
- -> Option<T> {
- let (timeout_po, timeout_ch) = stream::<()>();
- let mut timeout_po = timeout_po;
- delayed_send(iotask, msecs, &timeout_ch, ());
-
- // XXX: Workaround due to ports and channels not being &mut. They should
- // be.
- unsafe {
- let wait_po = cast::transmute_mut(wait_po);
-
- either::either(
- |_| {
- None
- }, |_| {
- Some(wait_po.recv())
- }, &select2i(&mut timeout_po, wait_po)
- )
- }
-}
-
-// INTERNAL API
-extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t, status: libc::c_int) {
- unsafe {
- debug!(
- "delayed_send_cb handle %? status %?", handle, status);
- // Faking a borrowed pointer to our ~SharedChan
- let timer_done_ch_ptr: &*c_void = &uv::ll::get_data_for_uv_handle(
- handle);
- let timer_done_ch_ptr = transmute::<&*c_void, &~SharedChan<()>>(
- timer_done_ch_ptr);
- let stop_result = uv::ll::timer_stop(handle);
- if (stop_result == 0i32) {
- timer_done_ch_ptr.send(());
- uv::ll::close(handle, delayed_send_close_cb);
- } else {
- let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
- let error_msg = uv::ll::get_last_err_info(loop_ptr);
- fail!("timer::sleep() init failed: %s", error_msg);
- }
- }
-}
-
-extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) {
- unsafe {
- debug!("delayed_send_close_cb handle %?", handle);
- let timer_done_ch_ptr = uv::ll::get_data_for_uv_handle(handle);
- let timer_done_ch = transmute::<*c_void, ~SharedChan<()>>(
- timer_done_ch_ptr);
- timer_done_ch.send(());
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use timer::*;
- use uv;
-
- use std::cell::Cell;
- use std::pipes::{stream, SharedChan};
- use std::rand::RngUtil;
- use std::rand;
- use std::task;
-
- #[test]
- fn test_gl_timer_simple_sleep_test() {
- let hl_loop = &uv::global_loop::get();
- sleep(hl_loop, 1u);
- }
-
- #[test]
- fn test_gl_timer_sleep_stress1() {
- let hl_loop = &uv::global_loop::get();
- for 50u.times {
- sleep(hl_loop, 1u);
- }
- }
-
- #[test]
- fn test_gl_timer_sleep_stress2() {
- let (po, ch) = stream();
- let ch = SharedChan::new(ch);
- let hl_loop = &uv::global_loop::get();
-
- let repeat = 20u;
- let spec = {
-
- ~[(1u, 20u),
- (10u, 10u),
- (20u, 2u)]
-
- };
-
- for repeat.times {
- let ch = ch.clone();
- for spec.iter().advance |spec| {
- let (times, maxms) = *spec;
- let ch = ch.clone();
- let hl_loop_clone = hl_loop.clone();
- do task::spawn {
- use std::rand::*;
- let mut rng = rng();
- for times.times {
- sleep(&hl_loop_clone, rng.next() as uint % maxms);
- }
- ch.send(());
- }
- }
- }
-
- for (repeat * spec.len()).times {
- po.recv()
- }
- }
-
- // Because valgrind serializes multithreaded programs it can
- // make timing-sensitive tests fail in wierd ways. In these
- // next test we run them many times and expect them to pass
- // the majority of tries.
-
- #[test]
- #[cfg(ignore)]
- fn test_gl_timer_recv_timeout_before_time_passes() {
- let times = 100;
- let mut successes = 0;
- let mut failures = 0;
- let hl_loop = uv::global_loop::get();
-
- for (times as uint).times {
- task::yield();
-
- let expected = rand::rng().gen_str(16u);
- let (test_po, test_ch) = stream::<~str>();
-
- do task::spawn() {
- delayed_send(hl_loop, 1u, &test_ch, expected);
- };
-
- match recv_timeout(hl_loop, 10u, &test_po) {
- Some(val) => {
- assert_eq!(val, expected);
- successes += 1;
- }
- _ => failures += 1
- };
- }
-
- assert!(successes > times / 2);
- }
-
- #[test]
- fn test_gl_timer_recv_timeout_after_time_passes() {
- let times = 100;
- let mut successes = 0;
- let mut failures = 0;
- let hl_loop = uv::global_loop::get();
-
- for (times as uint).times {
- let mut rng = rand::rng();
- let expected = Cell::new(rng.gen_str(16u));
- let (test_po, test_ch) = stream::<~str>();
- let hl_loop_clone = hl_loop.clone();
- do task::spawn() {
- delayed_send(&hl_loop_clone, 50u, &test_ch, expected.take());
- };
-
- match recv_timeout(&hl_loop, 1u, &test_po) {
- None => successes += 1,
- _ => failures += 1
- };
- }
-
- assert!(successes > times / 2);
- }
-}
}
}
}
- return match replace(node, None) {
+ return match node.take() {
Some(~TreeNode{value, _}) => Some(value), None => fail!()
};
}
assert_eq!(map.find(&k), Some(&v));
}
}
+
+}
+
+#[cfg(test)]
+mod bench {
+
+ use super::*;
+ use test::BenchHarness;
+ use container::bench::*;
+
+ // Find seq
+ #[bench]
+ pub fn insert_rand_100(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ insert_rand_n(100, &mut m, bh);
+ }
+
+ #[bench]
+ pub fn insert_rand_10_000(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ insert_rand_n(10_000, &mut m, bh);
+ }
+
+ // Insert seq
+ #[bench]
+ pub fn insert_seq_100(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ insert_seq_n(100, &mut m, bh);
+ }
+
+ #[bench]
+ pub fn insert_seq_10_000(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ insert_seq_n(10_000, &mut m, bh);
+ }
+
+ // Find rand
+ #[bench]
+ pub fn find_rand_100(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ find_rand_n(100, &mut m, bh);
+ }
+
+ #[bench]
+ pub fn find_rand_10_000(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ find_rand_n(10_000, &mut m, bh);
+ }
+
+ // Find seq
+ #[bench]
+ pub fn find_seq_100(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ find_seq_n(100, &mut m, bh);
+ }
+
+ #[bench]
+ pub fn find_seq_10_000(bh: &mut BenchHarness) {
+ let mut m : TreeMap<uint,uint> = TreeMap::new();
+ find_seq_n(10_000, &mut m, bh);
+ }
}
#[cfg(test)]
pub mod libicu {
#[link_name = "icuuc"]
#[abi = "cdecl"]
- pub extern {
- unsafe fn u_hasBinaryProperty(c: UChar32, which: UProperty)
- -> UBool;
- unsafe fn u_isdigit(c: UChar32) -> UBool;
- unsafe fn u_islower(c: UChar32) -> UBool;
- unsafe fn u_isspace(c: UChar32) -> UBool;
- unsafe fn u_isupper(c: UChar32) -> UBool;
- unsafe fn u_tolower(c: UChar32) -> UChar32;
- unsafe fn u_toupper(c: UChar32) -> UChar32;
+ extern {
+ pub unsafe fn u_hasBinaryProperty(c: UChar32, which: UProperty)
+ -> UBool;
+ pub unsafe fn u_isdigit(c: UChar32) -> UBool;
+ pub unsafe fn u_islower(c: UChar32) -> UBool;
+ pub unsafe fn u_isspace(c: UChar32) -> UBool;
+ pub unsafe fn u_isupper(c: UChar32) -> UBool;
+ pub unsafe fn u_tolower(c: UChar32) -> UChar32;
+ pub unsafe fn u_toupper(c: UChar32) -> UChar32;
}
}
}
--- /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.
+
+//! Types/fns concerning URLs (see RFC 3986)
+
+#[allow(missing_doc)];
+
+
+use std::cmp::Eq;
+use std::io::{Reader, ReaderUtil};
+use std::io;
+use std::hashmap::HashMap;
+use std::to_bytes;
+use std::uint;
+
+#[deriving(Clone, Eq)]
+struct Url {
+ scheme: ~str,
+ user: Option<UserInfo>,
+ host: ~str,
+ port: Option<~str>,
+ path: ~str,
+ query: Query,
+ fragment: Option<~str>
+}
+
+#[deriving(Clone, Eq)]
+struct UserInfo {
+ user: ~str,
+ pass: Option<~str>
+}
+
+pub type Query = ~[(~str, ~str)];
+
+impl Url {
+ pub fn new(scheme: ~str,
+ user: Option<UserInfo>,
+ host: ~str,
+ port: Option<~str>,
+ path: ~str,
+ query: Query,
+ fragment: Option<~str>)
+ -> Url {
+ Url {
+ scheme: scheme,
+ user: user,
+ host: host,
+ port: port,
+ path: path,
+ query: query,
+ fragment: fragment,
+ }
+ }
+}
+
+impl UserInfo {
+ pub fn new(user: ~str, pass: Option<~str>) -> UserInfo {
+ UserInfo { user: user, pass: pass }
+ }
+}
+
+fn encode_inner(s: &str, full_url: bool) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ let ch = rdr.read_byte() as char;
+ match ch {
+ // unreserved:
+ 'A' .. 'Z' |
+ 'a' .. 'z' |
+ '0' .. '9' |
+ '-' | '.' | '_' | '~' => {
+ out.push_char(ch);
+ }
+ _ => {
+ if full_url {
+ match ch {
+ // gen-delims:
+ ':' | '/' | '?' | '#' | '[' | ']' | '@' |
+
+ // sub-delims:
+ '!' | '$' | '&' | '"' | '(' | ')' | '*' |
+ '+' | ',' | ';' | '=' => {
+ out.push_char(ch);
+ }
+
+ _ => out.push_str(fmt!("%%%X", ch as uint))
+ }
+ } else {
+ out.push_str(fmt!("%%%X", ch as uint));
+ }
+ }
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Encodes a URI by replacing reserved characters with percent encoded
+ * character sequences.
+ *
+ * This function is compliant with RFC 3986.
+ */
+pub fn encode(s: &str) -> ~str {
+ encode_inner(s, true)
+}
+
+/**
+ * Encodes a URI component by replacing reserved characters with percent
+ * encoded character sequences.
+ *
+ * This function is compliant with RFC 3986.
+ */
+
+pub fn encode_component(s: &str) -> ~str {
+ encode_inner(s, false)
+}
+
+fn decode_inner(s: &str, full_url: bool) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ match rdr.read_char() {
+ '%' => {
+ let bytes = rdr.read_bytes(2u);
+ let ch = uint::parse_bytes(bytes, 16u).get() as char;
+
+ if full_url {
+ // Only decode some characters:
+ match ch {
+ // gen-delims:
+ ':' | '/' | '?' | '#' | '[' | ']' | '@' |
+
+ // sub-delims:
+ '!' | '$' | '&' | '"' | '(' | ')' | '*' |
+ '+' | ',' | ';' | '=' => {
+ out.push_char('%');
+ out.push_char(bytes[0u] as char);
+ out.push_char(bytes[1u] as char);
+ }
+
+ ch => out.push_char(ch)
+ }
+ } else {
+ out.push_char(ch);
+ }
+ }
+ ch => out.push_char(ch)
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Decode a string encoded with percent encoding.
+ *
+ * This will only decode escape sequences generated by encode.
+ */
+pub fn decode(s: &str) -> ~str {
+ decode_inner(s, true)
+}
+
+/**
+ * Decode a string encoded with percent encoding.
+ */
+pub fn decode_component(s: &str) -> ~str {
+ decode_inner(s, false)
+}
+
+fn encode_plus(s: &str) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ let ch = rdr.read_byte() as char;
+ match ch {
+ 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => {
+ out.push_char(ch);
+ }
+ ' ' => out.push_char('+'),
+ _ => out.push_str(fmt!("%%%X", ch as uint))
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Encode a hashmap to the 'application/x-www-form-urlencoded' media type.
+ */
+pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str {
+ let mut out = ~"";
+ let mut first = true;
+
+ for m.iter().advance |(key, values)| {
+ let key = encode_plus(*key);
+
+ for values.iter().advance |value| {
+ if first {
+ first = false;
+ } else {
+ out.push_char('&');
+ first = false;
+ }
+
+ out.push_str(fmt!("%s=%s", key, encode_plus(*value)));
+ }
+ }
+
+ out
+}
+
+/**
+ * Decode a string encoded with the 'application/x-www-form-urlencoded' media
+ * type into a hashmap.
+ */
+pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
+ do io::with_bytes_reader(s) |rdr| {
+ let mut m = HashMap::new();
+ let mut key = ~"";
+ let mut value = ~"";
+ let mut parsing_key = true;
+
+ while !rdr.eof() {
+ match rdr.read_char() {
+ '&' | ';' => {
+ if key != ~"" && value != ~"" {
+ let mut values = match m.pop(&key) {
+ Some(values) => values,
+ None => ~[],
+ };
+
+ values.push(value);
+ m.insert(key, values);
+ }
+
+ parsing_key = true;
+ key = ~"";
+ value = ~"";
+ }
+ '=' => parsing_key = false,
+ ch => {
+ let ch = match ch {
+ '%' => {
+ let bytes = rdr.read_bytes(2u);
+ uint::parse_bytes(bytes, 16u).get() as char
+ }
+ '+' => ' ',
+ ch => ch
+ };
+
+ if parsing_key {
+ key.push_char(ch)
+ } else {
+ value.push_char(ch)
+ }
+ }
+ }
+ }
+
+ if key != ~"" && value != ~"" {
+ let mut values = match m.pop(&key) {
+ Some(values) => values,
+ None => ~[],
+ };
+
+ values.push(value);
+ m.insert(key, values);
+ }
+
+ m
+ }
+}
+
+
+fn split_char_first(s: &str, c: char) -> (~str, ~str) {
+ let len = s.len();
+ let mut index = len;
+ let mut mat = 0;
+ do io::with_str_reader(s) |rdr| {
+ let mut ch;
+ while !rdr.eof() {
+ ch = rdr.read_byte() as char;
+ if ch == c {
+ // found a match, adjust markers
+ index = rdr.tell()-1;
+ mat = 1;
+ break;
+ }
+ }
+ }
+ if index+mat == len {
+ return (s.slice(0, index).to_owned(), ~"");
+ } else {
+ return (s.slice(0, index).to_owned(),
+ s.slice(index + mat, s.len()).to_owned());
+ }
+}
+
+fn userinfo_from_str(uinfo: &str) -> UserInfo {
+ let (user, p) = split_char_first(uinfo, ':');
+ let pass = if p.is_empty() {
+ None
+ } else {
+ Some(p)
+ };
+ return UserInfo::new(user, pass);
+}
+
+fn userinfo_to_str(userinfo: &UserInfo) -> ~str {
+ match userinfo.pass {
+ Some(ref pass) => fmt!("%s:%s@", userinfo.user, *pass),
+ None => fmt!("%s@", userinfo.user),
+ }
+}
+
+fn query_from_str(rawquery: &str) -> Query {
+ let mut query: Query = ~[];
+ if !rawquery.is_empty() {
+ for rawquery.split_iter('&').advance |p| {
+ let (k, v) = split_char_first(p, '=');
+ query.push((decode_component(k), decode_component(v)));
+ };
+ }
+ return query;
+}
+
+pub fn query_to_str(query: &Query) -> ~str {
+ let mut strvec = ~[];
+ for query.iter().advance |kv| {
+ match kv {
+ &(ref k, ref v) => {
+ strvec.push(fmt!("%s=%s",
+ encode_component(*k),
+ encode_component(*v))
+ );
+ }
+ }
+ }
+ return strvec.connect("&");
+}
+
+// returns the scheme and the rest of the url, or a parsing error
+pub fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> {
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ match c {
+ 'A' .. 'Z' | 'a' .. 'z' => loop,
+ '0' .. '9' | '+' | '-' | '.' => {
+ if i == 0 {
+ return Err(~"url: Scheme must begin with a letter.");
+ }
+ loop;
+ }
+ ':' => {
+ if i == 0 {
+ return Err(~"url: Scheme cannot be empty.");
+ } else {
+ return Ok((rawurl.slice(0,i).to_owned(),
+ rawurl.slice(i+1,rawurl.len()).to_owned()));
+ }
+ }
+ _ => {
+ return Err(~"url: Invalid character in scheme.");
+ }
+ }
+ };
+ return Err(~"url: Scheme must be terminated with a colon.");
+}
+
+#[deriving(Clone, Eq)]
+enum Input {
+ Digit, // all digits
+ Hex, // digits and letters a-f
+ Unreserved // all other legal characters
+}
+
+// returns userinfo, host, port, and unparsed part, or an error
+fn get_authority(rawurl: &str) ->
+ Result<(Option<UserInfo>, ~str, Option<~str>, ~str), ~str> {
+ if !rawurl.starts_with("//") {
+ // there is no authority.
+ return Ok((None, ~"", None, rawurl.to_str()));
+ }
+
+ enum State {
+ Start, // starting state
+ PassHostPort, // could be in user or port
+ Ip6Port, // either in ipv6 host or port
+ Ip6Host, // are in an ipv6 host
+ InHost, // are in a host - may be ipv6, but don't know yet
+ InPort // are in port
+ }
+
+ let len = rawurl.len();
+ let mut st = Start;
+ let mut in = Digit; // most restricted, start here.
+
+ let mut userinfo = None;
+ let mut host = ~"";
+ let mut port = None;
+
+ let mut colon_count = 0;
+ let mut pos = 0;
+ let mut begin = 2;
+ let mut end = len;
+
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ if i < 2 { loop; } // ignore the leading //
+
+ // deal with input class first
+ match c {
+ '0' .. '9' => (),
+ 'A' .. 'F' | 'a' .. 'f' => {
+ if in == Digit {
+ in = Hex;
+ }
+ }
+ 'G' .. 'Z' | 'g' .. 'z' | '-' | '.' | '_' | '~' | '%' |
+ '&' |'\'' | '(' | ')' | '+' | '!' | '*' | ',' | ';' | '=' => {
+ in = Unreserved;
+ }
+ ':' | '@' | '?' | '#' | '/' => {
+ // separators, don't change anything
+ }
+ _ => {
+ return Err(~"Illegal character in authority");
+ }
+ }
+
+ // now process states
+ match c {
+ ':' => {
+ colon_count += 1;
+ match st {
+ Start => {
+ pos = i;
+ st = PassHostPort;
+ }
+ PassHostPort => {
+ // multiple colons means ipv6 address.
+ if in == Unreserved {
+ return Err(
+ ~"Illegal characters in IPv6 address.");
+ }
+ st = Ip6Host;
+ }
+ InHost => {
+ pos = i;
+ // can't be sure whether this is an ipv6 address or a port
+ if in == Unreserved {
+ return Err(~"Illegal characters in authority.");
+ }
+ st = Ip6Port;
+ }
+ Ip6Port => {
+ if in == Unreserved {
+ return Err(~"Illegal characters in authority.");
+ }
+ st = Ip6Host;
+ }
+ Ip6Host => {
+ if colon_count > 7 {
+ host = rawurl.slice(begin, i).to_owned();
+ pos = i;
+ st = InPort;
+ }
+ }
+ _ => {
+ return Err(~"Invalid ':' in authority.");
+ }
+ }
+ in = Digit; // reset input class
+ }
+
+ '@' => {
+ in = Digit; // reset input class
+ colon_count = 0; // reset count
+ match st {
+ Start => {
+ let user = rawurl.slice(begin, i).to_owned();
+ userinfo = Some(UserInfo::new(user, None));
+ st = InHost;
+ }
+ PassHostPort => {
+ let user = rawurl.slice(begin, pos).to_owned();
+ let pass = rawurl.slice(pos+1, i).to_owned();
+ userinfo = Some(UserInfo::new(user, Some(pass)));
+ st = InHost;
+ }
+ _ => {
+ return Err(~"Invalid '@' in authority.");
+ }
+ }
+ begin = i+1;
+ }
+
+ '?' | '#' | '/' => {
+ end = i;
+ break;
+ }
+ _ => ()
+ }
+ end = i;
+ }
+
+ let end = end; // make end immutable so it can be captured
+
+ let host_is_end_plus_one: &fn() -> bool = || {
+ let xs = ['?', '#', '/'];
+ end+1 == len
+ && !xs.iter().any(|x| *x == (rawurl[end] as char))
+ };
+
+ // finish up
+ match st {
+ Start => {
+ if host_is_end_plus_one() {
+ host = rawurl.slice(begin, end+1).to_owned();
+ } else {
+ host = rawurl.slice(begin, end).to_owned();
+ }
+ }
+ PassHostPort | Ip6Port => {
+ if in != Digit {
+ return Err(~"Non-digit characters in port.");
+ }
+ host = rawurl.slice(begin, pos).to_owned();
+ port = Some(rawurl.slice(pos+1, end).to_owned());
+ }
+ Ip6Host | InHost => {
+ host = rawurl.slice(begin, end).to_owned();
+ }
+ InPort => {
+ if in != Digit {
+ return Err(~"Non-digit characters in port.");
+ }
+ port = Some(rawurl.slice(pos+1, end).to_owned());
+ }
+ }
+
+ let rest = if host_is_end_plus_one() { ~"" }
+ else { rawurl.slice(end, len).to_owned() };
+ return Ok((userinfo, host, port, rest));
+}
+
+
+// returns the path and unparsed part of url, or an error
+fn get_path(rawurl: &str, authority: bool) ->
+ Result<(~str, ~str), ~str> {
+ let len = rawurl.len();
+ let mut end = len;
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ match c {
+ 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '&' |'\'' | '(' | ')' | '.'
+ | '@' | ':' | '%' | '/' | '+' | '!' | '*' | ',' | ';' | '='
+ | '_' | '-' => {
+ loop;
+ }
+ '?' | '#' => {
+ end = i;
+ break;
+ }
+ _ => return Err(~"Invalid character in path.")
+ }
+ }
+
+ if authority {
+ if end != 0 && !rawurl.starts_with("/") {
+ return Err(~"Non-empty path must begin with\
+ '/' in presence of authority.");
+ }
+ }
+
+ return Ok((decode_component(rawurl.slice(0, end)),
+ rawurl.slice(end, len).to_owned()));
+}
+
+// returns the parsed query and the fragment, if present
+fn get_query_fragment(rawurl: &str) ->
+ Result<(Query, Option<~str>), ~str> {
+ if !rawurl.starts_with("?") {
+ if rawurl.starts_with("#") {
+ let f = decode_component(rawurl.slice(
+ 1,
+ rawurl.len()));
+ return Ok((~[], Some(f)));
+ } else {
+ return Ok((~[], None));
+ }
+ }
+ let (q, r) = split_char_first(rawurl.slice(1, rawurl.len()), '#');
+ let f = if r.len() != 0 {
+ Some(decode_component(r)) } else { None };
+ return Ok((query_from_str(q), f));
+}
+
+/**
+ * Parse a `str` to a `url`
+ *
+ * # Arguments
+ *
+ * `rawurl` - a string representing a full url, including scheme.
+ *
+ * # Returns
+ *
+ * a `url` that contains the parsed representation of the url.
+ *
+ */
+
+pub fn from_str(rawurl: &str) -> Result<Url, ~str> {
+ // scheme
+ let (scheme, rest) = match get_scheme(rawurl) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // authority
+ let (userinfo, host, port, rest) = match get_authority(rest) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // path
+ let has_authority = if host == ~"" { false } else { true };
+ let (path, rest) = match get_path(rest, has_authority) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // query and fragment
+ let (query, fragment) = match get_query_fragment(rest) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ Ok(Url::new(scheme, userinfo, host, port, path, query, fragment))
+}
+
+impl FromStr for Url {
+ fn from_str(s: &str) -> Option<Url> {
+ match from_str(s) {
+ Ok(url) => Some(url),
+ Err(_) => None
+ }
+ }
+}
+
+/**
+ * Format a `url` as a string
+ *
+ * # Arguments
+ *
+ * `url` - a url.
+ *
+ * # Returns
+ *
+ * a `str` that contains the formatted url. Note that this will usually
+ * be an inverse of `from_str` but might strip out unneeded separators.
+ * for example, "http://somehost.com?", when parsed and formatted, will
+ * result in just "http://somehost.com".
+ *
+ */
+pub fn to_str(url: &Url) -> ~str {
+ let user = match url.user {
+ Some(ref user) => userinfo_to_str(user),
+ None => ~"",
+ };
+
+ let authority = if url.host.is_empty() {
+ ~""
+ } else {
+ fmt!("//%s%s", user, url.host)
+ };
+
+ let query = if url.query.is_empty() {
+ ~""
+ } else {
+ fmt!("?%s", query_to_str(&url.query))
+ };
+
+ let fragment = match url.fragment {
+ Some(ref fragment) => fmt!("#%s", encode_component(*fragment)),
+ None => ~"",
+ };
+
+ fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment)
+}
+
+impl ToStr for Url {
+ pub fn to_str(&self) -> ~str {
+ to_str(self)
+ }
+}
+
+impl IterBytes for Url {
+ fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
+ self.to_str().iter_bytes(lsb0, f)
+ }
+}
+
+// Put a few tests outside of the 'test' module so they can test the internal
+// functions and those functions don't need 'pub'
+
+#[test]
+fn test_split_char_first() {
+ let (u,v) = split_char_first("hello, sweet world", ',');
+ assert_eq!(u, ~"hello");
+ assert_eq!(v, ~" sweet world");
+
+ let (u,v) = split_char_first("hello sweet world", ',');
+ assert_eq!(u, ~"hello sweet world");
+ assert_eq!(v, ~"");
+}
+
+#[test]
+fn test_get_authority() {
+ let (u, h, p, r) = get_authority(
+ "//user:pass@rust-lang.org/something").unwrap();
+ assert_eq!(u, Some(UserInfo::new(~"user", Some(~"pass"))));
+ assert_eq!(h, ~"rust-lang.org");
+ assert!(p.is_none());
+ assert_eq!(r, ~"/something");
+
+ let (u, h, p, r) = get_authority(
+ "//rust-lang.org:8000?something").unwrap();
+ assert!(u.is_none());
+ assert_eq!(h, ~"rust-lang.org");
+ assert_eq!(p, Some(~"8000"));
+ assert_eq!(r, ~"?something");
+
+ let (u, h, p, r) = get_authority(
+ "//rust-lang.org#blah").unwrap();
+ assert!(u.is_none());
+ assert_eq!(h, ~"rust-lang.org");
+ assert!(p.is_none());
+ assert_eq!(r, ~"#blah");
+
+ // ipv6 tests
+ let (_, h, _, _) = get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah").unwrap();
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+
+ let (_, h, p, _) = get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah").unwrap();
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+ assert_eq!(p, Some(~"8000"));
+
+ let (u, h, p, _) = get_authority(
+ "//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah"
+ ).unwrap();
+ assert_eq!(u, Some(UserInfo::new(~"us", Some(~"p"))));
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+ assert_eq!(p, Some(~"8000"));
+
+ // invalid authorities;
+ assert!(get_authority("//user:pass@rust-lang:something").is_err());
+ assert!(get_authority("//user@rust-lang:something:/path").is_err());
+ assert!(get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a").is_err());
+ assert!(get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00").is_err());
+
+ // these parse as empty, because they don't start with '//'
+ let (_, h, _, _) = get_authority("user:pass@rust-lang").unwrap();
+ assert_eq!(h, ~"");
+ let (_, h, _, _) = get_authority("rust-lang.org").unwrap();
+ assert_eq!(h, ~"");
+}
+
+#[test]
+fn test_get_path() {
+ let (p, r) = get_path("/something+%20orother", true).unwrap();
+ assert_eq!(p, ~"/something+ orother");
+ assert_eq!(r, ~"");
+ let (p, r) = get_path("test@email.com#fragment", false).unwrap();
+ assert_eq!(p, ~"test@email.com");
+ assert_eq!(r, ~"#fragment");
+ let (p, r) = get_path("/gen/:addr=?q=v", false).unwrap();
+ assert_eq!(p, ~"/gen/:addr=");
+ assert_eq!(r, ~"?q=v");
+
+ //failure cases
+ assert!(get_path("something?q", true).is_err());
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ use std::hashmap::HashMap;
+
+ #[test]
+ fn test_url_parse() {
+ let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
+
+ let up = from_str(url);
+ let u = up.unwrap();
+ assert!(u.scheme == ~"http");
+ let userinfo = u.user.get_ref();
+ assert!(userinfo.user == ~"user");
+ assert!(userinfo.pass.get_ref() == &~"pass");
+ assert!(u.host == ~"rust-lang.org");
+ assert!(u.path == ~"/doc");
+ assert!(u.query == ~[(~"s", ~"v")]);
+ assert!(u.fragment.get_ref() == &~"something");
+ }
+
+ #[test]
+ fn test_url_parse_host_slash() {
+ let urlstr = ~"http://0.42.42.42/";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.host == ~"0.42.42.42");
+ assert!(url.path == ~"/");
+ }
+
+ #[test]
+ fn test_url_with_underscores() {
+ let urlstr = ~"http://dotcom.com/file_name.html";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.path == ~"/file_name.html");
+ }
+
+ #[test]
+ fn test_url_with_dashes() {
+ let urlstr = ~"http://dotcom.com/file-name.html";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.path == ~"/file-name.html");
+ }
+
+ #[test]
+ fn test_no_scheme() {
+ assert!(get_scheme("noschemehere.html").is_err());
+ }
+
+ #[test]
+ fn test_invalid_scheme_errors() {
+ assert!(from_str("99://something").is_err());
+ assert!(from_str("://something").is_err());
+ }
+
+ #[test]
+ fn test_full_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_userless_url_parse_and_format() {
+ let url = ~"http://rust-lang.org/doc?s=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_queryless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_empty_query_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?#something";
+ let should_be = ~"http://user:pass@rust-lang.org/doc#something";
+ assert_eq!(from_str(url).unwrap().to_str(), should_be);
+ }
+
+ #[test]
+ fn test_fragmentless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?q=v";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_minimal_url_parse_and_format() {
+ let url = ~"http://rust-lang.org/doc";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_scheme_host_only_url_parse_and_format() {
+ let url = ~"http://rust-lang.org";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_pathless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org?q=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_scheme_host_fragment_only_url_parse_and_format() {
+ let url = ~"http://rust-lang.org#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_url_component_encoding() {
+ let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B";
+ let u = from_str(url).unwrap();
+ assert!(u.path == ~"/doc uments");
+ assert!(u.query == ~[(~"ba%d ", ~"#&+")]);
+ }
+
+ #[test]
+ fn test_url_without_authority() {
+ let url = ~"mailto:test@email.com";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_encode() {
+ assert_eq!(encode(""), ~"");
+ assert_eq!(encode("http://example.com"), ~"http://example.com");
+ assert_eq!(encode("foo bar% baz"), ~"foo%20bar%25%20baz");
+ assert_eq!(encode(" "), ~"%20");
+ assert_eq!(encode("!"), ~"!");
+ assert_eq!(encode("\""), ~"\"");
+ assert_eq!(encode("#"), ~"#");
+ assert_eq!(encode("$"), ~"$");
+ assert_eq!(encode("%"), ~"%25");
+ assert_eq!(encode("&"), ~"&");
+ assert_eq!(encode("'"), ~"%27");
+ assert_eq!(encode("("), ~"(");
+ assert_eq!(encode(")"), ~")");
+ assert_eq!(encode("*"), ~"*");
+ assert_eq!(encode("+"), ~"+");
+ assert_eq!(encode(","), ~",");
+ assert_eq!(encode("/"), ~"/");
+ assert_eq!(encode(":"), ~":");
+ assert_eq!(encode(";"), ~";");
+ assert_eq!(encode("="), ~"=");
+ assert_eq!(encode("?"), ~"?");
+ assert_eq!(encode("@"), ~"@");
+ assert_eq!(encode("["), ~"[");
+ assert_eq!(encode("]"), ~"]");
+ }
+
+ #[test]
+ fn test_encode_component() {
+ assert_eq!(encode_component(""), ~"");
+ assert!(encode_component("http://example.com") ==
+ ~"http%3A%2F%2Fexample.com");
+ assert!(encode_component("foo bar% baz") ==
+ ~"foo%20bar%25%20baz");
+ assert_eq!(encode_component(" "), ~"%20");
+ assert_eq!(encode_component("!"), ~"%21");
+ assert_eq!(encode_component("#"), ~"%23");
+ assert_eq!(encode_component("$"), ~"%24");
+ assert_eq!(encode_component("%"), ~"%25");
+ assert_eq!(encode_component("&"), ~"%26");
+ assert_eq!(encode_component("'"), ~"%27");
+ assert_eq!(encode_component("("), ~"%28");
+ assert_eq!(encode_component(")"), ~"%29");
+ assert_eq!(encode_component("*"), ~"%2A");
+ assert_eq!(encode_component("+"), ~"%2B");
+ assert_eq!(encode_component(","), ~"%2C");
+ assert_eq!(encode_component("/"), ~"%2F");
+ assert_eq!(encode_component(":"), ~"%3A");
+ assert_eq!(encode_component(";"), ~"%3B");
+ assert_eq!(encode_component("="), ~"%3D");
+ assert_eq!(encode_component("?"), ~"%3F");
+ assert_eq!(encode_component("@"), ~"%40");
+ assert_eq!(encode_component("["), ~"%5B");
+ assert_eq!(encode_component("]"), ~"%5D");
+ }
+
+ #[test]
+ fn test_decode() {
+ assert_eq!(decode(""), ~"");
+ assert_eq!(decode("abc/def 123"), ~"abc/def 123");
+ assert_eq!(decode("abc%2Fdef%20123"), ~"abc%2Fdef 123");
+ assert_eq!(decode("%20"), ~" ");
+ assert_eq!(decode("%21"), ~"%21");
+ assert_eq!(decode("%22"), ~"%22");
+ assert_eq!(decode("%23"), ~"%23");
+ assert_eq!(decode("%24"), ~"%24");
+ assert_eq!(decode("%25"), ~"%");
+ assert_eq!(decode("%26"), ~"%26");
+ assert_eq!(decode("%27"), ~"'");
+ assert_eq!(decode("%28"), ~"%28");
+ assert_eq!(decode("%29"), ~"%29");
+ assert_eq!(decode("%2A"), ~"%2A");
+ assert_eq!(decode("%2B"), ~"%2B");
+ assert_eq!(decode("%2C"), ~"%2C");
+ assert_eq!(decode("%2F"), ~"%2F");
+ assert_eq!(decode("%3A"), ~"%3A");
+ assert_eq!(decode("%3B"), ~"%3B");
+ assert_eq!(decode("%3D"), ~"%3D");
+ assert_eq!(decode("%3F"), ~"%3F");
+ assert_eq!(decode("%40"), ~"%40");
+ assert_eq!(decode("%5B"), ~"%5B");
+ assert_eq!(decode("%5D"), ~"%5D");
+ }
+
+ #[test]
+ fn test_decode_component() {
+ assert_eq!(decode_component(""), ~"");
+ assert_eq!(decode_component("abc/def 123"), ~"abc/def 123");
+ assert_eq!(decode_component("abc%2Fdef%20123"), ~"abc/def 123");
+ assert_eq!(decode_component("%20"), ~" ");
+ assert_eq!(decode_component("%21"), ~"!");
+ assert_eq!(decode_component("%22"), ~"\"");
+ assert_eq!(decode_component("%23"), ~"#");
+ assert_eq!(decode_component("%24"), ~"$");
+ assert_eq!(decode_component("%25"), ~"%");
+ assert_eq!(decode_component("%26"), ~"&");
+ assert_eq!(decode_component("%27"), ~"'");
+ assert_eq!(decode_component("%28"), ~"(");
+ assert_eq!(decode_component("%29"), ~")");
+ assert_eq!(decode_component("%2A"), ~"*");
+ assert_eq!(decode_component("%2B"), ~"+");
+ assert_eq!(decode_component("%2C"), ~",");
+ assert_eq!(decode_component("%2F"), ~"/");
+ assert_eq!(decode_component("%3A"), ~":");
+ assert_eq!(decode_component("%3B"), ~";");
+ assert_eq!(decode_component("%3D"), ~"=");
+ assert_eq!(decode_component("%3F"), ~"?");
+ assert_eq!(decode_component("%40"), ~"@");
+ assert_eq!(decode_component("%5B"), ~"[");
+ assert_eq!(decode_component("%5D"), ~"]");
+ }
+
+ #[test]
+ fn test_encode_form_urlencoded() {
+ let mut m = HashMap::new();
+ assert_eq!(encode_form_urlencoded(&m), ~"");
+
+ m.insert(~"", ~[]);
+ m.insert(~"foo", ~[]);
+ assert_eq!(encode_form_urlencoded(&m), ~"");
+
+ let mut m = HashMap::new();
+ m.insert(~"foo", ~[~"bar", ~"123"]);
+ assert_eq!(encode_form_urlencoded(&m), ~"foo=bar&foo=123");
+
+ let mut m = HashMap::new();
+ m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]);
+ assert!(encode_form_urlencoded(&m) ==
+ ~"foo+bar=abc&foo+bar=12+%3D+34");
+ }
+
+ #[test]
+ fn test_decode_form_urlencoded() {
+ // FIXME #4449: Commented out because this causes an ICE, but only
+ // on FreeBSD
+ /*
+ assert_eq!(decode_form_urlencoded([]).len(), 0);
+
+ let s = "a=1&foo+bar=abc&foo+bar=12+%3D+34".as_bytes();
+ let form = decode_form_urlencoded(s);
+ assert_eq!(form.len(), 2);
+ assert_eq!(form.get_ref(&~"a"), &~[~"1"]);
+ assert_eq!(form.get_ref(&~"foo bar"), &~[~"abc", ~"12 = 34"]);
+ */
+ }
+}
+++ /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.
-
-/*!
- * Rust bindings to libuv
- *
- * This is the base-module for various levels of bindings to
- * the libuv library.
- *
- * These modules are seeing heavy work, currently, and the final
- * API layout should not be inferred from its current form.
- *
- * This base module currently contains a historical, rust-based
- * implementation of a few libuv operations that hews closely to
- * the patterns of the libuv C-API. It was used, mostly, to explore
- * some implementation details and will most likely be deprecated
- * in the near future.
- *
- * The `ll` module contains low-level mappings for working directly
- * with the libuv C-API.
- *
- * The `hl` module contains a set of tools library developers can
- * use for interacting with an active libuv loop. This modules's
- * API is meant to be used to write high-level,
- * rust-idiomatic abstractions for utilizes libuv's asynchronous IO
- * facilities.
- */
-
-pub use ll = super::uv_ll;
-pub use iotask = uv_iotask;
-pub use global_loop = uv_global_loop;
+++ /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.
-
-//! A process-wide libuv event loop for library use.
-
-
-use iotask = uv_iotask;
-use uv_iotask::{IoTask, spawn_iotask};
-
-use std::comm::Chan;
-use std::option::{Some, None};
-use std::task::task;
-use std::unstable::global::{global_data_clone_create, global_data_clone};
-use std::unstable::weak_task::weaken_task;
-
-/**
- * Race-free helper to get access to a global task where a libuv
- * loop is running.
- *
- * Use `uv::hl::interact` to do operations against the global
- * loop that this function returns.
- *
- * # Return
- *
- * * A `hl::high_level_loop` that encapsulates communication with the global
- * loop.
- */
-pub fn get() -> IoTask {
- return get_monitor_task_gl();
-}
-
-#[doc(hidden)]
-fn get_monitor_task_gl() -> IoTask {
-
- type MonChan = Chan<IoTask>;
-
- struct GlobalIoTask(IoTask);
-
- impl Clone for GlobalIoTask {
- fn clone(&self) -> GlobalIoTask {
- GlobalIoTask((**self).clone())
- }
- }
-
- fn key(_: GlobalIoTask) { }
-
- match unsafe { global_data_clone(key) } {
- Some(GlobalIoTask(iotask)) => iotask,
- None => {
- let iotask: IoTask = spawn_loop();
- let mut installed = false;
- let final_iotask = unsafe {
- do global_data_clone_create(key) {
- installed = true;
- ~GlobalIoTask(iotask.clone())
- }
- };
- if installed {
- let mut task = task();
- task.unlinked();
- do task.spawn {
- unsafe {
- debug!("global monitor task starting");
- // As a weak task the runtime will notify us
- // when to exit
- do weaken_task |weak_exit_po| {
- debug!("global monitor task is weak");
- weak_exit_po.recv();
- iotask::exit(&iotask);
- debug!("global monitor task is unweak");
- };
- debug!("global monitor task exiting");
- }
- }
- } else {
- iotask::exit(&iotask);
- }
-
- match final_iotask {
- GlobalIoTask(iotask) => iotask
- }
- }
- }
-}
-
-fn spawn_loop() -> IoTask {
- let mut builder = task();
-
- do builder.add_wrapper |task_body| {
- let result: ~fn() = || {
- // The I/O loop task also needs to be weak so it doesn't keep
- // the runtime alive
- unsafe {
- do weaken_task |_| {
- debug!("global libuv task is now weak");
- task_body();
-
- // We don't wait for the exit message on weak_exit_po
- // because the monitor task will tell the uv loop when to
- // exit
-
- debug!("global libuv task is leaving weakened state");
- }
- }
- };
- result
- };
-
- builder.unlinked();
- spawn_iotask(builder)
-}
-
-#[cfg(test)]
-mod test {
-
- use get_gl = uv_global_loop::get;
- use uv::iotask;
- use uv::ll;
- use uv_iotask::IoTask;
-
- use std::libc;
- use std::task;
- use std::cast::transmute;
- use std::libc::c_void;
- use std::comm::{stream, SharedChan, Chan};
-
- extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) {
- unsafe {
- let exit_ch_ptr = ll::get_data_for_uv_handle(
- timer_ptr as *libc::c_void);
- let exit_ch = transmute::<*c_void, ~Chan<bool>>(exit_ch_ptr);
- exit_ch.send(true);
- debug!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
- exit_ch_ptr);
- }
- }
- extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
- _status: libc::c_int) {
- unsafe {
- debug!(~"in simple timer cb");
- ll::timer_stop(timer_ptr);
- let hl_loop = &get_gl();
- do iotask::interact(hl_loop) |_loop_ptr| {
- debug!(~"closing timer");
- ll::close(timer_ptr, simple_timer_close_cb);
- debug!(~"about to deref exit_ch_ptr");
- debug!(~"after msg sent on deref'd exit_ch");
- };
- debug!(~"exiting simple timer cb");
- }
- }
-
- fn impl_uv_hl_simple_timer(iotask: &IoTask) {
- unsafe {
- let (exit_po, exit_ch) = stream::<bool>();
- let exit_ch_ptr: *libc::c_void = transmute(~exit_ch);
- debug!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
- exit_ch_ptr);
- let timer_handle = ll::timer_t();
- let timer_ptr: *ll::uv_timer_t = &timer_handle;
- do iotask::interact(iotask) |loop_ptr| {
- debug!(~"user code inside interact loop!!!");
- let init_status = ll::timer_init(loop_ptr, timer_ptr);
- if(init_status == 0i32) {
- ll::set_data_for_uv_handle(
- timer_ptr as *libc::c_void,
- exit_ch_ptr);
- let start_status = ll::timer_start(timer_ptr,
- simple_timer_cb,
- 1u, 0u);
- if(start_status != 0i32) {
- fail!("failure on ll::timer_start()");
- }
- }
- else {
- fail!("failure on ll::timer_init()");
- }
- };
- exit_po.recv();
- debug!(
- ~"global_loop timer test: msg recv on exit_po, done..");
- }
- }
-
- #[test]
- fn test_gl_uv_global_loop_high_level_global_timer() {
- let hl_loop = &get_gl();
- let (exit_po, exit_ch) = stream::<()>();
- task::spawn_sched(task::ManualThreads(1u), || {
- let hl_loop = &get_gl();
- impl_uv_hl_simple_timer(hl_loop);
- exit_ch.send(());
- });
- impl_uv_hl_simple_timer(hl_loop);
- exit_po.recv();
- }
-
- // keeping this test ignored until some kind of stress-test-harness
- // is set up for the build bots
- #[test]
- #[ignore]
- fn test_stress_gl_uv_global_loop_high_level_global_timer() {
- let (exit_po, exit_ch) = stream::<()>();
- let exit_ch = SharedChan::new(exit_ch);
- let cycles = 5000u;
- for cycles.times {
- let exit_ch_clone = exit_ch.clone();
- task::spawn_sched(task::ManualThreads(1u), || {
- let hl_loop = &get_gl();
- impl_uv_hl_simple_timer(hl_loop);
- exit_ch_clone.send(());
- });
- };
- for cycles.times {
- exit_po.recv();
- };
- debug!("test_stress_gl_uv_global_loop_high_level_global_timer \
- exiting successfully!");
- }
-}
+++ /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.
-
-/*!
- * A task-based interface to the uv loop
- *
- * The I/O task runs in its own single-threaded scheduler. By using the
- * `interact` function you can execute code in a uv callback.
- */
-
-#[allow(missing_doc)];
-
-
-use ll = uv_ll;
-
-use std::comm::{stream, Port, Chan, SharedChan};
-use std::libc::c_void;
-use std::libc;
-use std::task;
-
-/// Used to abstract-away direct interaction with a libuv loop.
-pub struct IoTask {
- async_handle: *ll::uv_async_t,
- op_chan: SharedChan<IoTaskMsg>
-}
-
-impl Clone for IoTask {
- fn clone(&self) -> IoTask {
- IoTask{
- async_handle: self.async_handle,
- op_chan: self.op_chan.clone()
- }
- }
-}
-
-pub fn spawn_iotask(mut task: task::TaskBuilder) -> IoTask {
- let (iotask_port, iotask_chan) = stream();
-
- task.sched_mode(task::SingleThreaded);
- do task.spawn {
- debug!("entering libuv task");
- run_loop(&iotask_chan);
- debug!("libuv task exiting");
- };
-
- iotask_port.recv()
-}
-
-
-/**
- * Provide a callback to be processed by `iotask`
- *
- * The primary way to do operations again a running `iotask` that
- * doesn't involve creating a uv handle via `safe_handle`
- *
- * # Warning
- *
- * This function is the only safe way to interact with _any_ `iotask`.
- * Using functions in the `uv::ll` module outside of the `cb` passed into
- * this function is _very dangerous_.
- *
- * # Arguments
- *
- * * iotask - a uv I/O task that you want to do operations against
- * * cb - a function callback to be processed on the running loop's
- * thread. The only parameter passed in is an opaque pointer representing the
- * running `uv_loop_t*`. In the context of this callback, it is safe to use
- * this pointer to do various uv_* API calls contained within the `uv::ll`
- * module. It is not safe to send the `loop_ptr` param to this callback out
- * via ports/chans.
- */
-pub fn interact(iotask: &IoTask, cb: ~fn(*c_void)) {
- send_msg(iotask, Interaction(cb));
-}
-
-/**
- * Shut down the I/O task
- *
- * Is used to signal to the loop that it should close the internally-held
- * async handle and do a sanity check to make sure that all other handles are
- * closed, causing a failure otherwise.
- */
-pub fn exit(iotask: &IoTask) {
- send_msg(iotask, TeardownLoop);
-}
-
-
-// INTERNAL API
-
-enum IoTaskMsg {
- Interaction(~fn(*libc::c_void)),
- TeardownLoop
-}
-
-/// Run the loop and begin handling messages
-fn run_loop(iotask_ch: &Chan<IoTask>) {
-
- unsafe {
- debug!("creating loop");
- let loop_ptr = ll::loop_new();
-
- // set up the special async handle we'll use to allow multi-task
- // communication with this loop
- let async = ll::async_t();
- let async_handle: *ll::uv_async_t = &async;
-
- // associate the async handle with the loop
- ll::async_init(loop_ptr, async_handle, wake_up_cb);
-
- let (msg_po, msg_ch) = stream::<IoTaskMsg>();
-
- // initialize our loop data and store it in the loop
- let data: IoTaskLoopData = IoTaskLoopData {
- async_handle: async_handle,
- msg_po: msg_po
- };
- ll::set_data_for_uv_handle(async_handle, &data);
-
- // Send out a handle through which folks can talk to us
- // while we dwell in the I/O loop
- let iotask = IoTask {
- async_handle: async_handle,
- op_chan: SharedChan::new(msg_ch)
- };
- iotask_ch.send(iotask);
-
- debug!("about to run uv loop");
- // enter the loop... this blocks until the loop is done..
- ll::run(loop_ptr);
- debug!("uv loop ended");
- ll::loop_delete(loop_ptr);
- }
-}
-
-// data that lives for the lifetime of the high-evel oo
-struct IoTaskLoopData {
- async_handle: *ll::uv_async_t,
- msg_po: Port<IoTaskMsg>,
-}
-
-fn send_msg(iotask: &IoTask,
- msg: IoTaskMsg) {
- iotask.op_chan.send(msg);
- unsafe {
- ll::async_send(iotask.async_handle);
- }
-}
-
-/// Dispatch all pending messages
-extern fn wake_up_cb(async_handle: *ll::uv_async_t,
- status: int) {
-
- debug!("wake_up_cb extern.. handle: %? status: %?",
- async_handle, status);
-
- unsafe {
- let loop_ptr = ll::get_loop_for_uv_handle(async_handle);
- let data =
- ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData;
- let msg_po = &(*data).msg_po;
-
- while msg_po.peek() {
- match msg_po.recv() {
- Interaction(ref cb) => (*cb)(loop_ptr),
- TeardownLoop => begin_teardown(data)
- }
- }
- }
-}
-
-fn begin_teardown(data: *IoTaskLoopData) {
- unsafe {
- debug!("iotask begin_teardown() called, close async_handle");
- let async_handle = (*data).async_handle;
- ll::close(async_handle as *c_void, tear_down_close_cb);
- }
-}
-extern fn tear_down_walk_cb(handle: *libc::c_void, arg: *libc::c_void) {
- debug!("IN TEARDOWN WALK CB");
- // pretty much, if we still have an active handle and it is *not*
- // the async handle that facilities global loop communication, we
- // want to barf out and fail
- assert_eq!(handle, arg);
-}
-
-extern fn tear_down_close_cb(handle: *ll::uv_async_t) {
- unsafe {
- let loop_ptr = ll::get_loop_for_uv_handle(handle);
- debug!("in tear_down_close_cb");
- ll::walk(loop_ptr, tear_down_walk_cb, handle as *libc::c_void);
- }
-}
-
-#[cfg(test)]
-extern fn async_close_cb(handle: *ll::uv_async_t) {
- unsafe {
- debug!("async_close_cb handle %?", handle);
- let exit_ch = &(*(ll::get_data_for_uv_handle(handle)
- as *AhData)).exit_ch;
- let exit_ch = exit_ch.clone();
- exit_ch.send(());
- }
-}
-
-#[cfg(test)]
-extern fn async_handle_cb(handle: *ll::uv_async_t, status: libc::c_int) {
- unsafe {
- debug!("async_handle_cb handle %? status %?",handle,status);
- ll::close(handle, async_close_cb);
- }
-}
-
-#[cfg(test)]
-struct AhData {
- iotask: IoTask,
- exit_ch: SharedChan<()>
-}
-
-#[cfg(test)]
-fn impl_uv_iotask_async(iotask: &IoTask) {
- use std::ptr;
-
- let async_handle = ll::async_t();
- let ah_ptr: *ll::uv_async_t = &async_handle;
- let (exit_po, exit_ch) = stream::<()>();
- let ah_data = AhData {
- iotask: iotask.clone(),
- exit_ch: SharedChan::new(exit_ch)
- };
- let ah_data_ptr: *AhData = ptr::to_unsafe_ptr(&ah_data);
- debug!("about to interact");
- do interact(iotask) |loop_ptr| {
- unsafe {
- debug!("interacting");
- ll::async_init(loop_ptr, ah_ptr, async_handle_cb);
- ll::set_data_for_uv_handle(
- ah_ptr, ah_data_ptr as *libc::c_void);
- ll::async_send(ah_ptr);
- }
- };
- debug!("waiting for async close");
- exit_po.recv();
-}
-
-// this fn documents the bear minimum necessary to roll your own
-// high_level_loop
-#[cfg(test)]
-fn spawn_test_loop(exit_ch: ~Chan<()>) -> IoTask {
- let (iotask_port, iotask_ch) = stream::<IoTask>();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("about to run a test loop");
- run_loop(&iotask_ch);
- exit_ch.send(());
- };
- return iotask_port.recv();
-}
-
-#[cfg(test)]
-extern fn lifetime_handle_close(handle: *libc::c_void) {
- debug!("lifetime_handle_close ptr %?", handle);
-}
-
-#[cfg(test)]
-extern fn lifetime_async_callback(handle: *libc::c_void,
- status: libc::c_int) {
- debug!("lifetime_handle_close ptr %? status %?",
- handle, status);
-}
-
-#[test]
-fn test_uv_iotask_async() {
- let (exit_po, exit_ch) = stream::<()>();
- let iotask = &spawn_test_loop(~exit_ch);
-
- debug!("spawned iotask");
-
- // using this handle to manage the lifetime of the
- // high_level_loop, as it will exit the first time one of
- // the impl_uv_hl_async() is cleaned up with no one ref'd
- // handles on the loop (Which can happen under
- // race-condition type situations.. this ensures that the
- // loop lives until, at least, all of the
- // impl_uv_hl_async() runs have been called, at least.
- let (work_exit_po, work_exit_ch) = stream::<()>();
- let work_exit_ch = SharedChan::new(work_exit_ch);
- for 7u.times {
- let iotask_clone = iotask.clone();
- let work_exit_ch_clone = work_exit_ch.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("async");
- impl_uv_iotask_async(&iotask_clone);
- debug!("done async");
- work_exit_ch_clone.send(());
- };
- };
- for 7u.times {
- debug!("waiting");
- work_exit_po.recv();
- };
- debug!(~"sending teardown_loop msg..");
- exit(iotask);
- exit_po.recv();
- debug!(~"after recv on exit_po.. exiting..");
-}
+++ /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.
-
-/*!
- * Low-level bindings to the libuv library.
- *
- * This module contains a set of direct, 'bare-metal' wrappers around
- * the libuv C-API.
- *
- * Also contained herein are a set of rust records that map, in
- * approximate memory-size, to the libuv data structures. The record
- * implementations are adjusted, per-platform, to match their respective
- * representations.
- *
- * There are also a collection of helper functions to ease interacting
- * with the low-level API (such as a function to return the latest
- * libuv error as a rust-formatted string).
- *
- * As new functionality, existant in uv.h, is added to the rust stdlib,
- * the mappings should be added in this module.
- *
- * This module's implementation will hopefully be, eventually, replaced
- * with per-platform, generated source files from rust-bindgen.
- */
-
-#[allow(non_camel_case_types)]; // C types
-#[allow(missing_doc)];
-
-
-use std::libc::{c_void, size_t};
-use std::libc;
-use std::ptr::to_unsafe_ptr;
-use std::ptr;
-use std::str;
-use std::vec;
-
-pub type uv_handle_t = c_void;
-pub type uv_loop_t = c_void;
-pub type uv_idle_t = c_void;
-pub type uv_idle_cb = *u8;
-
-// libuv struct mappings
-pub struct uv_ip4_addr {
- ip: ~[u8],
- port: int,
-}
-pub type uv_ip6_addr = uv_ip4_addr;
-
-pub enum uv_handle_type {
- UNKNOWN_HANDLE = 0,
- UV_TCP,
- UV_UDP,
- UV_NAMED_PIPE,
- UV_TTY,
- UV_FILE,
- UV_TIMER,
- UV_PREPARE,
- UV_CHECK,
- UV_IDLE,
- UV_ASYNC,
- UV_ARES_TASK,
- UV_ARES_EVENT,
- UV_PROCESS,
- UV_FS_EVENT
-}
-
-pub type handle_type = libc::c_uint;
-
-pub struct uv_handle_fields {
- loop_handle: *libc::c_void,
- type_: handle_type,
- close_cb: *u8,
- data: *libc::c_void,
-}
-
-// unix size: 8
-pub struct uv_err_t {
- code: libc::c_int,
- sys_errno_: libc::c_int
-}
-
-// don't create one of these directly. instead,
-// count on it appearing in libuv callbacks or embedded
-// in other types as a pointer to be used in other
-// operations (so mostly treat it as opaque, once you
-// have it in this form..)
-pub struct uv_stream_t {
- fields: uv_handle_fields,
-}
-
-// 64bit unix size: 216
-#[cfg(target_os="macos")]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8, a22: *u8,
- a23: uv_tcp_t_osx_riders
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_tcp_t_osx_riders {
- a23: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-pub struct uv_tcp_t_osx_riders {
- a23: *u8,
- a24: *u8, a25: *u8,
-}
-#[cfg(target_os="linux")]
-#[cfg(target_os="freebsd")]
-#[cfg(target_os="android")]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8,
- a22: uv_tcp_t_32bit_unix_riders,
-}
-// 32bit unix size: 328 (164)
-#[cfg(target_arch="x86_64")]
-pub struct uv_tcp_t_32bit_unix_riders {
- a29: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_tcp_t_32bit_unix_riders {
- a29: *u8, a30: *u8, a31: *u8,
-}
-
-// 32bit win32 size: 240 (120)
-#[cfg(windows)]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8, a22: *u8, a23: *u8,
- a24: *u8, a25: *u8,
-}
-
-// unix size: 64
-#[cfg(unix)]
-pub struct uv_connect_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8
-}
-// win32 size: 88 (44)
-#[cfg(windows)]
-pub struct uv_connect_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8,
-}
-
-// unix size: 16
-pub struct uv_buf_t {
- base: *u8,
- len: libc::size_t,
-}
-// no gen stub method.. should create
-// it via uv::direct::buf_init()
-
-// unix size: 160
-#[cfg(unix)]
-pub struct uv_write_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
- a14: uv_write_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_write_t_32bit_unix_riders {
- a13: *u8, a14: *u8, a15: *u8
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_write_t_32bit_unix_riders {
- a13: *u8, a14: *u8, a15: *u8,
- a16: *u8,
-}
-// win32 size: 136 (68)
-#[cfg(windows)]
-pub struct uv_write_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
-}
-// 64bit unix size: 96
-// 32bit unix size: 152 (76)
-#[cfg(unix)]
-pub struct uv_async_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8,
- a07: uv_async_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_async_t_32bit_unix_riders {
- a10: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_async_t_32bit_unix_riders {
- a10: *u8,
-}
-// win32 size 132 (68)
-#[cfg(windows)]
-pub struct uv_async_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
-}
-
-// 64bit unix size: 120
-// 32bit unix size: 84
-#[cfg(unix)]
-pub struct uv_timer_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8,
- a11: uv_timer_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_timer_t_32bit_unix_riders {
- a10: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_timer_t_32bit_unix_riders {
- a10: *u8, a11: *u8, a12: *u8
-}
-// win32 size: 64
-#[cfg(windows)]
-pub struct uv_timer_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
-}
-
-// unix size: 16
-#[deriving(Clone)]
-pub struct sockaddr_in {
- sin_family: u16,
- sin_port: u16,
- sin_addr: u32, // in_addr: this is an opaque, per-platform struct
- sin_zero: (u8, u8, u8, u8, u8, u8, u8, u8),
-}
-
-// unix size: 28 .. FIXME #1645
-// stuck with 32 because of rust padding structs?
-#[cfg(target_arch="x86_64")]
-pub struct sockaddr_in6 {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
-}
-
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct sockaddr_in6 {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- a4: *u8, a5: *u8,
- a6: *u8, a7: *u8,
-}
-
-impl Clone for sockaddr_in6 {
- fn clone(&self) -> sockaddr_in6 {
- *self
- }
-}
-
-// unix size: 28 .. FIXME #1645
-// stuck with 32 because of rust padding structs?
-pub type addr_in = addr_in_impl::addr_in;
-#[cfg(unix)]
-pub mod addr_in_impl {
- #[cfg(target_arch="x86_64")]
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- a4: *u8, a5: *u8,
- a6: *u8, a7: *u8,
- }
-}
-#[cfg(windows)]
-pub mod addr_in_impl {
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- }
-}
-
-// unix size: 48, 32bit: 32
-pub type addrinfo = addrinfo_impl::addrinfo;
-#[cfg(target_os="linux")]
-#[cfg(target_os="android")]
-pub mod addrinfo_impl {
- #[cfg(target_arch="x86_64")]
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- }
-}
-#[cfg(target_os="macos")]
-#[cfg(target_os="freebsd")]
-pub mod addrinfo_impl {
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
-}
-#[cfg(windows)]
-pub mod addrinfo_impl {
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
-}
-
-// unix size: 72
-pub struct uv_getaddrinfo_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8, a04: *u8, a05: *u8,
- a06: *u8, a07: *u8, a08: *u8, a09: *u8,
- a10: *u8, a11: *u8, a12: *u8, a13: *u8, a14: *u8, a15: *u8
-}
-
-pub mod uv_ll_struct_stubgen {
-
- use std::ptr;
-
- use super::{
- uv_async_t,
- uv_connect_t,
- uv_getaddrinfo_t,
- uv_handle_fields,
- uv_tcp_t,
- uv_timer_t,
- uv_write_t,
- };
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "macos")]
- #[cfg(target_os = "freebsd")]
- use super::{
- uv_async_t_32bit_unix_riders,
- uv_timer_t_32bit_unix_riders,
- uv_write_t_32bit_unix_riders,
- };
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "freebsd")]
- use super::uv_tcp_t_32bit_unix_riders;
-
- pub fn gen_stub_uv_tcp_t() -> uv_tcp_t {
- return gen_stub_os();
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "freebsd")]
- pub fn gen_stub_os() -> uv_tcp_t {
- return gen_stub_arch();
- #[cfg(target_arch="x86_64")]
- pub fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8,
- a22: uv_tcp_t_32bit_unix_riders { a29: 0 as *u8 },
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8,
- a22: uv_tcp_t_32bit_unix_riders {
- a29: 0 as *u8, a30: 0 as *u8, a31: 0 as *u8,
- },
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_os() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: 0 as *u8,
- a24: 0 as *u8, a25: 0 as *u8,
- }
- }
- #[cfg(target_os = "macos")]
- pub fn gen_stub_os() -> uv_tcp_t {
- use super::uv_tcp_t_osx_riders;
-
- return gen_stub_arch();
-
- #[cfg(target_arch = "x86_64")]
- fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: uv_tcp_t_osx_riders {
- a23: 0 as *u8,
- }
- }
- }
-
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch = "arm")]
- fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: uv_tcp_t_osx_riders {
- a23: 0 as *u8,
- a24: 0 as *u8, a25: 0 as *u8,
- }
- }
- }
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_connect_t() -> uv_connect_t {
- uv_connect_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_connect_t() -> uv_connect_t {
- uv_connect_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_async_t() -> uv_async_t {
- return gen_stub_arch();
- #[cfg(target_arch = "x86_64")]
- pub fn gen_stub_arch() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: uv_async_t_32bit_unix_riders { a10: 0 as *u8 },
- }
- }
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: uv_async_t_32bit_unix_riders {
- a10: 0 as *u8,
- }
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_async_t() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_timer_t() -> uv_timer_t {
- return gen_stub_arch();
- #[cfg(target_arch = "x86_64")]
- pub fn gen_stub_arch() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a11: uv_timer_t_32bit_unix_riders {
- a10: 0 as *u8
- },
- }
- }
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a11: uv_timer_t_32bit_unix_riders {
- a10: 0 as *u8, a11: 0 as *u8,
- a12: 0 as *u8,
- },
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_timer_t() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_write_t() -> uv_write_t {
- return gen_stub_arch();
- #[cfg(target_arch="x86_64")]
- pub fn gen_stub_arch() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- a14: uv_write_t_32bit_unix_riders { a13: 0 as *u8,
- a14: 0 as *u8,
- a15: 0 as *u8},
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- a14: uv_write_t_32bit_unix_riders {
- a13: 0 as *u8,
- a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8,
- }
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_write_t() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8
- }
- }
- pub fn gen_stub_uv_getaddrinfo_t() -> uv_getaddrinfo_t {
- uv_getaddrinfo_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a10: 1 as *u8, a11: 1 as *u8, a12: 1 as *u8, a13: 1 as *u8,
- a14: 1 as *u8, a15: 1 as *u8
- }
- }
-}
-
-#[nolink]
-extern {
- // libuv public API
- unsafe fn rust_uv_loop_new() -> *libc::c_void;
- unsafe fn rust_uv_loop_delete(lp: *libc::c_void);
- unsafe fn rust_uv_run(loop_handle: *libc::c_void);
- unsafe fn rust_uv_close(handle: *libc::c_void, cb: *u8);
- unsafe fn rust_uv_walk(loop_handle: *libc::c_void, cb: *u8,
- arg: *libc::c_void);
-
- unsafe fn rust_uv_idle_new() -> *uv_idle_t;
- unsafe fn rust_uv_idle_delete(handle: *uv_idle_t);
- unsafe fn rust_uv_idle_init(loop_handle: *uv_loop_t,
- handle: *uv_idle_t) -> libc::c_int;
- unsafe fn rust_uv_idle_start(handle: *uv_idle_t,
- cb: uv_idle_cb) -> libc::c_int;
- unsafe fn rust_uv_idle_stop(handle: *uv_idle_t) -> libc::c_int;
-
- unsafe fn rust_uv_async_send(handle: *uv_async_t);
- unsafe fn rust_uv_async_init(loop_handle: *libc::c_void,
- async_handle: *uv_async_t,
- cb: *u8) -> libc::c_int;
- unsafe fn rust_uv_tcp_init(
- loop_handle: *libc::c_void,
- handle_ptr: *uv_tcp_t) -> libc::c_int;
- // FIXME ref #2604 .. ?
- unsafe fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8,
- len: libc::size_t);
- unsafe fn rust_uv_last_error(loop_handle: *libc::c_void) -> uv_err_t;
- // FIXME ref #2064
- unsafe fn rust_uv_strerror(err: *uv_err_t) -> *libc::c_char;
- // FIXME ref #2064
- unsafe fn rust_uv_err_name(err: *uv_err_t) -> *libc::c_char;
- unsafe fn rust_uv_ip4_addr(ip: *u8, port: libc::c_int)
- -> sockaddr_in;
- unsafe fn rust_uv_ip6_addr(ip: *u8, port: libc::c_int)
- -> sockaddr_in6;
- unsafe fn rust_uv_ip4_name(src: *sockaddr_in,
- dst: *u8,
- size: libc::size_t)
- -> libc::c_int;
- unsafe fn rust_uv_ip6_name(src: *sockaddr_in6,
- dst: *u8,
- size: libc::size_t)
- -> libc::c_int;
- unsafe fn rust_uv_ip4_port(src: *sockaddr_in) -> libc::c_uint;
- unsafe fn rust_uv_ip6_port(src: *sockaddr_in6) -> libc::c_uint;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- after_cb: *u8,
- addr: *sockaddr_in)
- -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t,
- addr: *sockaddr_in) -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- after_cb: *u8,
- addr: *sockaddr_in6) -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t,
- addr: *sockaddr_in6) -> libc::c_int;
- unsafe fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in) -> libc::c_int;
- unsafe fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in6) ->libc::c_int;
- unsafe fn rust_uv_listen(stream: *libc::c_void,
- backlog: libc::c_int,
- cb: *u8) -> libc::c_int;
- unsafe fn rust_uv_accept(server: *libc::c_void, client: *libc::c_void)
- -> libc::c_int;
- unsafe fn rust_uv_write(req: *libc::c_void,
- stream: *libc::c_void,
- buf_in: *uv_buf_t,
- buf_cnt: libc::c_int,
- cb: *u8)
- -> libc::c_int;
- unsafe fn rust_uv_read_start(stream: *libc::c_void,
- on_alloc: *u8,
- on_read: *u8)
- -> libc::c_int;
- unsafe fn rust_uv_read_stop(stream: *libc::c_void) -> libc::c_int;
- unsafe fn rust_uv_timer_init(loop_handle: *libc::c_void,
- timer_handle: *uv_timer_t)
- -> libc::c_int;
- unsafe fn rust_uv_timer_start(
- timer_handle: *uv_timer_t,
- cb: *u8,
- timeout: libc::uint64_t,
- repeat: libc::uint64_t) -> libc::c_int;
- unsafe fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int;
-
- unsafe fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void,
- handle: *uv_getaddrinfo_t,
- cb: *u8,
- node_name_ptr: *u8,
- service_name_ptr: *u8,
- // should probably only pass ptr::null()
- hints: *addrinfo)
- -> libc::c_int;
- unsafe fn rust_uv_freeaddrinfo(res: *addrinfo);
-
- // data accessors/helpers for rust-mapped uv structs
- unsafe fn rust_uv_helper_get_INADDR_NONE() -> u32;
- unsafe fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool;
- unsafe fn rust_uv_is_ipv6_addrinfo(input: *addrinfo) -> bool;
- unsafe fn rust_uv_get_next_addrinfo(input: *addrinfo) -> *addrinfo;
- unsafe fn rust_uv_addrinfo_as_sockaddr_in(input: *addrinfo)
- -> *sockaddr_in;
- unsafe fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo)
- -> *sockaddr_in6;
- unsafe fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8;
- unsafe fn rust_uv_free_base_of_buf(buf: uv_buf_t);
- unsafe fn rust_uv_get_stream_handle_from_connect_req(
- connect_req: *uv_connect_t)
- -> *uv_stream_t;
- unsafe fn rust_uv_get_stream_handle_from_write_req(
- write_req: *uv_write_t)
- -> *uv_stream_t;
- unsafe fn rust_uv_get_loop_for_uv_handle(handle: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_get_data_for_uv_loop(loop_ptr: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_uv_loop(loop_ptr: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_data_for_uv_handle(handle: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_uv_handle(handle: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_data_for_req(req: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_req(req: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
- unsafe fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> libc::size_t;
-
- // sizeof testing helpers
- unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_connect_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_buf_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_write_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_err_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_sockaddr_in_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_sockaddr_in6_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_async_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_timer_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_getaddrinfo_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_addrinfo_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_addr_in_size() -> libc::c_uint;
-}
-
-pub unsafe fn loop_new() -> *libc::c_void {
- return rust_uv_loop_new();
-}
-
-pub unsafe fn loop_delete(loop_handle: *libc::c_void) {
- rust_uv_loop_delete(loop_handle);
-}
-
-pub unsafe fn run(loop_handle: *libc::c_void) {
- rust_uv_run(loop_handle);
-}
-
-pub unsafe fn close<T>(handle: *T, cb: *u8) {
- rust_uv_close(handle as *libc::c_void, cb);
-}
-
-pub unsafe fn walk(loop_handle: *libc::c_void, cb: *u8, arg: *libc::c_void) {
- rust_uv_walk(loop_handle, cb, arg);
-}
-
-pub unsafe fn idle_new() -> *uv_idle_t {
- rust_uv_idle_new()
-}
-
-pub unsafe fn idle_delete(handle: *uv_idle_t) {
- rust_uv_idle_delete(handle)
-}
-
-pub unsafe fn idle_init(loop_handle: *uv_loop_t,
- handle: *uv_idle_t) -> libc::c_int {
- rust_uv_idle_init(loop_handle, handle)
-}
-
-pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> libc::c_int {
- rust_uv_idle_start(handle, cb)
-}
-
-pub unsafe fn idle_stop(handle: *uv_idle_t) -> libc::c_int {
- rust_uv_idle_stop(handle)
-}
-
-pub unsafe fn tcp_init(loop_handle: *libc::c_void, handle: *uv_tcp_t)
- -> libc::c_int {
- return rust_uv_tcp_init(loop_handle, handle);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in,
- after_connect_cb: *u8)
--> libc::c_int {
- return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr,
- after_connect_cb, addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in6,
- after_connect_cb: *u8)
--> libc::c_int {
- return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr,
- after_connect_cb, addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in) -> libc::c_int {
- return rust_uv_tcp_bind(tcp_server_ptr,
- addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in6) -> libc::c_int {
- return rust_uv_tcp_bind6(tcp_server_ptr,
- addr_ptr);
-}
-
-pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in) -> libc::c_int {
- return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
-}
-
-pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in6) ->libc::c_int {
- return rust_uv_tcp_getpeername6(tcp_handle_ptr, name);
-}
-
-pub unsafe fn listen<T>(stream: *T, backlog: libc::c_int,
- cb: *u8) -> libc::c_int {
- return rust_uv_listen(stream as *libc::c_void, backlog, cb);
-}
-
-pub unsafe fn accept(server: *libc::c_void, client: *libc::c_void)
- -> libc::c_int {
- return rust_uv_accept(server as *libc::c_void,
- client as *libc::c_void);
-}
-
-pub unsafe fn write<T>(req: *uv_write_t, stream: *T,
- buf_in: *~[uv_buf_t], cb: *u8) -> libc::c_int {
- let buf_ptr = vec::raw::to_ptr(*buf_in);
- let buf_cnt = (*buf_in).len() as i32;
- return rust_uv_write(req as *libc::c_void,
- stream as *libc::c_void,
- buf_ptr, buf_cnt, cb);
-}
-pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8,
- on_read: *u8) -> libc::c_int {
- return rust_uv_read_start(stream as *libc::c_void,
- on_alloc, on_read);
-}
-
-pub unsafe fn read_stop(stream: *uv_stream_t) -> libc::c_int {
- return rust_uv_read_stop(stream as *libc::c_void);
-}
-
-pub unsafe fn last_error(loop_handle: *libc::c_void) -> uv_err_t {
- return rust_uv_last_error(loop_handle);
-}
-
-pub unsafe fn strerror(err: *uv_err_t) -> *libc::c_char {
- return rust_uv_strerror(err);
-}
-pub unsafe fn err_name(err: *uv_err_t) -> *libc::c_char {
- return rust_uv_err_name(err);
-}
-
-pub unsafe fn async_init(loop_handle: *libc::c_void,
- async_handle: *uv_async_t,
- cb: *u8) -> libc::c_int {
- return rust_uv_async_init(loop_handle,
- async_handle,
- cb);
-}
-
-pub unsafe fn async_send(async_handle: *uv_async_t) {
- return rust_uv_async_send(async_handle);
-}
-pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
- let out_buf = uv_buf_t { base: ptr::null(), len: 0 as libc::size_t };
- let out_buf_ptr: *uv_buf_t = &out_buf;
- rust_uv_buf_init(out_buf_ptr, input, len as size_t);
- return out_buf;
-}
-pub unsafe fn ip4_addr(ip: &str, port: int) -> sockaddr_in {
- do str::as_c_str(ip) |ip_buf| {
- rust_uv_ip4_addr(ip_buf as *u8,
- port as libc::c_int)
- }
-}
-pub unsafe fn ip6_addr(ip: &str, port: int) -> sockaddr_in6 {
- do str::as_c_str(ip) |ip_buf| {
- rust_uv_ip6_addr(ip_buf as *u8,
- port as libc::c_int)
- }
-}
-pub unsafe fn ip4_name(src: &sockaddr_in) -> ~str {
- // ipv4 addr max size: 15 + 1 trailing null byte
- let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
- do dst.as_imm_buf |dst_buf, size| {
- rust_uv_ip4_name(to_unsafe_ptr(src),
- dst_buf, size as libc::size_t);
- // seems that checking the result of uv_ip4_name
- // doesn't work too well..
- // you're stuck looking at the value of dst_buf
- // to see if it is the string representation of
- // INADDR_NONE (0xffffffff or 255.255.255.255 on
- // many platforms)
- str::raw::from_buf(dst_buf)
- }
-}
-pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str {
- // ipv6 addr max size: 45 + 1 trailing null byte
- let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8];
- do dst.as_imm_buf |dst_buf, size| {
- let src_unsafe_ptr = to_unsafe_ptr(src);
- let result = rust_uv_ip6_name(src_unsafe_ptr,
- dst_buf, size as libc::size_t);
- match result {
- 0i32 => str::raw::from_buf(dst_buf),
- _ => ~""
- }
- }
-}
-pub unsafe fn ip4_port(src: &sockaddr_in) -> uint {
- rust_uv_ip4_port(to_unsafe_ptr(src)) as uint
-}
-pub unsafe fn ip6_port(src: &sockaddr_in6) -> uint {
- rust_uv_ip6_port(to_unsafe_ptr(src)) as uint
-}
-
-pub unsafe fn timer_init(loop_ptr: *libc::c_void,
- timer_ptr: *uv_timer_t) -> libc::c_int {
- return rust_uv_timer_init(loop_ptr, timer_ptr);
-}
-pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint,
- repeat: uint) -> libc::c_int {
- return rust_uv_timer_start(timer_ptr, cb, timeout as libc::uint64_t,
- repeat as libc::uint64_t);
-}
-pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int {
- return rust_uv_timer_stop(timer_ptr);
-}
-pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void,
- handle: *uv_getaddrinfo_t,
- cb: *u8,
- node_name_ptr: *u8,
- service_name_ptr: *u8,
- hints: *addrinfo) -> libc::c_int {
- rust_uv_getaddrinfo(loop_ptr,
- handle,
- cb,
- node_name_ptr,
- service_name_ptr,
- hints)
-}
-pub unsafe fn freeaddrinfo(res: *addrinfo) {
- rust_uv_freeaddrinfo(res);
-}
-
-// libuv struct initializers
-pub fn tcp_t() -> uv_tcp_t {
- return uv_ll_struct_stubgen::gen_stub_uv_tcp_t();
-}
-pub fn connect_t() -> uv_connect_t {
- return uv_ll_struct_stubgen::gen_stub_uv_connect_t();
-}
-pub fn write_t() -> uv_write_t {
- return uv_ll_struct_stubgen::gen_stub_uv_write_t();
-}
-pub fn async_t() -> uv_async_t {
- return uv_ll_struct_stubgen::gen_stub_uv_async_t();
-}
-pub fn timer_t() -> uv_timer_t {
- return uv_ll_struct_stubgen::gen_stub_uv_timer_t();
-}
-pub fn getaddrinfo_t() -> uv_getaddrinfo_t {
- return uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t();
-}
-
-// data access helpers
-pub unsafe fn get_loop_for_uv_handle<T>(handle: *T)
- -> *libc::c_void {
- return rust_uv_get_loop_for_uv_handle(handle as *libc::c_void);
-}
-pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t)
- -> *uv_stream_t {
- return rust_uv_get_stream_handle_from_connect_req(
- connect);
-}
-pub unsafe fn get_stream_handle_from_write_req(
- write_req: *uv_write_t)
- -> *uv_stream_t {
- return rust_uv_get_stream_handle_from_write_req(
- write_req);
-}
-pub unsafe fn get_data_for_uv_loop(loop_ptr: *libc::c_void) -> *libc::c_void {
- rust_uv_get_data_for_uv_loop(loop_ptr)
-}
-pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void,
- data: *libc::c_void) {
- rust_uv_set_data_for_uv_loop(loop_ptr, data);
-}
-pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *libc::c_void {
- return rust_uv_get_data_for_uv_handle(handle as *libc::c_void);
-}
-pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
- rust_uv_set_data_for_uv_handle(handle as *libc::c_void,
- data as *libc::c_void);
-}
-pub unsafe fn get_data_for_req<T>(req: *T) -> *libc::c_void {
- return rust_uv_get_data_for_req(req as *libc::c_void);
-}
-pub unsafe fn set_data_for_req<T, U>(req: *T,
- data: *U) {
- rust_uv_set_data_for_req(req as *libc::c_void,
- data as *libc::c_void);
-}
-pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
- return rust_uv_get_base_from_buf(buf);
-}
-pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> libc::size_t {
- return rust_uv_get_len_from_buf(buf);
-}
-pub unsafe fn malloc_buf_base_of(suggested_size: libc::size_t)
- -> *u8 {
- return rust_uv_malloc_buf_base_of(suggested_size);
-}
-pub unsafe fn free_base_of_buf(buf: uv_buf_t) {
- rust_uv_free_base_of_buf(buf);
-}
-
-pub unsafe fn get_last_err_info(uv_loop: *libc::c_void) -> ~str {
- let err = last_error(uv_loop);
- let err_ptr: *uv_err_t = &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: *libc::c_void) -> uv_err_data {
- let err = last_error(uv_loop);
- let err_ptr: *uv_err_t = &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,
- err_msg: ~str,
-}
-
-pub unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool {
- rust_uv_is_ipv4_addrinfo(input)
-}
-pub unsafe fn is_ipv6_addrinfo(input: *addrinfo) -> bool {
- rust_uv_is_ipv6_addrinfo(input)
-}
-pub unsafe fn get_INADDR_NONE() -> u32 {
- rust_uv_helper_get_INADDR_NONE()
-}
-pub unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo {
- rust_uv_get_next_addrinfo(input)
-}
-pub unsafe fn addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in {
- rust_uv_addrinfo_as_sockaddr_in(input)
-}
-pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 {
- rust_uv_addrinfo_as_sockaddr_in6(input)
-}
-
-#[cfg(test)]
-mod test {
-
- use super::*;
-
- use std::comm::{SharedChan, stream, GenericChan, GenericPort};
- use std::libc;
- use std::str;
- use std::sys;
- use std::task;
- use std::vec;
-
- enum tcp_read_data {
- tcp_read_eof,
- tcp_read_more(~[u8]),
- tcp_read_error
- }
-
- struct request_wrapper {
- write_req: *uv_write_t,
- req_buf: *~[uv_buf_t],
- read_chan: SharedChan<~str>,
- }
-
- extern fn after_close_cb(handle: *libc::c_void) {
- debug!("after uv_close! handle ptr: %?",
- handle);
- }
-
- extern fn on_alloc_cb(handle: *libc::c_void,
- suggested_size: libc::size_t)
- -> uv_buf_t {
- unsafe {
- debug!(~"on_alloc_cb!");
- let char_ptr = malloc_buf_base_of(suggested_size);
- debug!("on_alloc_cb h: %? char_ptr: %u sugsize: %u",
- handle,
- char_ptr as uint,
- suggested_size as uint);
- return buf_init(char_ptr, suggested_size as uint);
- }
- }
-
- extern fn on_read_cb(stream: *uv_stream_t,
- nread: libc::ssize_t,
- buf: uv_buf_t) {
- unsafe {
- let nread = nread as int;
- debug!("CLIENT entering on_read_cb nred: %d",
- nread);
- if (nread > 0) {
- // we have data
- debug!("CLIENT read: data! nread: %d", nread);
- read_stop(stream);
- let client_data =
- get_data_for_uv_handle(stream as *libc::c_void)
- as *request_wrapper;
- let buf_base = get_base_from_buf(buf);
- let bytes = vec::from_buf(buf_base, nread as uint);
- let read_chan = (*client_data).read_chan.clone();
- let msg_from_server = str::from_bytes(bytes);
- read_chan.send(msg_from_server);
- close(stream as *libc::c_void, after_close_cb)
- }
- else if (nread == -1) {
- // err .. possibly EOF
- debug!(~"read: eof!");
- }
- else {
- // nread == 0 .. do nothing, just free buf as below
- debug!(~"read: do nothing!");
- }
- // when we're done
- free_base_of_buf(buf);
- debug!(~"CLIENT exiting on_read_cb");
- }
- }
-
- extern fn on_write_complete_cb(write_req: *uv_write_t,
- status: libc::c_int) {
- unsafe {
- debug!(
- "CLIENT beginning on_write_complete_cb status: %d",
- status as int);
- let stream = get_stream_handle_from_write_req(write_req);
- debug!(
- "CLIENT on_write_complete_cb: tcp:%d write_handle:%d",
- stream as int, write_req as int);
- let result = read_start(stream, on_alloc_cb, on_read_cb);
- debug!("CLIENT ending on_write_complete_cb .. status: %d",
- result as int);
- }
- }
-
- extern fn on_connect_cb(connect_req_ptr: *uv_connect_t,
- status: libc::c_int) {
- unsafe {
- debug!("beginning on_connect_cb .. status: %d",
- status as int);
- let stream =
- get_stream_handle_from_connect_req(connect_req_ptr);
- if (status == 0i32) {
- debug!(~"on_connect_cb: in status=0 if..");
- let client_data = get_data_for_req(
- connect_req_ptr as *libc::c_void)
- as *request_wrapper;
- let write_handle = (*client_data).write_req;
- debug!("on_connect_cb: tcp: %d write_hdl: %d",
- stream as int, write_handle as int);
- let write_result = write(write_handle,
- stream as *libc::c_void,
- (*client_data).req_buf,
- on_write_complete_cb);
- debug!("on_connect_cb: write() status: %d",
- write_result as int);
- }
- else {
- let test_loop = get_loop_for_uv_handle(
- stream as *libc::c_void);
- let err_msg = get_last_err_info(test_loop);
- debug!(err_msg);
- assert!(false);
- }
- debug!(~"finishing on_connect_cb");
- }
- }
-
- fn impl_uv_tcp_request(ip: &str, port: int, req_str: &str,
- client_chan: SharedChan<~str>) {
- unsafe {
- let test_loop = loop_new();
- let tcp_handle = tcp_t();
- let tcp_handle_ptr: *uv_tcp_t = &tcp_handle;
- let connect_handle = connect_t();
- let connect_req_ptr: *uv_connect_t = &connect_handle;
-
- // this is the persistent payload of data that we
- // need to pass around to get this example to work.
- // In C, this would be a malloc'd or stack-allocated
- // struct that we'd cast to a void* and store as the
- // data field in our uv_connect_t struct
- let req_str_bytes = req_str.as_bytes();
- let req_msg_ptr: *u8 = vec::raw::to_ptr(req_str_bytes);
- debug!("req_msg ptr: %u", req_msg_ptr as uint);
- let req_msg = ~[
- buf_init(req_msg_ptr, req_str_bytes.len())
- ];
- // this is the enclosing record, we'll pass a ptr to
- // this to C..
- let write_handle = write_t();
- let write_handle_ptr: *uv_write_t = &write_handle;
- debug!("tcp req: tcp stream: %d write_handle: %d",
- tcp_handle_ptr as int,
- write_handle_ptr as int);
- let client_data = request_wrapper {
- write_req: write_handle_ptr,
- req_buf: &req_msg,
- read_chan: client_chan
- };
-
- let tcp_init_result = tcp_init(test_loop as *libc::c_void,
- tcp_handle_ptr);
- if (tcp_init_result == 0) {
- debug!(~"successful tcp_init_result");
-
- debug!(~"building addr...");
- let addr = ip4_addr(ip, port);
- // FIXME ref #2064
- let addr_ptr: *sockaddr_in = &addr;
- debug!("after build addr in rust. port: %u",
- addr.sin_port as uint);
-
- // this should set up the connection request..
- debug!("b4 call tcp_connect connect cb: %u ",
- on_connect_cb as uint);
- let tcp_connect_result = tcp_connect(connect_req_ptr,
- tcp_handle_ptr,
- addr_ptr,
- on_connect_cb);
- if (tcp_connect_result == 0) {
- // not set the data on the connect_req
- // until its initialized
- set_data_for_req(connect_req_ptr as *libc::c_void,
- &client_data);
- set_data_for_uv_handle(tcp_handle_ptr as *libc::c_void,
- &client_data);
- debug!(~"before run tcp req loop");
- run(test_loop);
- debug!(~"after run tcp req loop");
- }
- else {
- debug!(~"tcp_connect() failure");
- assert!(false);
- }
- }
- else {
- debug!(~"tcp_init() failure");
- assert!(false);
- }
- loop_delete(test_loop);
- }
- }
-
- extern fn server_after_close_cb(handle: *libc::c_void) {
- debug!("SERVER server stream closed, should exit. h: %?",
- handle);
- }
-
- extern fn client_stream_after_close_cb(handle: *libc::c_void) {
- unsafe {
- debug!(~"SERVER: closed client stream, now closing server stream");
- let client_data = get_data_for_uv_handle(
- handle) as
- *tcp_server_data;
- close((*client_data).server as *libc::c_void,
- server_after_close_cb);
- }
- }
-
- extern fn after_server_resp_write(req: *uv_write_t) {
- unsafe {
- let client_stream_ptr =
- get_stream_handle_from_write_req(req);
- debug!(~"SERVER: resp sent... closing client stream");
- close(client_stream_ptr as *libc::c_void,
- client_stream_after_close_cb)
- }
- }
-
- extern fn on_server_read_cb(client_stream_ptr: *uv_stream_t,
- nread: libc::ssize_t,
- buf: uv_buf_t) {
- unsafe {
- let nread = nread as int;
- if (nread > 0) {
- // we have data
- debug!("SERVER read: data! nread: %d", nread);
-
- // pull out the contents of the write from the client
- let buf_base = get_base_from_buf(buf);
- let buf_len = get_len_from_buf(buf) as uint;
- debug!("SERVER buf base: %u, len: %u, nread: %d",
- buf_base as uint,
- buf_len as uint,
- nread);
- let bytes = vec::from_buf(buf_base, nread as uint);
- let request_str = str::from_bytes(bytes);
-
- let client_data = get_data_for_uv_handle(
- client_stream_ptr as *libc::c_void) as *tcp_server_data;
-
- let server_kill_msg = (*client_data).server_kill_msg.clone();
- let write_req = (*client_data).server_write_req;
- if request_str.contains(server_kill_msg) {
- debug!(~"SERVER: client req contains kill_msg!");
- debug!(~"SERVER: sending response to client");
- read_stop(client_stream_ptr);
- let server_chan = (*client_data).server_chan.clone();
- server_chan.send(request_str);
- let write_result = write(
- write_req,
- client_stream_ptr as *libc::c_void,
- (*client_data).server_resp_buf,
- after_server_resp_write);
- debug!("SERVER: resp write result: %d",
- write_result as int);
- if (write_result != 0i32) {
- debug!(~"bad result for server resp write()");
- debug!(get_last_err_info(
- get_loop_for_uv_handle(client_stream_ptr
- as *libc::c_void)));
- assert!(false);
- }
- }
- else {
- debug!(~"SERVER: client req !contain kill_msg!");
- }
- }
- else if (nread == -1) {
- // err .. possibly EOF
- debug!(~"read: eof!");
- }
- else {
- // nread == 0 .. do nothing, just free buf as below
- debug!(~"read: do nothing!");
- }
- // when we're done
- free_base_of_buf(buf);
- debug!(~"SERVER exiting on_read_cb");
- }
- }
-
- extern fn server_connection_cb(server_stream_ptr:
- *uv_stream_t,
- status: libc::c_int) {
- unsafe {
- debug!(~"client connecting!");
- let test_loop = get_loop_for_uv_handle(
- server_stream_ptr as *libc::c_void);
- if status != 0i32 {
- let err_msg = get_last_err_info(test_loop);
- debug!("server_connect_cb: non-zero status: %?",
- err_msg);
- return;
- }
- let server_data = get_data_for_uv_handle(
- server_stream_ptr as *libc::c_void) as *tcp_server_data;
- let client_stream_ptr = (*server_data).client;
- let client_init_result = tcp_init(test_loop,
- client_stream_ptr);
- set_data_for_uv_handle(
- client_stream_ptr as *libc::c_void,
- server_data as *libc::c_void);
- if (client_init_result == 0i32) {
- debug!(~"successfully initialized client stream");
- let accept_result = accept(server_stream_ptr as
- *libc::c_void,
- client_stream_ptr as
- *libc::c_void);
- if (accept_result == 0i32) {
- // start reading
- let read_result = read_start(
- client_stream_ptr as *uv_stream_t,
- on_alloc_cb,
- on_server_read_cb);
- if (read_result == 0i32) {
- debug!(~"successful server read start");
- }
- else {
- debug!("server_connection_cb: bad read:%d",
- read_result as int);
- assert!(false);
- }
- }
- else {
- debug!("server_connection_cb: bad accept: %d",
- accept_result as int);
- assert!(false);
- }
- }
- else {
- debug!("server_connection_cb: bad client init: %d",
- client_init_result as int);
- assert!(false);
- }
- }
- }
-
- struct tcp_server_data {
- client: *uv_tcp_t,
- server: *uv_tcp_t,
- server_kill_msg: ~str,
- server_resp_buf: *~[uv_buf_t],
- server_chan: SharedChan<~str>,
- server_write_req: *uv_write_t,
- }
-
- struct async_handle_data {
- continue_chan: SharedChan<bool>,
- }
-
- extern fn async_close_cb(handle: *libc::c_void) {
- debug!("SERVER: closing async cb... h: %?",
- handle);
- }
-
- extern fn continue_async_cb(async_handle: *uv_async_t,
- status: libc::c_int) {
- unsafe {
- // once we're in the body of this callback,
- // the tcp server's loop is set up, so we
- // can continue on to let the tcp client
- // do its thang
- let data = get_data_for_uv_handle(
- async_handle as *libc::c_void) as *async_handle_data;
- let continue_chan = (*data).continue_chan.clone();
- let should_continue = status == 0i32;
- continue_chan.send(should_continue);
- close(async_handle as *libc::c_void, async_close_cb);
- }
- }
-
- fn impl_uv_tcp_server(server_ip: &str,
- server_port: int,
- kill_server_msg: ~str,
- server_resp_msg: ~str,
- server_chan: SharedChan<~str>,
- continue_chan: SharedChan<bool>) {
- unsafe {
- let test_loop = loop_new();
- let tcp_server = tcp_t();
- let tcp_server_ptr: *uv_tcp_t = &tcp_server;
-
- let tcp_client = tcp_t();
- let tcp_client_ptr: *uv_tcp_t = &tcp_client;
-
- let server_write_req = write_t();
- let server_write_req_ptr: *uv_write_t = &server_write_req;
-
- let resp_str_bytes = server_resp_msg.as_bytes();
- let resp_msg_ptr: *u8 = vec::raw::to_ptr(resp_str_bytes);
- debug!("resp_msg ptr: %u", resp_msg_ptr as uint);
- let resp_msg = ~[
- buf_init(resp_msg_ptr, resp_str_bytes.len())
- ];
-
- let continue_async_handle = async_t();
- let continue_async_handle_ptr: *uv_async_t =
- &continue_async_handle;
- let async_data =
- async_handle_data { continue_chan: continue_chan };
- let async_data_ptr: *async_handle_data = &async_data;
-
- let server_data = tcp_server_data {
- client: tcp_client_ptr,
- server: tcp_server_ptr,
- server_kill_msg: kill_server_msg,
- server_resp_buf: &resp_msg,
- server_chan: server_chan,
- server_write_req: server_write_req_ptr
- };
- let server_data_ptr: *tcp_server_data = &server_data;
- set_data_for_uv_handle(tcp_server_ptr as *libc::c_void,
- server_data_ptr as *libc::c_void);
-
- // uv_tcp_init()
- let tcp_init_result = tcp_init(
- test_loop as *libc::c_void, tcp_server_ptr);
- if (tcp_init_result == 0i32) {
- let server_addr = ip4_addr(server_ip, server_port);
- // FIXME ref #2064
- let server_addr_ptr: *sockaddr_in = &server_addr;
-
- // uv_tcp_bind()
- let bind_result = tcp_bind(tcp_server_ptr, server_addr_ptr);
- if (bind_result == 0i32) {
- debug!(~"successful uv_tcp_bind, listening");
-
- // uv_listen()
- let listen_result = listen(tcp_server_ptr as
- *libc::c_void,
- 128i32,
- server_connection_cb);
- if (listen_result == 0i32) {
- // let the test know it can set up the tcp server,
- // now.. this may still present a race, not sure..
- let async_result = async_init(test_loop,
- continue_async_handle_ptr,
- continue_async_cb);
- if (async_result == 0i32) {
- set_data_for_uv_handle(
- continue_async_handle_ptr as *libc::c_void,
- async_data_ptr as *libc::c_void);
- async_send(continue_async_handle_ptr);
- // uv_run()
- run(test_loop);
- debug!(~"server uv::run() has returned");
- }
- else {
- debug!("uv_async_init failure: %d",
- async_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_listen: %d",
- listen_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_tcp_bind: %d",
- bind_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_tcp_init: %d",
- tcp_init_result as int);
- assert!(false);
- }
- loop_delete(test_loop);
- }
- }
-
- // this is the impl for a test that is (maybe) ran on a
- // per-platform/arch basis below
- pub fn impl_uv_tcp_server_and_request() {
- let bind_ip = ~"0.0.0.0";
- let request_ip = ~"127.0.0.1";
- let port = 8886;
- let kill_server_msg = ~"does a dog have buddha nature?";
- let server_resp_msg = ~"mu!";
- let (client_port, client_chan) = stream::<~str>();
- let client_chan = SharedChan::new(client_chan);
- let (server_port, server_chan) = stream::<~str>();
- let server_chan = SharedChan::new(server_chan);
-
- let (continue_port, continue_chan) = stream::<bool>();
- let continue_chan = SharedChan::new(continue_chan);
-
- let kill_server_msg_copy = kill_server_msg.clone();
- let server_resp_msg_copy = server_resp_msg.clone();
- do task::spawn_sched(task::ManualThreads(1)) {
- impl_uv_tcp_server(bind_ip, port,
- kill_server_msg_copy.clone(),
- server_resp_msg_copy.clone(),
- server_chan.clone(),
- continue_chan.clone());
- };
-
- // block until the server up is.. possibly a race?
- debug!(~"before receiving on server continue_port");
- continue_port.recv();
- debug!(~"received on continue port, set up tcp client");
-
- let kill_server_msg_copy = kill_server_msg.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- impl_uv_tcp_request(request_ip, port,
- kill_server_msg_copy,
- client_chan.clone());
- };
-
- let msg_from_client = server_port.recv();
- let msg_from_server = client_port.recv();
-
- assert!(msg_from_client.contains(kill_server_msg));
- assert!(msg_from_server.contains(server_resp_msg));
- }
-
- // FIXME don't run on fbsd or linux 32 bit(#2064)
- #[cfg(target_os="win32")]
- #[cfg(target_os="darwin")]
- #[cfg(target_os="linux")]
- #[cfg(target_os="android")]
- mod tcp_and_server_client_test {
- #[cfg(target_arch="x86_64")]
- mod impl64 {
- #[test]
- fn test_uv_ll_tcp_server_and_request() {
- super::super::impl_uv_tcp_server_and_request();
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- mod impl32 {
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_uv_ll_tcp_server_and_request() {
- unsafe {
- super::super::impl_uv_tcp_server_and_request();
- }
- }
- }
- }
-
- fn struct_size_check_common<TStruct>(t_name: ~str,
- foreign_size: libc::c_uint) {
- let rust_size = sys::size_of::<TStruct>();
- let sizes_match = foreign_size as uint == rust_size;
- if !sizes_match {
- let output = fmt!(
- "STRUCT_SIZE FAILURE: %s -- actual: %u expected: %u",
- t_name, rust_size, foreign_size as uint);
- debug!(output);
- }
- assert!(sizes_match);
- }
-
- // struct size tests
- #[test]
- fn test_uv_ll_struct_size_uv_tcp_t() {
- unsafe {
- struct_size_check_common::<uv_tcp_t>(
- ~"uv_tcp_t",
- super::rust_uv_helper_uv_tcp_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_connect_t() {
- unsafe {
- struct_size_check_common::<uv_connect_t>(
- ~"uv_connect_t",
- super::rust_uv_helper_uv_connect_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_buf_t() {
- unsafe {
- struct_size_check_common::<uv_buf_t>(
- ~"uv_buf_t",
- super::rust_uv_helper_uv_buf_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_write_t() {
- unsafe {
- struct_size_check_common::<uv_write_t>(
- ~"uv_write_t",
- super::rust_uv_helper_uv_write_t_size()
- );
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_sockaddr_in() {
- unsafe {
- struct_size_check_common::<sockaddr_in>(
- ~"sockaddr_in",
- super::rust_uv_helper_sockaddr_in_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_sockaddr_in6() {
- unsafe {
- let foreign_handle_size =
- super::rust_uv_helper_sockaddr_in6_size();
- let rust_handle_size = sys::size_of::<sockaddr_in6>();
- let output = fmt!("sockaddr_in6 -- foreign: %u rust: %u",
- foreign_handle_size as uint, rust_handle_size);
- debug!(output);
- // FIXME #1645 .. rust appears to pad structs to the nearest
- // byte..?
- // .. can't get the uv::ll::sockaddr_in6 to == 28 :/
- // .. so the type always appears to be 32 in size.. which is
- // good, i guess.. better too big than too little
- assert!((4u+foreign_handle_size as uint) ==
- rust_handle_size);
- }
- }
- #[test]
- #[ignore(reason = "questionable size calculations")]
- fn test_uv_ll_struct_size_addr_in() {
- unsafe {
- let foreign_handle_size =
- super::rust_uv_helper_addr_in_size();
- let rust_handle_size = sys::size_of::<addr_in>();
- let output = fmt!("addr_in -- foreign: %u rust: %u",
- foreign_handle_size as uint, rust_handle_size);
- debug!(output);
- // FIXME #1645 .. see note above about struct padding
- assert!((4u+foreign_handle_size as uint) ==
- rust_handle_size);
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_uv_async_t() {
- unsafe {
- struct_size_check_common::<uv_async_t>(
- ~"uv_async_t",
- super::rust_uv_helper_uv_async_t_size()
- );
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_uv_timer_t() {
- unsafe {
- struct_size_check_common::<uv_timer_t>(
- ~"uv_timer_t",
- super::rust_uv_helper_uv_timer_t_size()
- );
- }
- }
-
- #[test]
- #[ignore(cfg(target_os = "win32"))]
- fn test_uv_ll_struct_size_uv_getaddrinfo_t() {
- unsafe {
- struct_size_check_common::<uv_getaddrinfo_t>(
- ~"uv_getaddrinfo_t",
- super::rust_uv_helper_uv_getaddrinfo_t_size()
- );
- }
- }
- #[test]
- #[ignore(cfg(target_os = "macos"))]
- #[ignore(cfg(target_os = "win32"))]
- fn test_uv_ll_struct_size_addrinfo() {
- unsafe {
- struct_size_check_common::<uv_timer_t>(
- ~"addrinfo",
- super::rust_uv_helper_uv_timer_t_size()
- );
- }
- }
-}
use std::run;
use std::task;
use std::to_bytes;
-use std::util::replace;
/**
*
_ => {
let (port, chan) = oneshot();
- let blk = replace(&mut bo, None).unwrap();
+ let blk = bo.take_unwrap();
let chan = Cell::new(chan);
do task::spawn {
Decodable<json::Decoder>>( // FIXME(#5121)
w: Work<T>) -> T {
let mut ww = w;
- let s = replace(&mut ww.res, None);
+ let s = ww.res.take();
match s {
None => fail!(),
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name};
use syntax::attr;
+use syntax::attr::{AttrMetaMethods};
use syntax::print::pprust;
use syntax::parse::token;
use metadata::cstore;
use std::cast;
- #[cfg(not(stage0))]
use std::local_data;
use std::unstable::intrinsics;
// The stage1 compiler won't work, but that doesn't really matter. TLS
// changed only very recently to allow storage of owned values.
- #[cfg(not(stage0))]
static engine_key: local_data::Key<~Engine> = &local_data::Key;
- #[cfg(not(stage0))]
fn set_engine(engine: ~Engine) {
local_data::set(engine_key, engine)
}
- #[cfg(stage0)]
- fn set_engine(_: ~Engine) {}
- #[cfg(not(stage0))]
pub fn consume_engine() -> Option<~Engine> {
local_data::pop(engine_key)
}
- #[cfg(stage0)]
- pub fn consume_engine() -> Option<~Engine> { None }
}
pub mod write {
*/
pub fn build_link_meta(sess: Session,
- c: &ast::crate,
+ c: &ast::Crate,
output: &Path,
symbol_hasher: &mut hash::State)
-> LinkMeta {
struct ProvidedMetas {
name: Option<@str>,
vers: Option<@str>,
- cmh_items: ~[@ast::meta_item]
+ cmh_items: ~[@ast::MetaItem]
}
- fn provided_link_metas(sess: Session, c: &ast::crate) ->
+ fn provided_link_metas(sess: Session, c: &ast::Crate) ->
ProvidedMetas {
let mut name = None;
let mut vers = None;
let mut cmh_items = ~[];
- let linkage_metas = attr::find_linkage_metas(c.node.attrs);
+ let linkage_metas = attr::find_linkage_metas(c.attrs);
attr::require_unique_names(sess.diagnostic(), linkage_metas);
for linkage_metas.iter().advance |meta| {
- match attr::get_meta_item_value_str(*meta) {
- Some(value) => {
- let item_name : &str = attr::get_meta_item_name(*meta);
- match item_name {
- // Changing attr would avoid the need for the copy
- // here
- "name" => name = Some(value),
- "vers" => vers = Some(value),
- _ => cmh_items.push(*meta)
- }
- },
- None => cmh_items.push(*meta)
+ match meta.name_str_pair() {
+ Some((n, value)) if "name" == n => name = Some(value),
+ Some((n, value)) if "vers" == n => vers = Some(value),
+ _ => cmh_items.push(*meta)
}
}
// This calculates CMH as defined above
fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
- cmh_items: ~[@ast::meta_item],
+ cmh_items: ~[@ast::MetaItem],
dep_hashes: ~[@str]) -> @str {
fn len_and_str(s: &str) -> ~str {
fmt!("%u_%s", s.len(), s)
let cmh_items = attr::sort_meta_items(cmh_items);
- fn hash(symbol_hasher: &mut hash::State, m: &@ast::meta_item) {
+ fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
match m.node {
- ast::meta_name_value(key, value) => {
+ ast::MetaNameValue(key, value) => {
write_string(symbol_hasher, len_and_str(key));
write_string(symbol_hasher, len_and_str_lit(value));
}
- ast::meta_word(name) => {
+ ast::MetaWord(name) => {
write_string(symbol_hasher, len_and_str(name));
}
- ast::meta_list(name, ref mis) => {
+ ast::MetaList(name, ref mis) => {
write_string(symbol_hasher, len_and_str(name));
for mis.iter().advance |m_| {
hash(symbol_hasher, m_);
use syntax::ast;
use syntax::abi;
use syntax::attr;
+use syntax::attr::{AttrMetaMethods};
use syntax::codemap;
use syntax::diagnostic;
use syntax::parse;
}
pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
- ast::crate_cfg {
+ ast::CrateConfig {
let (libc, tos) = match sess.targ_cfg.os {
session::os_win32 => (@"msvcrt.dll", @"win32"),
session::os_macos => (@"libc.dylib", @"macos"),
mk(@"build_input", source_name(input))];
}
-pub fn append_configuration(cfg: ast::crate_cfg, name: @str)
- -> ast::crate_cfg {
- if attr::contains_name(cfg, name) {
- cfg
- } else {
- vec::append_one(cfg, attr::mk_word_item(name))
+pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
+ if !cfg.iter().any(|mi| mi.name() == name) {
+ cfg.push(attr::mk_word_item(name))
}
}
pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
- ast::crate_cfg {
+ ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
let default_cfg = default_configuration(sess, argv0, input);
- let user_cfg = sess.opts.cfg.clone();
+ let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
- let user_cfg = if sess.opts.test {
- append_configuration(user_cfg, @"test")
- } else {
- user_cfg
- };
-
+ if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
// If the user requested GC, then add the GC cfg
- let user_cfg = append_configuration(
- user_cfg,
- if sess.opts.gc { @"gc" } else { @"nogc" });
+ append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
return vec::append(user_cfg, default_cfg);
}
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
fn parse_cfgspecs(cfgspecs: ~[~str],
- demitter: diagnostic::Emitter) -> ast::crate_cfg {
+ demitter: diagnostic::Emitter) -> ast::CrateConfig {
do cfgspecs.consume_iter().transform |s| {
let sess = parse::new_parse_sess(Some(demitter));
parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
- }.collect()
+ }.collect::<ast::CrateConfig>()
}
pub enum input {
str_input(@str)
}
-pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input)
- -> @ast::crate {
+pub fn parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
+ -> @ast::Crate {
match *input {
file_input(ref file) => {
parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
#[fixed_stack_segment]
pub fn compile_rest(sess: Session,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
phases: compile_upto,
outputs: Option<@OutputFilenames>,
- curr: Option<@ast::crate>)
- -> (Option<@ast::crate>, Option<ty::ctxt>) {
+ curr: Option<@ast::Crate>)
+ -> (Option<@ast::Crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
crate = time(time_passes, ~"configuration 2", ||
front::config::strip_unconfigured_items(crate));
+
crate = time(time_passes, ~"maybe building test harness", ||
front::test::modify_for_testing(sess, crate));
}
}
pub fn compile_upto(sess: Session,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
input: &input,
upto: compile_phase,
outputs: Option<@OutputFilenames>)
- -> (Option<@ast::crate>, Option<ty::ctxt>) {
+ -> (Option<@ast::Crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
let crate = time(time_passes,
~"parsing",
Some(crate))
}
-pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input,
+pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
outdir: &Option<Path>, output: &Option<Path>) {
let upto = if sess.opts.parse_only { cu_parse }
else if sess.opts.no_trans { cu_no_trans }
compile_upto(sess, cfg, input, upto, Some(outputs));
}
-pub fn pretty_print_input(sess: Session, cfg: ast::crate_cfg, input: &input,
+pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
ppm: pp_mode) {
fn ann_paren_for_expr(node: pprust::ann_node) {
match node {
pub fn build_output_filenames(input: &input,
odir: &Option<Path>,
ofile: &Option<Path>,
- attrs: &[ast::attribute],
+ attrs: &[ast::Attribute],
sess: Session)
-> @OutputFilenames {
let obj_path;
let linkage_metas = attr::find_linkage_metas(attrs);
if !linkage_metas.is_empty() {
// But if a linkage meta is present, that overrides
- let maybe_matches = attr::find_meta_items_by_name(linkage_metas, "name");
- if !maybe_matches.is_empty() {
- match attr::get_meta_item_value_str(maybe_matches[0]) {
- Some(s) => stem = s,
- _ => ()
- }
+ let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
+ match maybe_name.chain(|m| m.value_str()) {
+ Some(s) => stem = s,
+ _ => ()
}
// If the name is missing, we just default to the filename
// version
@"rustc", matches, diagnostic::emit);
let sess = build_session(sessopts, diagnostic::emit);
let cfg = build_configuration(sess, @"whatever", &str_input(@""));
- let test_items = attr::find_meta_items_by_name(cfg, "test");
- assert_eq!(test_items.len(), 1u);
+ let mut test_items = cfg.iter().filter(|m| "test" == m.name());
+ assert!(test_items.next().is_some());
+ assert!(test_items.next().is_none());
}
}
// items to the crate config, and during parsing the entire crate config
// will be added to the crate AST node. This should not be used for
// anything except building the full crate config prior to parsing.
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
binary: @str,
test: bool,
parse_only: bool,
}
pub fn building_library(req_crate_type: crate_type,
- crate: &ast::crate,
+ crate: &ast::Crate,
testing: bool) -> bool {
match req_crate_type {
bin_crate => false,
false
} else {
match syntax::attr::first_attr_value_str_by_name(
- crate.node.attrs,
+ crate.attrs,
"crate_type") {
- Some(s) if "lib" == s => true,
+ Some(s) => "lib" == s,
_ => false
}
}
use driver::session::{unknown_crate};
use syntax::ast;
+ use syntax::attr;
use syntax::codemap;
- fn make_crate_type_attr(t: @str) -> ast::attribute {
- codemap::respan(codemap::dummy_sp(), ast::attribute_ {
- style: ast::attr_outer,
- value: @codemap::respan(codemap::dummy_sp(),
- ast::meta_name_value(
- @"crate_type",
- codemap::respan(codemap::dummy_sp(),
- ast::lit_str(t)))),
- is_sugared_doc: false
- })
+ fn make_crate_type_attr(t: @str) -> ast::Attribute {
+ attr::mk_attr(attr::mk_name_value_item_str(@"crate_type", t))
}
- fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate {
+ fn make_crate(with_bin: bool, with_lib: bool) -> @ast::Crate {
let mut attrs = ~[];
if with_bin {
attrs.push(make_crate_type_attr(@"bin"));
if with_lib {
attrs.push(make_crate_type_attr(@"lib"));
}
- @codemap::respan(codemap::dummy_sp(), ast::crate_ {
+ @ast::Crate {
module: ast::_mod { view_items: ~[], items: ~[] },
attrs: attrs,
- config: ~[]
- })
+ config: ~[],
+ span: codemap::dummy_sp(),
+ }
}
#[test]
use std::option;
use syntax::{ast, fold, attr};
-type in_cfg_pred = @fn(attrs: &[ast::attribute]) -> bool;
+type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
struct Context {
in_cfg: in_cfg_pred
// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate {
+pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
do strip_items(crate) |attrs| {
- in_cfg(crate.node.config, attrs)
+ in_cfg(crate.config, attrs)
}
}
-pub fn strip_items(crate: &ast::crate, in_cfg: in_cfg_pred)
- -> @ast::crate {
+pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred)
+ -> @ast::Crate {
let ctxt = @Context { in_cfg: in_cfg };
fn fold_block(
cx: @Context,
- b: &ast::blk,
+ b: &ast::Block,
fld: @fold::ast_fold
-) -> ast::blk {
+) -> ast::Block {
let resulting_stmts = do b.stmts.iter().filter_map |a| {
filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt))
}.collect();
let filtered_view_items = do b.view_items.iter().filter_map |a| {
filter_view_item(cx, a).map(|&x| fld.fold_view_item(x))
}.collect();
- ast::blk {
+ ast::Block {
view_items: filtered_view_items,
stmts: resulting_stmts,
expr: b.expr.map(|x| fld.fold_expr(*x)),
// Determine if an item should be translated in the current crate
// configuration based on the item's attributes
-fn in_cfg(cfg: &[@ast::meta_item], attrs: &[ast::attribute]) -> bool {
- metas_in_cfg(cfg, attr::attr_metas(attrs))
-}
-
-pub fn metas_in_cfg(cfg: &[@ast::meta_item],
- metas: &[@ast::meta_item]) -> bool {
- // The "cfg" attributes on the item
- let cfg_metas = attr::find_meta_items_by_name(metas, "cfg");
-
- // Pull the inner meta_items from the #[cfg(meta_item, ...)] attributes,
- // so we can match against them. This is the list of configurations for
- // which the item is valid
- let cfg_metas = cfg_metas.consume_iter()
- .filter_map(|i| attr::get_meta_item_list(i))
- .collect::<~[~[@ast::meta_item]]>();
-
- if cfg_metas.iter().all(|c| c.is_empty()) { return true; }
-
- cfg_metas.iter().any(|cfg_meta| {
- cfg_meta.iter().all(|cfg_mi| {
- match cfg_mi.node {
- ast::meta_list(s, ref it) if "not" == s
- => it.iter().all(|mi| !attr::contains(cfg, *mi)),
- _ => attr::contains(cfg, *cfg_mi)
- }
- })
- })
+fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool {
+ attr::test_cfg(cfg, attrs.iter().transform(|x| *x))
}
static STD_VERSION: &'static str = "0.8-pre";
-pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate)
- -> @ast::crate {
+pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::Crate)
+ -> @ast::Crate {
if use_std(crate) {
inject_libstd_ref(sess, crate)
} else {
}
}
-fn use_std(crate: &ast::crate) -> bool {
- !attr::attrs_contains_name(crate.node.attrs, "no_std")
+fn use_std(crate: &ast::Crate) -> bool {
+ !attr::contains_name(crate.attrs, "no_std")
}
-fn no_prelude(attrs: &[ast::attribute]) -> bool {
- attr::attrs_contains_name(attrs, "no_implicit_prelude")
+
+fn no_prelude(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "no_implicit_prelude")
}
-fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate {
+fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
fn spanned<T>(x: T) -> codemap::spanned<T> {
codemap::spanned { node: x, span: dummy_sp() }
}
let precursor = @fold::AstFoldFns {
- fold_crate: |crate, span, fld| {
+ fold_crate: |crate, fld| {
let n1 = sess.next_node_id();
let vi1 = ast::view_item {
node: ast::view_item_extern_mod(
sess.ident_of("std"), ~[], n1),
attrs: ~[
- spanned(ast::attribute_ {
- style: ast::attr_inner,
- value: @spanned(ast::meta_name_value(
- @"vers",
- spanned(ast::lit_str(STD_VERSION.to_managed()))
- )),
- is_sugared_doc: false
- })
+ attr::mk_attr(
+ attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
],
vis: ast::private,
span: dummy_sp()
}
// FIXME #2543: Bad copy.
- let new_crate = ast::crate_ {
+ ast::Crate {
module: new_module,
..(*crate).clone()
- };
- (new_crate, span)
+ }
},
fold_item: |item, fld| {
if !no_prelude(item.attrs) {
use syntax::fold;
use syntax::print::pprust;
use syntax::{ast, ast_util};
+use syntax::attr::AttrMetaMethods;
type node_id_gen = @fn() -> ast::node_id;
struct TestCtxt {
sess: session::Session,
- crate: @ast::crate,
+ crate: @ast::Crate,
path: ~[ast::ident],
ext_cx: @ExtCtxt,
testfns: ~[Test]
// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
- crate: @ast::crate)
- -> @ast::crate {
+ crate: @ast::Crate)
+ -> @ast::Crate {
// We generate the test harness when building in the 'test'
// configuration, either with the '--test' or '--cfg test'
// command line options.
- let should_test = attr::contains(crate.node.config,
- attr::mk_word_item(@"test"));
+ let should_test = attr::contains_name(crate.config, "test");
if should_test {
generate_test_harness(sess, crate)
}
fn generate_test_harness(sess: session::Session,
- crate: @ast::crate)
- -> @ast::crate {
+ crate: @ast::Crate)
+ -> @ast::Crate {
let cx: @mut TestCtxt = @mut TestCtxt {
sess: sess,
crate: crate,
});
let precursor = @fold::AstFoldFns {
- fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
+ fold_crate: |a,b| fold_crate(cx, a, b),
fold_item: |a,b| fold_item(cx, a, b),
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
return res;
}
-fn strip_test_functions(crate: &ast::crate) -> @ast::crate {
+fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
// When not compiling with --test we should not compile the
// #[test] functions
do config::strip_items(crate) |attrs| {
- !attr::contains_name(attr::attr_metas(attrs), "test") &&
- !attr::contains_name(attr::attr_metas(attrs), "bench")
+ !attr::contains_name(attrs, "test") &&
+ !attr::contains_name(attrs, "bench")
}
}
if !*cx.sess.building_library {
@ast::item {
attrs: do item.attrs.iter().filter_map |attr| {
- if "main" != attr::get_attr_name(attr) {
+ if "main" != attr.name() {
Some(*attr)
} else {
None
fold::noop_fold_mod(&mod_nomain, fld)
}
-fn fold_crate(cx: @mut TestCtxt, c: &ast::crate_, fld: @fold::ast_fold)
- -> ast::crate_ {
+fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
+ -> ast::Crate {
let folded = fold::noop_fold_crate(c, fld);
// Add a special __test module to the crate that will contain code
// generated for the test harness
- ast::crate_ {
+ ast::Crate {
module: add_test_module(cx, &folded.module),
.. folded
}
}
fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
- let has_test_attr = !attr::find_attrs_by_name(i.attrs,
- "test").is_empty();
+ let has_test_attr = attr::contains_name(i.attrs, "test");
fn has_test_signature(i: @ast::item) -> bool {
match &i.node {
"functions used as tests must have signature fn() -> ()."
);
}
+
return has_test_attr && has_test_signature(i);
}
fn is_bench_fn(i: @ast::item) -> bool {
- let has_bench_attr = !attr::find_attrs_by_name(i.attrs, "bench").is_empty();
+ let has_bench_attr = attr::contains_name(i.attrs, "bench");
fn has_test_signature(i: @ast::item) -> bool {
match i.node {
}
fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
- let ignoreattrs = attr::find_attrs_by_name(i.attrs, "ignore");
- let ignoreitems = attr::attr_metas(ignoreattrs);
- return if !ignoreitems.is_empty() {
- let cfg_metas = ignoreitems.consume_iter()
- .filter_map(|i| attr::get_meta_item_list(i))
- .collect::<~[~[@ast::meta_item]]>()
- .concat_vec();
- config::metas_in_cfg(cx.crate.node.config.clone(), cfg_metas)
- } else {
- false
+ do i.attrs.iter().any |attr| {
+ // check ignore(cfg(foo, bar))
+ "ignore" == attr.name() && match attr.meta_item_list() {
+ Some(ref cfgs) => attr::test_cfg(cx.crate.config, cfgs.iter().transform(|x| *x)),
+ None => true
+ }
}
}
fn should_fail(i: @ast::item) -> bool {
- !attr::find_attrs_by_name(i.attrs, "should_fail").is_empty()
+ attr::contains_name(i.attrs, "should_fail")
}
fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
*/
fn mk_std(cx: &TestCtxt) -> ast::view_item {
- let vers = ast::lit_str(@"0.8-pre");
- let vers = nospan(vers);
- let mi = ast::meta_name_value(@"vers", vers);
- let mi = nospan(mi);
- let id_std = cx.sess.ident_of("extra");
- let vi = if is_std(cx) {
+ let id_extra = cx.sess.ident_of("extra");
+ let vi = if is_extra(cx) {
ast::view_item_use(
- ~[@nospan(ast::view_path_simple(id_std,
- path_node(~[id_std]),
+ ~[@nospan(ast::view_path_simple(id_extra,
+ path_node(~[id_extra]),
cx.sess.next_node_id()))])
} else {
- ast::view_item_extern_mod(id_std, ~[@mi],
- cx.sess.next_node_id())
+ let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre");
+ ast::view_item_extern_mod(id_extra, ~[mi], cx.sess.next_node_id())
};
ast::view_item {
node: vi,
)).get()
}
-fn is_std(cx: &TestCtxt) -> bool {
- let is_std = {
- let items = attr::find_linkage_metas(cx.crate.node.attrs);
- match attr::last_meta_item_value_str_by_name(items, "name") {
- Some(s) if "extra" == s => true,
- _ => false
- }
- };
- return is_std;
+fn is_extra(cx: &TestCtxt) -> bool {
+ let items = attr::find_linkage_metas(cx.crate.attrs);
+ match attr::last_meta_item_value_str_by_name(items, "name") {
+ Some(s) if "extra" == s => true,
+ _ => false
+ }
}
fn mk_test_descs(cx: &TestCtxt) -> @ast::expr {
#[link_args = "-Lrustllvm -lrustllvm"]
#[link_name = "rustllvm"]
#[abi = "cdecl"]
- pub extern {
+ extern {
/* Create and destroy contexts. */
#[fast_ffi]
pub unsafe fn LLVMContextCreate() -> ContextRef;
pub unsafe fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef;
#[fast_ffi]
pub unsafe fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef;
+ #[fast_ffi]
+ pub unsafe fn LLVMInstructionEraseFromParent(Inst: ValueRef);
/* Operations on call sites */
#[fast_ffi]
#[fast_ffi]
pub unsafe fn LLVMABIAlignmentOfType(TD: TargetDataRef,
Ty: TypeRef) -> c_uint;
+
+ /** Computes the byte offset of the indexed struct element for a target. */
+ #[fast_ffi]
+ pub unsafe fn LLVMOffsetOfElement(TD: TargetDataRef,
+ StructTy: TypeRef,
+ Element: c_uint)
+ -> c_ulonglong;
+
/**
* Returns the minimum alignment of a type when part of a call frame.
*/
Val: ValueRef,
VarInfo: DIVariable,
InsertBefore: ValueRef) -> ValueRef;
+
+ #[fast_ffi]
+ pub unsafe fn LLVMDIBuilderCreateEnumerator(
+ Builder: DIBuilderRef,
+ Name: *c_char,
+ Val: c_ulonglong) -> ValueRef;
+
+ #[fast_ffi]
+ pub unsafe fn LLVMDIBuilderCreateEnumerationType(
+ Builder: DIBuilderRef,
+ Scope: ValueRef,
+ Name: *c_char,
+ File: ValueRef,
+ LineNumber: c_uint,
+ SizeInBits: c_ulonglong,
+ AlignInBits: c_ulonglong,
+ Elements: ValueRef,
+ ClassType: ValueRef) -> ValueRef;
+
+ #[fast_ffi]
+ pub unsafe fn LLVMDIBuilderCreateUnionType(
+ Builder: DIBuilderRef,
+ Scope: ValueRef,
+ Name: *c_char,
+ File: ValueRef,
+ LineNumber: c_uint,
+ SizeInBits: c_ulonglong,
+ AlignInBits: c_ulonglong,
+ Flags: c_uint ,
+ Elements: ValueRef,
+ RunTimeLang: c_uint) -> ValueRef;
}
}
pub static tag_misc_info: uint = 0x7f;
pub static tag_misc_info_crate_items: uint = 0x80;
+pub static tag_item_method_provided_source: uint = 0x81;
+
pub struct LinkMeta {
name: @str,
vers: @str,
use std::hashmap::HashMap;
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::{span, dummy_sp};
use syntax::diagnostic::span_handler;
use syntax::parse::token;
// Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc.
pub fn read_crates(diag: @span_handler,
- crate: &ast::crate,
+ crate: &ast::Crate,
cstore: @mut cstore::CStore,
filesearch: @FileSearch,
os: loader::os,
cnum: int,
span: span,
hash: @str,
- metas: @~[@ast::meta_item]
+ metas: @~[@ast::MetaItem]
}
fn dump_crates(crate_cache: &[cache_entry]) {
os: loader::os,
statik: bool,
crate_cache: @mut ~[cache_entry],
- next_crate_num: ast::crate_num,
+ next_crate_num: ast::CrateNum,
intr: @ident_interner
}
-fn visit_crate(e: &Env, c: &ast::crate) {
+fn visit_crate(e: &Env, c: &ast::Crate) {
let cstore = e.cstore;
- let link_args = attr::find_attrs_by_name(c.node.attrs, "link_args");
- for link_args.iter().advance |a| {
- match attr::get_meta_item_value_str(attr::attr_meta(*a)) {
+ for c.attrs.iter().filter(|m| "link_args" == m.name()).advance |a| {
+ match a.value_str() {
Some(ref linkarg) => {
cstore::add_used_link_args(cstore, *linkarg);
}
let cstore = e.cstore;
let mut already_added = false;
- let link_args = attr::find_attrs_by_name(i.attrs, "link_args");
+ let link_args = i.attrs.iter()
+ .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None})
+ .collect::<~[&ast::Attribute]>();
match fm.sort {
ast::named => {
- let foreign_name =
- match attr::first_attr_value_str_by_name(i.attrs,
- "link_name") {
+ let link_name = i.attrs.iter()
+ .find_(|at| "link_name" == at.name())
+ .chain(|at| at.value_str());
+
+ let foreign_name = match link_name {
Some(nn) => {
if nn.is_empty() {
e.diag.span_fatal(
}
None => token::ident_to_str(&i.ident)
};
- if attr::find_attrs_by_name(i.attrs, "nolink").is_empty() {
+ if !attr::contains_name(i.attrs, "nolink") {
already_added =
!cstore::add_used_library(cstore, foreign_name);
}
ast::anonymous => { /* do nothing */ }
}
- for link_args.iter().advance |a| {
- match attr::get_meta_item_value_str(attr::attr_meta(*a)) {
+ for link_args.iter().advance |m| {
+ match m.value_str() {
Some(linkarg) => {
cstore::add_used_link_args(cstore, linkarg);
}
}
}
-fn metas_with(ident: @str, key: @str, mut metas: ~[@ast::meta_item])
- -> ~[@ast::meta_item] {
- let name_items = attr::find_meta_items_by_name(metas, key);
- if name_items.is_empty() {
+fn metas_with(ident: @str, key: @str, mut metas: ~[@ast::MetaItem])
+ -> ~[@ast::MetaItem] {
+ // Check if key isn't there yet.
+ if !attr::contains_name(metas, key) {
metas.push(attr::mk_name_value_item_str(key, ident));
}
metas
}
-fn metas_with_ident(ident: @str, metas: ~[@ast::meta_item])
- -> ~[@ast::meta_item] {
+fn metas_with_ident(ident: @str, metas: ~[@ast::MetaItem])
+ -> ~[@ast::MetaItem] {
metas_with(ident, @"name", metas)
}
-fn existing_match(e: &Env, metas: &[@ast::meta_item], hash: &str)
+fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str)
-> Option<int> {
for e.crate_cache.iter().advance |c| {
if loader::metadata_matches(*c.metas, metas)
fn resolve_crate(e: @mut Env,
ident: ast::ident,
- metas: ~[@ast::meta_item],
+ metas: ~[@ast::MetaItem],
hash: @str,
span: span)
- -> ast::crate_num {
+ -> ast::CrateNum {
let metas = metas_with_ident(token::ident_to_str(&ident), metas);
match existing_match(e, metas, hash) {
use metadata::cstore;
use metadata::decoder;
use metadata;
-use middle::{ty, resolve};
+use middle::ty;
use std::vec;
use reader = extra::ebml::reader;
/// Iterates over all the language items in the given crate.
pub fn each_lang_item(cstore: @mut cstore::CStore,
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
f: &fn(ast::node_id, uint) -> bool) -> bool {
let crate_data = cstore::get_crate_data(cstore, cnum);
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::crate_num,
+ cnum: ast::CrateNum,
f: &fn(&str, decoder::def_like, ast::visibility) -> bool)
-> bool {
let crate_data = cstore::get_crate_data(cstore, cnum);
}
pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id)
- -> ~[ty::VariantInfo] {
+ -> ~[@ty::VariantInfo] {
let cstore = tcx.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx)
}
/// Returns information about the given implementation.
-pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id)
- -> resolve::Impl {
- let cdata = cstore::get_crate_data(cstore, impl_def_id.crate);
- decoder::get_impl(cstore.intr, cdata, impl_def_id.node)
+pub fn get_impl(tcx: ty::ctxt, impl_def_id: ast::def_id)
+ -> ty::Impl {
+ let cdata = cstore::get_crate_data(tcx.cstore, impl_def_id.crate);
+ decoder::get_impl(tcx.cstore.intr, cdata, impl_def_id.node, tcx)
}
pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method {
pub fn get_item_attrs(cstore: @mut cstore::CStore,
def_id: ast::def_id,
- f: &fn(~[@ast::meta_item])) {
+ f: &fn(~[@ast::MetaItem])) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::get_item_attrs(cdata, def_id.node, f)
}
}
pub fn get_link_args_for_crate(cstore: @mut cstore::CStore,
- crate_num: ast::crate_num)
+ crate_num: ast::CrateNum)
-> ~[~str] {
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::get_link_args_for_crate(cdata)
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
-pub type cnum_map = @mut HashMap<ast::crate_num, ast::crate_num>;
+pub type cnum_map = @mut HashMap<ast::CrateNum, ast::CrateNum>;
pub struct crate_metadata {
name: @str,
data: @~[u8],
cnum_map: cnum_map,
- cnum: ast::crate_num
+ cnum: ast::CrateNum
}
pub struct CStore {
- priv metas: HashMap <ast::crate_num, @crate_metadata>,
+ priv metas: HashMap <ast::CrateNum, @crate_metadata>,
priv extern_mod_crate_map: extern_mod_crate_map,
priv used_crate_files: ~[Path],
priv used_libraries: ~[@str],
}
// Map from node_id's of local extern mod statements to crate numbers
-type extern_mod_crate_map = HashMap<ast::node_id, ast::crate_num>;
+type extern_mod_crate_map = HashMap<ast::node_id, ast::CrateNum>;
pub fn mk_cstore(intr: @ident_interner) -> CStore {
return CStore {
};
}
-pub fn get_crate_data(cstore: &CStore, cnum: ast::crate_num)
+pub fn get_crate_data(cstore: &CStore, cnum: ast::CrateNum)
-> @crate_metadata {
return *cstore.metas.get(&cnum);
}
-pub fn get_crate_hash(cstore: &CStore, cnum: ast::crate_num) -> @str {
+pub fn get_crate_hash(cstore: &CStore, cnum: ast::CrateNum) -> @str {
let cdata = get_crate_data(cstore, cnum);
decoder::get_crate_hash(cdata.data)
}
-pub fn get_crate_vers(cstore: &CStore, cnum: ast::crate_num) -> @str {
+pub fn get_crate_vers(cstore: &CStore, cnum: ast::CrateNum) -> @str {
let cdata = get_crate_data(cstore, cnum);
decoder::get_crate_vers(cdata.data)
}
pub fn set_crate_data(cstore: &mut CStore,
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
data: @crate_metadata) {
cstore.metas.insert(cnum, data);
}
-pub fn have_crate_data(cstore: &CStore, cnum: ast::crate_num) -> bool {
+pub fn have_crate_data(cstore: &CStore, cnum: ast::CrateNum) -> bool {
cstore.metas.contains_key(&cnum)
}
pub fn iter_crate_data(cstore: &CStore,
- i: &fn(ast::crate_num, @crate_metadata)) {
+ i: &fn(ast::CrateNum, @crate_metadata)) {
for cstore.metas.iter().advance |(&k, &v)| {
i(k, v);
}
pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore,
emod_id: ast::node_id,
- cnum: ast::crate_num) {
+ cnum: ast::CrateNum) {
cstore.extern_mod_crate_map.insert(emod_id, cnum);
}
pub fn find_extern_mod_stmt_cnum(cstore: &CStore,
emod_id: ast::node_id)
- -> Option<ast::crate_num> {
+ -> Option<ast::CrateNum> {
cstore.extern_mod_crate_map.find(&emod_id).map_consume(|x| *x)
}
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, resolve};
+use middle::ty;
use std::hash::HashUtil;
use std::int;
None
}
-pub type GetCrateDataCb<'self> = &'self fn(ast::crate_num) -> cmd;
+pub type GetCrateDataCb<'self> = &'self fn(ast::CrateNum) -> cmd;
pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> {
fn eq_item(bytes: &[u8], item_id: int) -> bool {
None
}
-fn translated_parent_item_opt(cnum: ast::crate_num, d: ebml::Doc) ->
- Option<ast::def_id> {
- let trait_did_opt = item_parent_item(d);
- do trait_did_opt.map |trait_did| {
- ast::def_id { crate: cnum, node: trait_did.node }
- }
-}
-
-fn item_reqd_and_translated_parent_item(cnum: ast::crate_num,
+fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum,
d: ebml::Doc) -> ast::def_id {
let trait_did = item_parent_item(d).expect("item without parent");
ast::def_id { crate: cnum, node: trait_did.node }
return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
}
+fn get_provided_source(d: ebml::Doc, cdata: cmd) -> Option<ast::def_id> {
+ do reader::maybe_get_doc(d, tag_item_method_provided_source).map |doc| {
+ translate_def_id(cdata, reader::with_doc_data(*doc, parse_def_id))
+ }
+}
+
fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool {
for reader::tagged_docs(d, tag_items_data_item_reexport) |reexport_doc| {
if !f(reexport_doc) {
}
}
-fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
+fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::CrateNum)
-> def_like {
let fam = item_family(item);
match fam {
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
- UnsafeStaticMethod => {
- let trait_did_opt = translated_parent_item_opt(cnum, item);
- dl_def(ast::def_static_method(did, trait_did_opt, ast::unsafe_fn))
- }
- StaticMethod => {
- let trait_did_opt = translated_parent_item_opt(cnum, item);
- dl_def(ast::def_static_method(did, trait_did_opt, ast::impure_fn))
+ StaticMethod | UnsafeStaticMethod => {
+ 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(
+ 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))
}
Type | ForeignType => dl_def(ast::def_ty(did)),
Mod => dl_def(ast::def_mod(did)),
}
}
-pub fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) ->
+pub fn lookup_def(cnum: ast::CrateNum, data: @~[u8], did_: ast::def_id) ->
ast::def {
let item = lookup_item(did_.node, data);
let did = ast::def_id { crate: cnum, node: did_.node };
}
pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id,
- tcx: ty::ctxt) -> ~[ty::VariantInfo] {
+ tcx: ty::ctxt) -> ~[@ty::VariantInfo] {
let data = cdata.data;
let items = reader::get_doc(reader::Doc(data), tag_items);
let item = find_item(id, items);
- let mut infos: ~[ty::VariantInfo] = ~[];
+ let mut infos: ~[@ty::VariantInfo] = ~[];
let variant_ids = enum_variant_ids(item, cdata);
let mut disr_val = 0;
for variant_ids.iter().advance |did| {
Some(val) => { disr_val = val; }
_ => { /* empty */ }
}
- infos.push(@ty::VariantInfo_{args: arg_tys,
- ctor_ty: ctor_ty, name: name,
- // I'm not even sure if we encode visibility
- // for variants -- TEST -- tjc
- id: *did, disr_val: disr_val, vis: ast::inherited});
+ infos.push(@ty::VariantInfo{
+ args: arg_tys,
+ arg_names: None,
+ ctor_ty: ctor_ty,
+ name: name,
+ // I'm not even sure if we encode visibility
+ // for variants -- TEST -- tjc
+ id: *did,
+ disr_val: disr_val,
+ vis: ast::inherited});
disr_val += 1;
}
return infos;
}
fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
- base_tps: uint) -> ~[@resolve::MethodInfo] {
+ tcx: ty::ctxt) -> ~[@ty::Method] {
let mut rslt = ~[];
for reader::tagged_docs(item, tag_item_impl_method) |doc| {
let m_did = reader::with_doc_data(doc, parse_def_id);
- let mth_item = lookup_item(m_did.node, cdata.data);
- let explicit_self = get_explicit_self(mth_item);
- rslt.push(@resolve::MethodInfo {
- did: translate_def_id(cdata, m_did),
- n_tps: item_ty_param_count(mth_item) - base_tps,
- ident: item_name(intr, mth_item),
- explicit_self: explicit_self});
+ rslt.push(@get_method(intr, cdata, m_did.node, tcx));
}
+
rslt
}
/// Returns information about the given implementation.
-pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id)
- -> resolve::Impl {
+pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id,
+ tcx: ty::ctxt)
+ -> ty::Impl {
let data = cdata.data;
let impl_item = lookup_item(impl_id, data);
- let base_tps = item_ty_param_count(impl_item);
- resolve::Impl {
+ ty::Impl {
did: ast::def_id {
crate: cdata.cnum,
node: impl_id,
},
ident: item_name(intr, impl_item),
- methods: item_impl_methods(intr, cdata, impl_item, base_tps),
+ methods: item_impl_methods(intr, cdata, impl_item, tcx),
}
}
{
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 name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
+ let provided_source = get_provided_source(method_doc, cdata);
ty::Method::new(
name,
fty,
explicit_self,
vis,
- def_id
+ def_id,
+ container_id,
+ provided_source
)
}
pub fn get_item_attrs(cdata: cmd,
node_id: ast::node_id,
- f: &fn(~[@ast::meta_item])) {
+ f: &fn(~[@ast::MetaItem])) {
let item = lookup_item(node_id, cdata.data);
for reader::tagged_docs(item, tag_attributes) |attributes| {
}
}
-fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
- let mut items: ~[@ast::meta_item] = ~[];
+fn get_meta_items(md: ebml::Doc) -> ~[@ast::MetaItem] {
+ let mut items: ~[@ast::MetaItem] = ~[];
for reader::tagged_docs(md, tag_meta_item_word) |meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let n = nd.as_str_slice().to_managed();
let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
let n = nd.as_str_slice().to_managed();
let v = vd.as_str_slice().to_managed();
- // FIXME (#623): Should be able to decode meta_name_value variants,
+ // FIXME (#623): Should be able to decode MetaNameValue variants,
// but currently the encoder just drops them
items.push(attr::mk_name_value_item_str(n, v));
};
return items;
}
-fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] {
- let mut attrs: ~[ast::attribute] = ~[];
+fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] {
+ let mut attrs: ~[ast::Attribute] = ~[];
match reader::maybe_get_doc(md, tag_attributes) {
option::Some(attrs_d) => {
for reader::tagged_docs(attrs_d, tag_attribute) |attr_doc| {
let meta_item = meta_items[0];
attrs.push(
codemap::spanned {
- node: ast::attribute_ {
- style: ast::attr_outer,
+ node: ast::Attribute_ {
+ style: ast::AttrOuter,
value: meta_item,
is_sugared_doc: false,
},
out.write_str("\n\n");
}
-pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::attribute] {
+pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::Attribute] {
return get_attributes(reader::Doc(data));
}
#[deriving(Clone)]
pub struct crate_dep {
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
name: ast::ident,
vers: @str,
hash: @str
use metadata::cstore;
use metadata::decoder;
use metadata::tyencode;
-use middle::ty::node_id_to_type;
+use middle::ty::{node_id_to_type, lookup_item_type};
use middle::ty;
use middle;
-use util::ppaux::ty_to_str;
use std::hash::HashUtil;
use std::hashmap::{HashMap, HashSet};
use syntax::ast_map;
use syntax::ast_util::*;
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::span_handler;
-use syntax::opt_vec::OptVec;
-use syntax::opt_vec;
use syntax::parse::token::special_idents;
use syntax::{ast_util, visit};
use syntax::parse::token;
}
}
-fn encode_type_param_bounds(ebml_w: &mut writer::Encoder,
- ecx: &EncodeContext,
- params: &OptVec<TyParam>) {
- let ty_param_defs =
- @params.map_to_vec(|param| ecx.tcx.ty_param_defs.get_copy(¶m.id));
- encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs,
+fn encode_bounds_and_type(ebml_w: &mut writer::Encoder,
+ ecx: &EncodeContext,
+ tpt: &ty::ty_param_bounds_and_ty) {
+ encode_ty_type_param_defs(ebml_w, ecx, tpt.generics.type_param_defs,
tag_items_data_item_ty_param_bounds);
+ encode_type(ecx, ebml_w, tpt.ty);
}
fn encode_variant_id(ebml_w: &mut writer::Encoder, vid: def_id) {
let vi = ty::enum_variants(ecx.tcx,
ast::def_id { crate: local_crate, node: id });
for variants.iter().advance |variant| {
+ let def_id = local_def(variant.node.id);
index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()});
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(variant.node.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'v');
encode_name(ecx, ebml_w, variant.node.name);
encode_parent_item(ebml_w, local_def(id));
encode_visibility(ebml_w, variant.node.vis);
- encode_type(ecx, ebml_w,
- node_id_to_type(ecx.tcx, variant.node.id));
match variant.node.kind {
ast::tuple_variant_kind(ref args)
if args.len() > 0 && generics.ty_params.len() == 0 => {
encode_disr_val(ecx, ebml_w, vi[i].disr_val);
disr_val = vi[i].disr_val;
}
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
+ encode_bounds_and_type(ebml_w, ecx,
+ &lookup_item_type(ecx.tcx, def_id));
encode_path(ecx, ebml_w, path,
ast_map::path_name(variant.node.name));
ebml_w.end_tag();
ebml_w: &mut writer::Encoder,
exp: &middle::resolve::Export2)
-> bool {
- match ecx.tcx.base_impls.find(&exp.def_id) {
+ match ecx.tcx.inherent_impls.find(&exp.def_id) {
Some(implementations) => {
for implementations.iter().advance |&base_impl| {
for base_impl.methods.iter().advance |&m| {
if m.explicit_self == ast::sty_static {
encode_reexported_static_method(ecx, ebml_w, exp,
- m.did, m.ident);
+ m.def_id, m.ident);
}
}
}
ebml_w.end_tag();
}
+fn encode_provided_source(ebml_w: &mut writer::Encoder,
+ source_opt: Option<def_id>) {
+ for source_opt.iter().advance |source| {
+ ebml_w.start_tag(tag_item_method_provided_source);
+ let s = def_to_str(*source);
+ ebml_w.writer.write(s.as_bytes());
+ ebml_w.end_tag();
+ }
+}
+
/* Returns an index of items in this class */
fn encode_info_for_struct(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
index
}
-// This is for encoding info for ctors and dtors
-fn encode_info_for_ctor(ecx: &EncodeContext,
- ebml_w: &mut writer::Encoder,
- id: node_id,
- ident: ident,
- path: &[ast_map::path_elt],
- item: Option<inlined_item>,
- generics: &ast::Generics) {
- ebml_w.start_tag(tag_items_data_item);
- encode_name(ecx, ebml_w, ident);
- encode_def_id(ebml_w, local_def(id));
- encode_family(ebml_w, purity_fn_family(ast::impure_fn));
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- let its_ty = node_id_to_type(ecx.tcx, id);
- debug!("fn name = %s ty = %s its node id = %d",
- ecx.tcx.sess.str_of(ident),
- ty_to_str(ecx.tcx, its_ty), id);
- encode_type(ecx, ebml_w, its_ty);
- encode_path(ecx, ebml_w, path, ast_map::path_name(ident));
- match item {
- Some(it) => {
- (ecx.encode_inlined_item)(ecx, ebml_w, path, it);
- }
- None => {
- encode_symbol(ecx, ebml_w, id);
- }
- }
- ebml_w.end_tag();
-}
-
fn encode_info_for_struct_ctor(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
path: &[ast_map::path_elt],
encode_method_fty(ecx, ebml_w, &method_ty.fty);
encode_visibility(ebml_w, method_ty.vis);
encode_explicit_self(ebml_w, method_ty.explicit_self);
+ let purity = method_ty.fty.purity;
+ match method_ty.explicit_self {
+ ast::sty_static => {
+ encode_family(ebml_w, purity_static_method_family(purity));
+ }
+ _ => encode_family(ebml_w, purity_fn_family(purity))
+ }
+ encode_provided_source(ebml_w, method_ty.provided_source);
}
fn encode_info_for_method(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
+ m: &ty::Method,
impl_path: &[ast_map::path_elt],
- should_inline: bool,
+ is_default_impl: bool,
parent_id: node_id,
- m: @method,
- owner_generics: &ast::Generics,
- method_generics: &ast::Generics) {
- debug!("encode_info_for_method: %d %s %u %u", m.id,
- ecx.tcx.sess.str_of(m.ident),
- owner_generics.ty_params.len(),
- method_generics.ty_params.len());
+ ast_method_opt: Option<@method>) {
+
+ debug!("encode_info_for_method: %? %s", m.def_id,
+ ecx.tcx.sess.str_of(m.ident));
ebml_w.start_tag(tag_items_data_item);
- let method_def_id = local_def(m.id);
- let method_ty = ty::method(ecx.tcx, method_def_id);
- encode_method_ty_fields(ecx, ebml_w, method_ty);
+ encode_method_ty_fields(ecx, ebml_w, m);
+ encode_parent_item(ebml_w, local_def(parent_id));
- match m.explicit_self.node {
- ast::sty_static => {
- encode_family(ebml_w, purity_static_method_family(m.purity));
- }
- _ => encode_family(ebml_w, purity_fn_family(m.purity))
- }
+ // The type for methods gets encoded twice, which is unfortunate.
+ let tpt = lookup_item_type(ecx.tcx, m.def_id);
+ encode_bounds_and_type(ebml_w, ecx, &tpt);
- let mut combined_ty_params = opt_vec::Empty;
- for owner_generics.ty_params.iter().advance |x| {
- combined_ty_params.push((*x).clone())
- }
- for method_generics.ty_params.iter().advance |x| {
- combined_ty_params.push((*x).clone())
- }
- let len = combined_ty_params.len();
- encode_type_param_bounds(ebml_w, ecx, &combined_ty_params);
-
- encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
- if len > 0u || should_inline {
- (ecx.encode_inlined_item)(
- ecx, ebml_w, impl_path,
- ii_method(local_def(parent_id), false, m));
- } else {
- encode_symbol(ecx, ebml_w, m.id);
+ for ast_method_opt.iter().advance |ast_method| {
+ let num_params = tpt.generics.type_param_defs.len();
+ if num_params > 0u || is_default_impl
+ || should_inline(ast_method.attrs) {
+ (ecx.encode_inlined_item)(
+ ecx, ebml_w, impl_path,
+ ii_method(local_def(parent_id), false, *ast_method));
+ } else {
+ encode_symbol(ecx, ebml_w, m.def_id.node);
+ }
}
ebml_w.end_tag();
}
-fn should_inline(attrs: &[attribute]) -> bool {
- match attr::find_inline_attr(attrs) {
- attr::ia_none | attr::ia_never => false,
- attr::ia_hint | attr::ia_always => true
+fn should_inline(attrs: &[Attribute]) -> bool {
+ use syntax::attr::*;
+ match find_inline_attr(attrs) {
+ InlineNone | InlineNever => false,
+ InlineHint | InlineAlways => true
}
}
debug!("encoding info for item at %s",
ecx.tcx.sess.codemap.span_to_str(item.span));
+ let def_id = local_def(item.id);
match item.node {
item_static(_, m, _) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
if m == ast::m_mutbl {
encode_family(ebml_w, 'b');
} else {
item_fn(_, purity, _, ref generics, _) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, purity_fn_family(purity));
let tps_len = generics.ty_params.len();
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
+ encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_attributes(ebml_w, item.attrs);
item_foreign_mod(ref fm) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'n');
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
ebml_w.end_tag();
}
- item_ty(_, ref generics) => {
+ item_ty(*) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'y');
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
+ encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 't');
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
+ encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
for (*enum_definition).variants.iter().advance |v| {
encode_variant_id(ebml_w, local_def(v.node.id));
index,
generics);
}
- item_struct(struct_def, ref generics) => {
+ item_struct(struct_def, _) => {
/* First, encode the fields
These come first because we need to write them to make
the index, and the index needs to be in the item for the
/* Now, make an item for the class itself */
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'S');
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
+ encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
index);
}
}
- item_impl(ref generics, ref opt_trait, ref ty, ref methods) => {
+ item_impl(_, ref opt_trait, ref ty, ref ast_methods) => {
+ // We need to encode information about the default methods we
+ // have inherited, so we drive this based on the impl structure.
+ let imp = tcx.impls.get(&def_id);
+
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'i');
encode_region_param(ecx, ebml_w, item);
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
+ encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
match ty.node {
}
_ => {}
}
- for methods.iter().advance |m| {
+ for imp.methods.iter().advance |method| {
ebml_w.start_tag(tag_item_impl_method);
- let method_def_id = local_def(m.id);
- let s = def_to_str(method_def_id);
+ let s = def_to_str(method.def_id);
ebml_w.writer.write(s.as_bytes());
ebml_w.end_tag();
}
for opt_trait.iter().advance |ast_trait_ref| {
- let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
+ let trait_ref = ty::node_id_to_trait_ref(
+ tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref);
}
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
let mut impl_path = vec::append(~[], path);
impl_path.push(ast_map::path_name(item.ident));
- for methods.iter().advance |m| {
- index.push(entry {val: m.id, pos: ebml_w.writer.tell()});
+ // Iterate down the methods, emitting them. We rely on the
+ // assumption that all of the actually implemented methods
+ // appear first in the impl structure, in the same order they do
+ // in the ast. This is a little sketchy.
+ let num_implemented_methods = ast_methods.len();
+ for imp.methods.iter().enumerate().advance |(i, m)| {
+ let ast_method = if i < num_implemented_methods {
+ Some(ast_methods[i])
+ } else { None };
+
+ index.push(entry {val: m.def_id.node, pos: ebml_w.writer.tell()});
encode_info_for_method(ecx,
ebml_w,
+ *m,
impl_path,
- should_inline(m.attrs),
+ false,
item.id,
- *m,
- generics,
- &m.generics);
+ ast_method)
}
}
- item_trait(ref generics, ref super_traits, ref ms) => {
+ item_trait(_, ref super_traits, ref ms) => {
add_to_index();
ebml_w.start_tag(tag_items_data_item);
- encode_def_id(ebml_w, local_def(item.id));
+ encode_def_id(ebml_w, def_id);
encode_family(ebml_w, 'I');
encode_region_param(ecx, ebml_w, item);
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- let trait_def = ty::lookup_trait_def(tcx, local_def(item.id));
+ let trait_def = ty::lookup_trait_def(tcx, def_id);
+ encode_ty_type_param_defs(ebml_w, ecx,
+ trait_def.generics.type_param_defs,
+ tag_items_data_item_ty_param_bounds);
encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
- for ty::trait_method_def_ids(tcx, local_def(item.id)).iter().advance |&method_def_id| {
+ for ty::trait_method_def_ids(tcx, def_id).iter().advance |&method_def_id| {
ebml_w.start_tag(tag_item_trait_method);
encode_def_id(ebml_w, method_def_id);
ebml_w.end_tag();
ebml_w.end_tag();
// Now output the method info for each method.
- let r = ty::trait_method_def_ids(tcx, local_def(item.id));
+ let r = ty::trait_method_def_ids(tcx, def_id);
for r.iter().enumerate().advance |(i, &method_def_id)| {
assert_eq!(method_def_id.crate, ast::local_crate);
encode_method_ty_fields(ecx, ebml_w, method_ty);
- encode_parent_item(ebml_w, local_def(item.id));
+ encode_parent_item(ebml_w, def_id);
let mut trait_path = vec::append(~[], path);
trait_path.push(ast_map::path_name(item.ident));
method_ty.fty.purity));
let tpt = ty::lookup_item_type(tcx, method_def_id);
- encode_ty_type_param_defs(ebml_w, ecx,
- tpt.generics.type_param_defs,
- tag_items_data_item_ty_param_bounds);
- encode_type(ecx, ebml_w, tpt.ty);
+ encode_bounds_and_type(ebml_w, ecx, &tpt);
}
_ => {
// If this is a static method, we've already encoded
// this.
if method_ty.explicit_self != sty_static {
- encode_type_param_bounds(ebml_w, ecx,
- &m.generics.ty_params);
+ // XXX: I feel like there is something funny going on.
+ let tpt = ty::lookup_item_type(tcx, method_def_id);
+ encode_bounds_and_type(ebml_w, ecx, &tpt);
}
encode_method_sort(ebml_w, 'p');
(ecx.encode_inlined_item)(
ecx, ebml_w, path,
- ii_method(local_def(item.id), true, m));
+ ii_method(def_id, true, m));
}
}
ebml_w.start_tag(tag_items_data_item);
match nitem.node {
- foreign_item_fn(_, purity, ref generics) => {
+ foreign_item_fn(_, purity, _) => {
encode_def_id(ebml_w, local_def(nitem.id));
encode_family(ebml_w, purity_fn_family(purity));
- encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
- encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
+ encode_bounds_and_type(ebml_w, ecx,
+ &lookup_item_type(ecx.tcx,local_def(nitem.id)));
encode_name(ecx, ebml_w, nitem.ident);
if abi.is_intrinsic() {
(ecx.encode_inlined_item)(ecx, ebml_w, *path, ii_foreign(nitem));
fn encode_info_for_items(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
- crate: &crate)
+ crate: &Crate)
-> ~[entry<int>] {
let index = @mut ~[];
ebml_w.start_tag(tag_items_data);
index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() });
encode_info_for_mod(ecx,
ebml_w,
- &crate.node.module,
+ &crate.module,
crate_node_id,
[],
syntax::parse::token::special_idents::invalid,
// Path and definition ID indexing
-fn create_index<T:Clone + Hash + IterBytes>(index: ~[entry<T>])
- -> ~[@~[entry<T>]] {
+fn create_index<T:Clone + Hash + IterBytes + 'static>(
+ index: ~[entry<T>])
+ -> ~[@~[entry<T>]] {
let mut buckets: ~[@mut ~[entry<T>]] = ~[];
for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); };
for index.iter().advance |elt| {
return buckets_frozen;
}
-fn encode_index<T>(ebml_w: &mut writer::Encoder,
- buckets: ~[@~[entry<T>]],
- write_fn: &fn(@io::Writer, &T)) {
+fn encode_index<T:'static>(
+ ebml_w: &mut writer::Encoder,
+ buckets: ~[@~[entry<T>]],
+ write_fn: &fn(@io::Writer, &T)) {
let writer = ebml_w.writer;
ebml_w.start_tag(tag_index);
let mut bucket_locs: ~[uint] = ~[];
writer.write_be_u32(n as u32);
}
-fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) {
+fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) {
match mi.node {
- meta_word(name) => {
+ MetaWord(name) => {
ebml_w.start_tag(tag_meta_item_word);
ebml_w.start_tag(tag_meta_item_name);
ebml_w.writer.write(name.as_bytes());
ebml_w.end_tag();
ebml_w.end_tag();
}
- meta_name_value(name, value) => {
+ MetaNameValue(name, value) => {
match value.node {
lit_str(value) => {
ebml_w.start_tag(tag_meta_item_name_value);
_ => {/* FIXME (#623): encode other variants */ }
}
}
- meta_list(name, ref items) => {
+ MetaList(name, ref items) => {
ebml_w.start_tag(tag_meta_item_list);
ebml_w.start_tag(tag_meta_item_name);
ebml_w.writer.write(name.as_bytes());
}
}
-fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) {
+fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[Attribute]) {
ebml_w.start_tag(tag_attributes);
for attrs.iter().advance |attr| {
ebml_w.start_tag(tag_attribute);
// 'name' and 'vers' items, so if the user didn't provide them we will throw
// them in anyway with default values.
fn synthesize_crate_attrs(ecx: &EncodeContext,
- crate: &crate) -> ~[attribute] {
+ crate: &Crate) -> ~[Attribute] {
- fn synthesize_link_attr(ecx: &EncodeContext, items: ~[@meta_item]) ->
- attribute {
+ fn synthesize_link_attr(ecx: &EncodeContext, items: ~[@MetaItem]) ->
+ Attribute {
assert!(!ecx.link_meta.name.is_empty());
assert!(!ecx.link_meta.vers.is_empty());
attr::mk_name_value_item_str(@"vers",
ecx.link_meta.vers);
- let other_items =
- {
- let tmp = attr::remove_meta_items_by_name(items, "name");
- attr::remove_meta_items_by_name(tmp, "vers")
- };
+ let mut meta_items = ~[name_item, vers_item];
- let meta_items = vec::append(~[name_item, vers_item], other_items);
+ for items.iter()
+ .filter(|mi| "name" != mi.name() && "vers" != mi.name())
+ .advance |&mi| {
+ meta_items.push(mi);
+ }
let link_item = attr::mk_list_item(@"link", meta_items);
return attr::mk_attr(link_item);
}
- let mut attrs: ~[attribute] = ~[];
+ let mut attrs = ~[];
let mut found_link_attr = false;
- for crate.node.attrs.iter().advance |attr| {
+ for crate.attrs.iter().advance |attr| {
attrs.push(
- if "link" != attr::get_attr_name(attr) {
+ if "link" != attr.name() {
*attr
} else {
- match attr.node.value.node {
- meta_list(_, ref l) => {
+ match attr.meta_item_list() {
+ Some(l) => {
found_link_attr = true;;
- synthesize_link_attr(ecx, (*l).clone())
+ synthesize_link_attr(ecx, l.to_owned())
}
_ => *attr
}
}
fn encode_misc_info(ecx: &EncodeContext,
- crate: &crate,
+ crate: &Crate,
ebml_w: &mut writer::Encoder) {
ebml_w.start_tag(tag_misc_info);
ebml_w.start_tag(tag_misc_info_crate_items);
- for crate.node.module.items.iter().advance |&item| {
+ for crate.module.items.iter().advance |&item| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(item.id)));
ebml_w.end_tag();
0x74, //'t' as u8,
0, 0, 0, 1 ];
-pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
+pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
let wr = @io::BytesWriter::new();
let stats = Stats {
inline_bytes: 0,
let r = os::list_dir_path(lib_search_path);
for r.iter().advance |path| {
debug!("testing %s", path.to_str());
- let maybe_picked = pick(*path);
+ let maybe_picked = pick(path);
if maybe_picked.is_some() {
debug!("picked %s", path.to_str());
rslt = maybe_picked;
use syntax::parse::token::ident_interner;
use syntax::print::pprust;
use syntax::{ast, attr};
+use syntax::attr::AttrMetaMethods;
use std::cast;
use std::io;
filesearch: @FileSearch,
span: span,
ident: ast::ident,
- metas: ~[@ast::meta_item],
+ metas: ~[@ast::MetaItem],
hash: @str,
os: os,
is_static: bool,
pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
match find_library_crate(cx) {
- Some(ref t) => return (/*bad*/(*t).clone()),
+ Some(t) => t,
None => {
cx.diag.span_fatal(cx.span,
fmt!("can't find crate for `%s`",
}
}
-pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @str {
+pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str {
for metas.iter().advance |m| {
- match m.node {
- ast::meta_name_value(s, ref l) if s == @"name" =>
- match l.node {
- ast::lit_str(s) => return s,
- _ => ()
- },
- _ => ()
+ match m.name_str_pair() {
+ Some((name, s)) if "name" == name => { return s; }
+ _ => {}
}
}
fail!("expected to find the crate name")
pub fn note_linkage_attrs(intr: @ident_interner,
diag: @span_handler,
- attrs: ~[ast::attribute]) {
+ attrs: ~[ast::Attribute]) {
let r = attr::find_linkage_metas(attrs);
for r.iter().advance |mi| {
diag.handler().note(fmt!("meta: %s", pprust::meta_item_to_str(*mi,intr)));
}
fn crate_matches(crate_data: @~[u8],
- metas: &[@ast::meta_item],
+ metas: &[@ast::MetaItem],
hash: @str) -> bool {
let attrs = decoder::get_crate_attributes(crate_data);
let linkage_metas = attr::find_linkage_metas(attrs);
metadata_matches(linkage_metas, metas)
}
-pub fn metadata_matches(extern_metas: &[@ast::meta_item],
- local_metas: &[@ast::meta_item]) -> bool {
+pub fn metadata_matches(extern_metas: &[@ast::MetaItem],
+ local_metas: &[@ast::MetaItem]) -> bool {
debug!("matching %u metadata requirements against %u items",
local_metas.len(), extern_metas.len());
- for local_metas.iter().advance |needed| {
- if !attr::contains(extern_metas, *needed) {
- return false;
- }
+ do local_metas.iter().all |needed| {
+ attr::contains(extern_metas, *needed)
}
- return true;
}
fn get_metadata_section(os: os,
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
- fn drop_nested_items(blk: &ast::blk, fld: @fold::ast_fold) -> ast::blk {
+ fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
match stmt.node {
ast::stmt_expr(_, _) | ast::stmt_semi(_, _) |
ast::stmt_mac(*) => fail!("unexpanded macro in astencode")
}
}.collect();
- let blk_sans_items = ast::blk {
+ let blk_sans_items = ast::Block {
view_items: ~[], // I don't know if we need the view_items here,
// but it doesn't break tests!
stmts: stmts_sans_items,
#[cfg(test)]
trait fake_ext_ctxt {
- fn cfg(&self) -> ast::crate_cfg;
+ fn cfg(&self) -> ast::CrateConfig;
fn parse_sess(&self) -> @mut parse::ParseSess;
fn call_site(&self) -> span;
fn ident_of(&self, st: &str) -> ast::ident;
#[cfg(test)]
impl fake_ext_ctxt for fake_session {
- fn cfg(&self) -> ast::crate_cfg { ~[] }
+ fn cfg(&self) -> ast::CrateConfig { ~[] }
fn parse_sess(&self) -> @mut parse::ParseSess { *self }
fn call_site(&self) -> span {
codemap::span {
use syntax::visit;
use util::ppaux::Repr;
+#[deriving(Clone)]
struct CheckLoanCtxt<'self> {
bccx: @BorrowckCtxt,
dfcx_loans: &'self LoanDataFlow,
- move_data: move_data::FlowedMoveData,
+ move_data: @move_data::FlowedMoveData,
all_loans: &'self [Loan],
reported: @mut HashSet<ast::node_id>,
}
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
all_loans: &[Loan],
- body: &ast::blk) {
+ body: &ast::Block) {
debug!("check_loans(body id=%?)", body.id);
- let clcx = @mut CheckLoanCtxt {
+ let clcx = CheckLoanCtxt {
bccx: bccx,
dfcx_loans: dfcx_loans,
- move_data: move_data,
+ move_data: @move_data,
all_loans: all_loans,
reported: @mut HashSet::new(),
};
return result;
}
- pub fn check_for_conflicting_loans(&mut self, scope_id: ast::node_id) {
+ pub fn check_for_conflicting_loans(&self, scope_id: ast::node_id) {
//! Checks to see whether any of the loans that are issued
//! by `scope_id` conflict with loans that have already been
//! issued when we enter `scope_id` (for example, we do not
MoveOk
}
- pub fn check_call(&mut self,
+ pub fn check_call(&self,
_expr: @ast::expr,
_callee: Option<@ast::expr>,
_callee_id: ast::node_id,
fn check_loans_in_fn<'a>(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
- (this, visitor): (@mut CheckLoanCtxt<'a>,
- visit::vt<@mut CheckLoanCtxt<'a>>)) {
+ (this, visitor): (CheckLoanCtxt<'a>,
+ visit::vt<CheckLoanCtxt<'a>>)) {
match *fk {
visit::fk_item_fn(*) |
visit::fk_method(*) => {
visit::visit_fn(fk, decl, body, sp, id, (this, visitor));
- fn check_captured_variables(this: @mut CheckLoanCtxt,
+ fn check_captured_variables(this: CheckLoanCtxt,
closure_id: ast::node_id,
span: span) {
let cap_vars = this.bccx.capture_map.get(&closure_id);
}
return;
- fn check_by_move_capture(this: @mut CheckLoanCtxt,
+ fn check_by_move_capture(this: CheckLoanCtxt,
closure_id: ast::node_id,
cap_var: &moves::CaptureVar,
move_path: @LoanPath) {
}
}
-fn check_loans_in_local<'a>(local: @ast::local,
- (this, vt): (@mut CheckLoanCtxt<'a>,
- visit::vt<@mut CheckLoanCtxt<'a>>)) {
+fn check_loans_in_local<'a>(local: @ast::Local,
+ (this, vt): (CheckLoanCtxt<'a>,
+ visit::vt<CheckLoanCtxt<'a>>)) {
visit::visit_local(local, (this, vt));
}
fn check_loans_in_expr<'a>(expr: @ast::expr,
- (this, vt): (@mut CheckLoanCtxt<'a>,
- visit::vt<@mut CheckLoanCtxt<'a>>)) {
+ (this, vt): (CheckLoanCtxt<'a>,
+ visit::vt<CheckLoanCtxt<'a>>)) {
visit::visit_expr(expr, (this, vt));
debug!("check_loans_in_expr(expr=%s)",
}
fn check_loans_in_pat<'a>(pat: @ast::pat,
- (this, vt): (@mut CheckLoanCtxt<'a>,
- visit::vt<@mut CheckLoanCtxt<'a>>))
+ (this, vt): (CheckLoanCtxt<'a>,
+ visit::vt<CheckLoanCtxt<'a>>))
{
this.check_for_conflicting_loans(pat.id);
this.check_move_out_from_id(pat.id, pat.span);
visit::visit_pat(pat, (this, vt));
}
-fn check_loans_in_block<'a>(blk: &ast::blk,
- (this, vt): (@mut CheckLoanCtxt<'a>,
- visit::vt<@mut CheckLoanCtxt<'a>>))
+fn check_loans_in_block<'a>(blk: &ast::Block,
+ (this, vt): (CheckLoanCtxt<'a>,
+ visit::vt<CheckLoanCtxt<'a>>))
{
visit::visit_block(blk, (this, vt));
this.check_for_conflicting_loans(blk.id);
pub fn gather_loans(bccx: @BorrowckCtxt,
decl: &ast::fn_decl,
- body: &ast::blk)
+ body: &ast::Block)
-> (id_range, @mut ~[Loan], @mut move_data::MoveData) {
let glcx = @mut GatherLoanCtxt {
bccx: bccx,
fn gather_loans_in_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(this, v): (@mut GatherLoanCtxt,
}
}
-fn gather_loans_in_block(blk: &ast::blk,
+fn gather_loans_in_block(blk: &ast::Block,
(this, vt): (@mut GatherLoanCtxt,
visit::vt<@mut GatherLoanCtxt>)) {
this.id_range.add(blk.id);
visit::visit_block(blk, (this, vt));
}
-fn gather_loans_in_local(local: @ast::local,
+fn gather_loans_in_local(local: @ast::Local,
(this, vt): (@mut GatherLoanCtxt,
visit::vt<@mut GatherLoanCtxt>)) {
- match local.node.init {
+ match local.init {
None => {
// Variable declarations without initializers are considered "moves":
let tcx = this.bccx.tcx;
- do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+ do pat_util::pat_bindings(tcx.def_map, local.pat)
|_, id, span, _| {
gather_moves::gather_decl(this.bccx,
this.move_data,
Some(init) => {
// Variable declarations with initializers are considered "assigns":
let tcx = this.bccx.tcx;
- do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+ do pat_util::pat_bindings(tcx.def_map, local.pat)
|_, id, span, _| {
gather_moves::gather_assignment(this.bccx,
this.move_data,
id);
}
let init_cmt = this.bccx.cat_expr(init);
- this.gather_pat(init_cmt, local.node.pat, None);
+ this.gather_pat(init_cmt, local.pat, None);
}
}
fn gather_fn_arg_patterns(&mut self,
decl: &ast::fn_decl,
- body: &ast::blk) {
+ body: &ast::Block) {
/*!
* Walks the patterns for fn arguments, checking that they
* do not attempt illegal moves or create refs that outlive
moves_map: moves::MovesMap,
moved_variables_set: moves::MovedVariablesSet,
capture_map: moves::CaptureMap,
- crate: &ast::crate) -> (root_map, write_guard_map)
+ crate: &ast::Crate) -> (root_map, write_guard_map)
{
let bccx = @BorrowckCtxt {
tcx: tcx,
fn borrowck_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(this, v): (@BorrowckCtxt,
tcx: ty::ctxt,
method_map: typeck::method_map,
id_range: ast_util::id_range,
- body: &ast::blk)
+ body: &ast::Block)
-> FlowedMoveData
{
let mut dfcx_moves =
pub fn construct(tcx: ty::ctxt,
method_map: typeck::method_map,
- blk: &ast::blk) -> CFG {
+ blk: &ast::Block) -> CFG {
let mut cfg_builder = CFGBuilder {
exit_map: HashMap::new(),
graph: graph::Graph::new(),
}
impl CFGBuilder {
- fn block(&mut self, blk: &ast::blk, pred: CFGIndex) -> CFGIndex {
+ fn block(&mut self, blk: &ast::Block, pred: CFGIndex) -> CFGIndex {
let mut stmts_exit = pred;
for blk.stmts.iter().advance |&stmt| {
stmts_exit = self.stmt(stmt, stmts_exit);
fn decl(&mut self, decl: @ast::decl, pred: CFGIndex) -> CFGIndex {
match decl.node {
ast::decl_local(local) => {
- let init_exit = self.opt_expr(local.node.init, pred);
- self.pat(local.node.pat, init_exit)
+ let init_exit = self.opt_expr(local.init, pred);
+ self.pat(local.pat, init_exit)
}
ast::decl_item(_) => {
ast::expr_struct(_, ref fields, base) => {
let base_exit = self.opt_expr(base, pred);
let field_exprs: ~[@ast::expr] =
- fields.iter().transform(|f| f.node.expr).collect();
+ fields.iter().transform(|f| f.expr).collect();
self.straightline(expr, base_exit, field_exprs)
}
impl CFG {
pub fn new(tcx: ty::ctxt,
method_map: typeck::method_map,
- blk: &ast::blk) -> CFG {
+ blk: &ast::Block) -> CFG {
construct::construct(tcx, method_map, blk)
}
}
\ No newline at end of file
use syntax::{visit, ast_util, ast_map};
pub fn check_crate(sess: Session,
- crate: &crate,
+ crate: &Crate,
ast_map: ast_map::map,
def_map: resolve::DefMap,
method_map: typeck::method_map,
can_ret: bool
}
-pub fn check_crate(tcx: ty::ctxt, crate: &crate) {
+pub fn check_crate(tcx: ty::ctxt, crate: &Crate) {
visit::visit_crate(crate,
(Context { in_loop: false, can_ret: true },
visit::mk_vt(@visit::Visitor {
pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
moves_map: moves::MovesMap,
- crate: &crate) {
+ crate: &Crate) {
let cx = @MatchCheckCtxt {tcx: tcx,
method_map: method_map,
moves_map: moves_map};
}
pub fn check_local(cx: &MatchCheckCtxt,
- loc: @local,
+ loc: @Local,
(s, v): ((),
visit::vt<()>)) {
visit::visit_local(loc, (s, v));
- if is_refutable(cx, loc.node.pat) {
- cx.tcx.sess.span_err(loc.node.pat.span,
+ if is_refutable(cx, loc.pat) {
+ cx.tcx.sess.span_err(loc.pat.span,
"refutable pattern in local binding");
}
// Check legality of move bindings.
- check_legality_of_move_bindings(cx, false, [ loc.node.pat ]);
+ check_legality_of_move_bindings(cx, false, [ loc.pat ]);
}
pub fn check_fn(cx: &MatchCheckCtxt,
kind: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(s, v): ((),
ast::expr_struct(_, ref fs, None) => {
let cs = do fs.iter().transform |f| {
- classify(f.node.expr, tcx)
+ classify(f.expr, tcx)
};
join_all(cs)
}
}
}
-pub fn process_crate(crate: &ast::crate,
+pub fn process_crate(crate: &ast::Crate,
tcx: ty::ctxt) {
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr_post: |e| { classify(e, tcx); },
impl<O:DataFlowOperator+Clone+'static> DataFlowContext<O> {
// ^^^^^^^^^^^^^ only needed for pretty printing
- pub fn propagate(&mut self, blk: &ast::blk) {
+ pub fn propagate(&mut self, blk: &ast::Block) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
});
}
- fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::blk) {
+ fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) {
let pre: @fn(pprust::ann_node) = |node| {
let (ps, id) = match node {
pprust::node_expr(ps, expr) => (ps, expr.id),
}
fn walk_block(&mut self,
- blk: &ast::blk,
+ blk: &ast::Block,
in_out: &mut [uint],
loop_scopes: &mut ~[LoopScope]) {
debug!("DataFlowContext::walk_block(blk.id=%?, in_out=%s)",
loop_scopes: &mut ~[LoopScope]) {
match decl.node {
ast::decl_local(local) => {
- self.walk_opt_expr(local.node.init, in_out, loop_scopes);
- self.walk_pat(local.node.pat, in_out, loop_scopes);
+ self.walk_opt_expr(local.init, in_out, loop_scopes);
+ self.walk_pat(local.pat, in_out, loop_scopes);
}
ast::decl_item(_) => {}
ast::expr_struct(_, ref fields, with_expr) => {
for fields.iter().advance |field| {
- self.walk_expr(field.node.expr, in_out, loop_scopes);
+ self.walk_expr(field.expr, in_out, loop_scopes);
}
self.walk_opt_expr(with_expr, in_out, loop_scopes);
}
pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
- crate: &ast::crate) {
+ crate: &ast::Crate) {
let context = @mut Context {
method_map: method_map,
unsafe_context: SafeContext,
use driver::session;
use driver::session::Session;
use syntax::parse::token::special_idents;
-use syntax::ast::{crate, node_id, item, item_fn};
+use syntax::ast::{Crate, node_id, item, item_fn};
+use syntax::attr;
use syntax::codemap::span;
use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item};
-use syntax::attr::{attrs_contains_name};
use syntax::ast_map;
use std::util;
type EntryVisitor = vt<@mut EntryContext>;
-pub fn find_entry_point(session: Session, crate: &crate, ast_map: ast_map::map) {
+pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) {
// FIXME #4404 android JNI hacks
if *session.building_library &&
}
}
- if attrs_contains_name(item.attrs, "main") {
+ if attr::contains_name(item.attrs, "main") {
if ctxt.attr_main_fn.is_none() {
ctxt.attr_main_fn = Some((item.id, item.span));
} else {
}
}
- if attrs_contains_name(item.attrs, "start") {
+ if attr::contains_name(item.attrs, "start") {
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.id, item.span));
} else {
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
-fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk)
+fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
-pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::crate) ->
+pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
freevar_map {
let freevars = @mut HashMap::new();
let walk_fn: @fn(&visit::fn_kind,
&ast::fn_decl,
- &ast::blk,
+ &ast::Block,
span,
ast::node_id) = |_, _, blk, _, nid| {
let vars = collect_freevars(def_map, blk);
use util::ppaux::UserString;
use syntax::ast::*;
-use syntax::attr::attrs_contains_name;
+use syntax::attr;
use syntax::codemap::span;
use syntax::print::pprust::expr_to_str;
use syntax::{visit, ast_util};
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
- crate: &crate) {
+ crate: &Crate) {
let ctx = Context {
tcx: tcx,
method_map: method_map,
}
}
-fn check_block(block: &blk, (cx, visitor): (Context, visit::vt<Context>)) {
+fn check_block(block: &Block, (cx, visitor): (Context, visit::vt<Context>)) {
visit::visit_block(block, (cx, visitor));
}
fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
// If this is a destructor, check kinds.
- if !attrs_contains_name(item.attrs, "unsafe_destructor") {
+ if !attr::contains_name(item.attrs, "unsafe_destructor") {
match item.node {
item_impl(_, Some(ref trait_ref), ref self_type, _) => {
match cx.tcx.def_map.find(&trait_ref.ref_id) {
fn check_fn(
fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
fn_id: node_id,
(cx, v): (Context,
}
match e.node {
+ expr_unary(_, box(_), interior) => {
+ let interior_type = ty::expr_ty(cx.tcx, interior);
+ let _ = check_durable(cx.tcx, interior_type, interior.span);
+ }
expr_cast(source, _) => {
check_cast_for_escaping_regions(cx, source, e);
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
cx.tcx.region_maps.is_subregion_of(r_sub, r_sup)
}
}
-
use driver::session::Session;
use metadata::csearch::each_lang_item;
use metadata::cstore::iter_crate_data;
-use syntax::ast::{crate, def_id, lit_str, meta_item};
-use syntax::ast::{meta_list, meta_name_value, meta_word};
+use syntax::ast::{Crate, def_id, MetaItem};
use syntax::ast_util::local_def;
+use syntax::attr::AttrMetaMethods;
use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor};
use syntax::visit::visit_crate;
struct LanguageItemCollector<'self> {
items: LanguageItems,
- crate: &'self crate,
+ crate: &'self Crate,
session: Session,
item_refs: HashMap<@str, uint>,
}
impl<'self> LanguageItemCollector<'self> {
- pub fn new<'a>(crate: &'a crate, session: Session)
+ pub fn new<'a>(crate: &'a Crate, session: Session)
-> LanguageItemCollector<'a> {
let mut item_refs = HashMap::new();
pub fn match_and_collect_meta_item(&mut self,
item_def_id: def_id,
- meta_item: &meta_item) {
- match meta_item.node {
- meta_name_value(key, literal) => {
- match literal.node {
- lit_str(value) => {
- self.match_and_collect_item(item_def_id, key, value);
- }
- _ => {} // Skip.
- }
+ meta_item: &MetaItem) {
+ match meta_item.name_str_pair() {
+ Some((key, value)) => {
+ self.match_and_collect_item(item_def_id, key, value);
}
- meta_word(*) | meta_list(*) => {} // Skip.
+ None => {} // skip
}
}
}
}
-pub fn collect_language_items(crate: &crate,
+pub fn collect_language_items(crate: &Crate,
session: Session)
-> LanguageItems {
let mut collector = LanguageItemCollector::new(crate, session);
use std::u8;
use extra::smallintmap::SmallIntMap;
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::span;
use syntax::codemap;
use syntax::{ast, visit, ast_util};
unnecessary_qualification,
while_true,
path_statement,
- implicit_copies,
unrecognized_lint,
- deprecated_pattern,
non_camel_case_types,
non_uppercase_statics,
type_limits,
enum AttributedNode<'self> {
Item(@ast::item),
Method(&'self ast::method),
- Crate(@ast::crate),
+ Crate(@ast::Crate),
}
#[deriving(Eq)]
default: warn
}),
- ("implicit_copies",
- LintSpec {
- lint: implicit_copies,
- desc: "implicit copies of non implicitly copyable data",
- default: warn
- }),
-
- ("deprecated_pattern",
- LintSpec {
- lint: deprecated_pattern,
- desc: "warn about deprecated uses of pattern bindings",
- default: allow
- }),
-
("non_camel_case_types",
LintSpec {
lint: non_camel_case_types,
* current lint context, call the provided function, then reset the
* lints in effect to their previous state.
*/
- fn with_lint_attrs(@mut self, attrs: &[ast::attribute], f: &fn()) {
+ fn with_lint_attrs(@mut self, attrs: &[ast::Attribute], f: &fn()) {
// Parse all of the lint attributes, and then add them all to the
// current dictionary of lint information. Along the way, keep a history
// of what we changed so we can roll everything back after invoking the
}
// detect doc(hidden)
- let mut doc_hidden = false;
- let r = attr::find_attrs_by_name(attrs, "doc");
- for r.iter().advance |attr| {
- match attr::get_meta_item_list(attr.node.value) {
- Some(s) => {
- if attr::find_meta_items_by_name(s, "hidden").len() > 0 {
- doc_hidden = true;
- }
+ let mut doc_hidden = do attrs.iter().any |attr| {
+ "doc" == attr.name() &&
+ match attr.meta_item_list() {
+ Some(l) => attr::contains_name(l, "hidden"),
+ None => false // not of the form #[doc(...)]
}
- None => {}
- }
- }
+ };
+
if doc_hidden && !self.doc_hidden {
self.doc_hidden = true;
} else {
}
pub fn each_lint(sess: session::Session,
- attrs: &[ast::attribute],
- f: &fn(@ast::meta_item, level, @str) -> bool) -> bool {
+ attrs: &[ast::Attribute],
+ f: &fn(@ast::MetaItem, level, @str) -> bool) -> bool {
let xs = [allow, warn, deny, forbid];
for xs.iter().advance |&level| {
let level_name = level_to_str(level);
- let attrs = attr::find_attrs_by_name(attrs, level_name);
- for attrs.iter().advance |attr| {
+ for attrs.iter().filter(|m| level_name == m.name()).advance |attr| {
let meta = attr.node.value;
let metas = match meta.node {
- ast::meta_list(_, ref metas) => metas,
+ ast::MetaList(_, ref metas) => metas,
_ => {
sess.span_err(meta.span, "malformed lint attribute");
loop;
};
for metas.iter().advance |meta| {
match meta.node {
- ast::meta_word(lintname) => {
+ ast::MetaWord(lintname) => {
if !f(*meta, level, lintname) {
return false;
}
visit::mk_vt(@visit::Visitor {
visit_local: |l, (cx, vt): (@mut Context, visit::vt<@mut Context>)| {
- if l.node.is_mutbl {
- check_pat(cx, l.node.pat);
+ if l.is_mutbl {
+ check_pat(cx, l.pat);
}
visit::visit_local(l, (cx, vt));
},
}
fn lint_missing_doc() -> visit::vt<@mut Context> {
- fn check_attrs(cx: @mut Context, attrs: &[ast::attribute],
+ fn check_attrs(cx: @mut Context, attrs: &[ast::Attribute],
sp: span, msg: &str) {
// If we're building a test harness, then warning about documentation is
// probably not really relevant right now
})
}
-pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
+pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) {
let cx = @mut Context {
dict: @get_lint_dict(),
curr: SmallIntMap::new(),
cx.add_lint(lint_missing_doc());
// Actually perform the lint checks (iterating the ast)
- do cx.with_lint_attrs(crate.node.attrs) {
+ do cx.with_lint_attrs(crate.attrs) {
cx.process(Crate(crate));
visit::visit_crate(crate, (cx, visit::mk_vt(@visit::Visitor {
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
capture_map: moves::CaptureMap,
- crate: &crate) {
+ crate: &Crate) {
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: visit_fn,
visit_local: visit_local,
fn visit_fn(fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(this, v): (@mut IrMaps,
lsets.warn_about_unused_args(decl, entry_ln);
}
-fn visit_local(local: @local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
+fn visit_local(local: @Local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
let def_map = this.tcx.def_map;
- do pat_util::pat_bindings(def_map, local.node.pat) |_bm, p_id, sp, path| {
+ do pat_util::pat_bindings(def_map, local.pat) |_bm, p_id, sp, path| {
debug!("adding local variable %d", p_id);
let name = ast_util::path_to_ident(path);
this.add_live_node_for_node(p_id, VarDefNode(sp));
- let kind = match local.node.init {
+ let kind = match local.init {
Some(_) => FromLetWithInitializer,
None => FromLetNoInitializer
};
this.add_variable(Local(LocalInfo {
id: p_id,
ident: name,
- is_mutbl: local.node.is_mutbl,
+ is_mutbl: local.is_mutbl,
kind: kind
}));
}
// _______________________________________________________________________
- pub fn compute(&self, decl: &fn_decl, body: &blk) -> LiveNode {
+ pub fn compute(&self, decl: &fn_decl, body: &Block) -> LiveNode {
// if there is a `break` or `again` at the top level, then it's
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
entry_ln
}
- pub fn propagate_through_fn_block(&self, _: &fn_decl, blk: &blk)
+ pub fn propagate_through_fn_block(&self, _: &fn_decl, blk: &Block)
-> LiveNode {
// the fallthrough exit is only for those cases where we do not
// explicitly return:
self.propagate_through_block(blk, self.s.fallthrough_ln)
}
- pub fn propagate_through_block(&self, blk: &blk, succ: LiveNode)
+ pub fn propagate_through_block(&self, blk: &Block, succ: LiveNode)
-> LiveNode {
let succ = self.propagate_through_opt_expr(blk.expr, succ);
do blk.stmts.rev_iter().fold(succ) |succ, stmt| {
}
}
- pub fn propagate_through_local(&self, local: &local, succ: LiveNode)
+ pub fn propagate_through_local(&self, local: &Local, succ: LiveNode)
-> LiveNode {
// Note: we mark the variable as defined regardless of whether
// there is an initializer. Initially I had thought to only mark
// initialization, which is mildly more complex than checking
// once at the func header but otherwise equivalent.
- let succ = self.propagate_through_opt_expr(local.node.init, succ);
- self.define_bindings_in_pat(local.node.pat, succ)
+ let succ = self.propagate_through_opt_expr(local.init, succ);
+ self.define_bindings_in_pat(local.pat, succ)
}
pub fn propagate_through_exprs(&self, exprs: &[@expr], succ: LiveNode)
expr_struct(_, ref fields, with_expr) => {
let succ = self.propagate_through_opt_expr(with_expr, succ);
do fields.rev_iter().fold(succ) |succ, field| {
- self.propagate_through_expr(field.node.expr, succ)
+ self.propagate_through_expr(field.expr, succ)
}
}
pub fn propagate_through_loop(&self,
expr: &expr,
cond: Option<@expr>,
- body: &blk,
+ body: &Block,
succ: LiveNode)
-> LiveNode {
// _______________________________________________________________________
// Checking for error conditions
-fn check_local(local: @local, (this, vt): (@Liveness, vt<@Liveness>)) {
- match local.node.init {
+fn check_local(local: @Local, (this, vt): (@Liveness, vt<@Liveness>)) {
+ match local.init {
Some(_) => {
- this.warn_about_unused_or_dead_vars_in_pat(local.node.pat);
+ this.warn_about_unused_or_dead_vars_in_pat(local.pat);
}
None => {
// should not be live at this point.
debug!("check_local() with no initializer");
- do this.pat_bindings(local.node.pat) |ln, var, sp, id| {
+ do this.pat_bindings(local.pat) |ln, var, sp, id| {
if !this.warn_about_unused(sp, id, ln, var) {
match this.live_on_exit(ln, var) {
None => { /* not live: good */ }
}
fn check_fn(_fk: &visit::fn_kind, _decl: &fn_decl,
- _body: &blk, _sp: span, _id: node_id,
+ _body: &Block, _sp: span, _id: node_id,
(_self, _v): (@Liveness, vt<@Liveness>)) {
// do not check contents of nested fns
}
pub fn compute_moves(tcx: ty::ctxt,
method_map: method_map,
- crate: &crate) -> MoveMaps
+ crate: &Crate) -> MoveMaps
{
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: compute_modes_for_fn,
///////////////////////////////////////////////////////////////////////////
// Expressions
-fn compute_modes_for_local<'a>(local: @local,
+fn compute_modes_for_local<'a>(local: @Local,
(cx, v): (VisitContext,
vt<VisitContext>)) {
- cx.use_pat(local.node.pat);
- for local.node.init.iter().advance |&init| {
+ cx.use_pat(local.pat);
+ for local.init.iter().advance |&init| {
cx.use_expr(init, Read, v);
}
}
fn compute_modes_for_fn(fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
span: span,
id: node_id,
(cx, v): (VisitContext,
};
}
- pub fn consume_block(&self, blk: &blk, visitor: vt<VisitContext>) {
+ pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
/*!
* Indicates that the value of `blk` will be consumed,
* meaning either copied or moved depending on its type.
expr_struct(_, ref fields, opt_with) => {
for fields.iter().advance |field| {
- self.consume_expr(field.node.expr, visitor);
+ self.consume_expr(field.expr, visitor);
}
for opt_with.iter().advance |with_expr| {
// specified and (2) have a type that
// moves-by-default:
let consume_with = with_fields.iter().any(|tf| {
- !fields.iter().any(|f| f.node.ident == tf.ident) &&
+ !fields.iter().any(|f| f.ident == tf.ident) &&
ty::type_moves_by_default(self.tcx, tf.mt.ty)
});
pub fn check_crate<'mm>(tcx: ty::ctxt,
method_map: &'mm method_map,
- crate: &ast::crate) {
+ crate: &ast::Crate) {
let privileged_items = @mut ~[];
// Adds an item to its scope.
}
};
- // Returns the ID of the container (impl or trait) that a crate-local
- // method belongs to.
- let local_method_container_id:
- @fn(span: span, method_id: node_id) -> def_id =
- |span, method_id| {
- match tcx.items.find(&method_id) {
- Some(&node_method(_, impl_id, _)) => impl_id,
- Some(&node_trait_method(_, trait_id, _)) => trait_id,
- Some(_) => {
- tcx.sess.span_bug(span,
- fmt!("method was a %s?!",
- ast_map::node_id_to_str(
- tcx.items,
- method_id,
- token::get_ident_interner())));
- }
- None => {
- tcx.sess.span_bug(span, "method not found in \
- AST map?!");
- }
- }
- };
-
// Returns true if a crate-local method is private and false otherwise.
let method_is_private: @fn(span: span, method_id: node_id) -> bool =
|span, method_id| {
// If the method is a default method, we need to use the def_id of
// the default implementation.
// Having to do this this is really unfortunate.
- let method_id = match tcx.provided_method_sources.find(&method_id) {
- None => method_id,
- Some(source) => source.method_id
- };
+ let method_id = ty::method(tcx, method_id).provided_source
+ .get_or_default(method_id);
if method_id.crate == local_crate {
let is_private = method_is_private(span, method_id.node);
- let container_id = local_method_container_id(span,
- method_id.node);
+ let container_id = ty::method(tcx, method_id).container_id;
if is_private &&
(container_id.crate != local_crate ||
!privileged_items.iter().any(|x| x == &(container_id.node))) {
visit_item: |item, (method_map, visitor)| {
// Do not check privacy inside items with the resolve_unexported
// attribute. This is used for the test runner.
- if !attr::contains_name(attr::attr_metas(item.attrs),
- "!resolve_unexported") {
+ if !attr::contains_name(item.attrs, "!resolve_unexported") {
visit::visit_item(item, (method_map, visitor));
}
},
Some(ref entry) => {
debug!("(privacy checking) checking \
impl method");
- check_method(expr.span,
- &entry.origin,
- ident);
+ check_method(expr.span, &entry.origin, ident);
}
}
}
for (*fields).iter().advance |field| {
debug!("(privacy checking) checking \
field in struct literal");
- check_field(expr.span, id,
- field.node.ident);
+ check_field(expr.span, id, field.ident);
}
}
}
checking field in \
struct variant \
literal");
- check_field(expr.span, variant_id,
- field.node.ident);
+ check_field(expr.span, variant_id, field.ident);
}
}
_ => {
for fields.iter().advance |field| {
debug!("(privacy checking) checking \
struct pattern");
- check_field(pattern.span, id,
- field.ident);
+ check_field(pattern.span, id, field.ident);
}
}
}
debug!("(privacy checking) \
checking field in \
struct variant pattern");
- check_field(pattern.span,
- variant_id,
- field.ident);
+ check_field(pattern.span, variant_id, field.ident);
}
}
_ => {
// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
-fn attributes_specify_inlining(attrs: &[attribute]) -> bool {
- attr::attrs_contains_name(attrs, "inline")
+fn attributes_specify_inlining(attrs: &[Attribute]) -> bool {
+ attr::contains_name(attrs, "inline")
}
// Returns true if the given set of generics implies that the item it's
// Step 1: Mark all public symbols, and add all public symbols that might
// be inlined to a worklist.
- fn mark_public_symbols(&self, crate: @crate) {
+ fn mark_public_symbols(&self, crate: @Crate) {
let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist;
let visitor = visit::mk_vt(@Visitor {
pub fn find_reachable(tcx: ty::ctxt,
method_map: typeck::method_map,
- crate: @crate)
+ crate: @Crate)
-> @mut HashSet<node_id> {
// XXX(pcwalton): We only need to mark symbols that are exported. But this
// is more complicated than just looking at whether the symbol is `pub`,
// Return the set of reachable symbols.
reachable_context.reachable_symbols
}
-
}
}
-fn resolve_block(blk: &ast::blk, (cx, visitor): (Context, visit::vt<Context>)) {
+fn resolve_block(blk: &ast::Block, (cx, visitor): (Context, visit::vt<Context>)) {
// Record the parent of this block.
parent_to_expr(cx, blk.id, blk.span);
visit::visit_expr(expr, (new_cx, visitor));
}
-fn resolve_local(local: @ast::local,
+fn resolve_local(local: @ast::Local,
(cx, visitor) : (Context,
visit::vt<Context>)) {
assert_eq!(cx.var_parent, cx.parent);
- parent_to_expr(cx, local.node.id, local.span);
+ parent_to_expr(cx, local.id, local.span);
visit::visit_local(local, (cx, visitor));
}
fn resolve_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(cx, visitor): (Context,
pub fn resolve_crate(sess: Session,
def_map: resolve::DefMap,
- crate: &ast::crate) -> @mut RegionMaps
+ crate: &ast::Crate) -> @mut RegionMaps
{
let region_maps = @mut RegionMaps {
scope_map: HashMap::new(),
fn determine_rp_in_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
_: span,
_: ast::node_id,
(cx, visitor): (@mut DetermineRpCtxt,
pub fn determine_rp_in_crate(sess: Session,
ast_map: ast_map::map,
def_map: resolve::DefMap,
- crate: &ast::crate)
+ crate: &ast::Crate)
-> region_paramd_items {
let cx = @mut DetermineRpCtxt {
sess: sess,
use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
use syntax::ast_util::{Privacy, Public, Private};
use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy};
-use syntax::attr::{attr_metas, contains_name};
+use syntax::attr;
use syntax::parse::token;
use syntax::parse::token::ident_interner;
use syntax::parse::token::special_idents;
// Map from the name in a pattern to its binding mode.
pub type BindingMap = HashMap<ident,binding_info>;
-// Implementation resolution
-//
-// FIXME #4946: This kind of duplicates information kept in
-// ty::method. Maybe it should go away.
-
-pub struct MethodInfo {
- did: def_id,
- n_tps: uint,
- ident: ident,
- explicit_self: explicit_self_
-}
-
-pub struct Impl {
- did: def_id,
- ident: ident,
- methods: ~[@MethodInfo]
-}
-
// Trait method resolution
pub type TraitMap = HashMap<node_id,@mut ~[def_id]>;
pub fn Resolver(session: Session,
lang_items: LanguageItems,
- crate: @crate)
+ crate: @Crate)
-> Resolver {
let graph_root = @mut NameBindings();
pub struct Resolver {
session: @Session,
lang_items: LanguageItems,
- crate: @crate,
+ crate: @Crate,
intr: @ident_interner,
}
}
- pub fn block_needs_anonymous_module(@mut self, block: &blk) -> bool {
+ pub fn block_needs_anonymous_module(@mut self, block: &Block) -> bool {
// If the block has view items, we need an anonymous module.
if block.view_items.len() > 0 {
return true;
}
pub fn build_reduced_graph_for_block(@mut self,
- block: &blk,
+ block: &Block,
(parent, visitor):
(ReducedGraphParent,
vt<ReducedGraphParent>)) {
// Items with the !resolve_unexported attribute are X-ray contexts.
// This is used to allow the test runner to run unexported tests.
let orig_xray_flag = self.xray_context;
- if contains_name(attr_metas(item.attrs),
- "!resolve_unexported") {
+ if attr::contains_name(item.attrs, "!resolve_unexported") {
self.xray_context = Xray;
}
rib_kind: RibKind,
optional_declaration: Option<&fn_decl>,
type_parameters: TypeParameters,
- block: &blk,
+ block: &Block,
self_binding: SelfBinding,
visitor: ResolveVisitor) {
// Create a value rib for the function.
visit_mod(module_, span, id, ((), visitor));
}
- pub fn resolve_local(@mut self, local: @local, visitor: ResolveVisitor) {
- let mutability = if local.node.is_mutbl {Mutable} else {Immutable};
+ pub fn resolve_local(@mut self, local: @Local, visitor: ResolveVisitor) {
+ let mutability = if local.is_mutbl {Mutable} else {Immutable};
// Resolve the type.
- self.resolve_type(&local.node.ty, visitor);
+ self.resolve_type(&local.ty, visitor);
// Resolve the initializer, if necessary.
- match local.node.init {
+ match local.init {
None => {
// Nothing to do.
}
}
// Resolve the pattern.
- self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability,
+ self.resolve_pattern(local.pat, LocalIrrefutableMode, mutability,
None, visitor);
}
self.value_ribs.pop();
}
- pub fn resolve_block(@mut self, block: &blk, visitor: ResolveVisitor) {
+ pub fn resolve_block(@mut self, block: &Block, visitor: ResolveVisitor) {
debug!("(resolving block) entering block");
self.value_ribs.push(@Rib(NormalRibKind));
i -= 1;
match this.type_ribs[i].kind {
MethodRibKind(node_id, _) =>
- for this.crate.node.module.items.iter().advance |item| {
+ for this.crate.module.items.iter().advance |item| {
if item.id == node_id {
match item.node {
item_struct(class_def, _) => {
/// Entry point to crate resolution.
pub fn resolve_crate(session: Session,
lang_items: LanguageItems,
- crate: @crate)
+ crate: @Crate)
-> CrateMap {
let resolver = @mut Resolver(session, lang_items, crate);
resolver.resolve();
}
}
-impl<T:Subst> Subst for @T {
+impl<T:Subst + 'static> Subst for @T {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @T {
match self {
&@ref t => @t.subst(tcx, substs)
*
* ## Matching
*
- * The basic state of the code is maintained in an array `m` of `@Match`
- * objects. Each `@Match` describes some list of patterns, all of which must
+ * The basic state of the code is maintained in an array `m` of `Match`
+ * objects. Each `Match` describes some list of patterns, all of which must
* match against the current list of values. If those patterns match, then
* the arm listed in the match is the correct arm. A given arm may have
* multiple corresponding match entries, one for each alternative that
lower_bound(Result),
range_result(Result, Result),
}
-pub fn trans_opt(bcx: block, o: &Opt) -> opt_result {
+pub fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
let _icx = push_ctxt("match::trans_opt");
let ccx = bcx.ccx();
let bcx = bcx;
}
}
-pub fn variant_opt(bcx: block, pat_id: ast::node_id)
+pub fn variant_opt(bcx: @mut Block, pat_id: ast::node_id)
-> Opt {
let ccx = bcx.ccx();
match ccx.tcx.def_map.get_copy(&pat_id) {
}
}
+#[deriving(Clone)]
pub enum TransBindingMode {
TrByValue(/*llbinding:*/ ValueRef),
TrByRef,
* - `trmode` is the trans binding mode
* - `id` is the node id of the binding
* - `ty` is the Rust type of the binding */
+ #[deriving(Clone)]
pub struct BindingInfo {
llmatch: ValueRef,
trmode: TransBindingMode,
pub type BindingsMap = HashMap<ident, BindingInfo>;
+#[deriving(Clone)]
pub struct ArmData<'self> {
- bodycx: block,
+ bodycx: @mut Block,
arm: &'self ast::arm,
- bindings_map: BindingsMap
+ bindings_map: @BindingsMap
}
+#[deriving(Clone)]
pub struct Match<'self> {
pats: ~[@ast::pat],
- data: @ArmData<'self>
+ data: ArmData<'self>
}
-pub fn match_to_str(bcx: block, m: &Match) -> ~str {
+pub fn match_to_str(bcx: @mut Block, m: &Match) -> ~str {
if bcx.sess().verbose() {
// for many programs, this just take too long to serialize
fmt!("%?", m.pats.map(|p| pat_to_str(*p, bcx.sess().intr())))
}
}
-pub fn matches_to_str(bcx: block, m: &[@Match]) -> ~str {
- fmt!("%?", m.map(|n| match_to_str(bcx, *n)))
+pub fn matches_to_str(bcx: @mut Block, m: &[Match]) -> ~str {
+ fmt!("%?", m.map(|n| match_to_str(bcx, n)))
}
-pub fn has_nested_bindings(m: &[@Match], col: uint) -> bool {
+pub fn has_nested_bindings(m: &[Match], col: uint) -> bool {
for m.iter().advance |br| {
match br.pats[col].node {
ast::pat_ident(_, _, Some(_)) => return true,
return false;
}
-pub fn expand_nested_bindings<'r>(bcx: block,
- m: &[@Match<'r>],
+pub fn expand_nested_bindings<'r>(bcx: @mut Block,
+ m: &[Match<'r>],
col: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("expand_nested_bindings(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
br.data.bindings_map.get(&path_to_ident(path));
Store(bcx, val, binding_info.llmatch);
- @Match {pats: pats, data: br.data}
- }
- _ => {
- *br
+ Match {
+ pats: pats,
+ data: br.data.clone()
+ }
}
+ _ => (*br).clone(),
}
}
}
-pub fn assert_is_binding_or_wild(bcx: block, p: @ast::pat) {
+pub fn assert_is_binding_or_wild(bcx: @mut Block, p: @ast::pat) {
if !pat_is_binding_or_wild(bcx.tcx().def_map, p) {
bcx.sess().span_bug(
p.span,
pub type enter_pat<'self> = &'self fn(@ast::pat) -> Option<~[@ast::pat]>;
-pub fn enter_match<'r>(bcx: block,
+pub fn enter_match<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef,
e: enter_pat)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_match(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
_ => {}
}
- result.push(@Match {pats: pats, data: br.data});
+ result.push(Match {
+ pats: pats,
+ data: br.data.clone()
+ });
}
None => ()
}
return result;
}
-pub fn enter_default<'r>(bcx: block,
+pub fn enter_default<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
// <nmatsakis> so all patterns must either be records (resp. tuples) or
// wildcards
-pub fn enter_opt<'r>(bcx: block,
- m: &[@Match<'r>],
+pub fn enter_opt<'r>(bcx: @mut Block,
+ m: &[Match<'r>],
opt: &Opt,
col: uint,
variant_size: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_opt(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_rec_or_struct<'r>(bcx: block,
+pub fn enter_rec_or_struct<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
fields: &[ast::ident],
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_tup<'r>(bcx: block,
+pub fn enter_tup<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef,
n_elts: uint)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_tup(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_tuple_struct<'r>(bcx: block,
+pub fn enter_tuple_struct<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef,
n_elts: uint)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_box<'r>(bcx: block,
+pub fn enter_box<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_box(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_uniq<'r>(bcx: block,
+pub fn enter_uniq<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_uniq(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
}
}
-pub fn enter_region<'r>(bcx: block,
+pub fn enter_region<'r>(bcx: @mut Block,
dm: DefMap,
- m: &[@Match<'r>],
+ m: &[Match<'r>],
col: uint,
val: ValueRef)
- -> ~[@Match<'r>] {
+ -> ~[Match<'r>] {
debug!("enter_region(bcx=%s, m=%s, col=%u, val=%?)",
bcx.to_str(),
matches_to_str(bcx, m),
// Returns the options in one column of matches. An option is something that
// needs to be conditionally matched at runtime; for example, the discriminant
// on a set of enum variants or a literal.
-pub fn get_options(bcx: block, m: &[@Match], col: uint) -> ~[Opt] {
+pub fn get_options(bcx: @mut Block, m: &[Match], col: uint) -> ~[Opt] {
let ccx = bcx.ccx();
fn add_to_set(tcx: ty::ctxt, set: &mut ~[Opt], val: Opt) {
if set.iter().any(|l| opt_eq(tcx, l, &val)) {return;}
pub struct ExtractedBlock {
vals: ~[ValueRef],
- bcx: block
+ bcx: @mut Block
}
-pub fn extract_variant_args(bcx: block,
+pub fn extract_variant_args(bcx: @mut Block,
repr: &adt::Repr,
disr_val: int,
val: ValueRef)
ExtractedBlock { vals: args, bcx: bcx }
}
-fn match_datum(bcx: block, val: ValueRef, pat_id: ast::node_id) -> Datum {
+fn match_datum(bcx: @mut Block, val: ValueRef, pat_id: ast::node_id) -> Datum {
//! Helper for converting from the ValueRef that we pass around in
//! the match code, which is always by ref, into a Datum. Eventually
//! we should just pass around a Datum and be done with it.
}
-pub fn extract_vec_elems(bcx: block,
+pub fn extract_vec_elems(bcx: @mut Block,
pat_span: span,
pat_id: ast::node_id,
elem_count: uint,
}
// NB: This function does not collect fields from struct-like enum variants.
-pub fn collect_record_or_struct_fields(bcx: block,
- m: &[@Match],
+pub fn collect_record_or_struct_fields(bcx: @mut Block,
+ m: &[Match],
col: uint)
-> ~[ast::ident] {
let mut fields: ~[ast::ident] = ~[];
}
}
-pub fn pats_require_rooting(bcx: block,
- m: &[@Match],
+pub fn pats_require_rooting(bcx: @mut Block,
+ m: &[Match],
col: uint)
-> bool {
do m.iter().any |br| {
}
}
-pub fn root_pats_as_necessary(mut bcx: block,
- m: &[@Match],
+pub fn root_pats_as_necessary(mut bcx: @mut Block,
+ m: &[Match],
col: uint,
val: ValueRef)
- -> block {
+ -> @mut Block {
for m.iter().advance |br| {
let pat_id = br.pats[col].id;
if pat_id != 0 {
)
)
-pub fn any_box_pat(m: &[@Match], col: uint) -> bool {
+pub fn any_box_pat(m: &[Match], col: uint) -> bool {
any_pat!(m, ast::pat_box(_))
}
-pub fn any_uniq_pat(m: &[@Match], col: uint) -> bool {
+pub fn any_uniq_pat(m: &[Match], col: uint) -> bool {
any_pat!(m, ast::pat_uniq(_))
}
-pub fn any_region_pat(m: &[@Match], col: uint) -> bool {
+pub fn any_region_pat(m: &[Match], col: uint) -> bool {
any_pat!(m, ast::pat_region(_))
}
-pub fn any_tup_pat(m: &[@Match], col: uint) -> bool {
+pub fn any_tup_pat(m: &[Match], col: uint) -> bool {
any_pat!(m, ast::pat_tup(_))
}
-pub fn any_tuple_struct_pat(bcx: block, m: &[@Match], col: uint) -> bool {
+pub fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool {
do m.iter().any |br| {
let pat = br.pats[col];
match pat.node {
pub type mk_fail = @fn() -> BasicBlockRef;
-pub fn pick_col(m: &[@Match]) -> uint {
+pub fn pick_col(m: &[Match]) -> uint {
fn score(p: &ast::pat) -> uint {
match p.node {
ast::pat_lit(_) | ast::pat_enum(_, _) | ast::pat_range(_, _) => 1u,
// Compiles a comparison between two things.
//
// NB: This must produce an i1, not a Rust bool (i8).
-pub fn compare_values(cx: block,
+pub fn compare_values(cx: @mut Block,
lhs: ValueRef,
rhs: ValueRef,
rhs_t: ty::t)
}
}
-fn store_non_ref_bindings(bcx: block,
+fn store_non_ref_bindings(bcx: @mut Block,
bindings_map: &BindingsMap,
mut opt_temp_cleanups: Option<&mut ~[ValueRef]>)
- -> block
+ -> @mut Block
{
/*!
*
return bcx;
}
-fn insert_lllocals(bcx: block,
+fn insert_lllocals(bcx: @mut Block,
bindings_map: &BindingsMap,
binding_mode: IrrefutablePatternBindingMode,
- add_cleans: bool) -> block {
+ add_cleans: bool) -> @mut Block {
/*!
* For each binding in `data.bindings_map`, adds an appropriate entry into
* the `fcx.lllocals` map. If add_cleans is true, then adds cleanups for
return bcx;
}
-pub fn compile_guard(bcx: block,
+pub fn compile_guard(bcx: @mut Block,
guard_expr: @ast::expr,
data: &ArmData,
- m: &[@Match],
+ m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>)
- -> block {
+ -> @mut Block {
debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%?)",
bcx.to_str(),
bcx.expr_to_str(guard_expr),
let mut bcx = bcx;
let mut temp_cleanups = ~[];
- bcx = store_non_ref_bindings(bcx, &data.bindings_map, Some(&mut temp_cleanups));
- bcx = insert_lllocals(bcx, &data.bindings_map, BindLocal, false);
+ bcx = store_non_ref_bindings(bcx,
+ data.bindings_map,
+ Some(&mut temp_cleanups));
+ bcx = insert_lllocals(bcx, data.bindings_map, BindLocal, false);
let val = unpack_result!(bcx, {
do with_scope_result(bcx, guard_expr.info(),
bcx
};
- fn drop_bindings(bcx: block, data: &ArmData) -> block {
+ fn drop_bindings(bcx: @mut Block, data: &ArmData) -> @mut Block {
let mut bcx = bcx;
for data.bindings_map.each_value |&binding_info| {
match binding_info.trmode {
}
}
-pub fn compile_submatch(bcx: block,
- m: &[@Match],
+pub fn compile_submatch(bcx: @mut Block,
+ m: &[Match],
vals: &[ValueRef],
chk: Option<mk_fail>) {
debug!("compile_submatch(bcx=%s, m=%s, vals=%?)",
return;
}
if m[0].pats.len() == 0u {
- let data = m[0].data;
+ let data = &m[0].data;
match data.arm.guard {
Some(guard_expr) => {
- bcx = compile_guard(bcx, guard_expr, m[0].data,
+ bcx = compile_guard(bcx,
+ guard_expr,
+ &m[0].data,
m.slice(1, m.len()),
- vals, chk);
+ vals,
+ chk);
}
_ => ()
}
let col = pick_col(m);
let val = vals[col];
- let m = {
- if has_nested_bindings(m, col) {
- expand_nested_bindings(bcx, m, col, val)
- } else {
- m.to_owned()
- }
- };
+
+ if has_nested_bindings(m, col) {
+ let expanded = expand_nested_bindings(bcx, m, col, val);
+ compile_submatch_continue(bcx, expanded, vals, chk, col, val)
+ } else {
+ compile_submatch_continue(bcx, m, vals, chk, col, val)
+ }
+}
+
+fn compile_submatch_continue(mut bcx: @mut Block,
+ m: &[Match],
+ vals: &[ValueRef],
+ chk: Option<mk_fail>,
+ col: uint,
+ val: ValueRef) {
+ let tcx = bcx.tcx();
+ let dm = tcx.def_map;
let vals_left = vec::append(vals.slice(0u, col).to_owned(),
vals.slice(col + 1u, vals.len()));
}
}
-pub fn trans_match(bcx: block,
+pub fn trans_match(bcx: @mut Block,
match_expr: &ast::expr,
discr_expr: @ast::expr,
arms: &[ast::arm],
- dest: Dest) -> block {
+ dest: Dest) -> @mut Block {
let _icx = push_ctxt("match::trans_match");
do with_scope(bcx, match_expr.info(), "match") |bcx| {
trans_match_inner(bcx, discr_expr, arms, dest)
}
}
-fn create_bindings_map(bcx: block, pat: @ast::pat) -> BindingsMap {
+fn create_bindings_map(bcx: @mut Block, pat: @ast::pat) -> BindingsMap {
// Create the bindings map, which is a mapping from each binding name
// to an alloca() that will be the value for that local variable.
// Note that we use the names because each binding will have many ids
return bindings_map;
}
-pub fn trans_match_inner(scope_cx: block,
+pub fn trans_match_inner(scope_cx: @mut Block,
discr_expr: @ast::expr,
arms: &[ast::arm],
- dest: Dest) -> block {
+ dest: Dest) -> @mut Block {
let _icx = push_ctxt("match::trans_match_inner");
let mut bcx = scope_cx;
let tcx = bcx.tcx();
for arms.iter().advance |arm| {
let body = scope_block(bcx, arm.body.info(), "case_body");
let bindings_map = create_bindings_map(bcx, arm.pats[0]);
- let arm_data = @ArmData {bodycx: body,
- arm: arm,
- bindings_map: bindings_map};
- arm_datas.push(arm_data);
+ let arm_data = ArmData {
+ bodycx: body,
+ arm: arm,
+ bindings_map: @bindings_map
+ };
+ arm_datas.push(arm_data.clone());
for arm.pats.iter().advance |p| {
- matches.push(@Match {pats: ~[*p], data: arm_data});
+ matches.push(Match {
+ pats: ~[*p],
+ data: arm_data.clone(),
+ });
}
}
// is just to reduce code space. See extensive comment at the start
// of the file for more details.
if arm_data.arm.guard.is_none() {
- bcx = store_non_ref_bindings(bcx, &arm_data.bindings_map, None);
+ bcx = store_non_ref_bindings(bcx, arm_data.bindings_map, None);
}
// insert bindings into the lllocals map and add cleanups
- bcx = insert_lllocals(bcx, &arm_data.bindings_map, BindLocal, true);
+ bcx = insert_lllocals(bcx, arm_data.bindings_map, BindLocal, true);
bcx = controlflow::trans_block(bcx, &arm_data.arm.body, dest);
bcx = trans_block_cleanups(bcx, block_cleanups(arm_data.bodycx));
bcx = controlflow::join_blocks(scope_cx, arm_cxs);
return bcx;
- fn mk_fail(bcx: block, sp: span, msg: @str,
+ fn mk_fail(bcx: @mut Block, sp: span, msg: @str,
finished: @mut Option<BasicBlockRef>) -> BasicBlockRef {
match *finished { Some(bb) => return bb, _ => () }
let fail_cx = sub_block(bcx, "case_fallthrough");
BindArgument
}
-pub fn store_local(bcx: block,
+pub fn store_local(bcx: @mut Block,
pat: @ast::pat,
opt_init_expr: Option<@ast::expr>)
- -> block {
+ -> @mut Block {
/*!
* Generates code for a local variable declaration like
* `let <pat>;` or `let <pat> = <opt_init_expr>`.
}
};
- fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block {
+ fn create_dummy_locals(mut bcx: @mut Block, pat: @ast::pat) -> @mut Block {
// create dummy memory for the variables if we have no
// value to store into them immediately
let tcx = bcx.tcx();
}
}
-pub fn store_arg(mut bcx: block,
+pub fn store_arg(mut bcx: @mut Block,
pat: @ast::pat,
llval: ValueRef)
- -> block {
+ -> @mut Block {
/*!
* Generates code for argument patterns like `fn foo(<pat>: T)`.
* Creates entries in the `llargs` map for each of the bindings
return bcx;
}
-fn mk_binding_alloca(mut bcx: block,
+fn mk_binding_alloca(mut bcx: @mut Block,
p_id: ast::node_id,
path: &ast::Path,
binding_mode: IrrefutablePatternBindingMode,
- populate: &fn(block, ty::t, ValueRef) -> block) -> block {
+ populate: &fn(@mut Block, ty::t, ValueRef) -> @mut Block) -> @mut Block {
let var_ty = node_id_type(bcx, p_id);
let ident = ast_util::path_to_ident(path);
let llval = alloc_ty(bcx, var_ty, bcx.ident(ident));
return bcx;
}
-fn bind_irrefutable_pat(bcx: block,
+fn bind_irrefutable_pat(bcx: @mut Block,
pat: @ast::pat,
val: ValueRef,
binding_mode: IrrefutablePatternBindingMode)
- -> block {
+ -> @mut Block {
/*!
* A simple version of the pattern matching code that only handles
* irrefutable patterns. This is used in let/argument patterns,
}
/// For structs, and struct-like parts of anything fancier.
-struct Struct {
+pub struct Struct {
size: u64,
align: u64,
packed: bool,
* these, for places in trans where the `ty::t` isn't directly
* available.
*/
-pub fn represent_node(bcx: block, node: ast::node_id) -> @Repr {
+pub fn represent_node(bcx: @mut Block, node: ast::node_id) -> @Repr {
represent_type(bcx.ccx(), node_id_type(bcx, node))
}
*
* This should ideally be less tightly tied to `_match`.
*/
-pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
+pub fn trans_switch(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
-> (_match::branch_kind, Option<ValueRef>) {
match *r {
CEnum(*) | General(*) => {
/// Obtain the actual discriminant of a value.
-pub fn trans_get_discr(bcx: block, r: &Repr, scrutinee: ValueRef)
+pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
-> ValueRef {
match *r {
CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
}
}
-fn nullable_bitdiscr(bcx: block, nonnull: &Struct, nndiscr: int, ptrfield: uint,
+fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: int, 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: block, scrutinee: ValueRef, min: int, max: int)
+fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: int, max: int)
-> 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: block, r: &Repr, discr: int) -> _match::opt_result {
+pub fn trans_case(bcx: @mut Block, r: &Repr, discr: int) -> _match::opt_result {
match *r {
CEnum(*) => {
_match::single_result(rslt(bcx, C_int(bcx.ccx(), discr)))
* representation. The fields, if any, should then be initialized via
* `trans_field_ptr`.
*/
-pub fn trans_start_init(bcx: block, r: &Repr, val: ValueRef, discr: int) {
+pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) {
match *r {
CEnum(min, max) => {
assert!(min <= discr && discr <= max);
}
/// Access a field, at a point when the value's case is known.
-pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int,
+pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int,
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
}
}
-fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint,
+fn struct_field_ptr(bcx: @mut Block, st: &Struct, val: ValueRef, ix: uint,
needs_cast: bool) -> ValueRef {
let ccx = bcx.ccx();
}
/// Access the struct drop flag, if present.
-pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
+pub fn trans_drop_flag_ptr(bcx: @mut Block, r: &Repr, val: ValueRef) -> ValueRef {
match *r {
Univariant(ref st, true) => GEPi(bcx, val, [0, st.fields.len() - 1]),
_ => bcx.ccx().sess.bug("tried to get drop flag of non-droppable type")
use syntax::ast;
// Take an inline assembly expression and splat it out via LLVM
-pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block {
+pub fn trans_inline_asm(bcx: @mut Block, ia: &ast::inline_asm) -> @mut Block {
let mut bcx = bcx;
let mut constraints = ~[];
use middle::trans::adt;
use middle::trans::base;
use middle::trans::build::*;
+use middle::trans::builder::{Builder, noname};
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::consts;
use syntax::ast_map::{path, path_elt_to_str, path_name};
use syntax::ast_util::{local_def};
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::span;
use syntax::parse::token;
use syntax::parse::token::{special_idents};
pub use middle::trans::context::task_llcx;
-#[cfg(not(stage0))]
static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
-#[cfg(stage0)]
-fn task_local_insn_key(_: @~[&'static str]) {}
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k));
_InsnCtxt { _x: () }
}
-fn fcx_has_nonzero_span(fcx: fn_ctxt) -> bool {
+fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
match fcx.span {
None => true,
Some(span) => *span.lo != 0 || *span.hi != 0
return c;
}
}
-pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
+pub fn umax(cx: @mut Block, a: ValueRef, b: ValueRef) -> ValueRef {
let _icx = push_ctxt("umax");
let cond = ICmp(cx, lib::llvm::IntULT, a, b);
return Select(cx, cond, b, a);
}
-pub fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
+pub fn umin(cx: @mut Block, a: ValueRef, b: ValueRef) -> ValueRef {
let _icx = push_ctxt("umin");
let cond = ICmp(cx, lib::llvm::IntULT, a, b);
return Select(cx, cond, a, b);
// Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes).
// The type of the returned pointer is always i8*. If you care about the
// return type, use bump_ptr().
-pub fn ptr_offs(bcx: block, base: ValueRef, sz: ValueRef) -> ValueRef {
+pub fn ptr_offs(bcx: @mut Block, base: ValueRef, sz: ValueRef) -> ValueRef {
let _icx = push_ctxt("ptr_offs");
let raw = PointerCast(bcx, base, Type::i8p());
InBoundsGEP(bcx, raw, [sz])
// Increment a pointer by a given amount and then cast it to be a pointer
// to a given type.
-pub fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) ->
+pub fn bump_ptr(bcx: @mut Block, t: ty::t, base: ValueRef, sz: ValueRef) ->
ValueRef {
let _icx = push_ctxt("bump_ptr");
let ccx = bcx.ccx();
// known.
//
// The runtime equivalent is box_body() in "rust_internal.h".
-pub fn opaque_box_body(bcx: block,
+pub fn opaque_box_body(bcx: @mut Block,
body_t: ty::t,
boxptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("opaque_box_body");
// malloc_raw_dyn: allocates a box to contain a given type, but with a
// potentially dynamic size.
-pub fn malloc_raw_dyn(bcx: block,
+pub fn malloc_raw_dyn(bcx: @mut Block,
t: ty::t,
heap: heap,
size: ValueRef) -> Result {
let _icx = push_ctxt("malloc_raw");
let ccx = bcx.ccx();
- fn require_alloc_fn(bcx: block, t: ty::t, it: LangItem) -> ast::def_id {
+ fn require_alloc_fn(bcx: @mut Block, t: ty::t, it: LangItem) -> ast::def_id {
let li = &bcx.tcx().lang_items;
match li.require(it) {
Ok(id) => id,
// malloc_raw: expects an unboxed type and returns a pointer to
// enough space for a box of that type. This includes a rust_opaque_box
// header.
-pub fn malloc_raw(bcx: block, t: ty::t, heap: heap) -> Result {
+pub fn malloc_raw(bcx: @mut Block, t: ty::t, heap: heap) -> Result {
let ty = type_of(bcx.ccx(), t);
let size = llsize_of(bcx.ccx(), ty);
malloc_raw_dyn(bcx, t, heap, size)
}
pub struct MallocResult {
- bcx: block,
+ bcx: @mut Block,
box: ValueRef,
body: ValueRef
}
// malloc_general_dyn: usefully wraps malloc_raw_dyn; allocates a box,
// and pulls out the body
-pub fn malloc_general_dyn(bcx: block, t: ty::t, heap: heap, size: ValueRef)
+pub fn malloc_general_dyn(bcx: @mut Block, t: ty::t, heap: heap, size: ValueRef)
-> MallocResult {
assert!(heap != heap_exchange);
let _icx = push_ctxt("malloc_general");
MallocResult { bcx: bcx, box: llbox, body: body }
}
-pub fn malloc_general(bcx: block, t: ty::t, heap: heap) -> MallocResult {
+pub fn malloc_general(bcx: @mut Block, t: ty::t, heap: heap) -> MallocResult {
let ty = type_of(bcx.ccx(), t);
assert!(heap != heap_exchange);
malloc_general_dyn(bcx, t, heap, llsize_of(bcx.ccx(), ty))
}
-pub fn malloc_boxed(bcx: block, t: ty::t)
+pub fn malloc_boxed(bcx: @mut Block, t: ty::t)
-> MallocResult {
malloc_general(bcx, t, heap_managed)
}
-pub fn heap_for_unique(bcx: block, t: ty::t) -> heap {
+pub fn heap_for_unique(bcx: @mut Block, t: ty::t) -> heap {
if ty::type_contents(bcx.tcx(), t).contains_managed() {
heap_managed_unique
} else {
}
}
-pub fn maybe_set_managed_unique_rc(bcx: block, bx: ValueRef, heap: heap) {
+pub fn maybe_set_managed_unique_rc(bcx: @mut Block, bx: ValueRef, heap: heap) {
assert!(heap != heap_exchange);
if heap == heap_managed_unique {
// In cases where we are looking at a unique-typed allocation in the
}
}
-pub fn set_inline_hint_if_appr(attrs: &[ast::attribute],
+pub fn set_inline_hint_if_appr(attrs: &[ast::Attribute],
llfn: ValueRef) {
- match attr::find_inline_attr(attrs) {
- attr::ia_hint => set_inline_hint(llfn),
- attr::ia_always => set_always_inline(llfn),
- attr::ia_never => set_no_inline(llfn),
- attr::ia_none => { /* fallthrough */ }
+ use syntax::attr::*;
+ match find_inline_attr(attrs) {
+ InlineHint => set_inline_hint(llfn),
+ InlineAlways => set_always_inline(llfn),
+ InlineNever => set_no_inline(llfn),
+ InlineNone => { /* fallthrough */ }
}
}
&tsubsts,
None,
None,
- None,
None);
val
pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
// NB: This produces an i1, not a Rust bool (i8).
-pub fn compare_scalar_types(cx: block,
+pub fn compare_scalar_types(cx: @mut Block,
lhs: ValueRef,
rhs: ValueRef,
t: ty::t,
// A helper function to do the actual comparison of scalar values.
-pub fn compare_scalar_values(cx: block,
+pub fn compare_scalar_values(cx: @mut Block,
lhs: ValueRef,
rhs: ValueRef,
nt: scalar_type,
op: ast::binop)
-> ValueRef {
let _icx = push_ctxt("compare_scalar_values");
- fn die(cx: block) -> ! {
+ fn die(cx: @mut Block) -> ! {
cx.tcx().sess.bug("compare_scalar_values: must be a\
comparison operator");
}
}
}
-pub type val_and_ty_fn<'self> = &'self fn(block, ValueRef, ty::t) -> block;
+pub type val_and_ty_fn<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
-pub fn load_inbounds(cx: block, p: ValueRef, idxs: &[uint]) -> ValueRef {
+pub fn load_inbounds(cx: @mut Block, p: ValueRef, idxs: &[uint]) -> ValueRef {
return Load(cx, GEPi(cx, p, idxs));
}
-pub fn store_inbounds(cx: block, v: ValueRef, p: ValueRef, idxs: &[uint]) {
+pub fn store_inbounds(cx: @mut Block, v: ValueRef, p: ValueRef, idxs: &[uint]) {
Store(cx, v, GEPi(cx, p, idxs));
}
// Iterates through the elements of a structural type.
-pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
- f: val_and_ty_fn) -> block {
+pub fn iter_structural_ty(cx: @mut Block, av: ValueRef, t: ty::t,
+ f: val_and_ty_fn) -> @mut Block {
let _icx = push_ctxt("iter_structural_ty");
- fn iter_variant(cx: block, repr: &adt::Repr, av: ValueRef,
- variant: ty::VariantInfo,
- tps: &[ty::t], f: val_and_ty_fn) -> block {
+ fn iter_variant(cx: @mut Block, repr: &adt::Repr, av: ValueRef,
+ variant: @ty::VariantInfo,
+ tps: &[ty::t], f: val_and_ty_fn) -> @mut Block {
let _icx = push_ctxt("iter_variant");
let tcx = cx.tcx();
let mut cx = cx;
return cx;
}
-pub fn cast_shift_expr_rhs(cx: block, op: ast::binop,
+pub fn cast_shift_expr_rhs(cx: @mut Block, op: ast::binop,
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
cast_shift_rhs(op, lhs, rhs,
|a,b| Trunc(cx, a, b),
}
}
-pub fn fail_if_zero(cx: block, span: span, divrem: ast::binop,
- rhs: ValueRef, rhs_t: ty::t) -> block {
+pub fn fail_if_zero(cx: @mut Block, span: span, divrem: ast::binop,
+ rhs: ValueRef, rhs_t: ty::t) -> @mut Block {
let text = if divrem == ast::div {
@"attempted to divide by zero"
} else {
}
}
-pub fn null_env_ptr(bcx: block) -> ValueRef {
+pub fn null_env_ptr(bcx: @mut Block) -> ValueRef {
C_null(Type::opaque_box(bcx.ccx()).ptr_to())
}
};
}
-pub fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef])
- -> (ValueRef, block) {
+pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef])
+ -> (ValueRef, @mut Block) {
let _icx = push_ctxt("invoke_");
if bcx.unreachable {
return (C_null(Type::i8()), bcx);
}
}
-pub fn need_invoke(bcx: block) -> bool {
+pub fn need_invoke(bcx: @mut Block) -> bool {
if (bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0) {
return false;
}
}
}
-pub fn have_cached_lpad(bcx: block) -> bool {
+pub fn have_cached_lpad(bcx: @mut Block) -> bool {
let mut res = false;
do in_lpad_scope_cx(bcx) |inf| {
match inf.landing_pad {
return res;
}
-pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) {
+pub fn in_lpad_scope_cx(bcx: @mut Block, f: &fn(si: &mut ScopeInfo)) {
let mut bcx = bcx;
let mut cur_scope = bcx.scope;
loop {
}
}
-pub fn get_landing_pad(bcx: block) -> BasicBlockRef {
+pub fn get_landing_pad(bcx: @mut Block) -> BasicBlockRef {
let _icx = push_ctxt("get_landing_pad");
let mut cached = None;
return pad_bcx.llbb;
}
-pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
+pub fn find_bcx_for_scope(bcx: @mut Block, scope_id: ast::node_id) -> @mut Block {
let mut bcx_sid = bcx;
let mut cur_scope = bcx_sid.scope;
loop {
}
-pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
+pub fn do_spill(bcx: @mut Block, v: ValueRef, t: ty::t) -> ValueRef {
if ty::type_is_bot(t) {
return C_null(Type::i8p());
}
// Since this function does *not* root, it is the caller's responsibility to
// ensure that the referent is pointed to by a root.
-pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef {
+pub fn do_spill_noroot(cx: @mut Block, v: ValueRef) -> ValueRef {
let llptr = alloca(cx, val_ty(v), "");
Store(cx, v, llptr);
return llptr;
}
-pub fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
+pub fn spill_if_immediate(cx: @mut Block, v: ValueRef, t: ty::t) -> ValueRef {
let _icx = push_ctxt("spill_if_immediate");
if ty::type_is_immediate(cx.tcx(), t) { return do_spill(cx, v, t); }
return v;
}
-pub fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
+pub fn load_if_immediate(cx: @mut Block, v: ValueRef, t: ty::t) -> ValueRef {
let _icx = push_ctxt("load_if_immediate");
if ty::type_is_immediate(cx.tcx(), t) { return Load(cx, v); }
return v;
}
-pub fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: @str) {
+pub fn trans_trace(bcx: @mut Block, sp_opt: Option<span>, trace_str: @str) {
if !bcx.sess().trace() { return; }
let _icx = push_ctxt("trans_trace");
add_comment(bcx, trace_str);
Call(bcx, ccx.upcalls.trace, args);
}
-pub fn ignore_lhs(_bcx: block, local: &ast::local) -> bool {
- match local.node.pat.node {
+pub fn ignore_lhs(_bcx: @mut Block, local: &ast::Local) -> bool {
+ match local.pat.node {
ast::pat_wild => true, _ => false
}
}
-pub fn init_local(bcx: block, local: &ast::local) -> block {
+pub fn init_local(bcx: @mut Block, local: &ast::Local) -> @mut Block {
debug!("init_local(bcx=%s, local.id=%?)",
- bcx.to_str(), local.node.id);
+ bcx.to_str(), local.id);
let _indenter = indenter();
let _icx = push_ctxt("init_local");
if ignore_lhs(bcx, local) {
// Handle let _ = e; just like e;
- match local.node.init {
+ match local.init {
Some(init) => {
return expr::trans_into(bcx, init, expr::Ignore);
}
}
}
- _match::store_local(bcx, local.node.pat, local.node.init)
+ _match::store_local(bcx, local.pat, local.init)
}
-pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
+pub fn trans_stmt(cx: @mut Block, s: &ast::stmt) -> @mut Block {
let _icx = push_ctxt("trans_stmt");
debug!("trans_stmt(%s)", stmt_to_str(s, cx.tcx().sess.intr()));
bcx = init_local(bcx, *local);
if cx.sess().opts.extra_debuginfo
&& fcx_has_nonzero_span(bcx.fcx) {
- debuginfo::create_local_var(bcx, *local);
+ debuginfo::create_local_var_metadata(bcx, *local);
}
}
ast::decl_item(i) => trans_item(cx.fcx.ccx, i)
// You probably don't want to use this one. See the
// next three functions instead.
-pub fn new_block(cx: fn_ctxt, parent: Option<block>, scope: Option<@mut scope_info>,
- is_lpad: bool, name: &str, opt_node_info: Option<NodeInfo>)
- -> block {
-
+pub fn new_block(cx: @mut FunctionContext,
+ parent: Option<@mut Block>,
+ scope: Option<@mut ScopeInfo>,
+ is_lpad: bool,
+ name: &str,
+ opt_node_info: Option<NodeInfo>)
+ -> @mut Block {
unsafe {
let llbb = do name.as_c_str |buf| {
llvm::LLVMAppendBasicBlockInContext(cx.ccx.llcx, cx.llfn, buf)
};
- let bcx = mk_block(llbb,
- parent,
- is_lpad,
- opt_node_info,
- cx);
+ let bcx = @mut Block::new(llbb,
+ parent,
+ is_lpad,
+ opt_node_info,
+ cx);
bcx.scope = scope;
for parent.iter().advance |cx| {
if cx.unreachable {
}
}
-pub fn simple_block_scope(parent: Option<@mut scope_info>,
- node_info: Option<NodeInfo>) -> @mut scope_info {
- @mut scope_info {
+pub fn simple_block_scope(parent: Option<@mut ScopeInfo>,
+ node_info: Option<NodeInfo>) -> @mut ScopeInfo {
+ @mut ScopeInfo {
parent: parent,
loop_break: None,
loop_label: None,
}
// Use this when you're at the top block of a function or the like.
-pub fn top_scope_block(fcx: fn_ctxt, opt_node_info: Option<NodeInfo>)
- -> block {
+pub fn top_scope_block(fcx: @mut FunctionContext, opt_node_info: Option<NodeInfo>)
+ -> @mut Block {
return new_block(fcx, None, Some(simple_block_scope(None, opt_node_info)), false,
"function top level", opt_node_info);
}
-pub fn scope_block(bcx: block,
+pub fn scope_block(bcx: @mut Block,
opt_node_info: Option<NodeInfo>,
- n: &str) -> block {
+ n: &str) -> @mut Block {
return new_block(bcx.fcx, Some(bcx), Some(simple_block_scope(None, opt_node_info)), bcx.is_lpad,
n, opt_node_info);
}
-pub fn loop_scope_block(bcx: block,
- loop_break: block,
+pub fn loop_scope_block(bcx: @mut Block,
+ loop_break: @mut Block,
loop_label: Option<ident>,
n: &str,
- opt_node_info: Option<NodeInfo>) -> block {
- return new_block(bcx.fcx, Some(bcx), Some(@mut scope_info {
+ opt_node_info: Option<NodeInfo>) -> @mut Block {
+ return new_block(bcx.fcx, Some(bcx), Some(@mut ScopeInfo {
parent: None,
loop_break: Some(loop_break),
loop_label: loop_label,
}
// Use this when creating a block for the inside of a landing pad.
-pub fn lpad_block(bcx: block, n: &str) -> block {
+pub fn lpad_block(bcx: @mut Block, n: &str) -> @mut Block {
new_block(bcx.fcx, Some(bcx), None, true, n, None)
}
// Use this when you're making a general CFG BB within a scope.
-pub fn sub_block(bcx: block, n: &str) -> block {
+pub fn sub_block(bcx: @mut Block, n: &str) -> @mut Block {
new_block(bcx.fcx, Some(bcx), None, bcx.is_lpad, n, None)
}
-pub fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block {
- mk_block(llbb, None, is_lpad, None, fcx)
+pub fn raw_block(fcx: @mut FunctionContext, is_lpad: bool, llbb: BasicBlockRef) -> @mut Block {
+ @mut Block::new(llbb, None, is_lpad, None, fcx)
}
// need to make sure those variables go out of scope when the block ends. We
// do that by running a 'cleanup' function for each variable.
// trans_block_cleanups runs all the cleanup functions for the block.
-pub fn trans_block_cleanups(bcx: block, cleanups: ~[cleanup]) -> block {
+pub fn trans_block_cleanups(bcx: @mut Block, cleanups: ~[cleanup]) -> @mut Block {
trans_block_cleanups_(bcx, cleanups, false)
}
-pub fn trans_block_cleanups_(bcx: block,
+pub fn trans_block_cleanups_(bcx: @mut Block,
cleanups: &[cleanup],
/* cleanup_cx: block, */
- is_lpad: bool) -> block {
+ is_lpad: bool) -> @mut Block {
let _icx = push_ctxt("trans_block_cleanups");
// NB: Don't short-circuit even if this block is unreachable because
// GC-based cleanup needs to the see that the roots are live.
// In the last argument, Some(block) mean jump to this block, and none means
// this is a landing pad and leaving should be accomplished with a resume
// instruction.
-pub fn cleanup_and_leave(bcx: block,
+pub fn cleanup_and_leave(bcx: @mut Block,
upto: Option<BasicBlockRef>,
leave: Option<BasicBlockRef>) {
let _icx = push_ctxt("cleanup_and_leave");
}
}
-pub fn cleanup_block(bcx: block, upto: Option<BasicBlockRef>) -> block{
+pub fn cleanup_block(bcx: @mut Block, upto: Option<BasicBlockRef>) -> @mut Block{
let _icx = push_ctxt("cleanup_block");
let mut cur = bcx;
let mut bcx = bcx;
bcx
}
-pub fn cleanup_and_Br(bcx: block, upto: block, target: BasicBlockRef) {
+pub fn cleanup_and_Br(bcx: @mut Block, upto: @mut Block, target: BasicBlockRef) {
let _icx = push_ctxt("cleanup_and_Br");
cleanup_and_leave(bcx, Some(upto.llbb), Some(target));
}
-pub fn leave_block(bcx: block, out_of: block) -> block {
+pub fn leave_block(bcx: @mut Block, out_of: @mut Block) -> @mut Block {
let _icx = push_ctxt("leave_block");
let next_cx = sub_block(block_parent(out_of), "next");
if bcx.unreachable { Unreachable(next_cx); }
next_cx
}
-pub fn with_scope(bcx: block,
+pub fn with_scope(bcx: @mut Block,
opt_node_info: Option<NodeInfo>,
name: &str,
- f: &fn(block) -> block) -> block {
+ f: &fn(@mut Block) -> @mut Block) -> @mut Block {
let _icx = push_ctxt("with_scope");
debug!("with_scope(bcx=%s, opt_node_info=%?, name=%s)",
ret
}
-pub fn with_scope_result(bcx: block,
+pub fn with_scope_result(bcx: @mut Block,
opt_node_info: Option<NodeInfo>,
_name: &str,
- f: &fn(block) -> Result) -> Result {
+ f: &fn(@mut Block) -> Result) -> Result {
let _icx = push_ctxt("with_scope_result");
let scope = simple_block_scope(bcx.scope, opt_node_info);
rslt(out_bcx, val)
}
-pub fn with_scope_datumblock(bcx: block, opt_node_info: Option<NodeInfo>,
- name: &str, f: &fn(block) -> datum::DatumBlock)
+pub fn with_scope_datumblock(bcx: @mut Block, opt_node_info: Option<NodeInfo>,
+ name: &str, f: &fn(@mut Block) -> datum::DatumBlock)
-> datum::DatumBlock {
use middle::trans::datum::DatumBlock;
DatumBlock {bcx: leave_block(bcx, scope_cx), datum: datum}
}
-pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) {
+pub fn block_locals(b: &ast::Block, it: &fn(@ast::Local)) {
for b.stmts.iter().advance |s| {
match s.node {
ast::stmt_decl(d, _) => {
}
}
-pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block {
+pub fn with_cond(bcx: @mut Block, val: ValueRef, f: &fn(@mut Block) -> @mut Block) -> @mut Block {
let _icx = push_ctxt("with_cond");
let next_cx = base::sub_block(bcx, "next");
let cond_cx = base::sub_block(bcx, "cond");
next_cx
}
-pub fn call_memcpy(cx: block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
+pub fn call_memcpy(cx: @mut Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
let _icx = push_ctxt("call_memcpy");
let ccx = cx.ccx();
let key = match ccx.sess.targ_cfg.arch {
Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile]);
}
-pub fn memcpy_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) {
+pub fn memcpy_ty(bcx: @mut Block, dst: ValueRef, src: ValueRef, t: ty::t) {
let _icx = push_ctxt("memcpy_ty");
let ccx = bcx.ccx();
if ty::type_is_structural(t) {
}
}
-pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
+pub fn zero_mem(cx: @mut Block, llptr: ValueRef, t: ty::t) {
+ if cx.unreachable { return; }
let _icx = push_ctxt("zero_mem");
let bcx = cx;
let ccx = cx.ccx();
let llty = type_of::type_of(ccx, t);
- memzero(bcx, llptr, llty);
+ memzero(&B(bcx), llptr, llty);
}
// Always use this function instead of storing a zero constant to the memory
// allocation for large data structures, and the generated code will be
// awful. (A telltale sign of this is large quantities of
// `mov [byte ptr foo],0` in the generated code.)
-pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
+pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
let _icx = push_ctxt("memzero");
- let ccx = cx.ccx();
+ let ccx = b.ccx;
let intrinsic_key = match ccx.sess.targ_cfg.arch {
X86 | Arm | Mips => "llvm.memset.p0i8.i32",
};
let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key);
- let llptr = PointerCast(cx, llptr, Type::i8().ptr_to());
+ let llptr = b.pointercast(llptr, Type::i8().ptr_to());
let llzeroval = C_u8(0);
- let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type);
+ let size = machine::llsize_of(ccx, ty);
let align = C_i32(llalign_of_min(ccx, ty) as i32);
let volatile = C_i1(false);
- Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
+ b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
}
-pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef {
+pub fn alloc_ty(bcx: @mut Block, t: ty::t, name: &str) -> ValueRef {
let _icx = push_ctxt("alloc_ty");
let ccx = bcx.ccx();
let ty = type_of::type_of(ccx, t);
return val;
}
-pub fn alloca(cx: block, ty: Type, name: &str) -> ValueRef {
+pub fn alloca(cx: @mut Block, ty: Type, name: &str) -> ValueRef {
alloca_maybe_zeroed(cx, ty, name, false)
}
-pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> ValueRef {
+pub fn alloca_maybe_zeroed(cx: @mut Block, ty: Type, name: &str, zero: bool) -> ValueRef {
let _icx = push_ctxt("alloca");
if cx.unreachable {
unsafe {
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
}
}
- let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas());
- let p = Alloca(initcx, ty, name);
- if zero { memzero(initcx, p, ty); }
+ let p = Alloca(cx, ty, name);
+ if zero {
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ memzero(&b, p, ty);
+ }
p
}
-pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef {
+pub fn arrayalloca(cx: @mut Block, ty: Type, v: ValueRef) -> ValueRef {
let _icx = push_ctxt("arrayalloca");
if cx.unreachable {
unsafe {
return llvm::LLVMGetUndef(ty.to_ref());
}
}
- return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()), ty, v);
+ return ArrayAlloca(cx, ty, v);
}
pub struct BasicBlocks {
// Creates and returns space for, or returns the argument representing, the
// slot where the return value of the function must go.
-pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
+pub fn make_return_pointer(fcx: @mut FunctionContext, output_type: ty::t) -> ValueRef {
unsafe {
if !ty::type_is_immediate(fcx.ccx.tcx, output_type) {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
- alloca(raw_block(fcx, false, fcx.get_llstaticallocas()), lloutputtype,
- "__make_return_pointer")
+ let bcx = fcx.entry_bcx.get();
+ Alloca(bcx, lloutputtype, "__make_return_pointer")
}
}
}
output_type: ty::t,
skip_retptr: bool,
param_substs: Option<@param_substs>,
+ opt_node_info: Option<NodeInfo>,
sp: Option<span>)
- -> fn_ctxt {
+ -> @mut FunctionContext {
for param_substs.iter().advance |p| { p.validate(); }
debug!("new_fn_ctxt_w_id(path=%s, id=%?, \
}
};
let is_immediate = ty::type_is_immediate(ccx.tcx, substd_output_type);
- let fcx = @mut fn_ctxt_ {
+ let fcx = @mut FunctionContext {
llfn: llfndecl,
llenv: unsafe {
llvm::LLVMGetUndef(Type::i8p().to_ref())
},
llretptr: None,
- llstaticallocas: None,
- llloadenv: None,
+ entry_bcx: None,
+ alloca_insert_pt: None,
llreturn: None,
llself: None,
personality: None,
fcx.llenv = unsafe {
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
};
+
+ unsafe {
+ let entry_bcx = top_scope_block(fcx, opt_node_info);
+ Load(entry_bcx, C_null(Type::i8p()));
+
+ fcx.entry_bcx = Some(entry_bcx);
+ fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
+ }
+
if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
}
llfndecl: ValueRef,
output_type: ty::t,
sp: Option<span>)
- -> fn_ctxt {
- new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp)
+ -> @mut FunctionContext {
+ new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, None, sp)
}
// NB: must keep 4 fns in sync:
// spaces that have been created for them (by code in the llallocas field of
// the function's fn_ctxt). create_llargs_for_fn_args populates the llargs
// field of the fn_ctxt with
-pub fn create_llargs_for_fn_args(cx: fn_ctxt,
+pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
self_arg: self_arg,
args: &[ast::arg])
-> ~[ValueRef] {
})
}
-pub fn copy_args_to_allocas(fcx: fn_ctxt,
- bcx: block,
+pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
+ bcx: @mut Block,
args: &[ast::arg],
raw_llargs: &[ValueRef],
- arg_tys: &[ty::t]) -> block {
+ arg_tys: &[ty::t]) -> @mut Block {
let _icx = push_ctxt("copy_args_to_allocas");
let mut bcx = bcx;
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
- debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span);
+ debuginfo::create_argument_metadata(bcx, &args[arg_n], args[arg_n].ty.span);
}
}
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block.
-pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
+pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
let _icx = push_ctxt("finish_fn");
- tie_up_header_blocks(fcx, lltop);
let ret_cx = match fcx.llreturn {
Some(llreturn) => {
None => last_bcx
};
build_return_block(fcx, ret_cx);
+ fcx.cleanup();
}
// Builds the return block for a function.
-pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) {
+pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
// Return the value if this function immediate; otherwise, return void.
if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
}
}
-pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
- let _icx = push_ctxt("tie_up_header_blocks");
- let llnext = match fcx.llloadenv {
- Some(ll) => {
- unsafe {
- llvm::LLVMMoveBasicBlockBefore(ll, lltop);
- }
- Br(raw_block(fcx, false, ll), lltop);
- ll
- }
- None => lltop
- };
- match fcx.llstaticallocas {
- Some(ll) => {
- unsafe {
- llvm::LLVMMoveBasicBlockBefore(ll, llnext);
- }
- Br(raw_block(fcx, false, ll), llnext);
- }
- None => ()
- }
-}
-
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
// trans_closure: Builds an LLVM function out of a source function.
pub fn trans_closure(ccx: @mut CrateContext,
path: path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llfndecl: ValueRef,
self_arg: self_arg,
param_substs: Option<@param_substs>,
id: ast::node_id,
- attributes: &[ast::attribute],
+ attributes: &[ast::Attribute],
output_type: ty::t,
- maybe_load_env: &fn(fn_ctxt),
- finish: &fn(block)) {
+ maybe_load_env: &fn(@mut FunctionContext),
+ finish: &fn(@mut Block)) {
ccx.stats.n_closures += 1;
let _icx = push_ctxt("trans_closure");
set_uwtable(llfndecl);
output_type,
false,
param_substs,
+ 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::attrs_contains_name(attributes, "fixed_stack_segment") {
+ 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 = top_scope_block(fcx, body.info());
+ let bcx_top = fcx.entry_bcx.get();
let mut bcx = bcx_top;
- let lltop = bcx.llbb;
let block_ty = node_id_type(bcx, body.id);
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
}
// Insert the mandatory first few basic blocks before lltop.
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
// trans_fn: creates an LLVM function corresponding to a source language
pub fn trans_fn(ccx: @mut CrateContext,
path: path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llfndecl: ValueRef,
self_arg: self_arg,
param_substs: Option<@param_substs>,
id: ast::node_id,
- attrs: &[ast::attribute]) {
+ attrs: &[ast::Attribute]) {
let the_path_str = path_str(ccx.sess, path);
let _s = StatRecorder::new(ccx, the_path_str);
|fcx| {
if ccx.sess.opts.extra_debuginfo
&& fcx_has_nonzero_span(fcx) {
- debuginfo::create_function(fcx);
+ debuginfo::create_function_metadata(fcx);
}
},
|_bcx| { });
}
-fn insert_synthetic_type_entries(bcx: block,
+fn insert_synthetic_type_entries(bcx: @mut Block,
fn_args: &[ast::arg],
arg_tys: &[ty::t])
{
result_ty,
false,
param_substs,
+ None,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let arg_tys = ty::ty_fn_args(ctor_ty);
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
- id: ast::node_id, vi: @~[ty::VariantInfo],
+ id: ast::node_id, vi: @~[@ty::VariantInfo],
i: &mut uint) {
for enum_definition.variants.iter().advance |variant| {
let disr_val = vi[*i].disr_val;
// Do static_assert checking. It can't really be done much earlier because we need to get
// the value of the bool out of LLVM
for item.attrs.iter().advance |attr| {
- match attr.node.value.node {
- ast::meta_word(x) => {
- if x.slice(0, x.len()) == "static_assert" {
- if m == ast::m_mutbl {
- ccx.sess.span_fatal(expr.span,
- "cannot have static_assert \
- on a mutable static");
- }
- let v = ccx.const_values.get_copy(&item.id);
- unsafe {
- if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
- ccx.sess.span_fatal(expr.span, "static assertion failed");
- }
- }
+ if "static_assert" == attr.name() {
+ if m == ast::m_mutbl {
+ ccx.sess.span_fatal(expr.span,
+ "cannot have static_assert on a mutable static");
+ }
+ let v = ccx.const_values.get_copy(&item.id);
+ unsafe {
+ if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
+ ccx.sess.span_fatal(expr.span, "static assertion failed");
}
- },
- _ => ()
+ }
}
}
},
sp: span,
path: path,
node_id: ast::node_id,
- attrs: &[ast::attribute])
+ attrs: &[ast::Attribute])
-> ValueRef {
let t = ty::node_id_to_type(ccx.tcx, node_id);
register_fn_full(ccx, sp, path, node_id, attrs, t)
sp: span,
path: path,
node_id: ast::node_id,
- attrs: &[ast::attribute],
+ attrs: &[ast::Attribute],
node_type: ty::t)
-> ValueRef {
let llfty = type_of_fn_from_ty(ccx, node_type);
sp: span,
path: path,
node_id: ast::node_id,
- attrs: &[ast::attribute],
+ attrs: &[ast::Attribute],
node_type: ty::t,
cc: lib::llvm::CallConv,
fn_ty: Type)
node_id,
ast_map::path_to_str(path, token::get_ident_interner()));
- let ps = if attr::attrs_contains_name(attrs, "no_mangle") {
+ let ps = if attr::contains_name(attrs, "no_mangle") {
path_elt_to_str(*path.last(), token::get_ident_interner())
} else {
mangle_exported_name(ccx, path, node_type)
// be updated if this assertion starts to fail.
assert!(fcx.has_immediate_return_value);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
-
+ let bcx = fcx.entry_bcx.get();
// Call main.
let llenvarg = unsafe {
let env_arg = fcx.env_arg_pos();
let args = ~[llenvarg];
Call(bcx, main_llfn, args);
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
return llfdecl;
}
}
}
-pub fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef,
+pub fn fill_fn_pair(bcx: @mut Block, pair: ValueRef, llfn: ValueRef,
llenvptr: ValueRef) {
let ccx = bcx.ccx();
let code_cell = GEPi(bcx, pair, [0u, abi::fn_field_code]);
}
}
-pub fn trans_constants(ccx: @mut CrateContext, crate: &ast::crate) {
+pub fn trans_constants(ccx: @mut CrateContext, crate: &ast::Crate) {
visit::visit_crate(
crate, ((),
visit::mk_simple_visitor(@visit::SimpleVisitor {
})));
}
-pub fn vp2i(cx: block, v: ValueRef) -> ValueRef {
+pub fn vp2i(cx: @mut Block, v: ValueRef) -> ValueRef {
let ccx = cx.ccx();
return PtrToInt(cx, v, ccx.int_type);
}
ifn!("llvm.dbg.value", [Type::metadata(), Type::i64(), Type::metadata()], Type::void());
}
-pub fn trap(bcx: block) {
+pub fn trap(bcx: @mut Block) {
match bcx.ccx().intrinsics.find_equiv(& &"llvm.trap") {
Some(&x) => { Call(bcx, x, []); },
_ => bcx.sess().bug("unbound llvm.trap in trap")
}
}
-pub fn write_metadata(cx: &mut CrateContext, crate: &ast::crate) {
+pub fn write_metadata(cx: &mut CrateContext, crate: &ast::Crate) {
if !*cx.sess.building_library { return; }
let encode_inlined_item: encoder::encode_inlined_item =
}
pub fn trans_crate(sess: session::Session,
- crate: &ast::crate,
+ crate: &ast::Crate,
tcx: ty::ctxt,
output: &Path,
emap2: resolve::ExportMap2,
{
let _icx = push_ctxt("text");
- trans_mod(ccx, &crate.node.module);
+ trans_mod(ccx, &crate.module);
}
decl_gc_metadata(ccx, llmod_id);
use lib::llvm::llvm;
use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
-use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
-use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
+use lib::llvm::{Opcode, IntPredicate, RealPredicate};
+use lib::llvm::{ValueRef, BasicBlockRef};
use lib;
use middle::trans::common::*;
-use middle::trans::machine::llalign_of_min;
use syntax::codemap::span;
-use middle::trans::base;
+use middle::trans::builder::Builder;
use middle::trans::type_::Type;
use std::cast;
use std::libc::{c_uint, c_ulonglong, c_char};
-use std::hashmap::HashMap;
-use std::str;
-use std::vec;
-pub fn terminate(cx: block, _: &str) {
+pub fn terminate(cx: @mut Block, _: &str) {
cx.terminated = true;
}
-pub fn check_not_terminated(cx: block) {
+pub fn check_not_terminated(cx: @mut Block) {
if cx.terminated {
fail!("already terminated!");
}
}
-pub fn B(cx: block) -> BuilderRef {
- unsafe {
- let b = cx.fcx.ccx.builder.B;
- llvm::LLVMPositionBuilderAtEnd(b, cx.llbb);
- return b;
- }
-}
-
-pub fn count_insn(cx: block, category: &str) {
- if cx.ccx().sess.trans_stats() {
- cx.ccx().stats.n_llvm_insns += 1;
- }
- do base::with_insn_ctxt |v| {
- let h = &mut cx.ccx().stats.llvm_insns;
-
- // Build version of path with cycles removed.
-
- // Pass 1: scan table mapping str -> rightmost pos.
- let mut mm = HashMap::new();
- let len = v.len();
- let mut i = 0u;
- while i < len {
- mm.insert(v[i], i);
- i += 1u;
- }
-
- // Pass 2: concat strings for each elt, skipping
- // forwards over any cycles by advancing to rightmost
- // occurrence of each element in path.
- let mut s = ~".";
- i = 0u;
- while i < len {
- i = *mm.get(&v[i]);
- s.push_char('/');
- s.push_str(v[i]);
- i += 1u;
- }
-
- s.push_char('/');
- s.push_str(category);
-
- let n = match h.find(&s) {
- Some(&n) => n,
- _ => 0u
- };
- h.insert(s, n+1u);
- }
+pub fn B(cx: @mut Block) -> Builder {
+ let b = cx.fcx.ccx.builder();
+ b.position_at_end(cx.llbb);
+ b
}
-
// The difference between a block being unreachable and being terminated is
// somewhat obscure, and has to do with error checking. When a block is
// terminated, we're saying that trying to add any further statements in the
// for (fail/break/return statements, call to diverging functions, etc), and
// further instructions to the block should simply be ignored.
-pub fn RetVoid(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "RetVoid");
- count_insn(cx, "retvoid");
- llvm::LLVMBuildRetVoid(B(cx));
- }
+pub fn RetVoid(cx: @mut Block) {
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "RetVoid");
+ B(cx).ret_void();
}
-pub fn Ret(cx: block, V: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "Ret");
- count_insn(cx, "ret");
- llvm::LLVMBuildRet(B(cx), V);
- }
+pub fn Ret(cx: @mut Block, V: ValueRef) {
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "Ret");
+ B(cx).ret(V);
}
-pub fn AggregateRet(cx: block, RetVals: &[ValueRef]) {
+pub fn AggregateRet(cx: @mut Block, RetVals: &[ValueRef]) {
if cx.unreachable { return; }
check_not_terminated(cx);
terminate(cx, "AggregateRet");
- unsafe {
- llvm::LLVMBuildAggregateRet(B(cx), vec::raw::to_ptr(RetVals),
- RetVals.len() as c_uint);
- }
+ B(cx).aggregate_ret(RetVals);
}
-pub fn Br(cx: block, Dest: BasicBlockRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "Br");
- count_insn(cx, "br");
- llvm::LLVMBuildBr(B(cx), Dest);
- }
+pub fn Br(cx: @mut Block, Dest: BasicBlockRef) {
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "Br");
+ B(cx).br(Dest);
}
-pub fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef,
+pub fn CondBr(cx: @mut Block, If: ValueRef, Then: BasicBlockRef,
Else: BasicBlockRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "CondBr");
- count_insn(cx, "condbr");
- llvm::LLVMBuildCondBr(B(cx), If, Then, Else);
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "CondBr");
+ B(cx).cond_br(If, Then, Else);
}
-pub fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint)
+pub fn Switch(cx: @mut Block, V: ValueRef, Else: BasicBlockRef, NumCases: uint)
-> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- check_not_terminated(cx);
- terminate(cx, "Switch");
- return llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases as c_uint);
- }
+ if cx.unreachable { return _Undef(V); }
+ check_not_terminated(cx);
+ terminate(cx, "Switch");
+ B(cx).switch(V, Else, NumCases)
}
pub fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) {
}
}
-pub fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "IndirectBr");
- count_insn(cx, "indirectbr");
- llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests as c_uint);
- }
-}
-
-// This is a really awful way to get a zero-length c-string, but better (and a
-// lot more efficient) than doing str::as_c_str("", ...) every time.
-pub fn noname() -> *c_char {
- unsafe {
- static cnull: uint = 0u;
- return cast::transmute(&cnull);
- }
+pub fn IndirectBr(cx: @mut Block, Addr: ValueRef, NumDests: uint) {
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "IndirectBr");
+ B(cx).indirect_br(Addr, NumDests);
}
-pub fn Invoke(cx: block,
+pub fn Invoke(cx: @mut Block,
Fn: ValueRef,
Args: &[ValueRef],
Then: BasicBlockRef,
debug!("Invoke(%s with arguments (%s))",
cx.val_to_str(Fn),
Args.map(|a| cx.val_to_str(*a)).connect(", "));
- unsafe {
- count_insn(cx, "invoke");
- llvm::LLVMBuildInvoke(B(cx),
- Fn,
- vec::raw::to_ptr(Args),
- Args.len() as c_uint,
- Then,
- Catch,
- noname())
- }
+ B(cx).invoke(Fn, Args, Then, Catch)
}
-pub fn FastInvoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
+pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
Then: BasicBlockRef, Catch: BasicBlockRef) {
if cx.unreachable { return; }
check_not_terminated(cx);
terminate(cx, "FastInvoke");
- unsafe {
- count_insn(cx, "fastinvoke");
- let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint,
- Then, Catch, noname());
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- }
+ B(cx).fast_invoke(Fn, Args, Then, Catch);
}
-pub fn Unreachable(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- cx.unreachable = true;
- if !cx.terminated {
- count_insn(cx, "unreachable");
- llvm::LLVMBuildUnreachable(B(cx));
- }
+pub fn Unreachable(cx: @mut Block) {
+ if cx.unreachable { return; }
+ cx.unreachable = true;
+ if !cx.terminated {
+ B(cx).unreachable();
}
}
}
/* Arithmetic */
-pub fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "add");
- return llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname());
- }
+pub fn Add(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).add(LHS, RHS)
}
-pub fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nswadd");
- return llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname());
- }
+pub fn NSWAdd(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswadd(LHS, RHS)
}
-pub fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwadd");
- return llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname());
- }
+pub fn NUWAdd(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwadd(LHS, RHS)
}
-pub fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fadd");
- return llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname());
- }
+pub fn FAdd(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fadd(LHS, RHS)
}
-pub fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sub");
- return llvm::LLVMBuildSub(B(cx), LHS, RHS, noname());
- }
+pub fn Sub(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).sub(LHS, RHS)
}
-pub fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nwsub");
- return llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname());
- }
+pub fn NSWSub(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswsub(LHS, RHS)
}
-pub fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwsub");
- return llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname());
- }
+pub fn NUWSub(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwsub(LHS, RHS)
}
-pub fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sub");
- return llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname());
- }
+pub fn FSub(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fsub(LHS, RHS)
}
-pub fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "mul");
- return llvm::LLVMBuildMul(B(cx), LHS, RHS, noname());
- }
+pub fn Mul(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).mul(LHS, RHS)
}
-pub fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nswmul");
- return llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname());
- }
+pub fn NSWMul(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswmul(LHS, RHS)
}
-pub fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwmul");
- return llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname());
- }
+pub fn NUWMul(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwmul(LHS, RHS)
}
-pub fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fmul");
- return llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname());
- }
+pub fn FMul(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fmul(LHS, RHS)
}
-pub fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "udiv");
- return llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname());
- }
+pub fn UDiv(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).udiv(LHS, RHS)
}
-pub fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sdiv");
- return llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname());
- }
+pub fn SDiv(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).sdiv(LHS, RHS)
}
-pub fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "extractsdiv");
- return llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname());
- }
+pub fn ExactSDiv(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).exactsdiv(LHS, RHS)
}
-pub fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fdiv");
- return llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname());
- }
+pub fn FDiv(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fdiv(LHS, RHS)
}
-pub fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "urem");
- return llvm::LLVMBuildURem(B(cx), LHS, RHS, noname());
- }
+pub fn URem(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).urem(LHS, RHS)
}
-pub fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "srem");
- return llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname());
- }
+pub fn SRem(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).srem(LHS, RHS)
}
-pub fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "frem");
- return llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname());
- }
+pub fn FRem(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).frem(LHS, RHS)
}
-pub fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "shl");
- return llvm::LLVMBuildShl(B(cx), LHS, RHS, noname());
- }
+pub fn Shl(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).shl(LHS, RHS)
}
-pub fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "lshr");
- return llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname());
- }
+pub fn LShr(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).lshr(LHS, RHS)
}
-pub fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "ashr");
- return llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname());
- }
+pub fn AShr(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).ashr(LHS, RHS)
}
-pub fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "and");
- return llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname());
- }
+pub fn And(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).and(LHS, RHS)
}
-pub fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "or");
- return llvm::LLVMBuildOr(B(cx), LHS, RHS, noname());
- }
+pub fn Or(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).or(LHS, RHS)
}
-pub fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "xor");
- return llvm::LLVMBuildXor(B(cx), LHS, RHS, noname());
- }
+pub fn Xor(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).xor(LHS, RHS)
}
-pub fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef)
+pub fn BinOp(cx: @mut Block, Op: Opcode, LHS: ValueRef, RHS: ValueRef)
-> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "binop");
- return llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).binop(Op, LHS, RHS)
}
-pub fn Neg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "neg");
- return llvm::LLVMBuildNeg(B(cx), V, noname());
- }
+pub fn Neg(cx: @mut Block, V: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(V); }
+ B(cx).neg(V)
}
-pub fn NSWNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "nswneg");
- return llvm::LLVMBuildNSWNeg(B(cx), V, noname());
- }
+pub fn NSWNeg(cx: @mut Block, V: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(V); }
+ B(cx).nswneg(V)
}
-pub fn NUWNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "nuwneg");
- return llvm::LLVMBuildNUWNeg(B(cx), V, noname());
- }
+pub fn NUWNeg(cx: @mut Block, V: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(V); }
+ B(cx).nuwneg(V)
}
-pub fn FNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "fneg");
- return llvm::LLVMBuildFNeg(B(cx), V, noname());
- }
+pub fn FNeg(cx: @mut Block, V: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(V); }
+ B(cx).fneg(V)
}
-pub fn Not(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "not");
- return llvm::LLVMBuildNot(B(cx), V, noname());
- }
+pub fn Not(cx: @mut Block, V: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(V); }
+ B(cx).not(V)
}
/* Memory */
-pub fn Malloc(cx: block, Ty: Type) -> ValueRef {
+pub fn Malloc(cx: @mut Block, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "malloc");
- return llvm::LLVMBuildMalloc(B(cx), Ty.to_ref(), noname());
+ B(cx).malloc(Ty)
}
}
-pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
+pub fn ArrayMalloc(cx: @mut Block, Ty: Type, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "arraymalloc");
- return llvm::LLVMBuildArrayMalloc(B(cx), Ty.to_ref(), Val, noname());
+ B(cx).array_malloc(Ty, Val)
}
}
-pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef {
+pub fn Alloca(cx: @mut Block, Ty: Type, name: &str) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
- count_insn(cx, "alloca");
- if name.is_empty() {
- llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname())
- } else {
- str::as_c_str(
- name,
- |c| llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), c))
- }
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ b.alloca(Ty, name)
}
}
-pub fn ArrayAlloca(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
+pub fn ArrayAlloca(cx: @mut Block, Ty: Type, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
- count_insn(cx, "arrayalloca");
- return llvm::LLVMBuildArrayAlloca(B(cx), Ty.to_ref(), Val, noname());
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ b.array_alloca(Ty, Val)
}
}
-pub fn Free(cx: block, PointerVal: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- count_insn(cx, "free");
- llvm::LLVMBuildFree(B(cx), PointerVal);
- }
+pub fn Free(cx: @mut Block, PointerVal: ValueRef) {
+ if cx.unreachable { return; }
+ B(cx).free(PointerVal)
}
-pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef {
+pub fn Load(cx: @mut Block, PointerVal: ValueRef) -> ValueRef {
unsafe {
let ccx = cx.fcx.ccx;
if cx.unreachable {
};
return llvm::LLVMGetUndef(eltty.to_ref());
}
- count_insn(cx, "load");
- return llvm::LLVMBuildLoad(B(cx), PointerVal, noname());
+ B(cx).load(PointerVal)
}
}
-pub fn AtomicLoad(cx: block, PointerVal: ValueRef, order: AtomicOrdering) -> ValueRef {
+pub fn AtomicLoad(cx: @mut Block, PointerVal: ValueRef, order: AtomicOrdering) -> ValueRef {
unsafe {
let ccx = cx.fcx.ccx;
if cx.unreachable {
return llvm::LLVMGetUndef(ccx.int_type.to_ref());
}
- count_insn(cx, "load.atomic");
- let align = llalign_of_min(ccx, ccx.int_type);
- return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, noname(), order, align as c_uint);
+ B(cx).atomic_load(PointerVal, order)
}
}
-pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong,
+pub fn LoadRangeAssert(cx: @mut Block, PointerVal: ValueRef, lo: c_ulonglong,
hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
- let value = Load(cx, PointerVal);
-
- if !cx.unreachable {
+ if cx.unreachable {
+ let ccx = cx.fcx.ccx;
+ let ty = val_ty(PointerVal);
+ let eltty = if ty.kind() == lib::llvm::Array {
+ ty.element_type()
+ } else {
+ ccx.int_type
+ };
unsafe {
- let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal));
- let min = llvm::LLVMConstInt(t, lo, signed);
- let max = llvm::LLVMConstInt(t, hi, signed);
-
- do [min, max].as_imm_buf |ptr, len| {
- llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
- llvm::LLVMMDNodeInContext(cx.fcx.ccx.llcx,
- ptr, len as c_uint));
- }
+ llvm::LLVMGetUndef(eltty.to_ref())
}
+ } else {
+ B(cx).load_range_assert(PointerVal, lo, hi, signed)
}
-
- value
}
-pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- debug!("Store %s -> %s",
- cx.val_to_str(Val),
- cx.val_to_str(Ptr));
- count_insn(cx, "store");
- llvm::LLVMBuildStore(B(cx), Val, Ptr);
- }
+pub fn Store(cx: @mut Block, Val: ValueRef, Ptr: ValueRef) {
+ if cx.unreachable { return; }
+ B(cx).store(Val, Ptr)
}
-pub fn AtomicStore(cx: block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrdering) {
- unsafe {
- if cx.unreachable { return; }
- debug!("Store %s -> %s",
- cx.val_to_str(Val),
- cx.val_to_str(Ptr));
- count_insn(cx, "store.atomic");
- let align = llalign_of_min(cx.ccx(), cx.ccx().int_type);
- llvm::LLVMBuildAtomicStore(B(cx), Val, Ptr, order, align as c_uint);
- }
+pub fn AtomicStore(cx: @mut Block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrdering) {
+ if cx.unreachable { return; }
+ B(cx).atomic_store(Val, Ptr, order)
}
-pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
+pub fn GEP(cx: @mut Block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "gep");
- return llvm::LLVMBuildGEP(B(cx), Pointer, vec::raw::to_ptr(Indices),
- Indices.len() as c_uint, noname());
+ B(cx).gep(Pointer, Indices)
}
}
// Simple wrapper around GEP that takes an array of ints and wraps them
// in C_i32()
#[inline]
-pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef {
- // Small vector optimization. This should catch 100% of the cases that
- // we care about.
- if ixs.len() < 16 {
- let mut small_vec = [ C_i32(0), ..16 ];
- for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| {
- *small_vec_e = C_i32(ix as i32);
- }
- InBoundsGEP(cx, base, small_vec.slice(0, ixs.len()))
- } else {
- let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>();
- count_insn(cx, "gepi");
- InBoundsGEP(cx, base, v)
+pub fn GEPi(cx: @mut Block, base: ValueRef, ixs: &[uint]) -> ValueRef {
+ unsafe {
+ if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
+ B(cx).gepi(base, ixs)
}
}
-pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
+pub fn InBoundsGEP(cx: @mut Block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "inboundsgep");
- return llvm::LLVMBuildInBoundsGEP(
- B(cx), Pointer, vec::raw::to_ptr(Indices), Indices.len() as c_uint, noname());
+ B(cx).inbounds_gep(Pointer, Indices)
}
}
-pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef {
+pub fn StructGEP(cx: @mut Block, Pointer: ValueRef, Idx: uint) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "structgep");
- return llvm::LLVMBuildStructGEP(B(cx),
- Pointer,
- Idx as c_uint,
- noname());
+ B(cx).struct_gep(Pointer, Idx)
}
}
-pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef {
+pub fn GlobalString(cx: @mut Block, _Str: *c_char) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "globalstring");
- return llvm::LLVMBuildGlobalString(B(cx), _Str, noname());
+ B(cx).global_string(_Str)
}
}
-pub fn GlobalStringPtr(cx: block, _Str: *c_char) -> ValueRef {
+pub fn GlobalStringPtr(cx: @mut Block, _Str: *c_char) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "globalstringptr");
- return llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname());
+ B(cx).global_string_ptr(_Str)
}
}
/* Casts */
-pub fn Trunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn Trunc(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "trunc");
- return llvm::LLVMBuildTrunc(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).trunc(Val, DestTy)
}
}
-pub fn ZExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn ZExt(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "zext");
- return llvm::LLVMBuildZExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).zext(Val, DestTy)
}
}
-pub fn SExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn SExt(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sext");
- return llvm::LLVMBuildSExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sext(Val, DestTy)
}
}
-pub fn FPToUI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn FPToUI(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptoui");
- return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fptoui(Val, DestTy)
}
}
-pub fn FPToSI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn FPToSI(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptosi");
- return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy.to_ref(),noname());
+ B(cx).fptosi(Val, DestTy)
}
}
-pub fn UIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn UIToFP(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "uitofp");
- return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).uitofp(Val, DestTy)
}
}
-pub fn SIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn SIToFP(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sitofp");
- return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sitofp(Val, DestTy)
}
}
-pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn FPTrunc(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptrunc");
- return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fptrunc(Val, DestTy)
}
}
-pub fn FPExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn FPExt(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fpext");
- return llvm::LLVMBuildFPExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fpext(Val, DestTy)
}
}
-pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn PtrToInt(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "ptrtoint");
- return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).ptrtoint(Val, DestTy)
}
}
-pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn IntToPtr(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "inttoptr");
- return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).inttoptr(Val, DestTy)
}
}
-pub fn BitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn BitCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "bitcast");
- return llvm::LLVMBuildBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).bitcast(Val, DestTy)
}
}
-pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn ZExtOrBitCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "zextorbitcast");
- return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).zext_or_bitcast(Val, DestTy)
}
}
-pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn SExtOrBitCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sextorbitcast");
- return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sext_or_bitcast(Val, DestTy)
}
}
-pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn TruncOrBitCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "truncorbitcast");
- return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).trunc_or_bitcast(Val, DestTy)
}
}
-pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: Type, _: *u8)
+pub fn Cast(cx: @mut Block, Op: Opcode, Val: ValueRef, DestTy: Type, _: *u8)
-> ValueRef {
unsafe {
- count_insn(cx, "cast");
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy.to_ref(), noname());
+ B(cx).cast(Op, Val, DestTy)
}
}
-pub fn PointerCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn PointerCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "pointercast");
- return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).pointercast(Val, DestTy)
}
}
-pub fn IntCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn IntCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "intcast");
- return llvm::LLVMBuildIntCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).intcast(Val, DestTy)
}
}
-pub fn FPCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
+pub fn FPCast(cx: @mut Block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fpcast");
- return llvm::LLVMBuildFPCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fpcast(Val, DestTy)
}
}
/* Comparisons */
-pub fn ICmp(cx: block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef)
+pub fn ICmp(cx: @mut Block, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef)
-> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "icmp");
- return llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname());
+ B(cx).icmp(Op, LHS, RHS)
}
}
-pub fn FCmp(cx: block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef)
+pub fn FCmp(cx: @mut Block, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef)
-> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "fcmp");
- return llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname());
+ B(cx).fcmp(Op, LHS, RHS)
}
}
/* Miscellaneous instructions */
-pub fn EmptyPhi(cx: block, Ty: Type) -> ValueRef {
+pub fn EmptyPhi(cx: @mut Block, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- count_insn(cx, "emptyphi");
- return llvm::LLVMBuildPhi(B(cx), Ty.to_ref(), noname());
+ B(cx).empty_phi(Ty)
}
}
-pub fn Phi(cx: block, Ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef])
- -> ValueRef {
+pub fn Phi(cx: @mut Block, Ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- assert_eq!(vals.len(), bbs.len());
- let phi = EmptyPhi(cx, Ty);
- count_insn(cx, "addincoming");
- llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
- vec::raw::to_ptr(bbs),
- vals.len() as c_uint);
- return phi;
+ B(cx).phi(Ty, vals, bbs)
}
}
}
}
-pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef {
+pub fn _UndefReturn(cx: @mut Block, Fn: ValueRef) -> ValueRef {
unsafe {
let ccx = cx.fcx.ccx;
let ty = val_ty(Fn);
} else {
ccx.int_type
};
- count_insn(cx, "ret_undef");
- return llvm::LLVMGetUndef(retty.to_ref());
+ B(cx).count_insn("ret_undef");
+ llvm::LLVMGetUndef(retty.to_ref())
}
}
-pub fn add_span_comment(bcx: block, sp: span, text: &str) {
- let ccx = bcx.ccx();
- if ccx.sess.asm_comments() {
- let s = fmt!("%s (%s)", text, ccx.sess.codemap.span_to_str(sp));
- debug!("%s", s);
- add_comment(bcx, s);
- }
+pub fn add_span_comment(cx: @mut Block, sp: span, text: &str) {
+ B(cx).add_span_comment(sp, text)
}
-pub fn add_comment(bcx: block, text: &str) {
- unsafe {
- let ccx = bcx.ccx();
- if ccx.sess.asm_comments() {
- let sanitized = text.replace("$", "");
- let comment_text = ~"# " +
- sanitized.replace("\n", "\n\t# ");
- count_insn(bcx, "inlineasm");
- let asm = do comment_text.as_c_str |c| {
- llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
- c, noname(), False, False)
- };
- Call(bcx, asm, []);
- }
- }
+pub fn add_comment(cx: @mut Block, text: &str) {
+ B(cx).add_comment(text)
}
-pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
+pub fn InlineAsmCall(cx: @mut Block, asm: *c_char, cons: *c_char,
inputs: &[ValueRef], output: Type,
volatile: bool, alignstack: bool,
dia: AsmDialect) -> ValueRef {
- unsafe {
- count_insn(cx, "inlineasm");
-
- let volatile = if volatile { lib::llvm::True }
- else { lib::llvm::False };
- let alignstack = if alignstack { lib::llvm::True }
- else { lib::llvm::False };
-
- let argtys = do inputs.map |v| {
- debug!("Asm Input Type: %?", cx.val_to_str(*v));
- val_ty(*v)
- };
-
- debug!("Asm Output Type: %?", cx.ccx().tn.type_to_str(output));
- let fty = Type::func(argtys, &output);
- let v = llvm::LLVMInlineAsm(fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
-
- Call(cx, v, inputs)
- }
+ B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
}
-pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn Call(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "call");
-
- debug!("Call(Fn=%s, Args=%?)",
- cx.val_to_str(Fn),
- Args.map(|arg| cx.val_to_str(*arg)));
-
- do Args.as_imm_buf |ptr, len| {
- llvm::LLVMBuildCall(B(cx), Fn, ptr, len as c_uint, noname())
- }
- }
+ B(cx).call(Fn, Args)
}
-pub fn FastCall(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn FastCall(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "fastcall");
- let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- return v;
- }
+ B(cx).call(Fn, Args)
}
-pub fn CallWithConv(cx: block, Fn: ValueRef, Args: &[ValueRef],
+pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
Conv: CallConv) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "callwithconv");
- let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, Conv);
- return v;
- }
+ B(cx).call_with_conv(Fn, Args, Conv)
}
-pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) ->
- ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(Then); }
- count_insn(cx, "select");
- return llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname());
- }
+pub fn Select(cx: @mut Block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(Then); }
+ B(cx).select(If, Then, Else)
}
-pub fn VAArg(cx: block, list: ValueRef, Ty: Type) -> ValueRef {
+pub fn VAArg(cx: @mut Block, list: ValueRef, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- count_insn(cx, "vaarg");
- return llvm::LLVMBuildVAArg(B(cx), list, Ty.to_ref(), noname());
+ B(cx).va_arg(list, Ty)
}
}
-pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) ->
- ValueRef {
+pub fn ExtractElement(cx: @mut Block, VecVal: ValueRef, Index: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "extractelement");
- return llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname());
+ B(cx).extract_element(VecVal, Index)
}
}
-pub fn InsertElement(cx: block, VecVal: ValueRef, EltVal: ValueRef,
+pub fn InsertElement(cx: @mut Block, VecVal: ValueRef, EltVal: ValueRef,
Index: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "insertelement");
- llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname())
+ B(cx).insert_element(VecVal, EltVal, Index)
}
}
-pub fn ShuffleVector(cx: block, V1: ValueRef, V2: ValueRef,
+pub fn ShuffleVector(cx: @mut Block, V1: ValueRef, V2: ValueRef,
Mask: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "shufflevector");
- llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname())
+ B(cx).shuffle_vector(V1, V2, Mask)
}
}
-pub fn VectorSplat(cx: block, NumElts: uint, EltVal: ValueRef) -> ValueRef {
+pub fn VectorSplat(cx: @mut Block, NumElts: uint, EltVal: ValueRef) -> ValueRef {
unsafe {
- let elt_ty = val_ty(EltVal);
- let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, NumElts as u64).to_ref());
- let VecVal = InsertElement(cx, Undef, EltVal, C_i32(0));
- ShuffleVector(cx, VecVal, Undef, C_null(Type::vector(&Type::i32(), NumElts as u64)))
+ if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
+ B(cx).vector_splat(NumElts, EltVal)
}
}
-pub fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef {
+pub fn ExtractValue(cx: @mut Block, AggVal: ValueRef, Index: uint) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "extractvalue");
- return llvm::LLVMBuildExtractValue(
- B(cx), AggVal, Index as c_uint, noname());
+ B(cx).extract_value(AggVal, Index)
}
}
-pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef,
- Index: uint) {
- unsafe {
- if cx.unreachable { return; }
- count_insn(cx, "insertvalue");
- llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint,
- noname());
- }
+pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) {
+ if cx.unreachable { return; }
+ B(cx).insert_value(AggVal, EltVal, Index)
}
-pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef {
+pub fn IsNull(cx: @mut Block, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "isnull");
- return llvm::LLVMBuildIsNull(B(cx), Val, noname());
+ B(cx).is_null(Val)
}
}
-pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef {
+pub fn IsNotNull(cx: @mut Block, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "isnotnull");
- return llvm::LLVMBuildIsNotNull(B(cx), Val, noname());
+ B(cx).is_not_null(Val)
}
}
-pub fn PtrDiff(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+pub fn PtrDiff(cx: @mut Block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
unsafe {
let ccx = cx.fcx.ccx;
if cx.unreachable { return llvm::LLVMGetUndef(ccx.int_type.to_ref()); }
- count_insn(cx, "ptrdiff");
- return llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname());
+ B(cx).ptrdiff(LHS, RHS)
}
}
-pub fn Trap(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- let b = B(cx);
- let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(b);
- let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
- let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
- let T: ValueRef = str::as_c_str("llvm.trap", |buf| {
- llvm::LLVMGetNamedFunction(M, buf)
- });
- assert!((T as int != 0));
- let Args: ~[ValueRef] = ~[];
- count_insn(cx, "trap");
- llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args), Args.len() as c_uint, noname());
- }
+pub fn Trap(cx: @mut Block) {
+ if cx.unreachable { return; }
+ B(cx).trap();
}
-pub fn LandingPad(cx: block, Ty: Type, PersFn: ValueRef,
+pub fn LandingPad(cx: @mut Block, Ty: Type, PersFn: ValueRef,
NumClauses: uint) -> ValueRef {
- unsafe {
- check_not_terminated(cx);
- assert!(!cx.unreachable);
- count_insn(cx, "landingpad");
- return llvm::LLVMBuildLandingPad(
- B(cx), Ty.to_ref(), PersFn, NumClauses as c_uint, noname());
- }
+ check_not_terminated(cx);
+ assert!(!cx.unreachable);
+ B(cx).landing_pad(Ty, PersFn, NumClauses)
}
-pub fn SetCleanup(cx: block, LandingPad: ValueRef) {
- unsafe {
- count_insn(cx, "setcleanup");
- llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
- }
+pub fn SetCleanup(cx: @mut Block, LandingPad: ValueRef) {
+ B(cx).set_cleanup(LandingPad)
}
-pub fn Resume(cx: block, Exn: ValueRef) -> ValueRef {
- unsafe {
- check_not_terminated(cx);
- terminate(cx, "Resume");
- count_insn(cx, "resume");
- return llvm::LLVMBuildResume(B(cx), Exn);
- }
+pub fn Resume(cx: @mut Block, Exn: ValueRef) -> ValueRef {
+ check_not_terminated(cx);
+ terminate(cx, "Resume");
+ B(cx).resume(Exn)
}
// Atomic Operations
-pub fn AtomicCmpXchg(cx: block, dst: ValueRef,
+pub fn AtomicCmpXchg(cx: @mut Block, dst: ValueRef,
cmp: ValueRef, src: ValueRef,
order: AtomicOrdering) -> ValueRef {
- unsafe {
- llvm::LLVMBuildAtomicCmpXchg(B(cx), dst, cmp, src, order)
- }
+ B(cx).atomic_cmpxchg(dst, cmp, src, order)
}
-pub fn AtomicRMW(cx: block, op: AtomicBinOp,
+pub fn AtomicRMW(cx: @mut Block, op: AtomicBinOp,
dst: ValueRef, src: ValueRef,
order: AtomicOrdering) -> ValueRef {
- unsafe {
- llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order)
- }
+ B(cx).atomic_rmw(op, dst, src, order)
}
--- /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 lib;
+use lib::llvm::llvm;
+use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
+use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
+use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
+use middle::trans::base;
+use middle::trans::common::*;
+use middle::trans::machine::llalign_of_min;
+use middle::trans::type_::Type;
+use std::cast;
+use std::hashmap::HashMap;
+use std::libc::{c_uint, c_ulonglong, c_char};
+use std::str;
+use std::vec;
+use syntax::codemap::span;
+
+pub struct Builder {
+ llbuilder: BuilderRef,
+ ccx: @mut CrateContext,
+}
+
+// This is a really awful way to get a zero-length c-string, but better (and a
+// lot more efficient) than doing str::as_c_str("", ...) every time.
+pub fn noname() -> *c_char {
+ unsafe {
+ static cnull: uint = 0u;
+ cast::transmute(&cnull)
+ }
+}
+
+impl Builder {
+ pub fn new(ccx: @mut CrateContext) -> Builder {
+ Builder {
+ llbuilder: ccx.builder.B,
+ ccx: ccx,
+ }
+ }
+
+ pub fn count_insn(&self, category: &str) {
+ if self.ccx.sess.trans_stats() {
+ self.ccx.stats.n_llvm_insns += 1;
+ }
+ if self.ccx.sess.count_llvm_insns() {
+ do base::with_insn_ctxt |v| {
+ let h = &mut self.ccx.stats.llvm_insns;
+
+ // Build version of path with cycles removed.
+
+ // Pass 1: scan table mapping str -> rightmost pos.
+ let mut mm = HashMap::new();
+ let len = v.len();
+ let mut i = 0u;
+ while i < len {
+ mm.insert(v[i], i);
+ i += 1u;
+ }
+
+ // Pass 2: concat strings for each elt, skipping
+ // forwards over any cycles by advancing to rightmost
+ // occurrence of each element in path.
+ let mut s = ~".";
+ i = 0u;
+ while i < len {
+ i = *mm.get(&v[i]);
+ s.push_char('/');
+ s.push_str(v[i]);
+ i += 1u;
+ }
+
+ s.push_char('/');
+ s.push_str(category);
+
+ let n = match h.find(&s) {
+ Some(&n) => n,
+ _ => 0u
+ };
+ h.insert(s, n+1u);
+ }
+ }
+ }
+
+ pub fn position_before(&self, insn: ValueRef) {
+ unsafe {
+ llvm::LLVMPositionBuilderBefore(self.llbuilder, insn);
+ }
+ }
+
+ pub fn position_at_end(&self, llbb: BasicBlockRef) {
+ unsafe {
+ llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
+ }
+ }
+
+ pub fn ret_void(&self) {
+ self.count_insn("retvoid");
+ unsafe {
+ llvm::LLVMBuildRetVoid(self.llbuilder);
+ }
+ }
+
+ pub fn ret(&self, v: ValueRef) {
+ self.count_insn("ret");
+ unsafe {
+ llvm::LLVMBuildRet(self.llbuilder, v);
+ }
+ }
+
+ pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) {
+ unsafe {
+ llvm::LLVMBuildAggregateRet(self.llbuilder,
+ vec::raw::to_ptr(ret_vals),
+ ret_vals.len() as c_uint);
+ }
+ }
+
+ pub fn br(&self, dest: BasicBlockRef) {
+ self.count_insn("br");
+ unsafe {
+ llvm::LLVMBuildBr(self.llbuilder, dest);
+ }
+ }
+
+ pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) {
+ self.count_insn("condbr");
+ unsafe {
+ llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
+ }
+ }
+
+ pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: uint) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
+ }
+ }
+
+ pub fn indirect_br(&self, addr: ValueRef, num_dests: uint) {
+ self.count_insn("indirectbr");
+ unsafe {
+ llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint);
+ }
+ }
+
+ pub fn invoke(&self,
+ llfn: ValueRef,
+ args: &[ValueRef],
+ then: BasicBlockRef,
+ catch: BasicBlockRef)
+ -> ValueRef {
+ self.count_insn("invoke");
+ unsafe {
+ llvm::LLVMBuildInvoke(self.llbuilder,
+ llfn,
+ vec::raw::to_ptr(args),
+ args.len() as c_uint,
+ then,
+ catch,
+ noname())
+ }
+ }
+
+ pub fn fast_invoke(&self,
+ llfn: ValueRef,
+ args: &[ValueRef],
+ then: BasicBlockRef,
+ catch: BasicBlockRef) {
+ self.count_insn("fastinvoke");
+ let v = self.invoke(llfn, args, then, catch);
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+ }
+
+ pub fn unreachable(&self) {
+ self.count_insn("unreachable");
+ unsafe {
+ llvm::LLVMBuildUnreachable(self.llbuilder);
+ }
+ }
+
+ /* Arithmetic */
+ pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("add");
+ unsafe {
+ llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nswadd");
+ unsafe {
+ llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwadd");
+ unsafe {
+ llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fadd");
+ unsafe {
+ llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sub");
+ unsafe {
+ llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nwsub");
+ unsafe {
+ llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwsub");
+ unsafe {
+ llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sub");
+ unsafe {
+ llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("mul");
+ unsafe {
+ llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nswmul");
+ unsafe {
+ llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwmul");
+ unsafe {
+ llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fmul");
+ unsafe {
+ llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("udiv");
+ unsafe {
+ llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sdiv");
+ unsafe {
+ llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("exactsdiv");
+ unsafe {
+ llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fdiv");
+ unsafe {
+ llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("urem");
+ unsafe {
+ llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("srem");
+ unsafe {
+ llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("frem");
+ unsafe {
+ llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("shl");
+ unsafe {
+ llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("lshr");
+ unsafe {
+ llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("ashr");
+ unsafe {
+ llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("and");
+ unsafe {
+ llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("or");
+ unsafe {
+ llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("xor");
+ unsafe {
+ llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef)
+ -> ValueRef {
+ self.count_insn("binop");
+ unsafe {
+ llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname())
+ }
+ }
+
+ pub fn neg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("neg");
+ unsafe {
+ llvm::LLVMBuildNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn nswneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("nswneg");
+ unsafe {
+ llvm::LLVMBuildNSWNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn nuwneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("nuwneg");
+ unsafe {
+ llvm::LLVMBuildNUWNeg(self.llbuilder, V, noname())
+ }
+ }
+ pub fn fneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("fneg");
+ unsafe {
+ llvm::LLVMBuildFNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn not(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("not");
+ unsafe {
+ llvm::LLVMBuildNot(self.llbuilder, V, noname())
+ }
+ }
+
+ /* Memory */
+ pub fn malloc(&self, ty: Type) -> ValueRef {
+ self.count_insn("malloc");
+ unsafe {
+ llvm::LLVMBuildMalloc(self.llbuilder, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn array_malloc(&self, ty: Type, val: ValueRef) -> ValueRef {
+ self.count_insn("arraymalloc");
+ unsafe {
+ llvm::LLVMBuildArrayMalloc(self.llbuilder, ty.to_ref(), val, noname())
+ }
+ }
+
+ pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+ self.count_insn("alloca");
+ unsafe {
+ if name.is_empty() {
+ llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
+ } else {
+ str::as_c_str(
+ name,
+ |c| llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c))
+ }
+ }
+ }
+
+ pub fn array_alloca(&self, ty: Type, val: ValueRef) -> ValueRef {
+ self.count_insn("arrayalloca");
+ unsafe {
+ llvm::LLVMBuildArrayAlloca(self.llbuilder, ty.to_ref(), val, noname())
+ }
+ }
+
+ pub fn free(&self, ptr: ValueRef) {
+ self.count_insn("free");
+ unsafe {
+ llvm::LLVMBuildFree(self.llbuilder, ptr);
+ }
+ }
+
+ pub fn load(&self, ptr: ValueRef) -> ValueRef {
+ self.count_insn("load");
+ unsafe {
+ llvm::LLVMBuildLoad(self.llbuilder, ptr, noname())
+ }
+ }
+
+ pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
+ self.count_insn("load.atomic");
+ unsafe {
+ let align = llalign_of_min(self.ccx, self.ccx.int_type);
+ llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order, align as c_uint)
+ }
+ }
+
+
+ pub fn load_range_assert(&self, ptr: ValueRef, lo: c_ulonglong,
+ hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
+ let value = self.load(ptr);
+
+ unsafe {
+ let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
+ let min = llvm::LLVMConstInt(t, lo, signed);
+ let max = llvm::LLVMConstInt(t, hi, signed);
+
+ do [min, max].as_imm_buf |ptr, len| {
+ llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
+ llvm::LLVMMDNodeInContext(self.ccx.llcx,
+ ptr, len as c_uint));
+ }
+ }
+
+ value
+ }
+
+ pub fn store(&self, val: ValueRef, ptr: ValueRef) {
+ debug!("Store %s -> %s",
+ self.ccx.tn.val_to_str(val),
+ self.ccx.tn.val_to_str(ptr));
+ self.count_insn("store");
+ unsafe {
+ llvm::LLVMBuildStore(self.llbuilder, val, ptr);
+ }
+ }
+
+ pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
+ debug!("Store %s -> %s",
+ self.ccx.tn.val_to_str(val),
+ self.ccx.tn.val_to_str(ptr));
+ self.count_insn("store.atomic");
+ let align = llalign_of_min(self.ccx, self.ccx.int_type);
+ unsafe {
+ llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint);
+ }
+ }
+
+ pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ self.count_insn("gep");
+ unsafe {
+ llvm::LLVMBuildGEP(self.llbuilder, ptr, vec::raw::to_ptr(indices),
+ indices.len() as c_uint, noname())
+ }
+ }
+
+ // Simple wrapper around GEP that takes an array of ints and wraps them
+ // in C_i32()
+ #[inline]
+ pub fn gepi(&self, base: ValueRef, ixs: &[uint]) -> ValueRef {
+ // Small vector optimization. This should catch 100% of the cases that
+ // we care about.
+ if ixs.len() < 16 {
+ let mut small_vec = [ C_i32(0), ..16 ];
+ for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| {
+ *small_vec_e = C_i32(ix as i32);
+ }
+ self.inbounds_gep(base, small_vec.slice(0, ixs.len()))
+ } else {
+ let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>();
+ self.count_insn("gepi");
+ self.inbounds_gep(base, v)
+ }
+ }
+
+ pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ self.count_insn("inboundsgep");
+ unsafe {
+ llvm::LLVMBuildInBoundsGEP(
+ self.llbuilder, ptr, vec::raw::to_ptr(indices), indices.len() as c_uint, noname())
+ }
+ }
+
+ pub fn struct_gep(&self, ptr: ValueRef, idx: uint) -> ValueRef {
+ self.count_insn("structgep");
+ unsafe {
+ llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
+ }
+ }
+
+ pub fn global_string(&self, _Str: *c_char) -> ValueRef {
+ self.count_insn("globalstring");
+ unsafe {
+ llvm::LLVMBuildGlobalString(self.llbuilder, _Str, noname())
+ }
+ }
+
+ pub fn global_string_ptr(&self, _Str: *c_char) -> ValueRef {
+ self.count_insn("globalstringptr");
+ unsafe {
+ llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _Str, noname())
+ }
+ }
+
+ /* Casts */
+ pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("trunc");
+ unsafe {
+ llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("zext");
+ unsafe {
+ llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sext");
+ unsafe {
+ llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptoui");
+ unsafe {
+ llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptosi");
+ unsafe {
+ llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname())
+ }
+ }
+
+ pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("uitofp");
+ unsafe {
+ llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sitofp");
+ unsafe {
+ llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptrunc");
+ unsafe {
+ llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fpext");
+ unsafe {
+ llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("ptrtoint");
+ unsafe {
+ llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("inttoptr");
+ unsafe {
+ llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("bitcast");
+ unsafe {
+ llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("zextorbitcast");
+ unsafe {
+ llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sextorbitcast");
+ unsafe {
+ llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("truncorbitcast");
+ unsafe {
+ llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("cast");
+ unsafe {
+ llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("pointercast");
+ unsafe {
+ llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn intcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("intcast");
+ unsafe {
+ llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fpcast");
+ unsafe {
+ llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+
+ /* Comparisons */
+ pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("icmp");
+ unsafe {
+ llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fcmp");
+ unsafe {
+ llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ }
+ }
+
+ /* Miscellaneous instructions */
+ pub fn empty_phi(&self, ty: Type) -> ValueRef {
+ self.count_insn("emptyphi");
+ unsafe {
+ llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
+ assert_eq!(vals.len(), bbs.len());
+ let phi = self.empty_phi(ty);
+ self.count_insn("addincoming");
+ unsafe {
+ llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
+ vec::raw::to_ptr(bbs),
+ vals.len() as c_uint);
+ phi
+ }
+ }
+
+ pub fn add_span_comment(&self, sp: span, text: &str) {
+ if self.ccx.sess.asm_comments() {
+ let s = fmt!("%s (%s)", text, self.ccx.sess.codemap.span_to_str(sp));
+ debug!("%s", s);
+ self.add_comment(s);
+ }
+ }
+
+ pub fn add_comment(&self, text: &str) {
+ if self.ccx.sess.asm_comments() {
+ let sanitized = text.replace("$", "");
+ let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# "));
+ self.count_insn("inlineasm");
+ let asm = do comment_text.as_c_str |c| {
+ unsafe {
+ llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
+ c, noname(), False, False)
+ }
+ };
+ self.call(asm, []);
+ }
+ }
+
+ pub fn inline_asm_call(&self, asm: *c_char, cons: *c_char,
+ inputs: &[ValueRef], output: Type,
+ volatile: bool, alignstack: bool,
+ dia: AsmDialect) -> ValueRef {
+ self.count_insn("inlineasm");
+
+ let volatile = if volatile { lib::llvm::True }
+ else { lib::llvm::False };
+ let alignstack = if alignstack { lib::llvm::True }
+ else { lib::llvm::False };
+
+ let argtys = do inputs.map |v| {
+ debug!("Asm Input Type: %?", self.ccx.tn.val_to_str(*v));
+ val_ty(*v)
+ };
+
+ debug!("Asm Output Type: %?", self.ccx.tn.type_to_str(output));
+ let fty = Type::func(argtys, &output);
+ unsafe {
+ let v = llvm::LLVMInlineAsm(
+ fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
+ self.call(v, inputs)
+ }
+ }
+
+ pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+ self.count_insn("call");
+
+ debug!("Call(llfn=%s, args=%?)",
+ self.ccx.tn.val_to_str(llfn),
+ args.map(|arg| self.ccx.tn.val_to_str(*arg)));
+
+ do args.as_imm_buf |ptr, len| {
+ unsafe {
+ llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
+ }
+ }
+ }
+
+ pub fn fastcall(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+ self.count_insn("fastcall");
+ unsafe {
+ let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
+ args.len() as c_uint, noname());
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+ v
+ }
+ }
+
+ pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
+ conv: CallConv) -> ValueRef {
+ self.count_insn("callwithconv");
+ unsafe {
+ let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
+ args.len() as c_uint, noname());
+ lib::llvm::SetInstructionCallConv(v, conv);
+ v
+ }
+ }
+
+ pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
+ self.count_insn("select");
+ unsafe {
+ llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
+ }
+ }
+
+ pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef {
+ self.count_insn("vaarg");
+ unsafe {
+ llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef {
+ self.count_insn("extractelement");
+ unsafe {
+ llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
+ }
+ }
+
+ pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
+ self.count_insn("insertelement");
+ unsafe {
+ llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
+ }
+ }
+
+ pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
+ self.count_insn("shufflevector");
+ unsafe {
+ llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
+ }
+ }
+
+ pub fn vector_splat(&self, num_elts: uint, elt: ValueRef) -> ValueRef {
+ unsafe {
+ let elt_ty = val_ty(elt);
+ let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref());
+ let vec = self.insert_element(Undef, elt, C_i32(0));
+ self.shuffle_vector(vec, Undef, C_null(Type::vector(&Type::i32(), num_elts as u64)))
+ }
+ }
+
+ pub fn extract_value(&self, agg_val: ValueRef, idx: uint) -> ValueRef {
+ self.count_insn("extractvalue");
+ unsafe {
+ llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname())
+ }
+ }
+
+ pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
+ idx: uint) {
+ self.count_insn("insertvalue");
+ unsafe {
+ llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
+ noname());
+ }
+ }
+
+ pub fn is_null(&self, val: ValueRef) -> ValueRef {
+ self.count_insn("isnull");
+ unsafe {
+ llvm::LLVMBuildIsNull(self.llbuilder, val, noname())
+ }
+ }
+
+ pub fn is_not_null(&self, val: ValueRef) -> ValueRef {
+ self.count_insn("isnotnull");
+ unsafe {
+ llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname())
+ }
+ }
+
+ pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("ptrdiff");
+ unsafe {
+ llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn trap(&self) {
+ unsafe {
+ let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
+ let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
+ let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
+ let T: ValueRef = str::as_c_str("llvm.trap", |buf| {
+ llvm::LLVMGetNamedFunction(M, buf)
+ });
+ assert!((T as int != 0));
+ let args: &[ValueRef] = [];
+ self.count_insn("trap");
+ llvm::LLVMBuildCall(
+ self.llbuilder, T, vec::raw::to_ptr(args), args.len() as c_uint, noname());
+ }
+ }
+
+ pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, num_clauses: uint) -> ValueRef {
+ self.count_insn("landingpad");
+ unsafe {
+ llvm::LLVMBuildLandingPad(
+ self.llbuilder, ty.to_ref(), pers_fn, num_clauses as c_uint, noname())
+ }
+ }
+
+ pub fn set_cleanup(&self, landing_pad: ValueRef) {
+ self.count_insn("setcleanup");
+ unsafe {
+ llvm::LLVMSetCleanup(landing_pad, lib::llvm::True);
+ }
+ }
+
+ pub fn resume(&self, exn: ValueRef) -> ValueRef {
+ self.count_insn("resume");
+ unsafe {
+ llvm::LLVMBuildResume(self.llbuilder, exn)
+ }
+ }
+
+ // Atomic Operations
+ pub fn atomic_cmpxchg(&self, dst: ValueRef,
+ cmp: ValueRef, src: ValueRef,
+ order: AtomicOrdering) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order)
+ }
+ }
+ pub fn atomic_rmw(&self, op: AtomicBinOp,
+ dst: ValueRef, src: ValueRef,
+ order: AtomicOrdering) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order)
+ }
+ }
+}
return llfn;
}
- pub fn build_shim_args(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef)
+ pub fn build_shim_args(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef)
-> ~[ValueRef] {
let mut atys: &[LLVMType] = self.arg_tys;
let mut attrs: &[option::Option<Attribute>] = self.attrs;
return llargvals;
}
- pub fn build_shim_ret(&self, bcx: block, arg_tys: &[Type], ret_def: bool,
+ pub fn build_shim_ret(&self, bcx: @mut Block, arg_tys: &[Type], ret_def: bool,
llargbundle: ValueRef, llretval: ValueRef) {
for self.attrs.iter().enumerate().advance |(i, a)| {
match *a {
};
}
- pub fn build_wrap_args(&self, bcx: block, ret_ty: Type,
+ pub fn build_wrap_args(&self, bcx: @mut Block, ret_ty: Type,
llwrapfn: ValueRef, llargbundle: ValueRef) {
let mut atys: &[LLVMType] = self.arg_tys;
let mut attrs: &[option::Option<Attribute>] = self.attrs;
store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
}
- pub fn build_wrap_ret(&self, bcx: block, arg_tys: &[Type], llargbundle: ValueRef) {
+ pub fn build_wrap_ret(&self, bcx: @mut Block, arg_tys: &[Type], llargbundle: ValueRef) {
if self.ret_ty.ty.kind() == Void {
return;
}
}
pub struct Callee {
- bcx: block,
+ bcx: @mut Block,
data: CalleeData
}
-pub fn trans(bcx: block, expr: @ast::expr) -> Callee {
+pub fn trans(bcx: @mut Block, expr: @ast::expr) -> Callee {
let _icx = push_ctxt("trans_callee");
debug!("callee::trans(expr=%s)", expr.repr(bcx.tcx()));
// any other expressions are closures:
return datum_callee(bcx, expr);
- fn datum_callee(bcx: block, expr: @ast::expr) -> Callee {
+ fn datum_callee(bcx: @mut Block, expr: @ast::expr) -> Callee {
let DatumBlock {bcx, datum} = expr::trans_to_datum(bcx, expr);
match ty::get(datum.ty).sty {
ty::ty_bare_fn(*) => {
}
}
- fn fn_callee(bcx: block, fd: FnData) -> Callee {
+ fn fn_callee(bcx: @mut Block, fd: FnData) -> Callee {
return Callee {bcx: bcx, data: Fn(fd)};
}
- fn trans_def(bcx: block, def: ast::def, ref_expr: @ast::expr) -> Callee {
+ 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, _) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
}
}
-pub fn trans_fn_ref_to_callee(bcx: block,
+pub fn trans_fn_ref_to_callee(bcx: @mut Block,
def_id: ast::def_id,
ref_id: ast::node_id) -> Callee {
Callee {bcx: bcx,
data: Fn(trans_fn_ref(bcx, def_id, ref_id))}
}
-pub fn trans_fn_ref(bcx: block,
+pub fn trans_fn_ref(bcx: @mut Block,
def_id: ast::def_id,
ref_id: ast::node_id) -> FnData {
/*!
}
pub fn trans_fn_ref_with_vtables_to_callee(
- bcx: block,
+ bcx: @mut Block,
def_id: ast::def_id,
ref_id: ast::node_id,
type_params: &[ty::t],
type_params, vtables))}
}
-fn get_impl_resolutions(bcx: block,
+fn get_impl_resolutions(bcx: @mut Block,
impl_id: ast::def_id)
-> typeck::vtable_res {
if impl_id.crate == ast::local_crate {
}
}
-fn resolve_default_method_vtables(bcx: block,
+fn resolve_default_method_vtables(bcx: @mut Block,
impl_id: ast::def_id,
method: &ty::Method,
substs: &ty::substs,
pub fn trans_fn_ref_with_vtables(
- bcx: block, //
+ bcx: @mut Block, //
def_id: ast::def_id, // def id of fn
ref_id: ast::node_id, // node id of use of fn; may be zero if N/A
type_params: &[ty::t], // values for fn's ty params
// 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.
- let (def_id, opt_impl_did, substs, self_vtable, vtables) =
- match tcx.provided_method_sources.find(&def_id) {
- None => (def_id, None, substs, None, vtables),
- Some(source) => {
+ let (is_default, def_id, substs, self_vtable, vtables) =
+ match ty::provided_source(tcx, def_id) {
+ None => (false, def_id, substs, None, vtables),
+ Some(source_id) => {
// There are two relevant substitutions when compiling
// default methods. First, there is the substitution for
// the type parameters of the impl we are using and the
// So, what we need to do is find this substitution and
// compose it with the one we already have.
- let trait_ref = ty::impl_trait_ref(tcx, source.impl_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 \
default methods");
- let method = ty::method(tcx, source.method_id);
// Get all of the type params for the receiver
let param_defs = method.generics.type_param_defs;
};
let self_vtable =
- typeck::vtable_static(source.impl_id, receiver_substs,
+ typeck::vtable_static(impl_id, receiver_substs,
receiver_vtables);
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
- tcx, source.impl_id, trait_ref, method);
+ tcx, impl_id, trait_ref, method);
// And compose them
let new_substs = first_subst.subst(tcx, &substs);
let vtables =
- resolve_default_method_vtables(bcx, source.impl_id,
+ resolve_default_method_vtables(bcx, impl_id,
method, &new_substs, vtables);
debug!("trans_fn_with_vtables - default method: \
first_subst.repr(tcx), new_substs.repr(tcx),
self_vtable.repr(tcx), vtables.repr(tcx));
- (source.method_id, Some(source.impl_id),
+ (true, source_id,
new_substs, Some(self_vtable), Some(vtables))
}
};
// intrinsic that is inlined from a different crate, we want to reemit the
// intrinsic instead of trying to call it in the other crate.
let must_monomorphise;
- if type_params.len() > 0 || opt_impl_did.is_some() {
+ if type_params.len() > 0 || is_default {
must_monomorphise = true;
} else if def_id.crate == ast::local_crate {
let map_node = session::expect(
let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, self_vtable,
- opt_impl_did, Some(ref_id));
+ Some(ref_id));
let mut val = val;
if must_cast && ref_id != 0 {
// Monotype of the REFERENCE to the function (type params
// ______________________________________________________________________
// Translating calls
-pub fn trans_call(in_cx: block,
+pub fn trans_call(in_cx: @mut Block,
call_ex: @ast::expr,
f: @ast::expr,
args: CallArgs,
id: ast::node_id,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_call");
trans_call_inner(in_cx,
call_ex.info(),
DontAutorefArg).bcx
}
-pub fn trans_method_call(in_cx: block,
+pub fn trans_method_call(in_cx: @mut Block,
call_ex: @ast::expr,
callee_id: ast::node_id,
rcvr: @ast::expr,
args: CallArgs,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_method_call");
debug!("trans_method_call(call_ex=%s, rcvr=%s)",
call_ex.repr(in_cx.tcx()),
DontAutorefArg).bcx
}
-pub fn trans_lang_call(bcx: block,
+pub fn trans_lang_call(bcx: @mut Block,
did: ast::def_id,
args: &[ValueRef],
dest: Option<expr::Dest>)
DontAutorefArg)
}
-pub fn trans_lang_call_with_type_params(bcx: block,
+pub fn trans_lang_call_with_type_params(bcx: @mut Block,
did: ast::def_id,
args: &[ValueRef],
type_params: &[ty::t],
dest: expr::Dest)
- -> block {
+ -> @mut Block {
let fty;
if did.crate == ast::local_crate {
fty = ty::node_id_to_type(bcx.tcx(), did.node);
ArgVals(args), Some(dest), DontAutorefArg).bcx;
}
-pub fn body_contains_ret(body: &ast::blk) -> bool {
+pub fn body_contains_ret(body: &ast::Block) -> bool {
let cx = @mut false;
visit::visit_block(body, (cx, visit::mk_vt(@visit::Visitor {
visit_item: |_i, (_cx, _v)| { },
}
// See [Note-arg-mode]
-pub fn trans_call_inner(in_cx: block,
+pub fn trans_call_inner(in_cx: @mut Block,
call_info: Option<NodeInfo>,
fn_expr_ty: ty::t,
ret_ty: ty::t,
- get_callee: &fn(block) -> Callee,
+ get_callee: &fn(@mut Block) -> Callee,
args: CallArgs,
dest: Option<expr::Dest>,
autoref_arg: AutorefArg)
ArgVals(&'self [ValueRef])
}
-pub fn trans_ret_slot(bcx: block, fn_ty: ty::t, dest: Option<expr::Dest>)
+pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
-> ValueRef {
let retty = ty::ty_fn_ret(fn_ty);
}
}
-pub fn trans_args(cx: block,
+pub fn trans_args(cx: @mut Block,
args: CallArgs,
fn_ty: ty::t,
ret_flag: Option<ValueRef>,
autoref_arg: AutorefArg,
- llargs: &mut ~[ValueRef]) -> block
+ llargs: &mut ~[ValueRef]) -> @mut Block
{
let _icx = push_ctxt("trans_args");
let mut temp_cleanups = ~[];
// temp_cleanups: cleanups that should run only if failure occurs before the
// call takes place:
-pub fn trans_arg_expr(bcx: block,
+pub fn trans_arg_expr(bcx: @mut Block,
formal_arg_ty: ty::t,
self_mode: ty::SelfMode,
arg_expr: @ast::expr,
use back::abi;
use back::link::{mangle_internal_name_by_path_and_seq};
-use lib::llvm::{llvm, ValueRef};
+use lib::llvm::ValueRef;
use middle::moves;
-use middle::lang_items::ClosureExchangeMallocFnLangItem;
use middle::trans::base::*;
use middle::trans::build::*;
-use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::datum::{Datum, INIT, ByRef, ZeroMem};
use middle::trans::expr;
use middle::trans::glue;
-use middle::trans::machine;
use middle::trans::type_of::*;
use middle::ty;
use util::ppaux::ty_to_str;
use middle::trans::type_::Type;
-use std::str;
use std::vec;
use syntax::ast;
use syntax::ast_map::path_name;
return cdata_ty;
}
-fn heap_for_unique_closure(bcx: block, t: ty::t) -> heap {
+fn heap_for_unique_closure(bcx: @mut Block, t: ty::t) -> heap {
if ty::type_contents(bcx.tcx(), t).contains_managed() {
heap_managed_unique
} else {
}
}
-pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t)
+pub fn allocate_cbox(bcx: @mut Block, sigil: ast::Sigil, cdata_ty: ty::t)
-> Result {
let _icx = push_ctxt("closure::allocate_cbox");
let ccx = bcx.ccx();
let tcx = ccx.tcx;
- fn nuke_ref_count(bcx: block, llbox: ValueRef) {
- let _icx = push_ctxt("closure::nuke_ref_count");
- // Initialize ref count to arbitrary value for debugging:
- let ccx = bcx.ccx();
- let llbox = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
- let ref_cnt = GEPi(bcx, llbox, [0u, abi::box_field_refcnt]);
- let rc = C_int(ccx, 0x12345678);
- Store(bcx, rc, ref_cnt);
- }
-
// Allocate and initialize the box:
match sigil {
ast::ManagedSigil => {
ast::BorrowedSigil => {
let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
let llbox = alloc_ty(bcx, cbox_ty, "__closure");
- nuke_ref_count(bcx, llbox);
rslt(bcx, llbox)
}
}
pub struct ClosureResult {
llbox: ValueRef, // llvalue of ptr to closure
cdata_ty: ty::t, // type of the closure data
- bcx: block // final bcx
+ bcx: @mut Block // final bcx
}
// Given a block context and a list of tydescs and values to bind
// construct a closure out of them. If copying is true, it is a
// heap allocated closure that copies the upvars into environment.
// Otherwise, it is stack allocated and copies pointers to the upvars.
-pub fn store_environment(bcx: block,
+pub fn store_environment(bcx: @mut Block,
bound_values: ~[EnvValue],
sigil: ast::Sigil) -> ClosureResult {
let _icx = push_ctxt("closure::store_environment");
// Given a context and a list of upvars, build a closure. This just
// collects the upvars and packages them up for store_environment.
-pub fn build_closure(bcx0: block,
+pub fn build_closure(bcx0: @mut Block,
cap_vars: &[moves::CaptureVar],
sigil: ast::Sigil,
include_ret_handle: Option<ValueRef>) -> ClosureResult {
// Given an enclosing block context, a new function context, a closure type,
// and a list of upvars, generate code to load and populate the environment
// with the upvars and type descriptors.
-pub fn load_environment(fcx: fn_ctxt,
+pub fn load_environment(fcx: @mut FunctionContext,
cdata_ty: ty::t,
cap_vars: &[moves::CaptureVar],
load_ret_handle: bool,
sigil: ast::Sigil) {
let _icx = push_ctxt("closure::load_environment");
- let llloadenv = match fcx.llloadenv {
- Some(ll) => ll,
- None => {
- let ll =
- str::as_c_str("load_env",
- |buf|
- unsafe {
- llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
- fcx.llfn,
- buf)
- });
- fcx.llloadenv = Some(ll);
- ll
- }
- };
+ // Don't bother to create the block if there's nothing to load
+ if cap_vars.len() == 0 && !load_ret_handle {
+ return;
+ }
- let bcx = raw_block(fcx, false, llloadenv);
+ let bcx = fcx.entry_bcx.get();
// Load a pointer to the closure data, skipping over the box header:
let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv);
}
}
-pub fn trans_expr_fn(bcx: block,
+pub fn trans_expr_fn(bcx: @mut Block,
sigil: ast::Sigil,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
outer_id: ast::node_id,
user_id: ast::node_id,
is_loop_body: Option<Option<ValueRef>>,
- dest: expr::Dest) -> block {
+ dest: expr::Dest) -> @mut Block {
/*!
*
* Translates the body of a closure expression.
}
pub fn make_closure_glue(
- cx: block,
+ cx: @mut Block,
v: ValueRef,
t: ty::t,
- glue_fn: &fn(block, v: ValueRef, t: ty::t) -> block) -> block {
+ glue_fn: &fn(@mut Block, v: ValueRef, t: ty::t) -> @mut Block) -> @mut Block {
let _icx = push_ctxt("closure::make_closure_glue");
let bcx = cx;
let tcx = cx.tcx();
}
pub fn make_opaque_cbox_take_glue(
- bcx: block,
+ bcx: @mut Block,
sigil: ast::Sigil,
cboxptr: ValueRef) // ptr to ptr to the opaque closure
- -> block {
+ -> @mut Block {
// Easy cases:
let _icx = push_ctxt("closure::make_opaque_cbox_take_glue");
match sigil {
return bcx;
}
ast::OwnedSigil => {
- /* hard case: fallthrough to code below */
+ fail!("unique closures are not copyable")
}
}
-
- // ~fn requires a deep copy.
- let ccx = bcx.ccx();
- let tcx = ccx.tcx;
- let llopaquecboxty = Type::opaque_box(ccx).ptr_to();
- let cbox_in = Load(bcx, cboxptr);
- do with_cond(bcx, IsNotNull(bcx, cbox_in)) |bcx| {
- // Load the size from the type descr found in the cbox
- let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty);
- let tydescptr = GEPi(bcx, cbox_in, [0u, abi::box_field_tydesc]);
- let tydesc = Load(bcx, tydescptr);
- let tydesc = PointerCast(bcx, tydesc, ccx.tydesc_type.ptr_to());
- let sz = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_size]));
-
- // Adjust sz to account for the rust_opaque_box header fields
- let sz = Add(bcx, sz, machine::llsize_of(ccx, Type::box_header(ccx)));
-
- // Allocate memory, update original ptr, and copy existing data
- let opaque_tydesc = PointerCast(bcx, tydesc, Type::i8p());
- let mut bcx = bcx;
- let alloc_fn = langcall(bcx, None,
- fmt!("allocation of type with sigil `%s`",
- sigil.to_str()),
- ClosureExchangeMallocFnLangItem);
- let llresult = unpack_result!(bcx, callee::trans_lang_call(
- bcx,
- alloc_fn,
- [opaque_tydesc, sz],
- None));
- let cbox_out = PointerCast(bcx, llresult, llopaquecboxty);
- call_memcpy(bcx, cbox_out, cbox_in, sz, 1);
- Store(bcx, cbox_out, cboxptr);
-
- // Take the (deeply cloned) type descriptor
- let tydesc_out = GEPi(bcx, cbox_out, [0u, abi::box_field_tydesc]);
- let bcx = glue::take_ty(bcx, tydesc_out, ty::mk_type(tcx));
-
- // Take the data in the tuple
- let cdata_out = GEPi(bcx, cbox_out, [0u, abi::box_field_body]);
- glue::call_tydesc_glue_full(bcx, cdata_out, tydesc,
- abi::tydesc_field_take_glue, None);
- bcx
- }
}
pub fn make_opaque_cbox_drop_glue(
- bcx: block,
+ bcx: @mut Block,
sigil: ast::Sigil,
cboxptr: ValueRef) // ptr to the opaque closure
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("closure::make_opaque_cbox_drop_glue");
match sigil {
ast::BorrowedSigil => bcx,
}
pub fn make_opaque_cbox_free_glue(
- bcx: block,
+ bcx: @mut Block,
sigil: ast::Sigil,
cbox: ValueRef) // ptr to ptr to the opaque closure
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("closure::make_opaque_cbox_free_glue");
match sigil {
ast::BorrowedSigil => {
// Function context. Every LLVM function we create will have one of
// these.
-pub struct fn_ctxt_ {
+pub struct FunctionContext {
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
// address of the first instruction in the sequence of
// instructions for this function that will go in the .text
// always be Some.
llretptr: Option<ValueRef>,
+ entry_bcx: Option<@mut Block>,
+
// These elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in
// the function, due to LLVM's quirks.
- // A block for all the function's static allocas, so that LLVM
- // will coalesce them into a single alloca call.
- llstaticallocas: Option<BasicBlockRef>,
- // A block containing code that copies incoming arguments to space
- // already allocated by code in one of the llallocas blocks.
- // (LLVM requires that arguments be copied to local allocas before
- // allowing most any operation to be performed on them.)
- llloadenv: Option<BasicBlockRef>,
+ // A marker for the place where we want to insert the function's static
+ // allocas, so that LLVM will coalesce them into a single alloca call.
+ alloca_insert_pt: Option<ValueRef>,
llreturn: Option<BasicBlockRef>,
// The 'self' value currently in use in this function, if there
// is one.
ccx: @mut CrateContext
}
-impl fn_ctxt_ {
+impl FunctionContext {
pub fn arg_pos(&self, arg: uint) -> uint {
if self.has_immediate_return_value {
arg + 1u
}
}
- pub fn get_llstaticallocas(&mut self) -> BasicBlockRef {
- if self.llstaticallocas.is_none() {
- self.llstaticallocas = Some(base::mk_staticallocas_basic_block(self.llfn));
+ pub fn cleanup(&mut self) {
+ unsafe {
+ llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.get());
}
-
- self.llstaticallocas.get()
+ // Remove the cycle between fcx and bcx, so memory can be freed
+ self.entry_bcx = None;
}
pub fn get_llreturn(&mut self) -> BasicBlockRef {
}
}
-pub type fn_ctxt = @mut fn_ctxt_;
-
pub fn warn_not_to_commit(ccx: &mut CrateContext, msg: &str) {
if !ccx.do_not_commit_warning_issued {
ccx.do_not_commit_warning_issued = true;
}
pub enum cleanup {
- clean(@fn(block) -> block, cleantype),
- clean_temp(ValueRef, @fn(block) -> block, cleantype),
+ clean(@fn(@mut Block) -> @mut Block, cleantype),
+ clean_temp(ValueRef, @fn(@mut Block) -> @mut Block, cleantype),
}
// Can't use deriving(Clone) because of the managed closure.
dest: BasicBlockRef
}
-pub fn shrink_scope_clean(scope_info: &mut scope_info, size: uint) {
+pub fn shrink_scope_clean(scope_info: &mut ScopeInfo, size: uint) {
scope_info.landing_pad = None;
scope_info.cleanup_paths = scope_info.cleanup_paths.iter()
.take_while(|&cu| cu.size <= size).transform(|&x|x).collect();
}
-pub fn grow_scope_clean(scope_info: &mut scope_info) {
+pub fn grow_scope_clean(scope_info: &mut ScopeInfo) {
scope_info.landing_pad = None;
}
}
}
-pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) {
+pub fn add_clean(bcx: @mut Block, val: ValueRef, t: ty::t) {
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
debug!("add_clean(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx()));
}
}
-pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) {
+pub fn add_clean_temp_immediate(cx: @mut Block, val: ValueRef, ty: ty::t) {
if !ty::type_needs_drop(cx.tcx(), ty) { return; }
debug!("add_clean_temp_immediate(%s, %s, %s)",
cx.to_str(), cx.val_to_str(val),
}
}
-pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) {
+pub fn add_clean_temp_mem(bcx: @mut Block, val: ValueRef, t: ty::t) {
add_clean_temp_mem_in_scope_(bcx, None, val, t);
}
-pub fn add_clean_temp_mem_in_scope(bcx: block, scope_id: ast::node_id, val: ValueRef, t: ty::t) {
+pub fn add_clean_temp_mem_in_scope(bcx: @mut Block,
+ scope_id: ast::node_id,
+ val: ValueRef,
+ t: ty::t) {
add_clean_temp_mem_in_scope_(bcx, Some(scope_id), val, t);
}
-pub fn add_clean_temp_mem_in_scope_(bcx: block, scope_id: Option<ast::node_id>,
+pub fn add_clean_temp_mem_in_scope_(bcx: @mut Block, scope_id: Option<ast::node_id>,
val: ValueRef, t: ty::t) {
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
debug!("add_clean_temp_mem(%s, %s, %s)",
grow_scope_clean(scope_info);
}
}
-pub fn add_clean_return_to_mut(bcx: block,
+pub fn add_clean_return_to_mut(bcx: @mut Block,
scope_id: ast::node_id,
root_key: root_map_key,
frozen_val_ref: ValueRef,
grow_scope_clean(scope_info);
}
}
-pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) {
+pub fn add_clean_free(cx: @mut Block, ptr: ValueRef, heap: heap) {
let free_fn = match heap {
heap_managed | heap_managed_unique => {
- let f: @fn(block) -> block = |a| glue::trans_free(a, ptr);
+ let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_free(a, ptr);
f
}
heap_exchange | heap_exchange_closure => {
- let f: @fn(block) -> block = |a| glue::trans_exchange_free(a, ptr);
+ let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_exchange_free(a, ptr);
f
}
};
// to a system where we can also cancel the cleanup on local variables, but
// this will be more involved. For now, we simply zero out the local, and the
// drop glue checks whether it is zero.
-pub fn revoke_clean(cx: block, val: ValueRef) {
+pub fn revoke_clean(cx: @mut Block, val: ValueRef) {
do in_scope_cx(cx, None) |scope_info| {
let cleanup_pos = scope_info.cleanups.iter().position(
|cu| match *cu {
}
}
-pub fn block_cleanups(bcx: block) -> ~[cleanup] {
+pub fn block_cleanups(bcx: @mut Block) -> ~[cleanup] {
match bcx.scope {
None => ~[],
Some(inf) => inf.cleanups.clone(),
}
}
-pub struct scope_info {
- parent: Option<@mut scope_info>,
- loop_break: Option<block>,
+pub struct ScopeInfo {
+ parent: Option<@mut ScopeInfo>,
+ loop_break: Option<@mut Block>,
loop_label: Option<ident>,
// A list of functions that must be run at when leaving this
// block, cleaning up any variables that were introduced in the
node_info: Option<NodeInfo>,
}
-impl scope_info {
+impl ScopeInfo {
pub fn empty_cleanups(&mut self) -> bool {
self.cleanups.is_empty()
}
}
}
-impl get_node_info for ast::blk {
+impl get_node_info for ast::Block {
fn info(&self) -> Option<NodeInfo> {
Some(NodeInfo {id: self.id,
callee_id: None,
// code. Each basic block we generate is attached to a function, typically
// with many basic blocks per function. All the basic blocks attached to a
// function are organized as a directed graph.
-pub struct block_ {
+pub struct Block {
// The BasicBlockRef returned from a call to
// llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic
// block to the function pointed to by llfn. We insert
llbb: BasicBlockRef,
terminated: bool,
unreachable: bool,
- parent: Option<block>,
+ parent: Option<@mut Block>,
// The current scope within this basic block
- scope: Option<@mut scope_info>,
+ scope: Option<@mut ScopeInfo>,
// Is this block part of a landing pad?
is_lpad: bool,
// info about the AST node this block originated from, if any
node_info: Option<NodeInfo>,
// The function context for the function to which this block is
// attached.
- fcx: fn_ctxt
-}
+ fcx: @mut FunctionContext
+}
+
+impl Block {
+
+ pub fn new(llbb: BasicBlockRef,
+ parent: Option<@mut Block>,
+ is_lpad: bool,
+ node_info: Option<NodeInfo>,
+ fcx: @mut FunctionContext)
+ -> Block {
+ Block {
+ llbb: llbb,
+ terminated: false,
+ unreachable: false,
+ parent: parent,
+ scope: None,
+ is_lpad: is_lpad,
+ node_info: node_info,
+ fcx: fcx
+ }
+ }
-pub fn block_(llbb: BasicBlockRef, parent: Option<block>,
- is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
- -> block_ {
+ pub fn ccx(&self) -> @mut CrateContext { self.fcx.ccx }
+ pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx }
+ pub fn sess(&self) -> Session { self.fcx.ccx.sess }
- block_ {
- llbb: llbb,
- terminated: false,
- unreachable: false,
- parent: parent,
- scope: None,
- is_lpad: is_lpad,
- node_info: node_info,
- fcx: fcx
+ pub fn ident(&self, ident: ident) -> @str {
+ token::ident_to_str(&ident)
}
-}
-pub type block = @mut block_;
+ pub fn node_id_to_str(&self, id: ast::node_id) -> ~str {
+ ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr())
+ }
+
+ pub fn expr_to_str(&self, e: @ast::expr) -> ~str {
+ e.repr(self.tcx())
+ }
+
+ pub fn expr_is_lval(&self, e: &ast::expr) -> bool {
+ ty::expr_is_lval(self.tcx(), self.ccx().maps.method_map, e)
+ }
-pub fn mk_block(llbb: BasicBlockRef, parent: Option<block>,
- is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
- -> block {
- @mut block_(llbb, parent, is_lpad, node_info, fcx)
+ pub fn expr_kind(&self, e: &ast::expr) -> ty::ExprKind {
+ ty::expr_kind(self.tcx(), self.ccx().maps.method_map, e)
+ }
+
+ pub fn def(&self, nid: ast::node_id) -> ast::def {
+ match self.tcx().def_map.find(&nid) {
+ Some(&v) => v,
+ None => {
+ self.tcx().sess.bug(fmt!(
+ "No def associated with node id %?", nid));
+ }
+ }
+ }
+
+ pub fn val_to_str(&self, val: ValueRef) -> ~str {
+ self.ccx().tn.val_to_str(val)
+ }
+
+ pub fn llty_str(&self, ty: Type) -> ~str {
+ self.ccx().tn.type_to_str(ty)
+ }
+
+ pub fn ty_to_str(&self, t: ty::t) -> ~str {
+ t.repr(self.tcx())
+ }
+
+ pub fn to_str(&self) -> ~str {
+ unsafe {
+ match self.node_info {
+ Some(node_info) => fmt!("[block %d]", node_info.id),
+ None => fmt!("[block %x]", transmute(&*self)),
+ }
+ }
+ }
}
pub struct Result {
- bcx: block,
+ bcx: @mut Block,
val: ValueRef
}
-pub fn rslt(bcx: block, val: ValueRef) -> Result {
+pub fn rslt(bcx: @mut Block, val: ValueRef) -> Result {
Result {bcx: bcx, val: val}
}
impl Result {
- pub fn unpack(&self, bcx: &mut block) -> ValueRef {
+ pub fn unpack(&self, bcx: &mut @mut Block) -> ValueRef {
*bcx = self.bcx;
return self.val;
}
}
}
-pub fn in_scope_cx(cx: block, scope_id: Option<ast::node_id>, f: &fn(si: &mut scope_info)) {
+pub fn in_scope_cx(cx: @mut Block, scope_id: Option<ast::node_id>, f: &fn(si: &mut ScopeInfo)) {
let mut cur = cx;
let mut cur_scope = cur.scope;
loop {
}
}
-pub fn block_parent(cx: block) -> block {
+pub fn block_parent(cx: @mut Block) -> @mut Block {
match cx.parent {
Some(b) => b,
None => cx.sess().bug(fmt!("block_parent called on root block %?",
}
}
-// Accessors
-
-impl block_ {
- pub fn ccx(&self) -> @mut CrateContext { self.fcx.ccx }
- pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx }
- pub fn sess(&self) -> Session { self.fcx.ccx.sess }
-
- pub fn ident(&self, ident: ident) -> @str {
- token::ident_to_str(&ident)
- }
-
- pub fn node_id_to_str(&self, id: ast::node_id) -> ~str {
- ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr())
- }
-
- pub fn expr_to_str(&self, e: @ast::expr) -> ~str {
- e.repr(self.tcx())
- }
-
- pub fn expr_is_lval(&self, e: &ast::expr) -> bool {
- ty::expr_is_lval(self.tcx(), self.ccx().maps.method_map, e)
- }
-
- pub fn expr_kind(&self, e: &ast::expr) -> ty::ExprKind {
- ty::expr_kind(self.tcx(), self.ccx().maps.method_map, e)
- }
-
- pub fn def(&self, nid: ast::node_id) -> ast::def {
- match self.tcx().def_map.find(&nid) {
- Some(&v) => v,
- None => {
- self.tcx().sess.bug(fmt!(
- "No def associated with node id %?", nid));
- }
- }
- }
-
- pub fn val_to_str(&self, val: ValueRef) -> ~str {
- self.ccx().tn.val_to_str(val)
- }
-
- pub fn llty_str(&self, ty: Type) -> ~str {
- self.ccx().tn.type_to_str(ty)
- }
-
- pub fn ty_to_str(&self, t: ty::t) -> ~str {
- t.repr(self.tcx())
- }
-
- pub fn to_str(&self) -> ~str {
- unsafe {
- match self.node_info {
- Some(node_info) => fmt!("[block %d]", node_info.id),
- None => fmt!("[block %x]", transmute(&*self)),
- }
- }
- }
-}
// Let T be the content of a box @T. tuplify_box_ty(t) returns the
// representation of @T as a tuple (i.e., the ty::t version of what T_box()
#[deriving(Eq,IterBytes)]
pub struct mono_id_ {
def: ast::def_id,
- params: ~[mono_param_id],
- impl_did_opt: Option<ast::def_id>
+ params: ~[mono_param_id]
}
pub type mono_id = @mono_id_;
-pub fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
+pub fn umax(cx: @mut Block, a: ValueRef, b: ValueRef) -> ValueRef {
let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
return build::Select(cx, cond, b, a);
}
-pub fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
+pub fn umin(cx: @mut Block, a: ValueRef, b: ValueRef) -> ValueRef {
let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
return build::Select(cx, cond, a, b);
}
-pub fn align_to(cx: block, off: ValueRef, align: ValueRef) -> ValueRef {
+pub fn align_to(cx: @mut Block, off: ValueRef, align: ValueRef) -> ValueRef {
let mask = build::Sub(cx, align, C_int(cx.ccx(), 1));
let bumped = build::Add(cx, off, mask);
return build::And(cx, bumped, build::Not(cx, mask));
r
}
-pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t {
+pub fn monomorphize_type(bcx: @mut Block, t: ty::t) -> ty::t {
match bcx.fcx.param_substs {
Some(substs) => {
ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
}
}
-pub fn node_id_type(bcx: block, id: ast::node_id) -> ty::t {
+pub fn node_id_type(bcx: @mut Block, id: ast::node_id) -> ty::t {
let tcx = bcx.tcx();
let t = ty::node_id_to_type(tcx, id);
monomorphize_type(bcx, t)
}
-pub fn expr_ty(bcx: block, ex: &ast::expr) -> ty::t {
+pub fn expr_ty(bcx: @mut Block, ex: &ast::expr) -> ty::t {
node_id_type(bcx, ex.id)
}
-pub fn expr_ty_adjusted(bcx: block, ex: &ast::expr) -> ty::t {
+pub fn expr_ty_adjusted(bcx: @mut Block, ex: &ast::expr) -> ty::t {
let tcx = bcx.tcx();
let t = ty::expr_ty_adjusted(tcx, ex);
monomorphize_type(bcx, t)
}
-pub fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] {
+pub fn node_id_type_params(bcx: @mut Block, id: ast::node_id) -> ~[ty::t] {
let tcx = bcx.tcx();
let params = ty::node_id_to_type_params(tcx, id);
}
}
-pub fn node_vtables(bcx: block, id: ast::node_id)
+pub fn node_vtables(bcx: @mut Block, id: ast::node_id)
-> Option<typeck::vtable_res> {
let raw_vtables = bcx.ccx().maps.vtable_map.find(&id);
raw_vtables.map(
|&vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
}
-pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
+pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
-> typeck::vtable_res {
resolve_vtables_under_param_substs(fcx.ccx.tcx,
fcx.param_substs,
}
-// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
+// Apply the typaram substitutions in the FunctionContext to a vtable. This should
// eliminate any vtable_params.
-pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: &typeck::vtable_origin)
+pub fn resolve_vtable_in_fn_ctxt(fcx: &FunctionContext, vt: &typeck::vtable_origin)
-> typeck::vtable_origin {
resolve_vtable_under_param_substs(fcx.ccx.tcx,
fcx.param_substs,
}
}
-pub fn filename_and_line_num_from_span(bcx: block,
+pub fn filename_and_line_num_from_span(bcx: @mut Block,
span: span) -> (ValueRef, ValueRef) {
let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo);
let filename_cstr = C_cstr(bcx.ccx(), loc.file.name);
}
// Casts a Rust bool value to an i1.
-pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef {
+pub fn bool_to_i1(bcx: @mut Block, llval: ValueRef) -> ValueRef {
build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false))
}
-pub fn langcall(bcx: block, span: Option<span>, msg: &str,
+pub fn langcall(bcx: @mut Block, span: Option<span>, msg: &str,
li: LangItem) -> ast::def_id {
match bcx.tcx().lang_items.require(li) {
Ok(id) => id,
do expr::with_field_tys(tcx, ety, Some(e.id))
|discr, field_tys| {
let cs = field_tys.map(|field_ty| {
- match fs.iter().find_(|f| field_ty.ident == f.node.ident) {
- Some(f) => const_expr(cx, (*f).node.expr),
+ match fs.iter().find_(|f| field_ty.ident == f.ident) {
+ Some(f) => const_expr(cx, (*f).expr),
None => {
cx.tcx.sess.span_bug(e.span, "missing struct field");
}
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
+use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
use middle::ty;
}
}
}
+
+ pub fn builder(@mut self) -> Builder {
+ Builder::new(self)
+ }
}
#[unsafe_destructor]
}
}
-#[cfg(stage0)]
-fn task_local_llcx_key(_v: @ContextRef) {}
-#[cfg(not(stage0))]
static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
pub fn task_llcx() -> ContextRef {
use syntax::ast_util;
use syntax::codemap::span;
-pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
+pub fn trans_block(bcx: @mut Block, b: &ast::Block, dest: expr::Dest) -> @mut Block {
let _icx = push_ctxt("trans_block");
let mut bcx = bcx;
for b.stmts.iter().advance |s| {
return bcx;
}
-pub fn trans_if(bcx: block,
+pub fn trans_if(bcx: @mut Block,
cond: @ast::expr,
- thn: &ast::blk,
+ thn: &ast::Block,
els: Option<@ast::expr>,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
debug!("trans_if(bcx=%s, cond=%s, thn=%?, dest=%s)",
bcx.to_str(), bcx.expr_to_str(cond), thn.id,
dest.to_str(bcx.ccx()));
return next_bcx;
// trans `else [ if { .. } ... | { .. } ]`
- fn trans_if_else(bcx: block, elexpr: @ast::expr,
- dest: expr::Dest, scope_name: &str) -> (block, block) {
+ fn trans_if_else(bcx: @mut Block, elexpr: @ast::expr,
+ dest: expr::Dest, scope_name: &str) -> (@mut Block, @mut Block) {
let else_bcx_in = scope_block(bcx, elexpr.info(), scope_name);
let else_bcx_out = match elexpr.node {
ast::expr_if(_, _, _) => {
}
}
-pub fn join_blocks(parent_bcx: block, in_cxs: &[block]) -> block {
+pub fn join_blocks(parent_bcx: @mut Block, in_cxs: &[@mut Block]) -> @mut Block {
let out = sub_block(parent_bcx, "join");
let mut reachable = false;
for in_cxs.iter().advance |bcx| {
return out;
}
-pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block {
+pub fn trans_while(bcx: @mut Block, cond: @ast::expr, body: &ast::Block) -> @mut Block {
let _icx = push_ctxt("trans_while");
let next_bcx = sub_block(bcx, "while next");
return next_bcx;
}
-pub fn trans_loop(bcx:block,
- body: &ast::blk,
+pub fn trans_loop(bcx:@mut Block,
+ body: &ast::Block,
opt_label: Option<ident>)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_loop");
let next_bcx = sub_block(bcx, "next");
let body_bcx_in = loop_scope_block(bcx, next_bcx, opt_label, "`loop`",
pub fn trans_log(log_ex: &ast::expr,
lvl: @ast::expr,
- bcx: block,
- e: @ast::expr) -> block {
+ bcx: @mut Block,
+ e: @ast::expr) -> @mut Block {
let _icx = push_ctxt("trans_log");
let ccx = bcx.ccx();
let mut bcx = bcx;
}
}
-pub fn trans_break_cont(bcx: block,
+pub fn trans_break_cont(bcx: @mut Block,
opt_label: Option<ident>,
to_end: bool)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_break_cont");
// Locate closest loop block, outputting cleanup as we go.
let mut unwind = bcx;
let mut target;
loop {
cur_scope = match cur_scope {
- Some(@scope_info {
+ Some(@ScopeInfo {
loop_break: Some(brk),
loop_label: l,
parent,
return bcx;
}
-pub fn trans_break(bcx: block, label_opt: Option<ident>) -> block {
+pub fn trans_break(bcx: @mut Block, label_opt: Option<ident>) -> @mut Block {
return trans_break_cont(bcx, label_opt, true);
}
-pub fn trans_cont(bcx: block, label_opt: Option<ident>) -> block {
+pub fn trans_cont(bcx: @mut Block, label_opt: Option<ident>) -> @mut Block {
return trans_break_cont(bcx, label_opt, false);
}
-pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
+pub fn trans_ret(bcx: @mut Block, e: Option<@ast::expr>) -> @mut Block {
let _icx = push_ctxt("trans_ret");
let mut bcx = bcx;
let dest = match bcx.fcx.loop_ret {
return bcx;
}
-pub fn trans_fail_expr(bcx: block,
+pub fn trans_fail_expr(bcx: @mut Block,
sp_opt: Option<span>,
fail_expr: Option<@ast::expr>)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_fail_expr");
let mut bcx = bcx;
match fail_expr {
}
}
-pub fn trans_fail(bcx: block,
+pub fn trans_fail(bcx: @mut Block,
sp_opt: Option<span>,
fail_str: @str)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_fail");
let V_fail_str = C_cstr(bcx.ccx(), fail_str);
return trans_fail_value(bcx, sp_opt, V_fail_str);
}
-fn trans_fail_value(bcx: block,
+fn trans_fail_value(bcx: @mut Block,
sp_opt: Option<span>,
V_fail_str: ValueRef)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("trans_fail_value");
let ccx = bcx.ccx();
let (V_filename, V_line) = match sp_opt {
return bcx;
}
-pub fn trans_fail_bounds_check(bcx: block, sp: span,
- index: ValueRef, len: ValueRef) -> block {
+pub fn trans_fail_bounds_check(bcx: @mut Block, sp: span,
+ index: ValueRef, len: ValueRef) -> @mut Block {
let _icx = push_ctxt("trans_fail_bounds_check");
let (filename, line) = filename_and_line_num_from_span(bcx, sp);
let args = ~[filename, line, index, len];
}
pub struct DatumBlock {
- bcx: block,
+ bcx: @mut Block,
datum: Datum,
}
return Datum {val: val, ty: ty, mode: ByValue};
}
-pub fn immediate_rvalue_bcx(bcx: block,
+pub fn immediate_rvalue_bcx(bcx: @mut Block,
val: ValueRef,
ty: ty::t)
-> DatumBlock {
return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)};
}
-pub fn scratch_datum(bcx: block, ty: ty::t, name: &str, zero: bool) -> Datum {
+pub fn scratch_datum(bcx: @mut Block, ty: ty::t, name: &str, zero: bool) -> Datum {
/*!
* Allocates temporary space on the stack using alloca() and
* returns a by-ref Datum pointing to it. If `zero` is true, the
impl Datum {
pub fn store_to(&self,
- bcx: block,
+ bcx: @mut Block,
action: CopyAction,
dst: ValueRef)
- -> block {
+ -> @mut Block {
/*!
*
* Stores this value into its final home. This moves if
}
pub fn store_to_dest(&self,
- bcx: block,
+ bcx: @mut Block,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
match dest {
expr::Ignore => {
return bcx;
}
pub fn store_to_datum(&self,
- bcx: block,
+ bcx: @mut Block,
action: CopyAction,
datum: Datum)
- -> block {
+ -> @mut Block {
debug!("store_to_datum(self=%s, action=%?, datum=%s)",
self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
assert!(datum.mode.is_by_ref());
self.store_to(bcx, action, datum.val)
}
- pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
- -> block {
+ pub fn move_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
+ -> @mut Block {
assert!(datum.mode.is_by_ref());
self.move_to(bcx, action, datum.val)
}
- pub fn copy_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
- -> block {
+ pub fn copy_to_datum(&self, bcx: @mut Block, action: CopyAction, datum: Datum)
+ -> @mut Block {
assert!(datum.mode.is_by_ref());
self.copy_to(bcx, action, datum.val)
}
- pub fn copy_to(&self, bcx: block, action: CopyAction, dst: ValueRef)
- -> block {
+ pub fn copy_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
+ -> @mut Block {
/*!
*
* Copies the value into `dst`, which should be a pointer to a
}
pub fn copy_to_no_check(&self,
- bcx: block,
+ bcx: @mut Block,
action: CopyAction,
dst: ValueRef)
- -> block {
+ -> @mut Block {
/*!
*
* A helper for `copy_to()` which does not check to see if we
// This works like copy_val, except that it deinitializes the source.
// Since it needs to zero out the source, src also needs to be an lval.
//
- pub fn move_to(&self, bcx: block, action: CopyAction, dst: ValueRef)
- -> block {
+ pub fn move_to(&self, bcx: @mut Block, action: CopyAction, dst: ValueRef)
+ -> @mut Block {
let _icx = push_ctxt("move_to");
let mut bcx = bcx;
return bcx;
}
- pub fn add_clean(&self, bcx: block) {
+ pub fn add_clean(&self, bcx: @mut Block) {
/*!
* Schedules this datum for cleanup in `bcx`. The datum
* must be an rvalue.
}
}
- pub fn cancel_clean(&self, bcx: block) {
+ pub fn cancel_clean(&self, bcx: @mut Block) {
if ty::type_needs_drop(bcx.tcx(), self.ty) {
match self.mode {
ByValue |
self.mode)
}
- pub fn to_value_datum(&self, bcx: block) -> Datum {
+ pub fn to_value_datum(&self, bcx: @mut Block) -> Datum {
/*!
*
* Yields a by-value form of this datum. This may involve
}
}
- pub fn to_value_llval(&self, bcx: block) -> ValueRef {
+ pub fn to_value_llval(&self, bcx: @mut Block) -> ValueRef {
/*!
*
* Yields the value itself. */
}
}
- pub fn to_ref_datum(&self, bcx: block) -> Datum {
+ pub fn to_ref_datum(&self, bcx: @mut Block) -> Datum {
/*!
* Yields a by-ref form of this datum. This may involve
* creation of a temporary stack slot. The value returned by
}
}
- pub fn to_ref_llval(&self, bcx: block) -> ValueRef {
+ pub fn to_ref_llval(&self, bcx: @mut Block) -> ValueRef {
match self.mode {
ByRef(_) => self.val,
ByValue => {
}
}
- pub fn to_zeroable_ref_llval(&self, bcx: block) -> ValueRef {
+ pub fn to_zeroable_ref_llval(&self, bcx: @mut Block) -> ValueRef {
/*!
* Returns a by-ref llvalue that can be zeroed in order to
* cancel cleanup. This is a kind of hokey bridge used
appropriate_mode(tcx, self.ty)
}
- pub fn to_appropriate_llval(&self, bcx: block) -> ValueRef {
+ pub fn to_appropriate_llval(&self, bcx: @mut Block) -> ValueRef {
/*!
*
* Yields an llvalue with the `appropriate_mode()`. */
}
}
- pub fn to_appropriate_datum(&self, bcx: block) -> Datum {
+ pub fn to_appropriate_datum(&self, bcx: @mut Block) -> Datum {
/*!
*
* Yields a datum with the `appropriate_mode()`. */
}
pub fn get_element(&self,
- bcx: block,
+ bcx: @mut Block,
ty: ty::t,
source: DatumCleanup,
gep: &fn(ValueRef) -> ValueRef)
}
}
- pub fn drop_val(&self, bcx: block) -> block {
+ pub fn drop_val(&self, bcx: @mut Block) -> @mut Block {
if !ty::type_needs_drop(bcx.tcx(), self.ty) {
return bcx;
}
};
}
- pub fn box_body(&self, bcx: block) -> Datum {
+ pub fn box_body(&self, bcx: @mut Block) -> Datum {
/*!
*
* This datum must represent an @T or ~T box. Returns a new
}
}
- pub fn to_rptr(&self, bcx: block) -> Datum {
+ pub fn to_rptr(&self, bcx: @mut Block) -> Datum {
//! Returns a new datum of region-pointer type containing the
//! the same ptr as this datum (after converting to by-ref
//! using `to_ref_llval()`).
/// derefs: Number of times deref'd already.
/// is_auto: If true, only deref if auto-derefable.
pub fn try_deref(&self,
- bcx: block,
+ bcx: @mut Block,
span: span,
expr_id: ast::node_id,
derefs: uint,
is_auto: bool)
- -> (Option<Datum>, block) {
+ -> (Option<Datum>, @mut Block) {
let ccx = bcx.ccx();
debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)",
}
}
- fn deref_ptr(bcx: block, lv: &Datum, ty: ty::t) -> Datum {
+ fn deref_ptr(bcx: @mut Block, lv: &Datum, ty: ty::t) -> Datum {
Datum {
val: lv.to_value_llval(bcx),
ty: ty,
}
/// expr: The deref expression.
- pub fn deref(&self, bcx: block, expr: &ast::expr, derefs: uint)
+ pub fn deref(&self, bcx: @mut Block, expr: &ast::expr, derefs: uint)
-> DatumBlock {
match self.try_deref(bcx, expr.span, expr.id, derefs, false) {
(Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres },
}
pub fn autoderef(&self,
- bcx: block,
+ bcx: @mut Block,
span: span,
expr_id: ast::node_id,
max: uint)
}
pub fn get_vec_base_and_len(&self,
- mut bcx: block,
+ mut bcx: @mut Block,
span: span,
expr_id: ast::node_id,
derefs: uint)
- -> (block, ValueRef, ValueRef) {
+ -> (@mut Block, ValueRef, ValueRef) {
//! Converts a vector into the slice pair. Performs rooting
//! and write guards checks.
(bcx, base, len)
}
- pub fn get_vec_base_and_len_no_root(&self, bcx: block)
+ pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block)
-> (ValueRef, ValueRef) {
//! Converts a vector into the slice pair. Des not root
//! nor perform write guard checks.
}
pub fn root_and_write_guard(&self,
- bcx: block,
+ bcx: @mut Block,
span: span,
expr_id: ast::node_id,
derefs: uint)
- -> block {
+ -> @mut Block {
write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs)
}
- pub fn to_result(&self, bcx: block) -> common::Result {
+ pub fn to_result(&self, bcx: @mut Block) -> common::Result {
rslt(bcx, self.to_appropriate_llval(bcx))
}
}
impl DatumBlock {
- pub fn unpack(&self, bcx: &mut block) -> Datum {
+ pub fn unpack(&self, bcx: &mut @mut Block) -> Datum {
*bcx = self.bcx;
return self.datum;
}
*self
}
- pub fn drop_val(&self) -> block {
+ pub fn drop_val(&self) -> @mut Block {
self.datum.drop_val(self.bcx)
}
pub fn store_to(&self,
action: CopyAction,
dst: ValueRef)
- -> block {
+ -> @mut Block {
self.datum.store_to(self.bcx, action, dst)
}
- pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block {
+ pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
self.datum.copy_to(self.bcx, action, dst)
}
- pub fn move_to(&self, action: CopyAction, dst: ValueRef) -> block {
+ pub fn move_to(&self, action: CopyAction, dst: ValueRef) -> @mut Block {
self.datum.move_to(self.bcx, action, dst)
}
The public API of the module is a set of functions that will insert the correct metadata into the
LLVM IR when called with the right parameters. The module is thus driven from an outside client with
-functions like `debuginfo::create_local_var(bcx: block, local: @ast::local)`.
+functions like `debuginfo::local_var_metadata(bcx: block, local: &ast::local)`.
-Internally the module will try to reuse already created metadata by utilizing a cache. All private
-state used by the module is stored within a DebugContext struct, which in turn is contained in the
-CrateContext.
+Internally the module will try to reuse already created metadata by utilizing a cache. The way to
+get a shared metadata node when needed is thus to just call the corresponding function in this
+module:
+
+ let file_metadata = file_metadata(crate_context, path);
+
+The function will take care of probing the cache for an existing node for that exact file path.
+
+All private state used by the module is stored within a DebugContext struct, which in turn is
+contained in the CrateContext.
This file consists of three conceptual sections:
use driver::session;
use lib::llvm::llvm;
-use lib::llvm::{ValueRef, ModuleRef, ContextRef};
+use lib::llvm::{ModuleRef, ContextRef};
use lib::llvm::debuginfo::*;
use middle::trans::common::*;
use middle::trans::machine;
use middle::trans::type_of;
+use middle::trans::type_::Type;
+use middle::trans::adt;
use middle::trans;
use middle::ty;
use util::ppaux::ty_to_str;
use std::hashmap::HashMap;
-use std::libc;
-use std::libc::{c_uint, c_ulonglong};
-use std::cmp;
+use std::libc::{c_uint, c_ulonglong, c_longlong};
use std::ptr;
use std::str::as_c_str;
-use std::sys;
use std::vec;
use syntax::codemap::span;
use syntax::{ast, codemap, ast_util, ast_map};
-use syntax::parse::token;
static DW_LANG_RUST: int = 0x9000;
-static AutoVariableTag: int = 256;
-static ArgVariableTag: int = 257;
+static DW_TAG_auto_variable: int = 0x100;
+static DW_TAG_arg_variable: int = 0x101;
static DW_ATE_boolean: int = 0x02;
static DW_ATE_float: int = 0x04;
/// Create any deferred debug metadata nodes
pub fn finalize(cx: @mut CrateContext) {
debug!("finalize");
- create_compile_unit(cx);
+ compile_unit_metadata(cx);
unsafe {
llvm::LLVMDIBuilderFinalize(DIB(cx));
llvm::LLVMDIBuilderDispose(DIB(cx));
///
/// Adds the created metadata nodes directly to the crate's IR.
/// The return value should be ignored if called from outside of the debuginfo module.
-pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable {
+pub fn create_local_var_metadata(bcx: @mut Block, local: @ast::Local) -> DIVariable {
let cx = bcx.ccx();
- let ident = match local.node.pat.node {
+ let ident = match local.pat.node {
ast::pat_ident(_, ref pth, _) => ast_util::path_to_ident(pth),
// FIXME this should be handled (#2533)
_ => {
return ptr::null();
}
};
+
let name: &str = cx.sess.str_of(ident);
- debug!("create_local_var: %s", name);
+ debug!("create_local_var_metadata: %s", name);
let loc = span_start(cx, local.span);
- let ty = node_id_type(bcx, local.node.id);
- let tymd = create_ty(cx, ty, local.node.ty.span);
- let filemd = create_file(cx, loc.file.name);
+ let ty = node_id_type(bcx, local.id);
+ let type_metadata = type_metadata(cx, ty, local.ty.span);
+ let file_metadata = file_metadata(cx, loc.file.name);
+
let context = match bcx.parent {
- None => create_function(bcx.fcx),
- Some(_) => create_block(bcx)
+ None => create_function_metadata(bcx.fcx),
+ Some(_) => lexical_block_metadata(bcx)
};
- let var_md = do as_c_str(name) |name| { unsafe {
- llvm::LLVMDIBuilderCreateLocalVariable(
- DIB(cx), AutoVariableTag as u32,
- context, name, filemd,
- loc.line as c_uint, tymd, false, 0, 0)
- }};
+ let var_metadata = do as_c_str(name) |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateLocalVariable(
+ DIB(cx),
+ DW_TAG_auto_variable as u32,
+ context,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ false,
+ 0,
+ 0)
+ }
+ };
// FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc
- let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) {
+ let llptr = match bcx.fcx.lllocals.find_copy(&local.pat.id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(
local.span,
- fmt!("No entry in lllocals table for %?", local.node.id));
+ fmt!("No entry in lllocals table for %?", local.id));
}
};
- set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint());
+ set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
unsafe {
- let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb);
- llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+ let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb);
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
- return var_md;
+ return var_metadata;
}
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
/// The return value should be ignored if called from outside of the debuginfo module.
-pub fn create_arg(bcx: block, arg: &ast::arg, span: span) -> Option<DIVariable> {
- debug!("create_arg");
+pub fn create_argument_metadata(bcx: @mut Block, arg: &ast::arg, span: span) -> Option<DIVariable> {
+ debug!("create_argument_metadata");
if true {
- // XXX create_arg disabled for now because "node_id_type(bcx, arg.id)" below blows
- // up: "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`"
+ // XXX create_argument_metadata disabled for now because "node_id_type(bcx, arg.id)" below
+ // blows up:
+ // "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`"
return None;
}
}
let ty = node_id_type(bcx, arg.id);
- let tymd = create_ty(cx, ty, arg.ty.span);
- let filemd = create_file(cx, loc.file.name);
- let context = create_function(fcx);
+ let type_metadata = type_metadata(cx, ty, arg.ty.span);
+ let file_metadata = file_metadata(cx, loc.file.name);
+ let context = create_function_metadata(fcx);
match arg.pat.node {
ast::pat_ident(_, ref path, _) => {
// XXX: This is wrong; it should work for multiple bindings.
let ident = path.idents.last();
let name: &str = cx.sess.str_of(*ident);
- let mdnode = do as_c_str(name) |name| { unsafe {
- llvm::LLVMDIBuilderCreateLocalVariable(
- DIB(cx),
- ArgVariableTag as u32,
- context,
- name,
- filemd,
- loc.line as c_uint,
- tymd,
- false,
- 0,
- 0)
+ let var_metadata = do as_c_str(name) |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateLocalVariable(
+ DIB(cx),
+ DW_TAG_arg_variable as u32,
+ context,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ false,
+ 0,
+ 0)
// XXX need to pass in a real argument number
- }};
+ }
+ };
let llptr = fcx.llargs.get_copy(&arg.id);
- set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint());
+ set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
- DIB(cx), llptr, mdnode, bcx.llbb);
- llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+ DIB(cx), llptr, var_metadata, bcx.llbb);
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
- return Some(mdnode);
+ return Some(var_metadata);
}
_ => {
return None;
/// Sets the current debug location at the beginning of the span
///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
-pub fn update_source_pos(bcx: block, span: span) {
+pub fn update_source_pos(bcx: @mut Block, span: span) {
if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) {
return;
}
debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span));
let loc = span_start(bcx.ccx(), span);
- set_debug_location(bcx.ccx(), create_block(bcx), loc.line, loc.col.to_uint())
+ set_debug_location(bcx.ccx(), lexical_block_metadata(bcx), loc.line, loc.col.to_uint())
}
/// Creates debug information for the given function.
///
/// Adds the created metadata nodes directly to the crate's IR.
/// The return value should be ignored if called from outside of the debuginfo module.
-pub fn create_function(fcx: fn_ctxt) -> DISubprogram {
+pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
let cx = fcx.ccx;
- let fcx = &mut *fcx;
let span = fcx.span.get();
let fnitem = cx.tcx.items.get_copy(&fcx.id);
let (ident, ret_ty, id) = match fnitem {
- ast_map::node_item(ref item, _) => {
- match item.node {
- ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => {
- (item.ident, ty, item.id)
- }
- _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function")
+ ast_map::node_item(ref item, _) => {
+ match item.node {
+ ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => {
+ (item.ident, ty, item.id)
+ }
+ _ => fcx.ccx.sess.span_bug(item.span,
+ "create_function_metadata: item bound to non-function")
+ }
}
- }
- ast_map::node_method(@ast::method { decl: ast::fn_decl { output: ref ty, _ },
- id: id, ident: ident, _}, _, _) => {
- (ident, ty, id)
- }
- ast_map::node_expr(ref expr) => {
- match expr.node {
- ast::expr_fn_block(ref decl, _) => {
- let name = gensym_name("fn");
- (name, &decl.output, expr.id)
- }
- _ => fcx.ccx.sess.span_bug(expr.span,
- "create_function: expected an expr_fn_block here")
+ ast_map::node_method(
+ @ast::method {
+ decl: ast::fn_decl { output: ref ty, _ },
+ id: id,
+ ident: ident,
+ _
+ },
+ _,
+ _) => {
+ (ident, ty, id)
}
- }
- _ => fcx.ccx.sess.bug("create_function: unexpected sort of node")
+ ast_map::node_expr(ref expr) => {
+ match expr.node {
+ ast::expr_fn_block(ref decl, _) => {
+ let name = gensym_name("fn");
+ (name, &decl.output, expr.id)
+ }
+ _ => fcx.ccx.sess.span_bug(expr.span,
+ "create_function_metadata: expected an expr_fn_block here")
+ }
+ }
+ ast_map::node_trait_method(
+ @ast::provided(
+ @ast::method {
+ decl: ast::fn_decl { output: ref ty, _ },
+ id: id,
+ ident: ident,
+ _
+ }),
+ _,
+ _) => {
+ (ident, ty, id)
+ }
+ _ => fcx.ccx.sess.bug("create_function_metadata: unexpected sort of node")
};
match dbg_cx(cx).created_functions.find(&id) {
- Some(fn_md) => return *fn_md,
+ Some(fn_metadata) => return *fn_metadata,
None => ()
}
- debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span));
+ debug!("create_function_metadata: %s, %s",
+ cx.sess.str_of(ident),
+ cx.sess.codemap.span_to_str(span));
let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
+ let file_metadata = file_metadata(cx, loc.file.name);
- let ret_ty_md = if cx.sess.opts.extra_debuginfo {
+ let return_type_metadata = if cx.sess.opts.extra_debuginfo {
match ret_ty.node {
ast::ty_nil => ptr::null(),
- _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span)
+ _ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span)
}
} else {
ptr::null()
let fn_ty = unsafe {
llvm::LLVMDIBuilderCreateSubroutineType(
DIB(cx),
- file_md,
- create_DIArray(DIB(cx), [ret_ty_md]))
+ file_metadata,
+ create_DIArray(DIB(cx), [return_type_metadata]))
};
- let fn_md =
+ let fn_metadata =
do as_c_str(cx.sess.str_of(ident)) |name| {
- do as_c_str(cx.sess.str_of(ident)) |linkage| { unsafe {
- llvm::LLVMDIBuilderCreateFunction(
- DIB(cx),
- file_md,
- name,
- linkage,
- file_md,
- loc.line as c_uint,
- fn_ty,
- false,
- true,
- loc.line as c_uint,
- FlagPrototyped as c_uint,
- cx.sess.opts.optimize != session::No,
- fcx.llfn,
- ptr::null(),
- ptr::null())
- }}};
+ do as_c_str(cx.sess.str_of(ident)) |linkage| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateFunction(
+ DIB(cx),
+ file_metadata,
+ name,
+ linkage,
+ file_metadata,
+ loc.line as c_uint,
+ fn_ty,
+ false,
+ true,
+ loc.line as c_uint,
+ FlagPrototyped as c_uint,
+ cx.sess.opts.optimize != session::No,
+ fcx.llfn,
+ ptr::null(),
+ ptr::null())
+ }
+ }};
- dbg_cx(cx).created_functions.insert(id, fn_md);
- return fn_md;
+ dbg_cx(cx).created_functions.insert(id, fn_metadata);
+ return fn_metadata;
}
};
}
-fn create_compile_unit(cx: @mut CrateContext) {
+fn compile_unit_metadata(cx: @mut CrateContext) {
let dcx = dbg_cx(cx);
let crate_name: &str = dcx.crate_file;
- debug!("create_compile_unit: %?", crate_name);
+ debug!("compile_unit_metadata: %?", crate_name);
let work_dir = cx.sess.working_dir.to_str();
let producer = fmt!("rustc version %s", env!("CFG_VERSION"));
do as_c_str(work_dir) |work_dir| {
do as_c_str(producer) |producer| {
do as_c_str("") |flags| {
- do as_c_str("") |split_name| { unsafe {
- llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
- DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
- cx.sess.opts.optimize != session::No,
- flags, 0, split_name);
- }}}}}};
+ do as_c_str("") |split_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
+ DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
+ cx.sess.opts.optimize != session::No,
+ flags, 0, split_name);
+ }
+ }}}}};
}
-fn create_file(cx: &mut CrateContext, full_path: &str) -> DIFile {
+fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
match dbg_cx(cx).created_files.find_equiv(&full_path) {
- Some(file_md) => return *file_md,
+ Some(file_metadata) => return *file_metadata,
None => ()
}
- debug!("create_file: %s", full_path);
+ debug!("file_metadata: %s", full_path);
let work_dir = cx.sess.working_dir.to_str();
let file_name =
full_path
};
- let file_md =
+ let file_metadata =
do as_c_str(file_name) |file_name| {
- do as_c_str(work_dir) |work_dir| { unsafe {
- llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
- }}};
+ do as_c_str(work_dir) |work_dir| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
+ }
+ }};
- dbg_cx(cx).created_files.insert(full_path.to_owned(), file_md);
- return file_md;
+ dbg_cx(cx).created_files.insert(full_path.to_owned(), file_metadata);
+ return file_metadata;
}
-
-
-fn create_block(bcx: block) -> DILexicalBlock {
- let mut bcx = bcx;
+/// Get or create the lexical block metadata node for the given LLVM basic block.
+fn lexical_block_metadata(bcx: @mut Block) -> DILexicalBlock {
let cx = bcx.ccx();
+ let mut bcx = bcx;
+ // Search up the tree of basic blocks until we find one that knows the containing lexical block.
while bcx.node_info.is_none() {
match bcx.parent {
- Some(b) => bcx = b,
- None => fail!()
+ Some(b) => bcx = b,
+ None => cx.sess.bug("debuginfo: Could not find lexical block for LLVM basic block.")
}
}
+
let span = bcx.node_info.get().span;
let id = bcx.node_info.get().id;
+ // Check whether we already have a cache entry for this node id
match dbg_cx(cx).created_blocks.find(&id) {
Some(block) => return *block,
None => ()
}
- debug!("create_block: %s", bcx.sess().codemap.span_to_str(span));
+ debug!("lexical_block_metadata: %s", bcx.sess().codemap.span_to_str(span));
let parent = match bcx.parent {
- None => create_function(bcx.fcx),
- Some(b) => create_block(b)
+ None => create_function_metadata(bcx.fcx),
+ Some(b) => lexical_block_metadata(b)
};
- let cx = bcx.ccx();
+
let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
+ let file_metadata = file_metadata(cx, loc.file.name);
- let block_md = unsafe {
+ let lexical_block_metadata = unsafe {
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(cx),
- parent, file_md,
- loc.line as c_uint, loc.col.to_uint() as c_uint)
+ parent,
+ file_metadata,
+ loc.line as c_uint,
+ loc.col.to_uint() as c_uint)
};
- dbg_cx(cx).created_blocks.insert(id, block_md);
+ dbg_cx(cx).created_blocks.insert(id, lexical_block_metadata);
- return block_md;
+ return lexical_block_metadata;
}
+fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
-
-fn create_basic_type(cx: &mut CrateContext, t: ty::t, _span: span) -> DIType {
- let ty_id = ty::type_id(t);
- match dbg_cx(cx).created_types.find(&ty_id) {
- Some(ty_md) => return *ty_md,
- None => ()
- }
-
- debug!("create_basic_type: %?", ty::get(t));
+ debug!("basic_type_metadata: %?", ty::get(t));
let (name, encoding) = match ty::get(t).sty {
ty::ty_nil | ty::ty_bot => (~"uint", DW_ATE_unsigned),
ast::ty_f32 => (~"f32", DW_ATE_float),
ast::ty_f64 => (~"f64", DW_ATE_float)
},
- _ => cx.sess.bug("debuginfo::create_basic_type - t is invalid type")
+ _ => cx.sess.bug("debuginfo::basic_type_metadata - t is invalid type")
};
- let (size, align) = size_and_align_of(cx, t);
- let ty_md = do as_c_str(name) |name| { unsafe {
+ let llvm_type = type_of::type_of(cx, t);
+ let (size, align) = size_and_align_of(cx, llvm_type);
+ let ty_metadata = do as_c_str(name) |name| {
+ unsafe {
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
name,
bytes_to_bits(size),
bytes_to_bits(align),
encoding as c_uint)
- }};
+ }
+ };
- // One could think that this call is not necessary, as the create_ty() function will insert the
- // type descriptor into the cache anyway. Mind, however, that create_basic_type() is also called
- // directly from other functions (e.g. create_boxed_type()).
- dbg_cx(cx).created_types.insert(ty_id, ty_md);
- return ty_md;
+ return ty_metadata;
}
-fn create_pointer_type(cx: &mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType {
- let (size, align) = size_and_align_of(cx, t);
- let name = ty_to_str(cx.tcx, t);
- let ptr_md = do as_c_str(name) |name| { unsafe {
- llvm::LLVMDIBuilderCreatePointerType(
- DIB(cx),
- pointee,
- bytes_to_bits(size),
- bytes_to_bits(align),
- name)
- }};
- return ptr_md;
+fn pointer_type_metadata(cx: &mut CrateContext,
+ pointer_type: ty::t,
+ pointee_type_metadata: DIType)
+ -> DIType {
+ let pointer_llvm_type = type_of::type_of(cx, pointer_type);
+ let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
+ let name = ty_to_str(cx.tcx, pointer_type);
+ let ptr_metadata = do as_c_str(name) |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreatePointerType(
+ DIB(cx),
+ pointee_type_metadata,
+ bytes_to_bits(pointer_size),
+ bytes_to_bits(pointer_align),
+ name)
+ }
+ };
+ return ptr_metadata;
}
-struct StructContext {
- builder: DIBuilderRef,
- file: DIFile,
- name: ~str,
- line: uint,
- members: ~[DIDerivedType],
- total_size: uint,
- align: uint
-}
-
-impl StructContext {
- fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> StructContext {
- debug!("StructContext::create: %s", name);
- return StructContext {
- builder: DIB(cx),
- file: file,
- name: name,
- line: line,
- members: ~[],
- total_size: 0,
- align: 1
- };
+fn struct_metadata(cx: &mut CrateContext,
+ struct_type: ty::t,
+ fields: ~[ty::field],
+ span: span)
+ -> DICompositeType {
+ let struct_name = ty_to_str(cx.tcx, struct_type);
+ debug!("struct_metadata: %s", struct_name);
+
+ let struct_llvm_type = type_of::type_of(cx, struct_type);
+
+ let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
+ let field_names = do fields.map |field| { cx.sess.str_of(field.ident).to_owned() };
+ let field_types_metadata = do fields.map |field| {
+ type_metadata(cx, field.mt.ty, span)
+ };
+
+ return composite_type_metadata(
+ cx,
+ struct_llvm_type,
+ struct_name,
+ field_llvm_types,
+ field_names,
+ field_types_metadata,
+ span);
+}
+
+fn tuple_metadata(cx: &mut CrateContext,
+ tuple_type: ty::t,
+ component_types: &[ty::t],
+ span: span)
+ -> DICompositeType {
+
+ let tuple_name = ty_to_str(cx.tcx, tuple_type);
+ let tuple_llvm_type = type_of::type_of(cx, tuple_type);
+
+ let component_names = do component_types.map |_| { ~"" };
+ let component_llvm_types = do component_types.map |it| { type_of::type_of(cx, *it) };
+ let component_types_metadata = do component_types.map |it| {
+ type_metadata(cx, *it, span)
+ };
+
+ return composite_type_metadata(
+ cx,
+ tuple_llvm_type,
+ tuple_name,
+ component_llvm_types,
+ component_names,
+ component_types_metadata,
+ span);
+}
+
+fn enum_metadata(cx: &mut CrateContext,
+ enum_type: ty::t,
+ enum_def_id: ast::def_id,
+ // _substs is only needed in the other version. Will go away with new snapshot.
+ _substs: &ty::substs,
+ span: span)
+ -> DIType {
+
+ let enum_name = ty_to_str(cx.tcx, enum_type);
+
+ // For empty enums there is an early exit. Just describe it as an empty struct with the
+ // appropriate type name
+ if ty::type_is_empty(cx.tcx, enum_type) {
+ return composite_type_metadata(cx, Type::nil(), enum_name, [], [], [], span);
}
- fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) {
- let offset = roundup(self.total_size, align);
+ // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
+ // needed in all of the following cases.
+ let discriminant_llvm_type = Type::enum_discrim(cx);
+ let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
- debug!("StructContext(%s)::add_member: %s, size=%u, align=%u, offset=%u",
- self.name, name, size, align, offset);
+ assert!(Type::enum_discrim(cx) == cx.int_type);
+ let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span);
- let mem_t = do as_c_str(name) |name| { unsafe {
- llvm::LLVMDIBuilderCreateMemberType(
- self.builder,
- self.file,
- name,
- self.file,
- line as c_uint,
- bytes_to_bits(size),
- bytes_to_bits(align),
- bytes_to_bits(offset),
- 0,
- ty)
+ let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
+
+ let enumerators_metadata: ~[DIDescriptor] = variants
+ .iter()
+ .transform(|v| {
+ let name: &str = cx.sess.str_of(v.name);
+ let discriminant_value = v.disr_val as c_ulonglong;
+
+ do name.as_c_str |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateEnumerator(
+ DIB(cx),
+ name,
+ discriminant_value)
+ }
+ }
+ })
+ .collect();
+
+ let loc = span_start(cx, span);
+ let file_metadata = file_metadata(cx, loc.file.name);
+
+ let discriminant_type_metadata = do enum_name.as_c_str |enum_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateEnumerationType(
+ DIB(cx),
+ file_metadata,
+ enum_name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(discriminant_size),
+ bytes_to_bits(discriminant_align),
+ create_DIArray(DIB(cx), enumerators_metadata),
+ discriminant_type_metadata)
+ }
+ };
+
+ let type_rep = adt::represent_type(cx, enum_type);
+
+ match *type_rep {
+ adt::CEnum(*) => {
+ return discriminant_type_metadata;
+ }
+ adt::Univariant(ref struct_def, _) => {
+ assert!(variants.len() == 1);
+ return adt_struct_metadata(cx, struct_def, variants[0], None, span);
+ }
+ adt::General(ref struct_defs) => {
+ let variants_member_metadata: ~[DIDescriptor] = do struct_defs
+ .iter()
+ .enumerate()
+ .transform |(i, struct_def)| {
+ let variant_type_metadata = adt_struct_metadata(
+ cx,
+ struct_def,
+ variants[i],
+ Some(discriminant_type_metadata),
+ span);
+
+ do "".as_c_str |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateMemberType(
+ DIB(cx),
+ file_metadata,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(struct_def.size as uint),
+ bytes_to_bits(struct_def.align as uint),
+ bytes_to_bits(0),
+ 0,
+ variant_type_metadata)
+ }
+ }
+ }.collect();
+
+ let enum_llvm_type = type_of::type_of(cx, enum_type);
+ let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
+
+ return do enum_name.as_c_str |enum_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateUnionType(
+ DIB(cx),
+ file_metadata,
+ enum_name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(enum_type_size),
+ bytes_to_bits(enum_type_align),
+ 0, // Flags
+ create_DIArray(DIB(cx), variants_member_metadata),
+ 0) // RuntimeLang
}};
- self.members.push(mem_t);
- self.total_size = offset + size;
- // struct alignment is the max alignment of its' members
- self.align = cmp::max(self.align, align);
+ }
+ adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
+ return adt_struct_metadata(cx, struct_def, variants[nndiscr], None, span);
+ }
}
- fn get_total_size_with_alignment(&self) -> uint {
- roundup(self.total_size, self.align)
- }
+ fn adt_struct_metadata(cx: &mut CrateContext,
+ struct_def: &adt::Struct,
+ variant_info: &ty::VariantInfo,
+ discriminant_type_metadata: Option<DIType>,
+ span: span)
+ -> DICompositeType
+ {
+ let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) };
+ let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate()
+ .transform |(i, &ty)| {
+ match discriminant_type_metadata {
+ Some(metadata) if i == 0 => metadata,
+ _ => type_metadata(cx, ty, span)
+ }
+ }.collect();
- fn finalize(&self) -> DICompositeType {
- debug!("StructContext(%s)::finalize: total_size=%u, align=%u",
- self.name, self.total_size, self.align);
- let members_md = create_DIArray(self.builder, self.members);
-
- // The size of the struct/tuple must be rounded to the next multiple of its alignment.
- // Otherwise gdb has trouble reading the struct correctly when it is embedded into another
- // data structure. This is also the value `sizeof` in C would give.
- let actual_total_size = self.get_total_size_with_alignment();
-
- let struct_md =
- do as_c_str(self.name) |name| { unsafe {
- llvm::LLVMDIBuilderCreateStructType(
- self.builder,
- self.file,
- name,
- self.file,
- self.line as c_uint,
- bytes_to_bits(actual_total_size),
- bytes_to_bits(self.align),
- 0,
- ptr::null(),
- members_md,
- 0,
- ptr::null())
- }};
- return struct_md;
+ let mut arg_names = match variant_info.arg_names {
+ Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() },
+ None => do variant_info.args.map |_| { ~"" }
+ };
+
+ if discriminant_type_metadata.is_some() {
+ arg_names.insert(0, ~"");
+ }
+
+ let variant_llvm_type = Type::struct_(arg_llvm_types, struct_def.packed);
+ let variant_name: &str = cx.sess.str_of(variant_info.name);
+
+ return composite_type_metadata(
+ cx,
+ variant_llvm_type,
+ variant_name,
+ arg_llvm_types,
+ arg_names,
+ arg_metadata,
+ span);
}
}
-fn create_struct(cx: &mut CrateContext, struct_type: ty::t, fields: ~[ty::field], span: span)
- -> DICompositeType {
- debug!("create_struct: %?", ty::get(struct_type));
+/// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
+///
+/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
+fn composite_type_metadata(cx: &mut CrateContext,
+ composite_llvm_type: Type,
+ composite_type_name: &str,
+ member_llvm_types: &[Type],
+ member_names: &[~str],
+ member_type_metadata: &[DIType],
+ span: span)
+ -> DICompositeType {
let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
-
- let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, struct_type), file_md, loc.line);
- for fields.iter().advance |field| {
- let field_t = field.mt.ty;
- let ty_md = create_ty(cx, field_t, span);
- let (size, align) = size_and_align_of(cx, field_t);
- scx.add_member(cx.sess.str_of(field.ident), loc.line, size, align, ty_md);
- }
- return scx.finalize();
-}
+ let file_metadata = file_metadata(cx, loc.file.name);
+
+ let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type);
+
+ let member_metadata: ~[DIDescriptor] = member_llvm_types
+ .iter()
+ .enumerate()
+ .transform(|(i, &member_llvm_type)| {
+ let (member_size, member_align) = size_and_align_of(cx, member_llvm_type);
+ let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
+ let member_name: &str = member_names[i];
+
+ do member_name.as_c_str |member_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateMemberType(
+ DIB(cx),
+ file_metadata,
+ member_name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(member_size),
+ bytes_to_bits(member_align),
+ bytes_to_bits(member_offset),
+ 0,
+ member_type_metadata[i])
+ }
+ }
+ })
+ .collect();
-// returns (void* type as a ValueRef, size in bytes, align in bytes)
-fn voidptr(cx: &mut CrateContext) -> (DIDerivedType, uint, uint) {
- let size = sys::size_of::<ValueRef>();
- let align = sys::min_align_of::<ValueRef>();
- let vp = do as_c_str("*void") |name| { unsafe {
- llvm::LLVMDIBuilderCreatePointerType(
+ return do composite_type_name.as_c_str |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateStructType(
DIB(cx),
+ file_metadata,
+ name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(composite_size),
+ bytes_to_bits(composite_align),
+ 0,
ptr::null(),
- bytes_to_bits(size),
- bytes_to_bits(align),
- name)
- }};
- return (vp, size, align);
+ create_DIArray(DIB(cx), member_metadata),
+ 0,
+ ptr::null())
+ }
+ };
}
-fn create_tuple(cx: &mut CrateContext, tuple_type: ty::t, elements: &[ty::t], span: span)
- -> DICompositeType {
- debug!("create_tuple: %?", ty::get(tuple_type));
+fn boxed_type_metadata(cx: &mut CrateContext,
+ content_type_name: Option<&str>,
+ content_llvm_type: Type,
+ content_type_metadata: DIType,
+ span: span)
+ -> DICompositeType {
- let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
-
- let name = fmt!("tuple_%u", token::gensym("tuple"));
- let mut scx = StructContext::new(cx, name, file_md, loc.line);
- for elements.iter().advance |element| {
- let ty_md = create_ty(cx, *element, span);
- let (size, align) = size_and_align_of(cx, *element);
- scx.add_member("", loc.line, size, align, ty_md);
+ let box_type_name = match content_type_name {
+ Some(content_type_name) => fmt!("Boxed<%s>", content_type_name),
+ None => ~"BoxedType"
+ };
+
+ let box_llvm_type = Type::box(cx, &content_llvm_type);
+ let member_llvm_types = box_llvm_type.field_types();
+ let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"];
+
+ assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
+
+ let int_type = ty::mk_int();
+ let nil_pointer_type = ty::mk_nil_ptr(cx.tcx);
+
+ let member_types_metadata = [
+ type_metadata(cx, int_type, span),
+ type_metadata(cx, nil_pointer_type, span),
+ type_metadata(cx, nil_pointer_type, span),
+ type_metadata(cx, nil_pointer_type, span),
+ content_type_metadata
+ ];
+
+ return composite_type_metadata(
+ cx,
+ box_llvm_type,
+ box_type_name,
+ member_llvm_types,
+ member_names,
+ member_types_metadata,
+ span);
+
+ // Unfortunately, we cannot assert anything but the correct types here---and not whether the
+ // 'next' and 'prev' pointers are in the correct order.
+ fn box_layout_is_correct(cx: &CrateContext,
+ member_llvm_types: &[Type],
+ content_llvm_type: Type)
+ -> bool {
+ member_llvm_types.len() == 5 &&
+ member_llvm_types[0] == cx.int_type &&
+ member_llvm_types[1] == cx.tydesc_type.ptr_to() &&
+ member_llvm_types[2] == Type::i8().ptr_to() &&
+ member_llvm_types[3] == Type::i8().ptr_to() &&
+ member_llvm_types[4] == content_llvm_type
}
- return scx.finalize();
}
-fn create_boxed_type(cx: &mut CrateContext, contents: ty::t,
- span: span, boxed: DIType) -> DICompositeType {
- debug!("create_boxed_type: %?", ty::get(contents));
-
- let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
- let int_t = ty::mk_int();
- let refcount_type = create_basic_type(cx, int_t, span);
- let name = ty_to_str(cx.tcx, contents);
-
- let mut scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0);
- scx.add_member("refcnt", 0, sys::size_of::<uint>(),
- sys::min_align_of::<uint>(), refcount_type);
- // the tydesc and other pointers should be irrelevant to the
- // debugger, so treat them as void* types
- let (vp, vpsize, vpalign) = voidptr(cx);
- scx.add_member("tydesc", 0, vpsize, vpalign, vp);
- scx.add_member("prev", 0, vpsize, vpalign, vp);
- scx.add_member("next", 0, vpsize, vpalign, vp);
- let (size, align) = size_and_align_of(cx, contents);
- scx.add_member("boxed", 0, size, align, boxed);
- return scx.finalize();
-}
-
-fn create_fixed_vec(cx: &mut CrateContext, _vec_t: ty::t, elem_t: ty::t,
- len: uint, span: span) -> DIType {
- debug!("create_fixed_vec: %?", ty::get(_vec_t));
-
- let elem_ty_md = create_ty(cx, elem_t, span);
- let (size, align) = size_and_align_of(cx, elem_t);
+fn fixed_vec_metadata(cx: &mut CrateContext,
+ element_type: ty::t,
+ len: uint,
+ span: span)
+ -> DIType {
+ let element_type_metadata = type_metadata(cx, element_type, span);
+ let element_llvm_type = type_of::type_of(cx, element_type);
+ let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
let subrange = unsafe {
- llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, len as i64)
+ llvm::LLVMDIBuilderGetOrCreateSubrange(
+ DIB(cx),
+ 0,
+ len as c_longlong)
};
let subscripts = create_DIArray(DIB(cx), [subrange]);
return unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
- bytes_to_bits(size * len),
- bytes_to_bits(align),
- elem_ty_md,
+ bytes_to_bits(element_type_size * len),
+ bytes_to_bits(element_type_align),
+ element_type_metadata,
subscripts)
};
}
-fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t,
- vec_ty_span: span) -> DICompositeType {
- debug!("create_boxed_vec: %?", ty::get(vec_t));
+fn vec_metadata(cx: &mut CrateContext,
+ element_type: ty::t,
+ span: span)
+ -> DICompositeType {
- let loc = span_start(cx, vec_ty_span);
- let file_md = create_file(cx, loc.file.name);
- let elem_ty_md = create_ty(cx, elem_t, vec_ty_span);
-
- let mut vec_scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0);
- let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span);
-
- vec_scx.add_member(
- "fill",
- 0,
- sys::size_of::<libc::size_t>(),
- sys::min_align_of::<libc::size_t>(),
- size_t_type);
+ let element_type_metadata = type_metadata(cx, element_type, span);
+ let element_llvm_type = type_of::type_of(cx, element_type);
+ let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
- vec_scx.add_member(
- "alloc",
- 0,
- sys::size_of::<libc::size_t>(),
- sys::min_align_of::<libc::size_t>(),
- size_t_type);
+ let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
+ let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
- let subrange = unsafe {
- llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, 0_i64)
- };
- let (arr_size, arr_align) = size_and_align_of(cx, elem_t);
- let name = fmt!("[%s]", ty_to_str(cx.tcx, elem_t));
+ let member_llvm_types = vec_llvm_type.field_types();
+ let member_names = &[~"fill", ~"alloc", ~"elements"];
- let subscripts = create_DIArray(DIB(cx), [subrange]);
- let data_ptr = unsafe {
+ let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
+ let array_type_metadata = unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
- bytes_to_bits(arr_size),
- bytes_to_bits(arr_align),
- elem_ty_md,
- subscripts)
+ bytes_to_bits(element_size),
+ bytes_to_bits(element_align),
+ element_type_metadata,
+ create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
};
- vec_scx.add_member(
- "data",
- 0,
- 0, // clang says the size should be 0
- sys::min_align_of::<u8>(), data_ptr);
- let vec_md = vec_scx.finalize();
+ // fill alloc elements
+ let member_type_metadata = &[int_type_metadata, int_type_metadata, array_type_metadata];
+
+ return composite_type_metadata(
+ cx,
+ vec_llvm_type,
+ vec_type_name,
+ member_llvm_types,
+ member_names,
+ member_type_metadata,
+ span);
+}
- let mut box_scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0);
- let int_t = ty::mk_int();
- let refcount_type = create_basic_type(cx, int_t, vec_ty_span);
+fn boxed_vec_metadata(cx: &mut CrateContext,
+ element_type: ty::t,
+ span: span)
+ -> DICompositeType {
+
+ let element_llvm_type = type_of::type_of(cx, element_type);
+ let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
+ let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
+ let vec_metadata = vec_metadata(cx, element_type, span);
+
+ return boxed_type_metadata(
+ cx,
+ Some(vec_type_name),
+ vec_llvm_type,
+ vec_metadata,
+ span);
+}
- box_scx.add_member(
- "refcnt",
- 0,
- sys::size_of::<uint>(),
- sys::min_align_of::<uint>(),
- refcount_type);
-
- let (vp, vpsize, vpalign) = voidptr(cx);
- box_scx.add_member("tydesc", 0, vpsize, vpalign, vp);
- box_scx.add_member("prev", 0, vpsize, vpalign, vp);
- box_scx.add_member("next", 0, vpsize, vpalign, vp);
- let size = 2 * sys::size_of::<int>();
- let align = sys::min_align_of::<int>();
- box_scx.add_member("boxed", 0, size, align, vec_md);
- let mdval = box_scx.finalize();
- return mdval;
-}
-
-fn create_vec_slice(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span)
- -> DICompositeType {
- debug!("create_vec_slice: %?", ty::get(vec_t));
+fn vec_slice_metadata(cx: &mut CrateContext,
+ vec_type: ty::t,
+ element_type: ty::t,
+ span: span)
+ -> DICompositeType {
- let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
- let elem_ty_md = create_ty(cx, elem_t, span);
- let uint_type = create_basic_type(cx, ty::mk_uint(), span);
- let elem_ptr = create_pointer_type(cx, elem_t, span, elem_ty_md);
+ debug!("vec_slice_metadata: %?", ty::get(vec_type));
+
+ let slice_llvm_type = type_of::type_of(cx, vec_type);
+ let slice_type_name = ty_to_str(cx.tcx, vec_type);
- let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0);
- let (_, ptr_size, ptr_align) = voidptr(cx);
- scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr);
- scx.add_member("length", 0, sys::size_of::<uint>(), sys::min_align_of::<uint>(), uint_type);
- return scx.finalize();
+ let member_llvm_types = slice_llvm_type.field_types();
+ let member_names = &[~"data_ptr", ~"size_in_bytes"];
+
+ assert!(slice_layout_is_correct(cx, member_llvm_types, element_type));
+
+ let data_ptr_type = ty::mk_ptr(cx.tcx, ty::mt { ty: element_type, mutbl: ast::m_imm });
+
+ let member_type_metadata = &[type_metadata(cx, data_ptr_type, span),
+ type_metadata(cx, ty::mk_uint(), span)];
+
+ return composite_type_metadata(
+ cx,
+ slice_llvm_type,
+ slice_type_name,
+ member_llvm_types,
+ member_names,
+ member_type_metadata,
+ span);
+
+ fn slice_layout_is_correct(cx: &mut CrateContext,
+ member_llvm_types: &[Type],
+ element_type: ty::t)
+ -> bool {
+ member_llvm_types.len() == 2 &&
+ member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() &&
+ member_llvm_types[1] == cx.int_type
+ }
}
-fn create_fn_ty(cx: &mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t,
- span: span) -> DICompositeType {
- debug!("create_fn_ty: %?", ty::get(_fn_ty));
+fn bare_fn_metadata(cx: &mut CrateContext,
+ _fn_ty: ty::t,
+ inputs: ~[ty::t],
+ output: ty::t,
+ span: span)
+ -> DICompositeType {
+
+ debug!("bare_fn_metadata: %?", ty::get(_fn_ty));
let loc = span_start(cx, span);
- let file_md = create_file(cx, loc.file.name);
- let (vp, _, _) = voidptr(cx);
- let output_md = create_ty(cx, output, span);
- let output_ptr_md = create_pointer_type(cx, output, span, output_md);
- let inputs_vals = do inputs.map |arg| { create_ty(cx, *arg, span) };
- let members = ~[output_ptr_md, vp] + inputs_vals;
+ let file_metadata = file_metadata(cx, loc.file.name);
+
+ let nil_pointer_type_metadata = type_metadata(cx, ty::mk_nil_ptr(cx.tcx), span);
+ let output_metadata = type_metadata(cx, output, span);
+ let output_ptr_metadata = pointer_type_metadata(cx, output, output_metadata);
+
+ let inputs_vals = do inputs.map |arg| { type_metadata(cx, *arg, span) };
+ let members = ~[output_ptr_metadata, nil_pointer_type_metadata] + inputs_vals;
return unsafe {
llvm::LLVMDIBuilderCreateSubroutineType(
DIB(cx),
- file_md,
+ file_metadata,
create_DIArray(DIB(cx), members))
};
}
-fn create_unimpl_ty(cx: &mut CrateContext, t: ty::t) -> DIType {
- debug!("create_unimpl_ty: %?", ty::get(t));
+fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
+ debug!("unimplemented_type_metadata: %?", ty::get(t));
let name = ty_to_str(cx.tcx, t);
- let md = do as_c_str(fmt!("NYI<%s>", name)) |name| { unsafe {
- llvm::LLVMDIBuilderCreateBasicType(
- DIB(cx),
- name,
- 0_u64,
- 8_u64,
- DW_ATE_unsigned as c_uint)
- }};
- return md;
+ let metadata = do as_c_str(fmt!("NYI<%s>", name)) |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateBasicType(
+ DIB(cx),
+ name,
+ 0_u64,
+ 8_u64,
+ DW_ATE_unsigned as c_uint)
+ }
+ };
+
+ return metadata;
}
-fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) -> DIType {
- let ty_id = ty::type_id(t);
- match dbg_cx(cx).created_types.find(&ty_id) {
- Some(ty_md) => return *ty_md,
+fn type_metadata(cx: &mut CrateContext,
+ t: ty::t,
+ span: span)
+ -> DIType {
+ let type_id = ty::type_id(t);
+ match dbg_cx(cx).created_types.find(&type_id) {
+ Some(type_metadata) => return *type_metadata,
None => ()
}
- debug!("create_ty: %?", ty::get(t));
+ fn create_pointer_to_box_metadata(cx: &mut CrateContext,
+ pointer_type: ty::t,
+ type_in_box: ty::t)
+ -> DIType {
+
+ let content_type_name: &str = ty_to_str(cx.tcx, type_in_box);
+ let content_llvm_type = type_of::type_of(cx, type_in_box);
+ let content_type_metadata = type_metadata(
+ cx,
+ type_in_box,
+ codemap::dummy_sp());
+
+ let box_metadata = boxed_type_metadata(
+ cx,
+ Some(content_type_name),
+ content_llvm_type,
+ content_type_metadata,
+ codemap::dummy_sp());
+
+ pointer_type_metadata(cx, pointer_type, box_metadata)
+ }
+
+ debug!("type_metadata: %?", ty::get(t));
let sty = &ty::get(t).sty;
- let ty_md = match *sty {
- ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_)
- | ty::ty_float(_) => create_basic_type(cx, t, span),
+ let type_metadata = match *sty {
+ ty::ty_nil |
+ ty::ty_bot |
+ ty::ty_bool |
+ ty::ty_int(_) |
+ ty::ty_uint(_) |
+ ty::ty_float(_) => {
+ basic_type_metadata(cx, t)
+ },
ty::ty_estr(ref vstore) => {
let i8_t = ty::mk_i8();
match *vstore {
ty::vstore_fixed(len) => {
- create_fixed_vec(cx, t, i8_t, len + 1, span)
+ fixed_vec_metadata(cx, i8_t, len + 1, span)
},
- ty::vstore_uniq | ty::vstore_box => {
- let box_md = create_boxed_vec(cx, t, i8_t, span);
- create_pointer_type(cx, t, span, box_md)
+ ty::vstore_uniq => {
+ let vec_metadata = vec_metadata(cx, i8_t, span);
+ pointer_type_metadata(cx, t, vec_metadata)
+ }
+ ty::vstore_box => {
+ let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, span);
+ pointer_type_metadata(cx, t, boxed_vec_metadata)
}
ty::vstore_slice(_region) => {
- create_vec_slice(cx, t, i8_t, span)
+ vec_slice_metadata(cx, t, i8_t, span)
}
}
},
- ty::ty_enum(_did, ref _substs) => {
- cx.sess.span_note(span, "debuginfo for enum NYI");
- create_unimpl_ty(cx, t)
- }
- ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => {
- let boxed = create_ty(cx, mt.ty, span);
- let box_md = create_boxed_type(cx, mt.ty, span, boxed);
- create_pointer_type(cx, t, span, box_md)
+ ty::ty_enum(def_id, ref substs) => {
+ enum_metadata(cx, t, def_id, substs, span)
+ },
+ ty::ty_box(ref mt) => {
+ create_pointer_to_box_metadata(cx, t, mt.ty)
},
ty::ty_evec(ref mt, ref vstore) => {
match *vstore {
ty::vstore_fixed(len) => {
- create_fixed_vec(cx, t, mt.ty, len, span)
- },
- ty::vstore_uniq | ty::vstore_box => {
- let box_md = create_boxed_vec(cx, t, mt.ty, span);
- create_pointer_type(cx, t, span, box_md)
- },
- ty::vstore_slice(_region) => {
- create_vec_slice(cx, t, mt.ty, span)
+ fixed_vec_metadata(cx, mt.ty, len, span)
+ }
+ ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
+ let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+ pointer_type_metadata(cx, t, boxed_vec_metadata)
+ }
+ ty::vstore_uniq => {
+ let vec_metadata = vec_metadata(cx, mt.ty, span);
+ pointer_type_metadata(cx, t, vec_metadata)
+ }
+ ty::vstore_box => {
+ let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+ pointer_type_metadata(cx, t, boxed_vec_metadata)
+ }
+ ty::vstore_slice(_) => {
+ vec_slice_metadata(cx, t, mt.ty, span)
}
}
},
- ty::ty_ptr(ref mt) => {
- let pointee = create_ty(cx, mt.ty, span);
- create_pointer_type(cx, t, span, pointee)
+ ty::ty_uniq(ref mt) if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
+ create_pointer_to_box_metadata(cx, t, mt.ty)
},
+ ty::ty_uniq(ref mt) |
+ ty::ty_ptr(ref mt) |
ty::ty_rptr(_, ref mt) => {
- let pointee = create_ty(cx, mt.ty, span);
- create_pointer_type(cx, t, span, pointee)
+ let pointee = type_metadata(cx, mt.ty, span);
+ pointer_type_metadata(cx, t, pointee)
},
ty::ty_bare_fn(ref barefnty) => {
let inputs = barefnty.sig.inputs.map(|a| *a);
let output = barefnty.sig.output;
- create_fn_ty(cx, t, inputs, output, span)
+ bare_fn_metadata(cx, t, inputs, output, span)
},
ty::ty_closure(ref _closurety) => {
cx.sess.span_note(span, "debuginfo for closure NYI");
- create_unimpl_ty(cx, t)
+ unimplemented_type_metadata(cx, t)
},
ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
cx.sess.span_note(span, "debuginfo for trait NYI");
- create_unimpl_ty(cx, t)
+ unimplemented_type_metadata(cx, t)
},
ty::ty_struct(did, ref substs) => {
let fields = ty::struct_fields(cx.tcx, did, substs);
- create_struct(cx, t, fields, span)
+ struct_metadata(cx, t, fields, span)
},
ty::ty_tup(ref elements) => {
- create_tuple(cx, t, *elements, span)
+ tuple_metadata(cx, t, *elements, span)
},
- _ => cx.sess.bug("debuginfo: unexpected type in create_ty")
+ _ => cx.sess.bug("debuginfo: unexpected type in type_metadata")
};
- dbg_cx(cx).created_types.insert(ty_id, ty_md);
- return ty_md;
+ dbg_cx(cx).created_types.insert(type_id, type_metadata);
+ return type_metadata;
}
fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) {
cx.sess.codemap.lookup_char_pos(span.lo)
}
-fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (uint, uint) {
- let llty = type_of::type_of(cx, t);
- (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty))
+fn size_and_align_of(cx: &mut CrateContext, llvm_type: Type) -> (uint, uint) {
+ (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
}
fn bytes_to_bits(bytes: uint) -> c_ulonglong {
}
}
-fn drop_and_cancel_clean(bcx: block, dat: Datum) -> block {
+fn drop_and_cancel_clean(bcx: @mut Block, dat: Datum) -> @mut Block {
let bcx = dat.drop_val(bcx);
dat.cancel_clean(bcx);
return bcx;
}
-pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
+pub fn trans_to_datum(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
let mut bcx = bcx;
debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
return DatumBlock {bcx: bcx, datum: datum};
- fn auto_ref(bcx: block, datum: Datum) -> DatumBlock {
+ fn auto_ref(bcx: @mut Block, datum: Datum) -> DatumBlock {
DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
}
- fn auto_borrow_fn(bcx: block,
+ fn auto_borrow_fn(bcx: @mut Block,
adjusted_ty: ty::t,
datum: Datum) -> DatumBlock {
// Currently, all closure types are represented precisely the
mode: datum.mode}}
}
- fn auto_slice(bcx: block,
+ fn auto_slice(bcx: @mut Block,
autoderefs: uint,
expr: &ast::expr,
datum: Datum) -> DatumBlock {
DatumBlock {bcx: bcx, datum: scratch}
}
- fn add_env(bcx: block, expr: &ast::expr, datum: Datum) -> DatumBlock {
+ fn add_env(bcx: @mut Block, expr: &ast::expr, datum: Datum) -> DatumBlock {
// This is not the most efficient thing possible; since closures
// are two words it'd be better if this were compiled in
// 'dest' mode, but I can't find a nice way to structure the
DatumBlock {bcx: bcx, datum: scratch}
}
- fn auto_slice_and_ref(bcx: block,
+ fn auto_slice_and_ref(bcx: @mut Block,
autoderefs: uint,
expr: &ast::expr,
datum: Datum) -> DatumBlock {
}
}
-pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
+pub fn trans_into(bcx: @mut Block, expr: @ast::expr, dest: Dest) -> @mut Block {
if bcx.tcx().adjustments.contains_key(&expr.id) {
// use trans_to_datum, which is mildly less efficient but
// which will perform the adjustments:
};
}
-fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
+fn trans_lvalue(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
/*!
*
* Translates an lvalue expression, always yielding a by-ref
};
}
-fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
+fn trans_to_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
/*!
* Translates an expression into a datum. If this expression
* is an rvalue, this will result in a temporary value being
}
}
- fn nil(bcx: block, ty: ty::t) -> DatumBlock {
+ fn nil(bcx: @mut Block, ty: ty::t) -> DatumBlock {
let datum = immediate_rvalue(C_nil(), ty);
DatumBlock {bcx: bcx, datum: datum}
}
}
-fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
+fn trans_rvalue_datum_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
let _icx = push_ctxt("trans_rvalue_datum_unadjusted");
trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
}
}
-fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
+fn trans_rvalue_stmt_unadjusted(bcx: @mut Block, expr: @ast::expr) -> @mut Block {
let mut bcx = bcx;
let _icx = push_ctxt("trans_rvalue_stmt");
};
}
-fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
- dest: Dest) -> block {
+fn trans_rvalue_dps_unadjusted(bcx: @mut Block, expr: @ast::expr,
+ dest: Dest) -> @mut Block {
let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
let tcx = bcx.tcx();
}
}
-fn trans_def_dps_unadjusted(bcx: block, ref_expr: &ast::expr,
- def: ast::def, dest: Dest) -> block {
+fn trans_def_dps_unadjusted(bcx: @mut Block, ref_expr: &ast::expr,
+ def: ast::def, dest: Dest) -> @mut Block {
let _icx = push_ctxt("trans_def_dps_unadjusted");
let ccx = bcx.ccx();
}
}
-fn trans_def_datum_unadjusted(bcx: block,
+fn trans_def_datum_unadjusted(bcx: @mut Block,
ref_expr: &ast::expr,
def: ast::def) -> DatumBlock
{
}
}
- fn fn_data_to_datum(bcx: block,
+ fn fn_data_to_datum(bcx: @mut Block,
ref_expr: &ast::expr,
def_id: ast::def_id,
fn_data: callee::FnData) -> DatumBlock {
}
}
-fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
+fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock {
/*!
*
* Translates an lvalue expression, always yielding a by-ref
}
};
- fn trans_rec_field(bcx: block,
+ fn trans_rec_field(bcx: @mut Block,
base: @ast::expr,
field: ast::ident) -> DatumBlock {
//! Translates `base.field`.
}
}
- fn trans_index(bcx: block,
+ fn trans_index(bcx: @mut Block,
index_expr: &ast::expr,
base: @ast::expr,
idx: @ast::expr) -> DatumBlock {
};
}
- fn trans_def_lvalue(bcx: block,
+ fn trans_def_lvalue(bcx: @mut Block,
ref_expr: &ast::expr,
def: ast::def)
-> DatumBlock
}
}
- fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
+ fn get_val(bcx: @mut Block, did: ast::def_id, const_ty: ty::t)
-> ValueRef {
// For external constants, we don't inline.
if did.crate == ast::local_crate {
}
}
-pub fn trans_local_var(bcx: block, def: ast::def) -> Datum {
+pub fn trans_local_var(bcx: @mut Block, def: ast::def) -> Datum {
let _icx = push_ctxt("trans_local_var");
return match def {
}
};
- fn take_local(bcx: block,
+ fn take_local(bcx: @mut Block,
table: &HashMap<ast::node_id, ValueRef>,
nid: ast::node_id) -> Datum {
let v = match table.find(&nid) {
}
}
-fn trans_rec_or_struct(bcx: block,
- fields: &[ast::field],
+fn trans_rec_or_struct(bcx: @mut Block,
+ fields: &[ast::Field],
base: Option<@ast::expr>,
expr_span: codemap::span,
id: ast::node_id,
- dest: Dest) -> block
+ dest: Dest) -> @mut Block
{
let _icx = push_ctxt("trans_rec");
let bcx = bcx;
let mut need_base = vec::from_elem(field_tys.len(), true);
let numbered_fields = do fields.map |field| {
- let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.node.ident);
+ let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.ident);
match opt_pos {
Some(i) => {
need_base[i] = false;
- (i, field.node.expr)
+ (i, field.expr)
}
None => {
tcx.sess.span_bug(field.span,
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
-fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
+fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: int,
fields: &[(uint, @ast::expr)],
optbase: Option<StructBaseInfo>,
- dest: Dest) -> block {
+ dest: Dest) -> @mut Block {
let _icx = push_ctxt("trans_adt");
let mut bcx = bcx;
let addr = match dest {
}
-fn trans_immediate_lit(bcx: block, expr: @ast::expr,
+fn trans_immediate_lit(bcx: @mut Block, expr: @ast::expr,
lit: ast::lit) -> DatumBlock {
// must not be a string constant, that is a RvalueDpsExpr
let _icx = push_ctxt("trans_immediate_lit");
immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
}
-fn trans_unary_datum(bcx: block,
+fn trans_unary_datum(bcx: @mut Block,
un_expr: &ast::expr,
op: ast::unop,
sub_expr: @ast::expr) -> DatumBlock {
}
};
- fn trans_boxed_expr(bcx: block,
+ fn trans_boxed_expr(bcx: @mut Block,
box_ty: ty::t,
contents: @ast::expr,
contents_ty: ty::t,
}
}
-fn trans_addr_of(bcx: block, expr: &ast::expr,
+fn trans_addr_of(bcx: @mut Block, expr: &ast::expr,
subexpr: @ast::expr) -> DatumBlock {
let _icx = push_ctxt("trans_addr_of");
let mut bcx = bcx;
// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
-fn trans_eager_binop(bcx: block,
+fn trans_eager_binop(bcx: @mut Block,
binop_expr: &ast::expr,
binop_ty: ty::t,
op: ast::binop,
// refinement types would obviate the need for this
enum lazy_binop_ty { lazy_and, lazy_or }
-fn trans_lazy_binop(bcx: block,
+fn trans_lazy_binop(bcx: @mut Block,
binop_expr: &ast::expr,
op: lazy_binop_ty,
a: @ast::expr,
return immediate_rvalue_bcx(join, phi, binop_ty);
}
-fn trans_binary(bcx: block,
+fn trans_binary(bcx: @mut Block,
binop_expr: &ast::expr,
op: ast::binop,
lhs: @ast::expr,
}
}
-fn trans_overloaded_op(bcx: block,
+fn trans_overloaded_op(bcx: @mut Block,
expr: &ast::expr,
callee_id: ast::node_id,
rcvr: @ast::expr,
args: ~[@ast::expr],
ret_ty: ty::t,
dest: Dest)
- -> block {
+ -> @mut Block {
let origin = bcx.ccx().maps.method_map.get_copy(&expr.id);
let fty = node_id_type(bcx, callee_id);
callee::trans_call_inner(bcx,
DoAutorefArg).bcx
}
-fn int_cast(bcx: block, lldsttype: Type, llsrctype: Type,
+fn int_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
llsrc: ValueRef, signed: bool) -> ValueRef {
let _icx = push_ctxt("int_cast");
unsafe {
}
}
-fn float_cast(bcx: block, lldsttype: Type, llsrctype: Type,
+fn float_cast(bcx: @mut Block, lldsttype: Type, llsrctype: Type,
llsrc: ValueRef) -> ValueRef {
let _icx = push_ctxt("float_cast");
let srcsz = llsrctype.float_width();
}
}
-fn trans_imm_cast(bcx: block, expr: @ast::expr,
+fn trans_imm_cast(bcx: @mut Block, expr: @ast::expr,
id: ast::node_id) -> DatumBlock {
let _icx = push_ctxt("trans_cast");
let ccx = bcx.ccx();
return immediate_rvalue_bcx(bcx, newval, t_out);
}
-fn trans_assign_op(bcx: block,
+fn trans_assign_op(bcx: @mut Block,
expr: @ast::expr,
callee_id: ast::node_id,
op: ast::binop,
dst: @ast::expr,
- src: @ast::expr) -> block
+ src: @ast::expr) -> @mut Block
{
let _icx = push_ctxt("trans_assign_op");
let mut bcx = bcx;
}
type shim_arg_builder<'self> =
- &'self fn(bcx: block, tys: &ShimTypes,
+ &'self fn(bcx: @mut Block, tys: &ShimTypes,
llargbundle: ValueRef) -> ~[ValueRef];
type shim_ret_builder<'self> =
- &'self fn(bcx: block, tys: &ShimTypes,
+ &'self fn(bcx: @mut Block, tys: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef);
// Declare the body of the shim function:
let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llargbundle = get_param(llshimfn, 0u);
let llargvals = arg_builder(bcx, tys, llargbundle);
// Don't finish up the function in the usual way, because this doesn't
// follow the normal Rust calling conventions.
- tie_up_header_blocks(fcx, lltop);
-
let ret_cx = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
None => bcx
};
RetVoid(ret_cx);
+ fcx.cleanup();
return llshimfn;
}
-type wrap_arg_builder<'self> = &'self fn(bcx: block,
+type wrap_arg_builder<'self> = &'self fn(bcx: @mut Block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef);
-type wrap_ret_builder<'self> = &'self fn(bcx: block,
+type wrap_ret_builder<'self> = &'self fn(bcx: @mut Block,
tys: &ShimTypes,
llargbundle: ValueRef);
ret_builder: wrap_ret_builder) {
let _icx = push_ctxt("foreign::build_wrap_fn_");
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
+ let bcx = fcx.entry_bcx.get();
// Patch up the return type if it's not immediate and we're returning via
// the C ABI.
if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
- fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.get_llstaticallocas()),
- lloutputtype,
- ""));
+ fcx.llretptr = Some(alloca(bcx, lloutputtype, ""));
}
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
-
// Allocate the struct and write the arguments into it.
let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
arg_builder(bcx, tys, llwrapfn, llargbundle);
Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
ret_builder(bcx, tys, llargbundle);
- // Perform a custom version of `finish_fn`. First, tie up the header
- // blocks.
- tie_up_header_blocks(fcx, lltop);
-
// Then return according to the C ABI.
let return_context = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
let llretptr = BitCast(return_context, fcx.llretptr.get(), return_type.ptr_to());
Ret(return_context, Load(return_context, llretptr));
}
+ fcx.cleanup();
}
// For each foreign function F, we generate a wrapper function W and a shim
cc: lib::llvm::CallConv) {
let llwrapfn = get_item_val(ccx, id);
let tys = shim_types(ccx, id);
- if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") {
+ if attr::contains_name(foreign_item.attrs, "rust_stack") {
build_direct_fn(ccx, llwrapfn, foreign_item,
&tys, cc);
- } else if attr::attrs_contains_name(foreign_item.attrs, "fast_ffi") {
+ } else if attr::contains_name(foreign_item.attrs, "fast_ffi") {
build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
} else {
let llshimfn = build_shim_fn(ccx, foreign_item, &tys, cc);
let _icx = push_ctxt("foreign::build_shim_fn");
- fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef)
+ fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
-> ~[ValueRef] {
let _icx = push_ctxt("foreign::shim::build_args");
tys.fn_ty.build_shim_args(bcx, tys.llsig.llarg_tys, llargbundle)
}
- fn build_ret(bcx: block,
+ fn build_ret(bcx: @mut Block,
tys: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef) {
debug!("build_direct_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
debug!("build_fast_ffi_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
fn build_wrap_fn(ccx: @mut CrateContext,
build_args,
build_ret);
- fn build_args(bcx: block,
+ fn build_args(bcx: @mut Block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
}
}
- fn build_ret(bcx: block,
+ fn build_ret(bcx: @mut Block,
shim_types: &ShimTypes,
llargbundle: ValueRef) {
let _icx = push_ctxt("foreign::wrap::build_ret");
item: &ast::foreign_item,
path: ast_map::path,
substs: @param_substs,
- attributes: &[ast::attribute],
+ attributes: &[ast::Attribute],
ref_id: Option<ast::node_id>) {
debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
- fn simple_llvm_intrinsic(bcx: block, name: &'static str, num_args: uint) {
+ fn simple_llvm_intrinsic(bcx: @mut Block, name: &'static str, num_args: uint) {
assert!(num_args <= 4);
let mut args = [0 as ValueRef, ..4];
let first_real_arg = bcx.fcx.arg_pos(0u);
Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
}
- fn memcpy_intrinsic(bcx: block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
RetVoid(bcx);
}
- fn memset_intrinsic(bcx: block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
+ fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
RetVoid(bcx);
}
- fn count_zeros_intrinsic(bcx: block, name: &'static str) {
+ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
let y = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
output_type,
true,
Some(substs),
+ None,
Some(item.span));
set_always_inline(fcx.llfn);
// Set the fixed stack segment flag if necessary.
- if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
+ if attr::contains_name(attributes, "fixed_stack_segment") {
set_fixed_stack_segment(fcx.llfn);
}
- let mut bcx = top_scope_block(fcx, None);
+ let mut bcx = fcx.entry_bcx.get();
let first_real_arg = fcx.arg_pos(0u);
let nm = ccx.sess.str_of(item.ident);
}
}
+ fcx.cleanup();
return;
}
ccx.sess.span_bug(item.span, "unknown intrinsic");
}
}
+ fcx.cleanup();
}
/**
pub fn trans_foreign_fn(ccx: @mut CrateContext,
path: ast_map::path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llwrapfn: ValueRef,
id: ast::node_id) {
let _icx = push_ctxt("foreign::build_foreign_fn");
fn build_rust_fn(ccx: @mut CrateContext,
path: &ast_map::path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
id: ast::node_id)
-> ValueRef {
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
let _icx = push_ctxt("foreign::foreign::build_shim_fn");
- fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef)
+ fn build_args(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef)
-> ~[ValueRef] {
let _icx = push_ctxt("foreign::extern::shim::build_args");
let ccx = bcx.ccx();
return llargvals;
}
- fn build_ret(bcx: block,
+ fn build_ret(bcx: @mut Block,
shim_types: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef) {
build_args,
build_ret);
- fn build_args(bcx: block,
+ fn build_args(bcx: @mut Block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
llargbundle);
}
- fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) {
+ fn build_ret(bcx: @mut Block, tys: &ShimTypes, llargbundle: ValueRef) {
let _icx = push_ctxt("foreign::foreign::wrap::build_ret");
tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
}
sp: span,
path: ast_map::path,
node_id: ast::node_id,
- attrs: &[ast::attribute])
+ attrs: &[ast::Attribute])
-> ValueRef {
let _icx = push_ctxt("foreign::register_foreign_fn");
use std::str;
use syntax::ast;
-pub fn trans_free(cx: block, v: ValueRef) -> block {
+pub fn trans_free(cx: @mut Block, v: ValueRef) -> @mut Block {
let _icx = push_ctxt("trans_free");
callee::trans_lang_call(cx,
langcall(cx, None, "", FreeFnLangItem),
Some(expr::Ignore)).bcx
}
-pub fn trans_exchange_free(cx: block, v: ValueRef) -> block {
+pub fn trans_exchange_free(cx: @mut Block, v: ValueRef) -> @mut Block {
let _icx = push_ctxt("trans_exchange_free");
callee::trans_lang_call(cx,
langcall(cx, None, "", ExchangeFreeFnLangItem),
Some(expr::Ignore)).bcx
}
-pub fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+pub fn take_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
// NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("take_ty");
if ty::type_needs_drop(cx.tcx(), t) {
return cx;
}
-pub fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+pub fn drop_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
// NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("drop_ty");
if ty::type_needs_drop(cx.tcx(), t) {
return cx;
}
-pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
+pub fn drop_ty_immediate(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
let _icx = push_ctxt("drop_ty_immediate");
match ty::get(t).sty {
ty::ty_uniq(_)
}
}
-pub fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> Result {
- let _icx = push_ctxt("take_ty_immediate");
- match ty::get(t).sty {
- ty::ty_box(_) | ty::ty_opaque_box |
- ty::ty_evec(_, ty::vstore_box) |
- ty::ty_estr(ty::vstore_box) => {
- incr_refcnt_of_boxed(bcx, v);
- rslt(bcx, v)
- }
- ty::ty_uniq(_) => {
- uniq::duplicate(bcx, v, t)
- }
- ty::ty_evec(_, ty::vstore_uniq) |
- ty::ty_estr(ty::vstore_uniq) => {
- tvec::duplicate_uniq(bcx, v, t)
- }
- _ => rslt(bcx, v)
- }
-}
-
-pub fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
+pub fn free_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
// NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("free_ty");
if ty::type_needs_drop(cx.tcx(), t) {
return cx;
}
-pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
+pub fn free_ty_immediate(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
let _icx = push_ctxt("free_ty_immediate");
match ty::get(t).sty {
ty::ty_uniq(_) |
}
// See [Note-arg-mode]
-pub fn call_tydesc_glue_full(bcx: block,
+pub fn call_tydesc_glue_full(bcx: @mut Block,
v: ValueRef,
tydesc: ValueRef,
field: uint,
}
// See [Note-arg-mode]
-pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint)
- -> block {
+pub fn call_tydesc_glue(cx: @mut Block, v: ValueRef, t: ty::t, field: uint)
+ -> @mut Block {
let _icx = push_ctxt("call_tydesc_glue");
let ti = get_tydesc(cx.ccx(), t);
call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti));
return cx;
}
-pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
+pub fn make_visit_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
let _icx = push_ctxt("make_visit_glue");
do with_scope(bcx, None, "visitor cleanup") |bcx| {
let mut bcx = bcx;
}
}
-pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
+pub fn make_free_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_free_glue");
match ty::get(t).sty {
}
}
-pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
- class_did: ast::def_id, substs: &ty::substs) -> block {
+pub fn trans_struct_drop_flag(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
+ class_did: ast::def_id, substs: &ty::substs) -> @mut Block {
let repr = adt::represent_type(bcx.ccx(), t);
let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0);
do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| {
}
}
-pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
- class_did: ast::def_id, substs: &ty::substs) -> block {
+pub fn trans_struct_drop(mut bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
+ class_did: ast::def_id, substs: &ty::substs) -> @mut Block {
let repr = adt::represent_type(bcx.ccx(), t);
// Find and call the actual destructor
bcx
}
-pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) -> block {
+pub fn make_drop_glue(bcx: @mut Block, v0: ValueRef, t: ty::t) -> @mut Block {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");
let ccx = bcx.ccx();
}
// box_ptr_ptr is optional, it is constructed if not supplied.
-pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef,
+pub fn decr_refcnt_maybe_free(bcx: @mut Block, box_ptr: ValueRef,
box_ptr_ptr: Option<ValueRef>,
t: ty::t)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("decr_refcnt_maybe_free");
let ccx = bcx.ccx();
- do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
- let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
- let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
- Store(bcx, rc, rc_ptr);
- let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
- do with_cond(bcx, zero_test) |bcx| {
- match box_ptr_ptr {
- Some(p) => free_ty(bcx, p, t),
- None => free_ty_immediate(bcx, box_ptr, t)
- }
- }
- }
+ let decr_bcx = sub_block(bcx, "decr");
+ let free_bcx = sub_block(decr_bcx, "free");
+ let next_bcx = sub_block(bcx, "next");
+ CondBr(bcx, IsNotNull(bcx, box_ptr), decr_bcx.llbb, next_bcx.llbb);
+
+ let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
+ let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
+ Store(decr_bcx, rc, rc_ptr);
+ CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
+
+ let free_bcx = match box_ptr_ptr {
+ Some(p) => free_ty(free_bcx, p, t),
+ None => free_ty_immediate(free_bcx, box_ptr, t)
+ };
+ Br(free_bcx, next_bcx.llbb);
+
+ next_bcx
}
-pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
+pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
let _icx = push_ctxt("make_take_glue");
// NB: v is a *pointer* to type t here, not a direct value.
match ty::get(t).sty {
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
}
- ty::ty_uniq(_) => {
- let Result {bcx, val} = uniq::duplicate(bcx, Load(bcx, v), t);
- Store(bcx, val, v);
- bcx
- }
- ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
- let Result {bcx, val} = tvec::duplicate_uniq(bcx, Load(bcx, v), t);
- Store(bcx, val, v);
- bcx
- }
ty::ty_evec(_, ty::vstore_slice(_))
| ty::ty_estr(ty::vstore_slice(_)) => {
bcx
}
- ty::ty_closure(_) => {
+ ty::ty_closure(ty::ClosureTy { sigil: ast::BorrowedSigil, _ }) |
+ ty::ty_closure(ty::ClosureTy { sigil: ast::ManagedSigil, _ }) => {
closure::make_closure_glue(bcx, v, t, take_ty)
}
+ ty::ty_closure(ty::ClosureTy { sigil: ast::OwnedSigil, _ }) => bcx,
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
incr_refcnt_of_boxed(bcx, llbox);
// Zero out the struct
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(v));
- memzero(bcx, v, ty);
+ memzero(&B(bcx), v, ty);
}
}
}
}
-pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
+pub fn incr_refcnt_of_boxed(cx: @mut Block, box_ptr: ValueRef) {
let _icx = push_ctxt("incr_refcnt_of_boxed");
let ccx = cx.ccx();
let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]);
return inf;
}
-pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t) -> block;
+pub type glue_helper<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type,
name: &str) -> ValueRef {
// llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter.
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let rawptr0_arg = fcx.arg_pos(0u);
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
let bcx = helper(bcx, llrawptr0, t);
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
return llfn;
}
llvm::LLVMAlignOf(ty.to_ref()), cx.int_type.to_ref(), False);
}
}
+
+pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> uint {
+ unsafe {
+ return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as uint;
+ }
+}
[]);
}
-pub fn trans_self_arg(bcx: block,
+pub fn trans_self_arg(bcx: @mut Block,
base: @ast::expr,
temp_cleanups: &mut ~[ValueRef],
mentry: typeck::method_map_entry) -> Result {
DontAutorefArg)
}
-pub fn trans_method_callee(bcx: block,
+pub fn trans_method_callee(bcx: @mut Block,
callee_id: ast::node_id,
this: @ast::expr,
mentry: typeck::method_map_entry)
let self_ty = node_id_type(bcx, this.id);
// <impl_id> is the ID of the implementation of
// trait <trait_id> for type <self_ty>
- let impl_id = ty::get_impl_id(tcx, trait_id, self_ty);
+ let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty);
// Get the supertrait's methods
let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id);
// Make sure to fail with a readable error message if
// Now that we know the impl ID, we can look up the method
// ID from its name
origin = typeck::method_static(
- method_with_name_or_default(bcx.ccx(),
- impl_id,
- method_name));
+ method_with_name(bcx.ccx(), impl_id, method_name));
}
typeck::method_self(*) |
typeck::method_static(*) | typeck::method_param(*) |
}
}
-pub fn trans_static_method_callee(bcx: block,
+pub fn trans_static_method_callee(bcx: @mut Block,
method_id: ast::def_id,
trait_id: ast::def_id,
callee_id: ast::node_id)
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
- let mth_id = method_with_name_or_default(bcx.ccx(),
- impl_did,
- mname);
+ let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
- bcx, mth_id, impl_did, callee_id,
+ bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
let FnData {llfn: lval} =
}
}
-pub fn method_from_methods(ms: &[@ast::method], name: ast::ident)
- -> Option<ast::def_id> {
- ms.iter().find_(|m| m.ident == name).map(|m| ast_util::local_def(m.id))
-}
-
-pub fn method_with_name_or_default(ccx: &mut CrateContext,
- impl_id: ast::def_id,
- name: ast::ident) -> ast::def_id {
- let imp = ccx.impl_method_cache.find_copy(&(impl_id, name));
- match imp {
+pub fn method_with_name(ccx: &mut CrateContext,
+ impl_id: ast::def_id,
+ name: ast::ident) -> ast::def_id {
+ let meth_id_opt = ccx.impl_method_cache.find_copy(&(impl_id, name));
+ match meth_id_opt {
Some(m) => return m,
None => {}
}
- // None of this feels like it should be the best way to do this.
- let mut did = if impl_id.crate == ast::local_crate {
- match ccx.tcx.items.get_copy(&impl_id.node) {
- ast_map::node_item(@ast::item {
- node: ast::item_impl(_, _, _, ref ms), _
- }, _) => { method_from_methods(*ms, name) },
- _ => fail!("method_with_name")
- }
- } else {
- csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
- };
-
- if did.is_none() {
- // Look for a default method
- let pmm = ccx.tcx.provided_methods;
- match pmm.find(&impl_id) {
- Some(pmis) => {
- for pmis.iter().advance |pmi| {
- if pmi.method_info.ident == name {
- debug!("pmi.method_info.did = %?",
- pmi.method_info.did);
- did = Some(pmi.method_info.did);
- }
- }
- }
- None => {}
- }
- }
-
- let imp = did.expect("could not find method while translating");
- ccx.impl_method_cache.insert((impl_id, name), imp);
- imp
-}
+ let imp = ccx.tcx.impls.find(&impl_id)
+ .expect("could not find impl while translating");
+ let meth = imp.methods.iter().find_(|m| m.ident == name)
+ .expect("could not find method while translating");
-pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id,
- i_id: ast::def_id) -> uint {
- debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
- ty::method(ccx.tcx, m_id).generics.type_param_defs.len()
+ ccx.impl_method_cache.insert((impl_id, name), meth.def_id);
+ meth.def_id
}
-pub fn trans_monomorphized_callee(bcx: block,
+pub fn trans_monomorphized_callee(bcx: @mut Block,
callee_id: ast::node_id,
base: @ast::expr,
mentry: typeck::method_map_entry,
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
let ccx = bcx.ccx();
let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
- let mth_id = method_with_name_or_default(
- bcx.ccx(), impl_did, mname);
+ let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
// obtain the `self` value:
let mut temp_cleanups = ~[];
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
- bcx, mth_id, impl_did, callee_id,
+ bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
// translate the function
}
-pub fn combine_impl_and_methods_tps(bcx: block,
+pub fn combine_impl_and_methods_tps(bcx: @mut Block,
mth_did: ast::def_id,
- impl_did: ast::def_id,
callee_id: ast::node_id,
rcvr_substs: &[ty::t],
rcvr_origins: typeck::vtable_res)
* mapped to. */
let ccx = bcx.ccx();
- let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
+ let method = ty::method(ccx.tcx, mth_did);
+ let n_m_tps = method.generics.type_param_defs.len();
let node_substs = node_id_type_params(bcx, callee_id);
- debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(*t)));
+ debug!("rcvr_substs=%?", rcvr_substs.repr(ccx.tcx));
let ty_substs
= vec::append(rcvr_substs.to_owned(),
node_substs.tailn(node_substs.len() - n_m_tps));
debug!("n_m_tps=%?", n_m_tps);
- debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t)));
- debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t)));
+ debug!("node_substs=%?", node_substs.repr(ccx.tcx));
+ debug!("ty_substs=%?", ty_substs.repr(ccx.tcx));
// Now, do the same work for the vtables. The vtables might not
}
-pub fn trans_trait_callee(bcx: block,
+pub fn trans_trait_callee(bcx: @mut Block,
callee_id: ast::node_id,
n_method: uint,
self_expr: @ast::expr,
explicit_self)
}
-pub fn trans_trait_callee_from_llval(bcx: block,
+pub fn trans_trait_callee_from_llval(bcx: @mut Block,
callee_ty: ty::t,
n_method: uint,
llpair: ValueRef,
monomorphize::make_mono_id(
ccx,
impl_id,
- None,
&psubsts,
None)
}
/// Creates a returns a dynamic vtable for the given type and vtable origin.
/// This is used only for objects.
-pub fn get_vtable(bcx: block,
+pub fn get_vtable(bcx: @mut Block,
self_ty: ty::t,
origin: typeck::vtable_origin)
-> ValueRef {
}
/// Generates a dynamic vtable for objects.
-pub fn make_impl_vtable(bcx: block,
+pub fn make_impl_vtable(bcx: @mut Block,
impl_id: ast::def_id,
self_ty: ty::t,
substs: &[ty::t],
} else {
debug!("(making impl vtable) adding method to vtable: %s",
tcx.sess.str_of(im.ident));
- let m_id = method_with_name_or_default(ccx, impl_id, im.ident);
+ let m_id = method_with_name(ccx, impl_id, im.ident);
trans_fn_ref_with_vtables(bcx, m_id, 0,
substs, Some(vtables)).llfn
make_vtable(ccx, tydesc, methods)
}
-pub fn trans_trait_cast(bcx: block,
+pub fn trans_trait_cast(bcx: @mut Block,
val: @ast::expr,
id: ast::node_id,
dest: expr::Dest,
_store: ty::TraitStore)
- -> block {
+ -> @mut Block {
let mut bcx = bcx;
let _icx = push_ctxt("impl::trans_cast");
pub mod consts;
pub mod type_of;
pub mod build;
+pub mod builder;
pub mod base;
pub mod _match;
pub mod uniq;
real_substs: &ty::substs,
vtables: Option<typeck::vtable_res>,
self_vtable: Option<typeck::vtable_origin>,
- impl_did_opt: Option<ast::def_id>,
ref_id: Option<ast::node_id>)
-> (ValueRef, bool)
{
real_substs=%s, \
vtables=%s, \
self_vtable=%s, \
- impl_did_opt=%s, \
ref_id=%?)",
fn_id.repr(ccx.tcx),
real_substs.repr(ccx.tcx),
vtables.repr(ccx.tcx),
self_vtable.repr(ccx.tcx),
- impl_did_opt.repr(ccx.tcx),
ref_id);
assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
let param_uses = type_use::type_uses_for(ccx, fn_id, psubsts.tys.len());
- let hash_id = make_mono_id(ccx, fn_id, impl_did_opt,
- &*psubsts,
- Some(param_uses));
+ let hash_id = make_mono_id(ccx, fn_id, &*psubsts, Some(param_uses));
if hash_id.params.iter().any(
|p| match *p { mono_precise(_, _) => false, _ => true }) {
must_cast = true;
pub fn make_mono_id(ccx: @mut CrateContext,
item: ast::def_id,
- impl_did_opt: Option<ast::def_id>,
substs: ¶m_substs,
param_uses: Option<@~[type_use::type_uses]>) -> mono_id {
// FIXME (possibly #5801): Need a lot of type hints to get
}).collect()
}
};
- @mono_id_ {def: item, params: param_ids, impl_did_opt: impl_did_opt}
+ @mono_id_ {def: item, params: param_ids}
}
pub struct Reflector {
visitor_val: ValueRef,
visitor_methods: @~[@ty::Method],
- final_bcx: block,
+ final_bcx: @mut Block,
tydesc_ty: Type,
- bcx: block
+ bcx: @mut Block
}
impl Reflector {
//
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
};
- let mut bcx = top_scope_block(fcx, None);
+ let mut bcx = fcx.entry_bcx.get();
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, repr, arg);
Store(bcx, ret, fcx.llretptr.get());
Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx.llbb))
};
- finish_fn(fcx, bcx.llbb, bcx);
+ finish_fn(fcx, bcx);
llfdecl
};
}
// Emit a sequence of calls to visit_ty::visit_foo
-pub fn emit_calls_to_trait_visit_ty(bcx: block,
+pub fn emit_calls_to_trait_visit_ty(bcx: @mut Block,
t: ty::t,
visitor_val: ValueRef,
visitor_trait_id: def_id)
- -> block {
+ -> @mut Block {
let final = sub_block(bcx, "final");
let tydesc_ty = ty::get_tydesc_ty(bcx.ccx().tcx).unwrap();
let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
}
}
-pub fn get_fill(bcx: block, vptr: ValueRef) -> ValueRef {
+pub fn get_fill(bcx: @mut Block, vptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::get_fill");
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
}
-pub fn set_fill(bcx: block, vptr: ValueRef, fill: ValueRef) {
+pub fn set_fill(bcx: @mut Block, vptr: ValueRef, fill: ValueRef) {
Store(bcx, fill, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]));
}
-pub fn get_alloc(bcx: block, vptr: ValueRef) -> ValueRef {
+pub fn get_alloc(bcx: @mut Block, vptr: ValueRef) -> ValueRef {
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_alloc]))
}
-pub fn get_bodyptr(bcx: block, vptr: ValueRef, t: ty::t) -> ValueRef {
+pub fn get_bodyptr(bcx: @mut Block, vptr: ValueRef, t: ty::t) -> ValueRef {
if ty::type_contents(bcx.tcx(), t).contains_managed() {
GEPi(bcx, vptr, [0u, abi::box_field_body])
} else {
}
}
-pub fn get_dataptr(bcx: block, vptr: ValueRef) -> ValueRef {
+pub fn get_dataptr(bcx: @mut Block, vptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::get_dataptr");
GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
}
-pub fn pointer_add(bcx: block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
+pub fn pointer_add(bcx: @mut Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::pointer_add");
let old_ty = val_ty(ptr);
let bptr = PointerCast(bcx, ptr, Type::i8p());
return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty);
}
-pub fn alloc_raw(bcx: block, unit_ty: ty::t,
+pub fn alloc_raw(bcx: @mut Block, unit_ty: ty::t,
fill: ValueRef, alloc: ValueRef, heap: heap) -> Result {
let _icx = push_ctxt("tvec::alloc_uniq");
let ccx = bcx.ccx();
}
}
-pub fn alloc_uniq_raw(bcx: block, unit_ty: ty::t,
+pub fn alloc_uniq_raw(bcx: @mut Block, unit_ty: ty::t,
fill: ValueRef, alloc: ValueRef) -> Result {
alloc_raw(bcx, unit_ty, fill, alloc, base::heap_for_unique(bcx, unit_ty))
}
-pub fn alloc_vec(bcx: block,
+pub fn alloc_vec(bcx: @mut Block,
unit_ty: ty::t,
elts: uint,
heap: heap)
return rslt(bcx, vptr);
}
-pub fn duplicate_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t) -> Result {
- let _icx = push_ctxt("tvec::duplicate_uniq");
-
- let fill = get_fill(bcx, get_bodyptr(bcx, vptr, vec_ty));
- let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
- let Result {bcx, val: newptr} = alloc_uniq_raw(bcx, unit_ty, fill, fill);
-
- let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr, vec_ty));
- let new_data_ptr = get_dataptr(bcx, get_bodyptr(bcx, newptr, vec_ty));
- base::call_memcpy(bcx, new_data_ptr, data_ptr, fill, 1);
-
- let bcx = if ty::type_needs_drop(bcx.tcx(), unit_ty) {
- iter_vec_raw(bcx, new_data_ptr, vec_ty, fill, glue::take_ty)
- } else { bcx };
- return rslt(bcx, newptr);
-}
-
-pub fn make_drop_glue_unboxed(bcx: block, vptr: ValueRef, vec_ty: ty::t) ->
- block {
+pub fn make_drop_glue_unboxed(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t) ->
+ @mut Block {
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
let tcx = bcx.tcx();
let unit_ty = ty::sequence_element_type(tcx, vec_ty);
}
}
-pub fn trans_fixed_vstore(bcx: block,
+pub fn trans_fixed_vstore(bcx: @mut Block,
vstore_expr: @ast::expr,
content_expr: &ast::expr,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
//!
//
// [...] allocates a fixed-size array and moves it around "by value".
};
}
-pub fn trans_slice_vstore(bcx: block,
+pub fn trans_slice_vstore(bcx: @mut Block,
vstore_expr: @ast::expr,
content_expr: @ast::expr,
dest: expr::Dest)
- -> block {
+ -> @mut Block {
//!
//
// &[...] allocates memory on the stack and writes the values into it,
return bcx;
}
-pub fn trans_lit_str(bcx: block,
+pub fn trans_lit_str(bcx: @mut Block,
lit_expr: @ast::expr,
str_lit: @str,
dest: Dest)
- -> block {
+ -> @mut Block {
//!
//
// Literal strings translate to slices into static memory. This is
}
-pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::expr,
+pub fn trans_uniq_or_managed_vstore(bcx: @mut Block, heap: heap, vstore_expr: @ast::expr,
content_expr: &ast::expr) -> DatumBlock {
//!
//
return immediate_rvalue_bcx(bcx, val, vt.vec_ty);
}
-pub fn write_content(bcx: block,
+pub fn write_content(bcx: @mut Block,
vt: &VecTypes,
vstore_expr: @ast::expr,
content_expr: &ast::expr,
dest: Dest)
- -> block {
+ -> @mut Block {
let _icx = push_ctxt("tvec::write_content");
let mut bcx = bcx;
}
}
-pub fn vec_types_from_expr(bcx: block, vec_expr: &ast::expr) -> VecTypes {
+pub fn vec_types_from_expr(bcx: @mut Block, vec_expr: &ast::expr) -> VecTypes {
let vec_ty = node_id_type(bcx, vec_expr.id);
vec_types(bcx, vec_ty)
}
-pub fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes {
+pub fn vec_types(bcx: @mut Block, vec_ty: ty::t) -> VecTypes {
let ccx = bcx.ccx();
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
let llunit_ty = type_of::type_of(ccx, unit_ty);
llunit_size: llunit_size}
}
-pub fn elements_required(bcx: block, content_expr: &ast::expr) -> uint {
+pub fn elements_required(bcx: @mut Block, content_expr: &ast::expr) -> uint {
//! Figure out the number of elements we need to store this content
match content_expr.node {
}
}
-pub fn get_base_and_len(bcx: block,
+pub fn get_base_and_len(bcx: @mut Block,
llval: ValueRef,
vec_ty: ty::t) -> (ValueRef, ValueRef) {
//!
}
}
-pub type iter_vec_block<'self> = &'self fn(block, ValueRef, ty::t) -> block;
+pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
-pub fn iter_vec_raw(bcx: block, data_ptr: ValueRef, vec_ty: ty::t,
- fill: ValueRef, f: iter_vec_block) -> block {
+pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
+ fill: ValueRef, f: iter_vec_block) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_raw");
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
}
-pub fn iter_vec_uniq(bcx: block, vptr: ValueRef, vec_ty: ty::t,
- fill: ValueRef, f: iter_vec_block) -> block {
+pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t,
+ fill: ValueRef, f: iter_vec_block) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_uniq");
let data_ptr = get_dataptr(bcx, get_bodyptr(bcx, vptr, vec_ty));
iter_vec_raw(bcx, data_ptr, vec_ty, fill, f)
}
-pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t,
- f: iter_vec_block) -> block {
+pub fn iter_vec_unboxed(bcx: @mut Block, body_ptr: ValueRef, vec_ty: ty::t,
+ f: iter_vec_block) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_unboxed");
let fill = get_fill(bcx, body_ptr);
let dataptr = get_dataptr(bcx, body_ptr);
// used. This is imprecise, but simple. Getting it right is
// tricky because the substs on the call and the substs on the
// default method differ, because of substs on the trait/impl.
- let is_default = ccx.tcx.provided_method_sources.contains_key(&fn_id_loc);
+ let is_default = ty::provided_source(ccx.tcx, fn_id_loc).is_some();
// We also mark all of the params as used if it is an extern thing
// that we haven't been able to inline yet.
if is_default || fn_id_loc.crate != local_crate {
}
}
-pub fn handle_body(cx: &Context, body: &blk) {
+pub fn handle_body(cx: &Context, body: &Block) {
let v = visit::mk_vt(@visit::Visitor {
visit_expr: |e, (cx, v)| {
visit::visit_expr(e, (cx, v));
},
visit_local: |l, (cx, v)| {
visit::visit_local(l, (cx, v));
- node_type_needs(cx, use_repr, l.node.id);
+ node_type_needs(cx, use_repr, l.id);
},
visit_pat: |p, (cx, v)| {
visit::visit_pat(p, (cx, v));
use middle::trans::build::*;
use middle::trans::common::*;
use middle::trans::datum::immediate_rvalue;
-use middle::trans::datum;
use middle::trans::glue;
use middle::ty;
-use middle::trans::machine::llsize_of;
-use middle::trans::type_of;
-pub fn make_free_glue(bcx: block, vptrptr: ValueRef, box_ty: ty::t)
- -> block {
+pub fn make_free_glue(bcx: @mut Block, vptrptr: ValueRef, box_ty: ty::t)
+ -> @mut Block {
let _icx = push_ctxt("uniq::make_free_glue");
let box_datum = immediate_rvalue(Load(bcx, vptrptr), box_ty);
}
}
}
-
-pub fn duplicate(bcx: block, src_box: ValueRef, src_ty: ty::t) -> Result {
- let _icx = push_ctxt("uniq::duplicate");
-
- // Load the body of the source (*src)
- let src_datum = immediate_rvalue(src_box, src_ty);
- let body_datum = src_datum.box_body(bcx);
-
- // Malloc space in exchange heap and copy src into it
- if ty::type_contents(bcx.tcx(), src_ty).contains_managed() {
- let MallocResult {
- bcx: bcx,
- box: dst_box,
- body: dst_body
- } = malloc_general(bcx, body_datum.ty, heap_managed_unique);
- body_datum.copy_to(bcx, datum::INIT, dst_body);
-
- rslt(bcx, dst_box)
- } else {
- let body_datum = body_datum.to_value_datum(bcx);
- let llty = type_of(bcx.ccx(), body_datum.ty);
- let size = llsize_of(bcx.ccx(), llty);
- let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, body_datum.ty, heap_exchange, size);
- body_datum.copy_to(bcx, datum::INIT, val);
- Result { bcx: bcx, val: val }
- }
-}
use middle::trans::type_::Type;
pub fn root_and_write_guard(datum: &Datum,
- mut bcx: block,
+ mut bcx: @mut Block,
span: span,
expr_id: ast::node_id,
- derefs: uint) -> block {
+ derefs: uint) -> @mut Block {
let key = root_map_key { id: expr_id, derefs: derefs };
debug!("write_guard::root_and_write_guard(key=%?)", key);
}
}
-pub fn return_to_mut(mut bcx: block,
+pub fn return_to_mut(mut bcx: @mut Block,
root_key: root_map_key,
frozen_val_ref: ValueRef,
bits_val_ref: ValueRef,
filename_val: ValueRef,
- line_val: ValueRef) -> block {
+ line_val: ValueRef) -> @mut Block {
debug!("write_guard::return_to_mut(root_key=%?, %s, %s, %s)",
root_key,
bcx.to_str(),
}
fn root(datum: &Datum,
- mut bcx: block,
+ mut bcx: @mut Block,
span: span,
root_key: root_map_key,
- root_info: RootInfo) -> block {
+ root_info: RootInfo) -> @mut Block {
//! In some cases, borrowck will decide that an @T/@[]/@str
//! value must be rooted for the program to be safe. In that
//! case, we will call this function, which will stash a copy
}
fn perform_write_guard(datum: &Datum,
- bcx: block,
- span: span) -> block {
+ bcx: @mut Block,
+ span: span) -> @mut Block {
debug!("perform_write_guard");
let llval = datum.to_value_llval(bcx);
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
use middle::lang_items::OpaqueStructLangItem;
use middle::freevars;
-use middle::resolve::{Impl, MethodInfo};
use middle::resolve;
use middle::ty;
use middle::subst::Subst;
use syntax::abi::AbiSet;
use syntax;
+pub static INITIAL_DISCRIMINANT_VALUE: int = 0;
+
// Data types
#[deriving(Eq, IterBytes)]
fty: BareFnTy,
explicit_self: ast::explicit_self_,
vis: ast::visibility,
- def_id: ast::def_id
+ def_id: ast::def_id,
+ container_id: ast::def_id,
+
+ // If this method is provided, we need to know where it came from
+ provided_source: Option<ast::def_id>
}
impl Method {
fty: BareFnTy,
explicit_self: ast::explicit_self_,
vis: ast::visibility,
- def_id: ast::def_id)
+ def_id: ast::def_id,
+ container_id: ast::def_id,
+ provided_source: Option<ast::def_id>)
-> Method {
// Check the invariants.
if explicit_self == ast::sty_static {
fty: fty,
explicit_self: explicit_self,
vis: vis,
- def_id: def_id
+ def_id: def_id,
+ container_id: container_id,
+ provided_source: provided_source
}
}
}
+pub struct Impl {
+ did: def_id,
+ ident: ident,
+ methods: ~[@Method]
+}
+
#[deriving(Clone, Eq, IterBytes)]
pub struct mt {
ty: t,
AutoUnsafe(ast::mutability)
}
-// Stores information about provided methods (a.k.a. default methods) in
-// implementations.
-//
-// This is a map from ID of each implementation to the method info and trait
-// method ID of each of the default methods belonging to the trait that
-// implementation implements.
-pub type ProvidedMethodsMap = @mut HashMap<def_id,@mut ~[@ProvidedMethodInfo]>;
-
-// Stores the method info and definition ID of the associated trait method for
-// each instantiation of each provided method.
-pub struct ProvidedMethodInfo {
- method_info: @MethodInfo,
- trait_method_def_id: def_id
-}
-
-pub struct ProvidedMethodSource {
- method_id: ast::def_id,
- impl_id: ast::def_id
-}
-
pub type ctxt = @ctxt_;
struct ctxt_ {
needs_unwind_cleanup_cache: @mut HashMap<t, bool>,
tc_cache: @mut HashMap<uint, TypeContents>,
ast_ty_to_ty_cache: @mut HashMap<node_id, ast_ty_to_ty_cache_entry>,
- enum_var_cache: @mut HashMap<def_id, @~[VariantInfo]>,
+ enum_var_cache: @mut HashMap<def_id, @~[@VariantInfo]>,
ty_param_defs: @mut HashMap<ast::node_id, TypeParameterDef>,
adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>,
normalized_cache: @mut HashMap<t, t>,
lang_items: middle::lang_items::LanguageItems,
- // A mapping from an implementation ID to the method info and trait
- // method ID of the provided (a.k.a. default) methods in the traits that
- // that implementation implements.
- provided_methods: ProvidedMethodsMap,
- provided_method_sources: @mut HashMap<ast::def_id, ProvidedMethodSource>,
+ // A mapping of fake provided method def_ids to the default implementation
+ provided_method_sources: @mut HashMap<ast::def_id, ast::def_id>,
supertraits: @mut HashMap<ast::def_id, @~[@TraitRef]>,
// A mapping from the def ID of an enum or struct type to the def ID
// A method will be in this list if and only if it is a destructor.
destructors: @mut HashSet<ast::def_id>,
- // Maps a trait onto a mapping from self-ty to impl
- trait_impls: @mut HashMap<ast::def_id, @mut HashMap<t, @Impl>>,
+ // Maps a trait onto a list of impls of that trait.
+ trait_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,
- // Maps a base type to its impl
- base_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,
+ // Maps a def_id of a type to a list of its inherent impls.
+ // Contains implementations of methods that are inherent to a type.
+ // Methods in these implementations don't need to be exported.
+ inherent_impls: @mut HashMap<ast::def_id, @mut ~[@Impl]>,
+
+ // Maps a def_id of an impl to an Impl structure.
+ // Note that this contains all of the impls that we know about,
+ // including ones in other crates. It's not clear that this is the best
+ // way to do it.
+ impls: @mut HashMap<ast::def_id, @Impl>,
// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
// present in this set can be warned about.
return @mut HashMap::new();
}
-pub fn new_ty_hash<V>() -> @mut HashMap<t, V> {
+pub fn new_ty_hash<V:'static>() -> @mut HashMap<t, V> {
@mut HashMap::new()
}
adjustments: @mut HashMap::new(),
normalized_cache: new_ty_hash(),
lang_items: lang_items,
- provided_methods: @mut HashMap::new(),
provided_method_sources: @mut HashMap::new(),
supertraits: @mut HashMap::new(),
destructor_for_type: @mut HashMap::new(),
destructors: @mut HashSet::new(),
trait_impls: @mut HashMap::new(),
- base_impls: @mut HashMap::new(),
+ inherent_impls: @mut HashMap::new(),
+ impls: @mut HashMap::new(),
used_unsafe: @mut HashSet::new(),
used_mut_nodes: @mut HashSet::new(),
}
}
// Type accessors for AST nodes
-pub fn block_ty(cx: ctxt, b: &ast::blk) -> t {
+pub fn block_ty(cx: ctxt, b: &ast::Block) -> t {
return node_id_to_type(cx, b.id);
}
}
}
+pub fn provided_source(cx: ctxt, id: ast::def_id)
+ -> Option<ast::def_id> {
+ cx.provided_method_sources.find(&id).map(|x| **x)
+}
+
pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@Method] {
if is_local(id) {
match cx.items.find(&id.node) {
}
-pub fn add_base_impl(cx: ctxt, base_def_id: def_id, implementation: @Impl) {
- let implementations;
- match cx.base_impls.find(&base_def_id) {
- None => {
- implementations = @mut ~[];
- cx.base_impls.insert(base_def_id, implementations);
- }
- Some(&existing) => {
- implementations = existing;
- }
- }
- implementations.push(implementation);
-}
-
pub fn trait_methods(cx: ctxt, trait_did: ast::def_id) -> @~[@Method] {
match cx.trait_methods_cache.find(&trait_did) {
Some(&methods) => methods,
// Enum information
#[deriving(Clone)]
-pub struct VariantInfo_ {
+pub struct VariantInfo {
args: ~[t],
+ arg_names: Option<~[ast::ident]>,
ctor_ty: t,
name: ast::ident,
id: ast::def_id,
vis: visibility
}
-pub type VariantInfo = @VariantInfo_;
+impl VariantInfo {
+
+ /// Creates a new VariantInfo from the corresponding ast representation.
+ ///
+ /// Does not do any caching of the value in the type context.
+ pub fn from_ast_variant(cx: ctxt,
+ ast_variant: &ast::variant,
+ discriminant: int) -> VariantInfo {
+
+ let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
+
+ match ast_variant.node.kind {
+ ast::tuple_variant_kind(ref args) => {
+ let arg_tys = if args.len() > 0 { ty_fn_args(ctor_ty).map(|a| *a) } else { ~[] };
+
+ return VariantInfo {
+ args: arg_tys,
+ arg_names: None,
+ ctor_ty: ctor_ty,
+ name: ast_variant.node.name,
+ id: ast_util::local_def(ast_variant.node.id),
+ disr_val: discriminant,
+ vis: ast_variant.node.vis
+ };
+ },
+ ast::struct_variant_kind(ref struct_def) => {
+
+ let fields: &[@struct_field] = struct_def.fields;
+
+ assert!(fields.len() > 0);
+
+ let arg_tys = ty_fn_args(ctor_ty).map(|a| *a);
+ let arg_names = do fields.map |field| {
+ match field.node.kind {
+ named_field(ident, _) => ident,
+ unnamed_field => cx.sess.bug(
+ "enum_variants: all fields in struct must have a name")
+ }
+ };
+
+ return VariantInfo {
+ args: arg_tys,
+ arg_names: Some(arg_names),
+ ctor_ty: ctor_ty,
+ name: ast_variant.node.name,
+ id: ast_util::local_def(ast_variant.node.id),
+ disr_val: discriminant,
+ vis: ast_variant.node.vis
+ };
+ }
+ }
+ }
+}
pub fn substd_enum_variants(cx: ctxt,
id: ast::def_id,
substs: &substs)
- -> ~[VariantInfo] {
+ -> ~[@VariantInfo] {
do enum_variants(cx, id).iter().transform |variant_info| {
let substd_args = variant_info.args.iter()
.transform(|aty| subst(cx, substs, *aty)).collect();
let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty);
- @VariantInfo_ {
+ @VariantInfo {
args: substd_args,
ctor_ty: substd_ctor_ty,
..(**variant_info).clone()
}
}
-pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] {
+pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {
match cx.enum_var_cache.find(&id) {
Some(&variants) => return variants,
_ => { /* fallthrough */ }
node: ast::item_enum(ref enum_definition, _),
_
}, _) => {
- let mut disr_val = -1;
+ let mut last_discriminant: Option<int> = None;
@enum_definition.variants.iter().transform(|variant| {
- let ctor_ty = node_id_to_type(cx, variant.node.id);
-
- match variant.node.kind {
- ast::tuple_variant_kind(ref args) => {
- let arg_tys = if args.len() > 0u {
- ty_fn_args(ctor_ty).map(|a| *a) }
- else {
- ~[]
- };
-
- match variant.node.disr_expr {
- Some (ex) => {
- disr_val = match const_eval::eval_const_expr(cx,
- ex) {
- const_eval::const_int(val) => val as int,
- _ => cx.sess.bug("enum_variants: bad disr expr")
- }
- }
- _ => disr_val += 1
+ let mut discriminant = match last_discriminant {
+ Some(val) => val + 1,
+ None => INITIAL_DISCRIMINANT_VALUE
+ };
+
+ 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 int,
+ Ok(_) => {
+ cx.sess.span_err(e.span, "expected signed integer constant");
}
- @VariantInfo_{
- args: arg_tys,
- ctor_ty: ctor_ty,
- name: variant.node.name,
- id: ast_util::local_def(variant.node.id),
- disr_val: disr_val,
- vis: variant.node.vis
- }
- },
- ast::struct_variant_kind(struct_def) => {
- let arg_tys =
- // Is this check needed for structs too, or are they always guaranteed
- // to have a valid constructor function?
- if struct_def.fields.len() > 0 {
- ty_fn_args(ctor_ty).map(|a| *a)
- } else {
- ~[]
- };
-
- assert!(variant.node.disr_expr.is_none());
- disr_val += 1;
-
- @VariantInfo_{
- args: arg_tys,
- ctor_ty: ctor_ty,
- name: variant.node.name,
- id: ast_util::local_def(variant.node.id),
- disr_val: disr_val,
- vis: variant.node.vis
+ Err(ref err) => {
+ cx.sess.span_err(e.span, fmt!("expected constant: %s", (*err)));
}
- }
- }
+ },
+ None => {}
+ };
+
+ let variant_info = @VariantInfo::from_ast_variant(cx, variant, discriminant);
+ last_discriminant = Some(discriminant);
+ variant_info
+
}).collect()
}
_ => cx.sess.bug("enum_variants: id not bound to an enum")
pub fn enum_variant_with_id(cx: ctxt,
enum_id: ast::def_id,
variant_id: ast::def_id)
- -> VariantInfo {
+ -> @VariantInfo {
let variants = enum_variants(cx, enum_id);
let mut i = 0;
while i < variants.len() {
&ast_map::node_item(@ast::item {
attrs: ref attrs,
_
- }, _)) => attr::attrs_contains_name(*attrs, attr),
+ }, _)) => attr::contains_name(*attrs, attr),
_ => tcx.sess.bug(fmt!("has_attr: %? is not an item",
did))
}
return total;
}
-// Given a trait and a type, returns the impl of that type
-pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id {
+// Given a trait and a type, returns the impl of that type.
+// This is broken, of course, by parametric impls. This used to use
+// a table specifically for this mapping, but I removed that table.
+// This is only used when calling a supertrait method from a default method,
+// and should go away once I fix how that works. -sully
+pub fn bogus_get_impl_id_from_ty(tcx: ctxt,
+ trait_id: def_id, self_ty: t) -> def_id {
match tcx.trait_impls.find(&trait_id) {
- Some(ty_to_impl) => match ty_to_impl.find(&self_ty) {
- Some(the_impl) => the_impl.did,
- None => // try autoderef!
- match deref(tcx, self_ty, false) {
- Some(some_ty) => get_impl_id(tcx, trait_id, some_ty.ty),
- None => tcx.sess.bug("get_impl_id: no impl of trait for \
- this type")
+ Some(ty_to_impl) => {
+ for ty_to_impl.iter().advance |imp| {
+ let impl_ty = tcx.tcache.get_copy(&imp.did);
+ if impl_ty.ty == self_ty { return imp.did; }
+ }
+ // try autoderef!
+ match deref(tcx, self_ty, false) {
+ Some(some_ty) =>
+ bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty),
+ None => tcx.sess.bug("get_impl_id: no impl of trait for \
+ this type")
}
},
None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls")
for opt_applicable_traits.iter().advance |applicable_traits| {
for applicable_traits.iter().advance |trait_did| {
// Look for explicit implementations.
- let opt_impl_infos =
- self.fcx.ccx.coherence_info.extension_methods.find(trait_did);
+ let opt_impl_infos = self.tcx().trait_impls.find(trait_did);
for opt_impl_infos.iter().advance |impl_infos| {
for impl_infos.iter().advance |impl_info| {
self.push_candidates_from_impl(
}
pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
- let opt_impl_infos =
- self.fcx.ccx.coherence_info.inherent_methods.find(&did);
+ let opt_impl_infos = self.tcx().inherent_impls.find(&did);
for opt_impl_infos.iter().advance |impl_infos| {
for impl_infos.iter().advance |impl_info| {
self.push_candidates_from_impl(
pub fn push_candidates_from_impl(&self,
candidates: &mut ~[Candidate],
- impl_info: &resolve::Impl) {
+ impl_info: &ty::Impl) {
if !self.impl_dups.insert(impl_info.did) {
return; // already visited
}
}
};
- let method = ty::method(self.tcx(), impl_info.methods[idx].did);
+ let method = ty::method(self.tcx(), impl_info.methods[idx].def_id);
// determine the `self` of the impl with fresh
// variables for each parameter:
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::lint::unreachable_code;
-use middle::ty::{FnSig, VariantInfo_};
+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;
PurityState { def: def, purity: purity, from_fn: true }
}
- pub fn recurse(&mut self, blk: &ast::blk) -> PurityState {
+ pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
match self.purity {
// If this unsafe, then if the outer function was already marked as
// unsafe we shouldn't attribute the unsafe'ness to the block. This
}
}
-pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) {
+pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
let visit = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a| check_item(ccx, a),
.. *visit::default_simple_visitor()
pub fn check_bare_fn(ccx: @mut CrateCtxt,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
id: ast::node_id,
self_info: Option<SelfInfo>) {
let fty = ty::node_id_to_type(ccx.tcx, id);
fn_sig: &ty::FnSig,
decl: &ast::fn_decl,
id: ast::node_id,
- body: &ast::blk,
+ body: &ast::Block,
fn_kind: FnKind,
inherited_isr: isr_alist,
inherited: @inherited) -> @mut FnCtxt
fn gather_locals(fcx: @mut FnCtxt,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
arg_tys: &[ty::t],
opt_self_info: Option<SelfInfo>) {
let tcx = fcx.ccx.tcx;
}
// Add explicitly-declared locals.
- let visit_local: @fn(@ast::local, ((), visit::vt<()>)) =
+ let visit_local: @fn(@ast::Local, ((), visit::vt<()>)) =
|local, (e, v)| {
- let o_ty = match local.node.ty.node {
+ let o_ty = match local.ty.node {
ast::ty_infer => None,
- _ => Some(fcx.to_ty(&local.node.ty))
+ _ => Some(fcx.to_ty(&local.ty))
};
- assign(local.node.id, o_ty);
+ assign(local.id, o_ty);
debug!("Local variable %s is assigned type %s",
- fcx.pat_to_str(local.node.pat),
+ fcx.pat_to_str(local.pat),
fcx.infcx().ty_to_str(
- fcx.inh.locals.get_copy(&local.node.id)));
+ fcx.inh.locals.get_copy(&local.id)));
visit::visit_local(local, (e, v));
};
visit::visit_pat(p, (e, v));
};
- let visit_block: @fn(&ast::blk, ((), visit::vt<()>)) = |b, (e, v)| {
+ let visit_block: @fn(&ast::Block, ((), visit::vt<()>)) = |b, (e, v)| {
// non-obvious: the `blk` variable maps to region lb, so
// we have to keep this up-to-date. This
// is... unfortunate. It'd be nice to not need this.
// Don't descend into fns and items
fn visit_fn(_fk: &visit::fn_kind, _decl: &ast::fn_decl,
- _body: &ast::blk, _sp: span,
+ _body: &ast::Block, _sp: span,
_id: ast::node_id, (_t,_v): ((), visit::vt<()>)) {
}
fn visit_item(_i: @ast::item, (_e,_v): ((), visit::vt<()>)) { }
// or if-check
fn check_then_else(fcx: @mut FnCtxt,
cond_expr: @ast::expr,
- then_blk: &ast::blk,
+ then_blk: &ast::Block,
opt_else_expr: Option<@ast::expr>,
id: ast::node_id,
sp: span,
expr: @ast::expr,
ast_sigil_opt: Option<ast::Sigil>,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
fn_kind: FnKind,
expected: Option<ty::t>) {
let tcx = fcx.ccx.tcx;
node_id: ast::node_id,
substitutions: ty::substs,
field_types: &[ty::field_ty],
- ast_fields: &[ast::field],
+ ast_fields: &[ast::Field],
check_completeness: bool) {
let tcx = fcx.ccx.tcx;
for ast_fields.iter().advance |field| {
let mut expected_field_type = ty::mk_err();
- let pair = class_field_map.find(&field.node.ident).
+ let pair = class_field_map.find(&field.ident).
map_consume(|x| *x);
match pair {
None => {
tcx.sess.span_err(
field.span,
fmt!("structure has no field named `%s`",
- tcx.sess.str_of(field.node.ident)));
+ tcx.sess.str_of(field.ident)));
error_happened = true;
}
Some((_, true)) => {
tcx.sess.span_err(
field.span,
fmt!("field `%s` specified more than once",
- tcx.sess.str_of(field.node.ident)));
+ tcx.sess.str_of(field.ident)));
error_happened = true;
}
Some((field_id, false)) => {
ty::lookup_field_type(
tcx, class_id, field_id, &substitutions);
class_field_map.insert(
- field.node.ident, (field_id, true));
+ field.ident, (field_id, true));
fields_found += 1;
}
}
// an error, so we can continue typechecking
check_expr_coercable_to_type(
fcx,
- field.node.expr,
+ field.expr,
expected_field_type);
}
id: ast::node_id,
span: codemap::span,
class_id: ast::def_id,
- fields: &[ast::field],
+ fields: &[ast::Field],
base_expr: Option<@ast::expr>) {
let tcx = fcx.ccx.tcx;
span: codemap::span,
enum_id: ast::def_id,
variant_id: ast::def_id,
- fields: &[ast::field]) {
+ fields: &[ast::Field]) {
let tcx = fcx.ccx.tcx;
// Look up the number of type parameters and the raw type, and
check_expr_coercable_to_type(fcx, init, local_ty)
}
-pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) {
+pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::Local) {
let tcx = fcx.ccx.tcx;
- let t = fcx.local_ty(local.span, local.node.id);
- fcx.write_ty(local.node.id, t);
+ let t = fcx.local_ty(local.span, local.id);
+ fcx.write_ty(local.id, t);
- match local.node.init {
+ match local.init {
Some(init) => {
- check_decl_initializer(fcx, local.node.id, init);
+ check_decl_initializer(fcx, local.id, init);
let init_ty = fcx.expr_ty(init);
if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
- fcx.write_ty(local.node.id, init_ty);
+ fcx.write_ty(local.id, init_ty);
}
}
_ => {}
let pcx = pat_ctxt {
fcx: fcx,
- map: pat_id_map(tcx.def_map, local.node.pat),
+ map: pat_id_map(tcx.def_map, local.pat),
};
- _match::check_pat(&pcx, local.node.pat, t);
- let pat_ty = fcx.node_ty(local.node.pat.id);
+ _match::check_pat(&pcx, local.pat, t);
+ let pat_ty = fcx.node_ty(local.pat.id);
if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
- fcx.write_ty(local.node.id, pat_ty);
+ fcx.write_ty(local.id, pat_ty);
}
}
match decl.node {
ast::decl_local(ref l) => {
check_decl_local(fcx, *l);
- let l_t = fcx.node_ty(l.node.id);
+ let l_t = fcx.node_ty(l.id);
saw_bot = saw_bot || ty::type_is_bot(l_t);
saw_err = saw_err || ty::type_is_error(l_t);
}
}
}
-pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::blk) {
+pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::Block) {
check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
let blkty = fcx.node_ty(blk.id);
if ty::type_is_error(blkty) {
}
}
-pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::blk) {
+pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::Block) {
check_block_with_expected(fcx0, blk, None)
}
pub fn check_block_with_expected(fcx: @mut FnCtxt,
- blk: &ast::blk,
+ blk: &ast::Block,
expected: Option<ty::t>) {
let purity_state = fcx.ps.recurse(blk);
let prev = replace(&mut fcx.ps, purity_state);
vs: &[ast::variant],
id: ast::node_id) {
fn do_check(ccx: @mut CrateCtxt,
- _sp: span,
vs: &[ast::variant],
- id: ast::node_id,
- disr_vals: &mut ~[int],
- disr_val: &mut int,
- variants: &mut ~[ty::VariantInfo]) {
+ id: ast::node_id)
+ -> ~[@ty::VariantInfo] {
+
let rty = ty::node_id_to_type(ccx.tcx, id);
- for vs.iter().advance |v| {
- for v.node.disr_expr.iter().advance |e_ref| {
- let e = *e_ref;
- debug!("disr expr, checking %s",
- pprust::expr_to_str(e, ccx.tcx.sess.intr()));
- let declty = ty::mk_int();
- let fcx = blank_fn_ctxt(ccx, rty, e.id);
- check_const_with_ty(fcx, e.span, e, declty);
- // check_expr (from check_const pass) doesn't guarantee
- // that the expression is in an form that eval_const_expr can
- // 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)) => {
- *disr_val = val as int;
- }
- Ok(_) => {
- ccx.tcx.sess.span_err(e.span, "expected signed integer \
- constant");
- }
- Err(ref err) => {
- ccx.tcx.sess.span_err(e.span,
- fmt!("expected constant: %s", (*err)));
+ let mut variants: ~[@ty::VariantInfo] = ~[];
+ let mut disr_vals: ~[int] = ~[];
+ let mut prev_disr_val: Option<int> = None;
- }
- }
- }
- if disr_vals.contains(&*disr_val) {
- ccx.tcx.sess.span_err(v.span,
- "discriminator value already exists");
- }
- disr_vals.push(*disr_val);
- let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
+ for vs.iter().advance |v| {
- let this_disr_val = *disr_val;
- *disr_val += 1;
+ // If the discriminant value is specified explicitly in the enum check whether the
+ // initialization expression is valid, otherwise use the last value plus one.
+ let mut current_disr_val = match prev_disr_val {
+ Some(prev_disr_val) => prev_disr_val + 1,
+ None => ty::INITIAL_DISCRIMINANT_VALUE
+ };
- let arg_tys = match v.node.kind {
- ast::tuple_variant_kind(ref args) if args.len() > 0u => {
- Some(ty::ty_fn_args(ctor_ty).map(|a| *a))
- }
- ast::tuple_variant_kind(_) => {
- Some(~[])
- }
- ast::struct_variant_kind(_) => {
- Some(ty::lookup_struct_fields(
- ccx.tcx, local_def(v.node.id)).map(|cf|
- ty::node_id_to_type(ccx.tcx, cf.id.node)))
- }
+ match v.node.disr_expr {
+ Some(e) => {
+ debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr()));
+
+ let declty = ty::mk_int();
+ let fcx = blank_fn_ctxt(ccx, rty, e.id);
+ check_const_with_ty(fcx, e.span, e, declty);
+ // check_expr (from check_const pass) doesn't guarantee
+ // that the expression is in an form that eval_const_expr can
+ // 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 int,
+ Ok(_) => {
+ ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
+ }
+ Err(ref err) => {
+ ccx.tcx.sess.span_err(e.span, fmt!("expected constant: %s", (*err)));
+ }
+ }
+ },
+ None => ()
};
- match arg_tys {
- None => {}
- Some(arg_tys) => {
- variants.push(
- @VariantInfo_{args: arg_tys, ctor_ty: ctor_ty,
- name: v.node.name, id: local_def(v.node.id),
- disr_val: this_disr_val, vis: v.node.vis});
- }
+ // Check for duplicate discriminator values
+ if disr_vals.contains(¤t_disr_val) {
+ ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
}
+ disr_vals.push(current_disr_val);
+
+ let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val);
+ prev_disr_val = Some(current_disr_val);
+
+ variants.push(variant_info);
}
+
+ return variants;
}
let rty = ty::node_id_to_type(ccx.tcx, id);
- let mut disr_vals: ~[int] = ~[];
- let mut disr_val = 0;
- let mut variants = ~[];
- do_check(ccx, sp, vs, id, &mut disr_vals, &mut disr_val, &mut variants);
+ let variants = do_check(ccx, vs, id);
// cache so that ty::enum_variants won't repeat this work
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
}
// Returns true if b contains a break that can exit from b
-pub fn may_break(cx: ty::ctxt, id: ast::node_id, b: &ast::blk) -> bool {
+pub fn may_break(cx: ty::ctxt, id: ast::node_id, b: &ast::Block) -> bool {
// First: is there an unlabeled break immediately
// inside the loop?
(loop_query(b, |e| {
fcx.infcx().resolve_regions();
}
-pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) {
+pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::Block) {
let rcx = @mut Rcx { fcx: fcx, errors_reported: 0,
repeating_scope: blk.id };
if fcx.err_count_since_creation() == 0 {
// Ignore items
}
-fn visit_block(b: &ast::blk, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_block(b: &ast::Block, (rcx, v): (@mut Rcx, rvt)) {
rcx.fcx.tcx().region_maps.record_cleanup_scope(b.id);
visit::visit_block(b, (rcx, v));
}
visit::visit_arm(arm, (rcx, v));
}
-fn visit_local(l: @ast::local, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_local(l: @ast::Local, (rcx, v): (@mut Rcx, rvt)) {
// see above
- constrain_bindings_in_pat(l.node.pat, rcx);
+ constrain_bindings_in_pat(l.pat, rcx);
visit::visit_local(l, (rcx, v));
}
let mut impls_seen = HashSet::new();
- match vcx.ccx.coherence_info.extension_methods.find(&trait_ref.def_id) {
+ match tcx.trait_impls.find(&trait_ref.def_id) {
None => {
// Nothing found. Continue.
}
// 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::blk) {
+pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::Block) {
visit::visit_block(bl, (fcx, visit::mk_vt(@visit::Visitor {
visit_expr: resolve_expr,
visit_item: |_,_| {},
visit::visit_expr(e, (wbcx, v));
}
-fn visit_block(b: &ast::blk, (wbcx, v): (@mut WbCtxt, wb_vt)) {
+fn visit_block(b: &ast::Block, (wbcx, v): (@mut WbCtxt, wb_vt)) {
if !wbcx.success {
return;
}
visit::visit_pat(p, (wbcx, v));
}
-fn visit_local(l: @ast::local, (wbcx, v): (@mut WbCtxt, wb_vt)) {
+fn visit_local(l: @ast::Local, (wbcx, v): (@mut WbCtxt, wb_vt)) {
if !wbcx.success { return; }
- let var_ty = wbcx.fcx.local_ty(l.span, l.node.id);
+ let var_ty = wbcx.fcx.local_ty(l.span, l.id);
match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) {
Ok(lty) => {
debug!("Type for local %s (id %d) resolved to %s",
- pat_to_str(l.node.pat, wbcx.fcx.tcx().sess.intr()),
- l.node.id,
+ pat_to_str(l.pat, wbcx.fcx.tcx().sess.intr()),
+ l.id,
wbcx.fcx.infcx().ty_to_str(lty));
- write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty);
+ write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.id, lty);
}
Err(e) => {
wbcx.fcx.ccx.tcx.sess.span_err(
pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt,
decl: &ast::fn_decl,
- blk: &ast::blk,
+ blk: &ast::Block,
self_info: Option<SelfInfo>) -> bool {
let wbcx = @mut WbCtxt { fcx: fcx, success: true };
let visit = mk_visitor();
use metadata::csearch::{each_path, get_impl_trait};
use metadata::csearch;
-use metadata::cstore::{CStore, iter_crate_data};
+use metadata::cstore::iter_crate_data;
use metadata::decoder::{dl_def, dl_field, dl_impl};
-use middle::resolve::{Impl, MethodInfo};
-use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, get};
+use middle::ty::get;
use middle::ty::{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::{type_is_ty_var};
use middle::subst::Subst;
use middle::ty;
+use middle::ty::{Impl, Method};
use middle::typeck::CrateCtxt;
use middle::typeck::infer::combine::Combine;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
use middle::typeck::infer;
-use syntax::ast::{crate, def_id, def_struct, def_ty};
+use syntax::ast::{Crate, def_id, def_struct, def_ty};
use syntax::ast::{item, item_enum, item_impl, item_mod, item_struct};
-use syntax::ast::{local_crate, method, trait_ref, ty_path};
+use syntax::ast::{local_crate, trait_ref, ty_path};
use syntax::ast;
use syntax::ast_map::node_item;
use syntax::ast_map;
}
}
-
-pub fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
- @MethodInfo {
- did: local_def(ast_method.id),
- n_tps: ast_method.generics.ty_params.len(),
- ident: ast_method.ident,
- explicit_self: ast_method.explicit_self.node
- }
-}
-
-pub struct CoherenceInfo {
- // Contains implementations of methods that are inherent to a type.
- // Methods in these implementations don't need to be exported.
- inherent_methods: @mut HashMap<def_id, @mut ~[@Impl]>,
-
- // Contains implementations of methods associated with a trait. For these,
- // the associated trait must be imported at the call site.
- extension_methods: @mut HashMap<def_id, @mut ~[@Impl]>,
-}
-
-pub fn CoherenceInfo() -> CoherenceInfo {
- CoherenceInfo {
- inherent_methods: @mut HashMap::new(),
- extension_methods: @mut HashMap::new(),
- }
-}
-
pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
CoherenceChecker {
crate_context: crate_context,
}
impl CoherenceChecker {
- pub fn check_coherence(self, crate: &crate) {
+ pub fn check_coherence(self, crate: &Crate) {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
// builds up the trait inheritance table.
}
}
- // We only want to generate one Impl structure. When we generate one,
- // we store it here so that we don't recreate it.
- let mut implementation_opt = None;
+ let implementation = self.create_impl_from_item(item);
+
for associated_traits.iter().advance |associated_trait| {
- let trait_ref =
- ty::node_id_to_trait_ref(
- self.crate_context.tcx,
- associated_trait.ref_id);
+ let trait_ref = ty::node_id_to_trait_ref(
+ self.crate_context.tcx, associated_trait.ref_id);
debug!("(checking implementation) adding impl for trait '%s', item '%s'",
trait_ref.repr(self.crate_context.tcx),
self.crate_context.tcx.sess.str_of(item.ident));
- self.instantiate_default_methods(local_def(item.id), trait_ref);
-
- let implementation;
- if implementation_opt.is_none() {
- implementation = self.create_impl_from_item(item);
- implementation_opt = Some(implementation);
- }
-
- self.add_trait_method(trait_ref.def_id, implementation_opt.get());
+ self.add_trait_impl(trait_ref.def_id, implementation);
}
// Add the implementation to the mapping from implementation to base
Some(base_type_def_id) => {
// XXX: Gather up default methods?
if associated_traits.len() == 0 {
- let implementation;
- match implementation_opt {
- None => {
- implementation =
- self.create_impl_from_item(item);
- }
- Some(existing_implementation) => {
- implementation = existing_implementation;
- }
- }
-
- self.add_inherent_method(base_type_def_id,
- implementation);
+ self.add_inherent_impl(base_type_def_id, implementation);
}
self.base_type_def_ids.insert(local_def(item.id),
base_type_def_id);
}
}
+
+ tcx.impls.insert(implementation.did, implementation);
}
// Creates default method IDs and performs type substitutions for an impl
// `ProvidedMethodInfo` instance into the `provided_method_sources` map.
pub fn instantiate_default_methods(&self,
impl_id: ast::def_id,
- trait_ref: &ty::TraitRef) {
+ trait_ref: &ty::TraitRef,
+ all_methods: &mut ~[@Method]) {
let tcx = self.crate_context.tcx;
debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)",
impl_id, trait_ref.repr(tcx));
impl_id,
trait_ref,
new_did,
- *trait_method);
+ *trait_method,
+ Some(trait_method.def_id));
debug!("new_method_ty=%s", new_method_ty.repr(tcx));
+ all_methods.push(new_method_ty);
// construct the polytype for the method based on the method_ty
let new_generics = ty::Generics {
// Pair the new synthesized ID up with the
// ID of the method.
- let source = ProvidedMethodSource {
- method_id: trait_method.def_id,
- impl_id: impl_id
- };
-
- self.crate_context.tcx.provided_method_sources.insert(new_did,
- source);
-
- let provided_method_info =
- @ProvidedMethodInfo {
- method_info: @MethodInfo {
- did: new_did,
- n_tps: trait_method.generics.type_param_defs.len(),
- ident: trait_method.ident,
- explicit_self: trait_method.explicit_self
- },
- trait_method_def_id: trait_method.def_id
- };
-
- let pmm = self.crate_context.tcx.provided_methods;
- match pmm.find(&impl_id) {
- Some(&mis) => {
- // If the trait already has an entry in the
- // provided_methods_map, we just need to add this
- // method to that entry.
- debug!("(checking implementation) adding method `%s` \
- to entry for existing trait",
- self.crate_context.tcx.sess.str_of(
- provided_method_info.method_info.ident));
- mis.push(provided_method_info);
- }
- None => {
- // If the trait doesn't have an entry yet, create one.
- debug!("(checking implementation) creating new entry \
- for method `%s`",
- self.crate_context.tcx.sess.str_of(
- provided_method_info.method_info.ident));
- pmm.insert(impl_id,
- @mut ~[provided_method_info]);
- }
- }
+ self.crate_context.tcx.provided_method_sources
+ .insert(new_did, trait_method.def_id);
}
}
- pub fn add_inherent_method(&self,
- base_def_id: def_id,
- implementation: @Impl) {
+ pub fn add_inherent_impl(&self,
+ base_def_id: def_id,
+ implementation: @Impl) {
+ let tcx = self.crate_context.tcx;
let implementation_list;
- match self.crate_context.coherence_info.inherent_methods
- .find(&base_def_id) {
+ match tcx.inherent_impls.find(&base_def_id) {
None => {
implementation_list = @mut ~[];
- self.crate_context.coherence_info.inherent_methods
- .insert(base_def_id, implementation_list);
+ tcx.inherent_impls.insert(base_def_id, implementation_list);
}
Some(&existing_implementation_list) => {
implementation_list = existing_implementation_list;
}
implementation_list.push(implementation);
-
- ty::add_base_impl(self.crate_context.tcx, base_def_id, implementation);
}
- pub fn add_trait_method(&self, trait_id: def_id, implementation: @Impl) {
+ pub fn add_trait_impl(&self,
+ base_def_id: def_id,
+ implementation: @Impl) {
+ let tcx = self.crate_context.tcx;
let implementation_list;
- match self.crate_context.coherence_info.extension_methods
- .find(&trait_id) {
+ match tcx.trait_impls.find(&base_def_id) {
None => {
implementation_list = @mut ~[];
- self.crate_context.coherence_info.extension_methods
- .insert(trait_id, implementation_list);
+ tcx.trait_impls.insert(base_def_id, implementation_list);
}
Some(&existing_implementation_list) => {
implementation_list = existing_implementation_list;
}
pub fn check_implementation_coherence(&self) {
- let coherence_info = &self.crate_context.coherence_info;
- for coherence_info.extension_methods.each_key |&trait_id| {
+ for self.crate_context.tcx.trait_impls.each_key |&trait_id| {
self.check_implementation_coherence_of(trait_id);
}
}
// "We have an impl of trait <trait_def_id> for type <polytype_a>,
// and that impl is <implementation_a>"
- self.add_impl_for_trait(trait_def_id, polytype_a.ty,
- implementation_a);
do self.iter_impls_of_trait(trait_def_id) |b| {
let implementation_b = b;
}
}
- // Adds an impl of trait trait_t for self type self_t; that impl
- // is the_impl
- pub fn add_impl_for_trait(&self,
- trait_t: def_id,
- self_t: t,
- the_impl: @Impl) {
- debug!("Adding impl %? of %? for %s",
- the_impl.did, trait_t,
- ty_to_str(self.crate_context.tcx, self_t));
- match self.crate_context.tcx.trait_impls.find(&trait_t) {
- None => {
- let m = @mut HashMap::new();
- m.insert(self_t, the_impl);
- self.crate_context.tcx.trait_impls.insert(trait_t, m);
- }
- Some(&m) => {
- m.insert(self_t, the_impl);
- }
- }
- }
-
pub fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) {
- let coherence_info = &self.crate_context.coherence_info;
- let extension_methods = &*coherence_info.extension_methods;
-
- match extension_methods.find(&trait_def_id) {
+ match self.crate_context.tcx.trait_impls.find(&trait_def_id) {
Some(impls) => {
for impls.iter().advance |&im| {
f(im);
}
// Privileged scope checking
- pub fn check_privileged_scopes(self, crate: &crate) {
+ pub fn check_privileged_scopes(self, crate: &Crate) {
visit_crate(crate, ((), mk_vt(@Visitor {
visit_item: |item, (_context, visitor)| {
match item.node {
// This check doesn't really have anything to do with coherence. It's
// here for historical reasons
- pub fn please_check_that_trait_methods_are_implemented(&self,
- all_methods:
- &mut
- ~[@MethodInfo],
- trait_did: def_id,
- trait_ref_span:
- span) {
+ pub fn check_trait_methods_are_implemented(
+ &self,
+ all_methods: &mut ~[@Method],
+ trait_did: def_id,
+ trait_ref_span: span) {
let tcx = self.crate_context.tcx;
for uint::range(0, all_methods.len()) |i| {
provided_names.insert(all_methods[i].ident);
}
- // Default methods
- let r = ty::provided_trait_methods(tcx, trait_did);
- for r.iter().advance |method| {
- debug!("inserting provided method %s", method.ident.repr(tcx));
- provided_names.insert(method.ident);
- }
let r = ty::trait_methods(tcx, trait_did);
for r.iter().advance |method| {
}
}
- fn add_provided_methods_to_impl(
- &self,
- all_methods: &mut ~[@MethodInfo],
- trait_did: &ast::def_id,
- impl_id: &ast::def_id) {
-
-
- match self.crate_context.tcx
- .provided_methods
- .find(impl_id) {
- None => {
- debug!("(creating impl) trait with node_id `%d` \
- has no provided methods", trait_did.node);
- /* fall through */
- }
- Some(&all_provided_methods) => {
- debug!("(creating impl) trait with node_id `%d` \
- has provided methods", trait_did.node);
- // Add all provided methods.
- for all_provided_methods.iter().advance |provided_method| {
- debug!(
- "(creating impl) adding provided method \
- `%s` to impl",
- provided_method.method_info
- .ident.repr(self.crate_context.tcx));
- all_methods.push(provided_method.method_info);
- }
- }
- }
-
-
- }
-
// Converts an implementation in the AST to an Impl structure.
pub fn create_impl_from_item(&self, item: @item) -> @Impl {
+ let tcx = self.crate_context.tcx;
match item.node {
item_impl(_, ref trait_refs, _, ref ast_methods) => {
let mut methods = ~[];
for ast_methods.iter().advance |ast_method| {
- methods.push(method_to_MethodInfo(*ast_method));
+ methods.push(ty::method(tcx, local_def(ast_method.id)));
}
- // Check that we have implementations of every trait method
for trait_refs.iter().advance |trait_ref| {
- let trait_did =
- self.trait_ref_to_trait_def_id(trait_ref);
- self.please_check_that_trait_methods_are_implemented(
+ let ty_trait_ref = ty::node_id_to_trait_ref(
+ self.crate_context.tcx,
+ trait_ref.ref_id);
+ let trait_did = ty_trait_ref.def_id;
+
+ self.instantiate_default_methods(local_def(item.id),
+ ty_trait_ref,
+ &mut methods);
+
+ // Check that we have implementations of every trait method
+ self.check_trait_methods_are_implemented(
&mut methods,
trait_did,
trait_ref.path.span);
}
- // For each trait that the impl implements, see which
- // methods are provided. For each of those methods,
- // if a method of that name is not inherent to the
- // impl, use the provided definition in the trait.
- for trait_refs.iter().advance |trait_ref| {
- let trait_did = self.trait_ref_to_trait_def_id(trait_ref);
- self.add_provided_methods_to_impl(
- &mut methods,
- &trait_did,
- &local_def(item.id));
- }
-
return @Impl {
did: local_def(item.id),
ident: item.ident,
pub fn add_external_impl(&self,
impls_seen: &mut HashSet<def_id>,
- crate_store: @mut CStore,
impl_def_id: def_id) {
- let implementation = csearch::get_impl(crate_store, impl_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(self.crate_context.tcx, implementation.did));
+ ty::item_path_str(tcx, implementation.did));
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(implementation.did) {
}
// Good. Continue.
- let self_type = lookup_item_type(self.crate_context.tcx,
- implementation.did);
- let associated_traits = get_impl_trait(self.crate_context.tcx,
+ let self_type = 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
dummy_sp(),
self_type.ty) {
None => {
- let session = self.crate_context.tcx.sess;
- session.bug(fmt!("no base type for external impl with no \
+ tcx.sess.bug(fmt!("no base type for external impl with no \
trait: %s (type %s)!",
- session.str_of(implementation.ident),
- ty_to_str(self.crate_context.tcx,
- self_type.ty)));
+ tcx.sess.str_of(implementation.ident),
+ ty_to_str(tcx, self_type.ty)));
}
Some(_) => {} // Nothing to do.
}
}
// Record all the trait methods.
- let mut implementation = @implementation;
for associated_traits.iter().advance |trait_ref| {
- self.instantiate_default_methods(implementation.did,
- *trait_ref);
-
- // XXX(sully): We could probably avoid this copy if there are no
- // default methods.
- let mut methods = implementation.methods.clone();
- self.add_provided_methods_to_impl(&mut methods,
- &trait_ref.def_id,
- &implementation.did);
- implementation = @Impl {
- methods: methods,
- ..*implementation
- };
+ self.add_trait_impl(trait_ref.def_id, implementation);
+ }
- self.add_trait_method(trait_ref.def_id, implementation);
+ // For any methods that use a default implementation, add them to
+ // the map. This is a bit unfortunate.
+ for implementation.methods.iter().advance |method| {
+ for method.provided_source.iter().advance |source| {
+ tcx.provided_method_sources.insert(method.def_id, *source);
+ }
}
// Add the implementation to the mapping from implementation to base
// inherent methods apply to `impl Type` but not
// `impl Trait for Type`:
if associated_traits.is_none() {
- self.add_inherent_method(base_type_def_id,
- implementation);
+ 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);
}
// Adds implementations and traits from external crates to the coherence
for each_path(crate_store, crate_number) |_, def_like, _| {
match def_like {
dl_impl(def_id) => {
- self.add_external_impl(&mut impls_seen,
- crate_store,
- def_id)
+ self.add_external_impl(&mut impls_seen, def_id)
}
dl_def(_) | dl_field => loop, // Skip this.
}
//
pub fn populate_destructor_table(&self) {
- let coherence_info = &self.crate_context.coherence_info;
let tcx = self.crate_context.tcx;
let drop_trait = match tcx.lang_items.drop_trait() {
Some(id) => id, None => { return }
};
- let impls_opt = coherence_info.extension_methods.find(&drop_trait);
+ let impls_opt = tcx.trait_impls.find(&drop_trait);
let impls;
match impls_opt {
// We'll error out later. For now, just don't ICE.
loop;
}
- let method_def_id = impl_info.methods[0].did;
+ let method_def_id = impl_info.methods[0].def_id;
let self_type = self.get_self_type_for_implementation(*impl_info);
match ty::get(self_type.ty).sty {
impl_id: ast::def_id,
trait_ref: &ty::TraitRef,
new_def_id: ast::def_id,
- method: &ty::Method)
+ method: &ty::Method,
+ provided_source: Option<ast::def_id>)
-> ty::Method {
let combined_substs = make_substs_for_receiver_types(
method.explicit_self,
method.vis,
- new_def_id
+ new_def_id,
+ impl_id,
+ provided_source
)
}
-pub fn check_coherence(crate_context: @mut CrateCtxt, crate: &crate) {
+pub fn check_coherence(crate_context: @mut CrateCtxt, crate: &Crate) {
let coherence_checker = CoherenceChecker(crate_context);
coherence_checker.check_coherence(crate);
}
use syntax::opt_vec;
use syntax::parse::token::special_idents;
-pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) {
+pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
fn collect_intrinsic_type(ccx: &CrateCtxt,
lang_item: ast::def_id) {
let ty::ty_param_bounds_and_ty { ty: ty, _ } =
m_explicit_self.node,
// assume public, because this is only invoked on trait methods
ast::public,
- local_def(*m_id)
+ local_def(*m_id),
+ local_def(trait_id),
+ None
)
}
}
}
pub fn convert_methods(ccx: &CrateCtxt,
+ container_id: ast::node_id,
ms: &[@ast::method],
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
num_rcvr_ty_params);
let mty =
- @ty_of_method(ccx, *m, rcvr_ty_generics.region_param,
+ @ty_of_method(ccx, container_id, *m, rcvr_ty_generics.region_param,
untransformed_rcvr_ty,
rcvr_ast_generics, rcvr_visibility,
&m.generics);
}).collect();
fn ty_of_method(ccx: &CrateCtxt,
+ container_id: ast::node_id,
m: &ast::method,
rp: Option<ty::region_variance>,
untransformed_rcvr_ty: ty::t,
fty,
m.explicit_self.node,
method_vis,
- local_def(m.id)
+ local_def(m.id),
+ local_def(container_id),
+ None
)
}
}
it.vis
};
- let cms = convert_methods(ccx, *ms, selfty,
+ let cms = convert_methods(ccx, it.id, *ms, selfty,
&i_ty_generics, generics,
parent_visibility);
for opt_trait_ref.iter().advance |t| {
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, provided_methods,
+ let _ = convert_methods(ccx, it.id, provided_methods,
untransformed_rcvr_ty,
&ty_generics, generics,
it.vis);
use syntax::{ast, attr, parse};
struct Env {
- crate: @ast::crate,
+ crate: @ast::Crate,
tcx: ty::ctxt,
infcx: infer::infer_ctxt,
err_messages: @DVec<~str>
trait_map: resolve::TraitMap,
method_map: method_map,
vtable_map: vtable_map,
- coherence_info: coherence::CoherenceInfo,
tcx: ty::ctxt
}
pub fn check_crate(tcx: ty::ctxt,
trait_map: resolve::TraitMap,
- crate: &ast::crate)
+ crate: &ast::Crate)
-> (method_map, vtable_map) {
let time_passes = tcx.sess.time_passes();
let ccx = @mut CrateCtxt {
trait_map: trait_map,
method_map: @mut HashMap::new(),
vtable_map: @mut HashMap::new(),
- coherence_info: coherence::CoherenceInfo(),
tcx: tcx
};
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
-#[allow(non_implicitly_copyable_typarams)];
-#[deny(deprecated_pattern)];
-
extern mod extra;
extern mod syntax;
"));
let lint_dict = lint::get_lint_dict();
- let mut lint_dict = lint_dict.consume_iter()
+ let mut lint_dict = lint_dict.consume()
.transform(|(k, v)| (v, k))
.collect::<~[(lint::LintSpec, &'static str)]>();
lint_dict.qsort();
_indenter(())
}
-pub fn field_expr(f: ast::field) -> @ast::expr { return f.node.expr; }
+pub fn field_expr(f: ast::Field) -> @ast::expr { return f.expr; }
-pub fn field_exprs(fields: ~[ast::field]) -> ~[@ast::expr] {
- fields.map(|f| f.node.expr)
+pub fn field_exprs(fields: ~[ast::Field]) -> ~[@ast::expr] {
+ fields.map(|f| f.expr)
}
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn loop_query(b: &ast::blk, p: @fn(&ast::expr_) -> bool) -> bool {
+pub fn loop_query(b: &ast::Block, p: @fn(&ast::expr_) -> bool) -> bool {
let rs = @mut false;
let visit_expr: @fn(@ast::expr,
(@mut bool,
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn block_query(b: &ast::blk, p: @fn(@ast::expr) -> bool) -> bool {
+pub fn block_query(b: &ast::Block, p: @fn(@ast::expr) -> bool) -> bool {
let rs = @mut false;
let visit_expr: @fn(@ast::expr,
(@mut bool,
return *rs;
}
-pub fn local_rhs_span(l: @ast::local, def: span) -> span {
- match l.node.init {
+pub fn local_rhs_span(l: @ast::Local, def: span) -> span {
+ match l.init {
Some(i) => return i.span,
_ => return def
}
use syntax;
pub struct Ctxt {
- ast: @ast::crate,
+ ast: @ast::Crate,
ast_map: ast_map::map
}
type SrvOwner<'self,T> = &'self fn(srv: Srv) -> T;
pub type CtxtHandler<T> = ~fn(ctxt: Ctxt) -> T;
-type Parser = ~fn(Session, s: @str) -> @ast::crate;
+type Parser = ~fn(Session, s: @str) -> @ast::Crate;
enum Msg {
HandleRequest(~fn(Ctxt)),
}
fn build_ctxt(sess: Session,
- ast: @ast::crate) -> Ctxt {
+ ast: @ast::Crate) -> Ctxt {
use rustc::front::config;
do from_str(source) |srv| {
do exec(srv) |ctxt| {
// one item: the __std_macros secret module
- assert_eq!(ctxt.ast.node.module.items.len(), 1);
+ assert_eq!(ctxt.ast.module.items.len(), 1);
}
}
}
use syntax::ast;
use syntax::attr;
+use syntax::attr::{AttrMetaMethods, AttributeMethods};
pub struct CrateAttrs {
name: Option<~str>
}
-fn doc_metas(
- attrs: ~[ast::attribute]
-) -> ~[@ast::meta_item] {
-
- let doc_attrs = attr::find_attrs_by_name(attrs, "doc");
- let doc_metas = do doc_attrs.map |attr| {
- attr::attr_meta(attr::desugar_doc_attr(attr))
- };
-
- return doc_metas;
+fn doc_metas(attrs: ~[ast::Attribute]) -> ~[@ast::MetaItem] {
+ attrs.iter()
+ .filter(|at| "doc" == at.name())
+ .transform(|at| at.desugar_doc().meta())
+ .collect()
}
-pub fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs {
+pub fn parse_crate(attrs: ~[ast::Attribute]) -> CrateAttrs {
let link_metas = attr::find_linkage_metas(attrs);
let name = attr::last_meta_item_value_str_by_name(link_metas, "name");
}
}
-pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> {
+pub fn parse_desc(attrs: ~[ast::Attribute]) -> Option<~str> {
let doc_strs = do doc_metas(attrs).consume_iter().filter_map |meta| {
- attr::get_meta_item_value_str(meta).map(|s| s.to_owned())
- }.collect::<~[~str]>();
+ meta.value_str()
+ }.collect::<~[@str]>();
if doc_strs.is_empty() {
None
} else {
}
}
-pub fn parse_hidden(attrs: ~[ast::attribute]) -> bool {
+pub fn parse_hidden(attrs: ~[ast::Attribute]) -> bool {
let r = doc_metas(attrs);
do r.iter().any |meta| {
- match attr::get_meta_item_list(*meta) {
- Some(metas) => {
- let hiddens = attr::find_meta_items_by_name(metas, "hidden");
- !hiddens.is_empty()
- }
+ match meta.meta_item_list() {
+ Some(metas) => attr::contains_name(metas, "hidden"),
None => false
}
}
use syntax;
use super::{parse_hidden, parse_crate, parse_desc};
- fn parse_attributes(source: @str) -> ~[ast::attribute] {
+ fn parse_attributes(source: @str) -> ~[ast::Attribute] {
use syntax::parse;
use syntax::parse::attr::parser_attr;
let doc = fold::default_seq_fold_crate(fold, doc);
let attrs = do astsrv::exec(srv) |ctxt| {
- let attrs = ctxt.ast.node.attrs.clone();
+ let attrs = ctxt.ast.attrs.clone();
attr_parser::parse_crate(attrs)
};
doc::CrateDoc {
topmod: doc::ModDoc {
item: doc::ItemDoc {
- name: attrs.name.clone().get_or_default(doc.topmod.name()),
+ name: attrs.name.clone().get_or_default(doc.topmod.name_()),
.. doc.topmod.item.clone()
},
.. doc.topmod.clone()
let desc = if doc.id == ast::crate_node_id {
// This is the top-level mod, use the crate attributes
do astsrv::exec(srv) |ctxt| {
- attr_parser::parse_desc(ctxt.ast.node.attrs.clone())
+ attr_parser::parse_desc(ctxt.ast.attrs.clone())
}
} else {
parse_item_attrs(srv, doc.id, attr_parser::parse_desc)
fn parse_item_attrs<T:Send>(
srv: astsrv::Srv,
id: doc::AstId,
- parse_attrs: ~fn(a: ~[ast::attribute]) -> T) -> T {
+ parse_attrs: ~fn(a: ~[ast::Attribute]) -> T) -> T {
do astsrv::exec(srv) |ctxt| {
let attrs = match ctxt.ast_map.get_copy(&id) {
ast_map::node_item(item, _) => item.attrs.clone(),
#[test]
fn should_replace_top_module_name_with_crate_name() {
let doc = mk_doc(~"#[link(name = \"bond\")];");
- assert!(doc.cratemod().name() == ~"bond");
+ assert!(doc.cratemod().name_() == ~"bond");
}
#[test]
pub trait ItemUtils {
fn id(&self) -> AstId;
- fn name(&self) -> ~str;
+ /// FIXME #5898: This conflicts with
+ /// syntax::attr::AttrMetaMethods.name; This rustdoc seems to be on
+ /// the way out so I'm making this one look bad rather than the
+ /// new methods in attr.
+ fn name_(&self) -> ~str;
fn path(&self) -> ~[~str];
fn brief(&self) -> Option<~str>;
fn desc(&self) -> Option<~str>;
self.item().id
}
- fn name(&self) -> ~str {
+ fn name_(&self) -> ~str {
self.item().name.clone()
}
}
pub fn extract(
- crate: @ast::crate,
+ crate: @ast::Crate,
default_name: ~str
) -> doc::Doc {
doc::Doc {
}
fn top_moddoc_from_crate(
- crate: @ast::crate,
+ crate: @ast::Crate,
default_name: ~str
) -> doc::ModDoc {
moddoc_from_mod(mk_itemdoc(ast::crate_node_id, default_name),
- crate.node.module.clone())
+ crate.module.clone())
}
fn mk_itemdoc(id: ast::node_id, name: ~str) -> doc::ItemDoc {
#[test]
fn extract_mods() {
let doc = mk_doc(@"mod a { mod b { } mod c { } }");
- assert!(doc.cratemod().mods()[0].name() == ~"a");
- assert!(doc.cratemod().mods()[0].mods()[0].name() == ~"b");
- assert!(doc.cratemod().mods()[0].mods()[1].name() == ~"c");
+ assert!(doc.cratemod().mods()[0].name_() == ~"a");
+ assert!(doc.cratemod().mods()[0].mods()[0].name_() == ~"b");
+ assert!(doc.cratemod().mods()[0].mods()[1].name_() == ~"c");
}
#[test]
fn extract_fns_from_foreign_mods() {
let doc = mk_doc(@"extern { fn a(); }");
- assert!(doc.cratemod().nmods()[0].fns[0].name() == ~"a");
+ assert!(doc.cratemod().nmods()[0].fns[0].name_() == ~"a");
}
#[test]
fn extract_mods_deep() {
let doc = mk_doc(@"mod a { mod b { mod c { } } }");
- assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name() ==
+ assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name_() ==
~"c");
}
@"fn a() { } \
mod b { fn c() {
} }");
- assert!(doc.cratemod().fns()[0].name() == ~"a");
- assert!(doc.cratemod().mods()[0].fns()[0].name() == ~"c");
+ assert!(doc.cratemod().fns()[0].name_() == ~"a");
+ assert!(doc.cratemod().mods()[0].fns()[0].name_() == ~"c");
}
#[test]
let source = @"";
let ast = parse::from_str(source);
let doc = extract(ast, ~"burp");
- assert!(doc.cratemod().name() == ~"burp");
+ assert!(doc.cratemod().name_() == ~"burp");
}
#[test]
let source = ~"";
do astsrv::from_str(source) |srv| {
let doc = from_srv(srv, ~"name");
- assert!(doc.cratemod().name() == ~"name");
+ assert!(doc.cratemod().name_() == ~"name");
}
}
fn should_extract_const_name_and_id() {
let doc = mk_doc(@"static a: int = 0;");
assert!(doc.cratemod().consts()[0].id() != 0);
- assert!(doc.cratemod().consts()[0].name() == ~"a");
+ assert!(doc.cratemod().consts()[0].name_() == ~"a");
}
#[test]
fn should_extract_enums() {
let doc = mk_doc(@"enum e { v }");
assert!(doc.cratemod().enums()[0].id() != 0);
- assert!(doc.cratemod().enums()[0].name() == ~"e");
+ assert!(doc.cratemod().enums()[0].name_() == ~"e");
}
#[test]
#[test]
fn should_extract_traits() {
let doc = mk_doc(@"trait i { fn f(); }");
- assert!(doc.cratemod().traits()[0].name() == ~"i");
+ assert!(doc.cratemod().traits()[0].name_() == ~"i");
}
#[test]
#[test]
fn should_extract_tys() {
let doc = mk_doc(@"type a = int;");
- assert!(doc.cratemod().types()[0].name() == ~"a");
+ assert!(doc.cratemod().types()[0].name_() == ~"a");
}
#[test]
fn should_extract_structs() {
let doc = mk_doc(@"struct Foo { field: () }");
- assert!(doc.cratemod().structs()[0].name() == ~"Foo");
+ assert!(doc.cratemod().structs()[0].name_() == ~"Foo");
}
#[test]
}
pub fn header_name(doc: doc::ItemTag) -> ~str {
- let fullpath = (doc.path() + &[doc.name()]).connect("::");
+ let fullpath = (doc.path() + &[doc.name_()]).connect("::");
match &doc {
&doc::ModTag(_) if doc.id() != syntax::ast::crate_node_id => {
fullpath
fmt!("%s for %s%s", trait_part, *self_ty, bounds)
}
_ => {
- doc.name()
+ doc.name_()
}
}
}
config.output_style == config::DocPerMod {
~"index"
} else {
- assert!(doc.topmod.name() != ~"");
- doc.topmod.name()
+ assert!(doc.topmod.name_() != ~"");
+ doc.topmod.name_()
}
}
doc::ItemPage(doc) => {
- (doc.path() + &[doc.name()]).connect("_")
+ (doc.path() + &[doc.name_()]).connect("_")
}
}
};
fn should_make_a_page_for_every_mod() {
let doc = mk_doc(~"mod a { }");
// hidden __std_macros module at the start.
- assert_eq!(doc.pages.mods()[0].name(), ~"a");
+ assert_eq!(doc.pages.mods()[0].name_(), ~"a");
}
#[test]
use syntax::ast;
use syntax::parse;
-pub fn from_file(file: &Path) -> @ast::crate {
+pub fn from_file(file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
file, ~[], parse::new_parse_sess(None))
}
-pub fn from_str(source: @str) -> @ast::crate {
+pub fn from_str(source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
@"-", source, ~[], parse::new_parse_sess(None))
}
-pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::crate {
+pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
file, cfg(sess, file_input((*file).clone())), sess.parse_sess)
}
-pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::crate {
+pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
@"-", source, cfg(sess, str_input(source)), sess.parse_sess)
}
-fn cfg(sess: session::Session, input: driver::input) -> ast::crate_cfg {
+fn cfg(sess: session::Session, input: driver::input) -> ast::CrateConfig {
driver::build_configuration(sess, @"rustdoc", &input)
}
doc::CratePage(doc::CrateDoc{
topmod: doc::ModDoc{
item: doc::ItemDoc {
- name: doc.cratemod().name() + "two",
+ name: doc.cratemod().name_() + "two",
.. doc.cratemod().item.clone()
},
items: ~[],
doc::CratePage(doc::CrateDoc{
topmod: doc::ModDoc{
item: doc::ItemDoc {
- name: doc.cratemod().name() + "three",
+ name: doc.cratemod().name_() + "three",
.. doc.cratemod().item.clone()
},
items: ~[],
];
let doc = extract::from_srv(srv.clone(), ~"one");
let doc = run_passes(srv, doc, passes);
- assert_eq!(doc.cratemod().name(), ~"onetwothree");
+ assert_eq!(doc.cratemod().name_(), ~"onetwothree");
}
}
}
}
-#[allow(non_implicitly_copyable_typarams)]
fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
let ctxt = Ctxt {
srv: srv,
}
}
-#[allow(non_implicitly_copyable_typarams)]
fn fold_mod(fold: &fold::Fold<Ctxt>, doc: doc::ModDoc) -> doc::ModDoc {
let is_topmod = doc.id() == ast::crate_node_id;
- if !is_topmod { fold.ctxt.path.push(doc.name()); }
+ if !is_topmod { fold.ctxt.path.push(doc.name_()); }
let doc = fold::default_any_fold_mod(fold, doc);
if !is_topmod { fold.ctxt.path.pop(); }
}
fn fold_nmod(fold: &fold::Fold<Ctxt>, doc: doc::NmodDoc) -> doc::NmodDoc {
- fold.ctxt.path.push(doc.name());
+ fold.ctxt.path.push(doc.name_());
let doc = fold::default_seq_fold_nmod(fold, doc);
fold.ctxt.path.pop();
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
-#[allow(non_implicitly_copyable_typarams)];
-
extern mod extra;
extern mod rustc;
extern mod syntax;
pub fn mk_pass() -> Pass {
fn by_item_name(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- (*item1).name() <= (*item2).name()
+ (*item1).name_() <= (*item2).name_()
}
sort_pass::mk_pass(~"sort_item_name", by_item_name)
}
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass().f)(srv.clone(), doc);
// hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().items[1].name(), ~"y");
- assert_eq!(doc.cratemod().items[2].name(), ~"z");
+ assert_eq!(doc.cratemod().items[1].name_(), ~"y");
+ assert_eq!(doc.cratemod().items[2].name_(), ~"z");
}
}
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass().f)(srv.clone(), doc);
// hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().items[0].name(), ~"iconst");
- assert_eq!(doc.cratemod().items[1].name(), ~"itype");
- assert_eq!(doc.cratemod().items[2].name(), ~"ienum");
- assert_eq!(doc.cratemod().items[3].name(), ~"istruct");
- assert_eq!(doc.cratemod().items[4].name(), ~"itrait");
- assert_eq!(doc.cratemod().items[5].name(), ~"__extensions__");
- assert_eq!(doc.cratemod().items[6].name(), ~"ifn");
+ assert_eq!(doc.cratemod().items[0].name_(), ~"iconst");
+ assert_eq!(doc.cratemod().items[1].name_(), ~"itype");
+ assert_eq!(doc.cratemod().items[2].name_(), ~"ienum");
+ assert_eq!(doc.cratemod().items[3].name_(), ~"istruct");
+ assert_eq!(doc.cratemod().items[4].name_(), ~"itrait");
+ assert_eq!(doc.cratemod().items[5].name_(), ~"__extensions__");
+ assert_eq!(doc.cratemod().items[6].name_(), ~"ifn");
// hidden __std_macros module fits here.
- assert_eq!(doc.cratemod().items[8].name(), ~"imod");
+ assert_eq!(doc.cratemod().items[8].name_(), ~"imod");
}
}
}
}
-#[allow(non_implicitly_copyable_typarams)]
fn run(
_srv: astsrv::Srv,
doc: doc::Doc,
(fold.fold_doc)(&fold, doc)
}
-#[allow(non_implicitly_copyable_typarams)]
fn fold_mod(
fold: &fold::Fold<ItemLtEq>,
doc: doc::ModDoc
#[test]
fn test() {
fn name_lteq(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
- (*item1).name() <= (*item2).name()
+ (*item1).name_() <= (*item2).name_()
}
let source = ~"mod z { mod y { } fn x() { } } mod w { }";
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass(~"", name_lteq).f)(srv.clone(), doc);
// hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].name(), ~"w");
- assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"x");
- assert_eq!(doc.cratemod().mods()[2].items[1].name(), ~"y");
- assert_eq!(doc.cratemod().mods()[2].name(), ~"z");
+ assert_eq!(doc.cratemod().mods()[1].name_(), ~"w");
+ assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"x");
+ assert_eq!(doc.cratemod().mods()[2].items[1].name_(), ~"y");
+ assert_eq!(doc.cratemod().mods()[2].name_(), ~"z");
}
}
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
// hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().mods()[1].items[0].name(), ~"b");
- assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"d");
+ assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
+ assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
- assert_eq!(doc.cratemod().mods()[1].items[0].name(), ~"b");
- assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"d");
+ assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
+ assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
}
}
}
}
-#[allow(non_implicitly_copyable_typarams)]
fn run(
_srv: astsrv::Srv,
doc: doc::Doc,
// except according to those terms.
use std::cast;
+use std::util;
use std::hashmap::HashMap;
use std::local_data;
None => {}
}
- do self.newvars.consume |name, var| {
+ let newvars = util::replace(&mut self.newvars, HashMap::new());
+ for newvars.consume().advance |(name, var)| {
self.local_vars.insert(name, var);
}
/// it updates this cache with the new values of each local variable.
pub fn consume_cache(&mut self) {
let map = local_data::pop(tls_key).expect("tls is empty");
- do map.consume |name, value| {
+ let cons_map = util::replace(map, HashMap::new());
+ for cons_map.consume().advance |(name, value)| {
match self.local_vars.find_mut(&name) {
Some(v) => { v.data = (*value).clone(); }
None => { fail!("unknown variable %s", name) }
///
/// Once the types are known, they are inserted into the local_vars map in
/// this Program (to be deserialized later on
- pub fn register_new_vars(&mut self, blk: &ast::blk, tcx: ty::ctxt) {
+ pub fn register_new_vars(&mut self, blk: &ast::Block, tcx: ty::ctxt) {
debug!("looking for new variables");
let newvars = @mut HashMap::new();
do each_user_local(blk) |local| {
- let mutable = local.node.is_mutbl;
+ let mutable = local.is_mutbl;
do each_binding(local) |path, id| {
let name = do with_pp(token::get_ident_interner()) |pp, _| {
pprust::print_path(pp, path, false);
}
// I'm not an @ pointer, so this has to be done outside.
- do newvars.consume |k, v| {
+ let cons_newvars = util::replace(newvars, HashMap::new());
+ for cons_newvars.consume().advance |(k, v)| {
self.newvars.insert(k, v);
}
// helper functions to perform ast iteration
- fn each_user_local(blk: &ast::blk, f: &fn(@ast::local)) {
+ fn each_user_local(blk: &ast::Block, f: &fn(@ast::Local)) {
do find_user_block(blk) |blk| {
for blk.stmts.iter().advance |stmt| {
match stmt.node {
}
}
- fn find_user_block(blk: &ast::blk, f: &fn(&ast::blk)) {
+ fn find_user_block(blk: &ast::Block, f: &fn(&ast::Block)) {
for blk.stmts.iter().advance |stmt| {
match stmt.node {
ast::stmt_semi(e, _) => {
// Local declarations must be specially dealt with,
// record all local declarations for use later on
ast::decl_local(l) => {
- let mutbl = l.node.is_mutbl;
+ let mutbl = l.is_mutbl;
do each_binding(l) |path, _| {
let s = do with_pp(intr) |pp, _| {
pprust::print_path(pp, path, false);
return (program, jit::consume_engine());
fn parse_input(sess: session::Session, binary: @str,
- input: &str) -> @ast::crate {
+ input: &str) -> @ast::Crate {
let code = fmt!("fn main() {\n %s \n}", input);
let input = driver::str_input(code.to_managed());
let cfg = driver::build_configuration(sess, binary, &input);
crate.expect("parsing should return a crate")
}
- fn find_main(crate: @ast::crate, sess: session::Session,
- f: &fn(&ast::blk)) {
- for crate.node.module.items.iter().advance |item| {
+ fn find_main(crate: @ast::Crate, sess: session::Session,
+ f: &fn(&ast::Block)) {
+ for crate.module.items.iter().advance |item| {
match item.node {
ast::item_fn(_, _, _, _, ref blk) => {
if item.ident == sess.ident_of("main") {
#[cfg(test)]
mod tests {
use std::io;
- use std::iterator::IteratorUtil;
use program::Program;
use super::*;
use syntax::print::pprust;
use syntax::parse::token;
-pub fn each_binding(l: @ast::local, f: @fn(&ast::Path, ast::node_id)) {
+pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::node_id)) {
use syntax::visit;
let vt = visit::mk_simple_visitor(
.. *visit::default_simple_visitor()
}
);
- (vt.visit_pat)(l.node.pat, ((), vt));
+ (vt.visit_pat)(l.pat, ((), vt));
}
/// A utility function that hands off a pretty printer to a callback.
for workspaces.iter().advance |p| {
let binfiles = os::list_dir(&p.push("bin"));
for binfiles.iter().advance() |exec| {
- f(&PkgId::new(*exec, p));
+ let exec_path = Path(*exec).filestem();
+ do exec_path.iter().advance |s| {
+ f(&PkgId::new(*s, p))
+ };
}
let libfiles = os::list_dir(&p.push("lib"));
for libfiles.iter().advance() |lib| {
- f(&PkgId::new(*lib, p));
+ debug!("Full name: %s", *lib);
+ let lib_path = Path(*lib).filestem();
+ do lib_path.iter().advance |s| {
+ f(&PkgId::new(*s, p))
+ };
}
}
true
};
let cwd = os::getcwd();
// now add in default entries
- env_rust_path.push(cwd.push(".rust"));
env_rust_path.push(cwd.clone());
do cwd.each_parent() |p| { push_if_exists(&mut env_rust_path, p) };
let h = os::homedir();
- for h.iter().advance |h| { push_if_exists(&mut env_rust_path, h); }
+ // Avoid adding duplicates
+ // could still add dups if someone puts one of these in the RUST_PATH
+ // manually, though...
+ for h.iter().advance |hdir| {
+ if !(cwd.is_ancestor_of(hdir) || hdir.is_ancestor_of(&cwd)) {
+ push_if_exists(&mut env_rust_path, hdir);
+ }
+ }
env_rust_path
}
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};
+use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, in_workspace, cwd_to_workspace};
use context::Ctx;
use package_id::PkgId;
use package_source::PkgSrc;
/// build script
sess: session::Session,
/// The config for compiling the custom build script
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
/// The crate for the custom build script
- crate: @ast::crate,
+ crate: @ast::Crate,
/// Directory in which to store build output
build_dir: Path
}
match cmd {
"build" => {
if args.len() < 1 {
- return usage::build();
+ if !in_workspace(|| { usage::build() } ) {
+ return;
+ }
+ let (workspace, pkgid) = cwd_to_workspace();
+ self.build(&workspace, &pkgid);
}
- // The package id is presumed to be the first command-line
- // argument
- let pkgid = PkgId::new(args[0].clone(), &os::getcwd());
- for each_pkg_parent_workspace(&pkgid) |workspace| {
- debug!("found pkg %s in workspace %s, trying to build",
- pkgid.to_str(), workspace.to_str());
- self.build(workspace, &pkgid);
+ else {
+ // The package id is presumed to be the first command-line
+ // argument
+ let pkgid = PkgId::new(args[0].clone(), &os::getcwd());
+ for each_pkg_parent_workspace(&pkgid) |workspace| {
+ debug!("found pkg %s in workspace %s, trying to build",
+ pkgid.to_str(), workspace.to_str());
+ self.build(workspace, &pkgid);
+ }
}
}
"clean" => {
if args.len() < 1 {
- return usage::build();
+ if !in_workspace(|| { usage::clean() } ) {
+ return;
+ }
+ // tjc: Maybe clean should clean all the packages in the
+ // current workspace, though?
+ let (workspace, pkgid) = cwd_to_workspace();
+ self.clean(&workspace, &pkgid);
+
+ }
+ else {
+ // The package id is presumed to be the first command-line
+ // argument
+ let pkgid = PkgId::new(args[0].clone(), &os::getcwd());
+ let cwd = os::getcwd();
+ self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd
}
- // The package id is presumed to be the first command-line
- // argument
- let pkgid = PkgId::new(args[0].clone(), &os::getcwd());
- let cwd = os::getcwd();
- self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd
}
"do" => {
if args.len() < 2 {
}
"install" => {
if args.len() < 1 {
- return usage::install();
- }
-
- // The package id is presumed to be the first command-line
- // argument
- let pkgid = PkgId::new(args[0], &os::getcwd());
- let workspaces = pkg_parent_workspaces(&pkgid);
- if workspaces.is_empty() {
- debug!("install! workspaces was empty");
- let rp = rust_path();
- assert!(!rp.is_empty());
- let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]),
- &pkgid);
- src.fetch_git();
- self.install(&rp[0], &pkgid);
+ if !in_workspace(|| { usage::install() }) {
+ return;
+ }
+ let (workspace, pkgid) = cwd_to_workspace();
+ self.install(&workspace, &pkgid);
}
else {
- for each_pkg_parent_workspace(&pkgid) |workspace| {
- debug!("install: found pkg %s in workspace %s, trying to build",
- pkgid.to_str(), workspace.to_str());
-
- self.install(workspace, &pkgid);
+ // The package id is presumed to be the first command-line
+ // argument
+ let pkgid = PkgId::new(args[0], &os::getcwd());
+ let workspaces = pkg_parent_workspaces(&pkgid);
+ if workspaces.is_empty() {
+ let rp = rust_path();
+ assert!(!rp.is_empty());
+ let src = PkgSrc::new(&rp[0], &build_pkg_id_in_workspace(&pkgid, &rp[0]),
+ &pkgid);
+ src.fetch_git();
+ self.install(&rp[0], &pkgid);
+ }
+ else {
+ for each_pkg_parent_workspace(&pkgid) |workspace| {
+ self.install(workspace, &pkgid);
+ }
}
}
}
"list" => {
io::println("Installed packages:");
for installed_packages::list_installed_packages |pkg_id| {
- io::println(fmt!("%s-%s",
- pkg_id.local_path.to_str(),
- pkg_id.version.to_str()));
+ io::println(pkg_id.local_path.to_str());
}
}
"prefer" => {
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
-> ProcessOutput {
let cmd = test_sysroot().push("bin").push("rustpkg").to_str();
- let cwd = normalize(RemotePath((*cwd).clone()));
debug!("About to run command: %? %? in %s", cmd, args, cwd.to_str());
assert!(os::path_is_dir(&*cwd));
let cwd = (*cwd).clone();
assert!(is_rwx(&exec));
}
+fn assert_built_executable_exists(repo: &Path, short_name: &str) {
+ debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
+ let exec = built_executable_in_workspace(&PkgId::new(short_name, repo),
+ repo).expect("assert_built_executable_exists failed");
+ assert!(os::path_exists(&exec));
+ assert!(is_rwx(&exec));
+}
+
fn command_line_test_output(args: &[~str]) -> ~[~str] {
let mut result = ~[];
let p_output = command_line_test(args, &os::getcwd());
}
match maybe_p {
Some(p) => {
- let w = io::file_writer(*p, &[io::Append]);
+ let w = io::file_writer(p, &[io::Append]);
match w {
- Err(s) => { let _ = cond.raise(((**p).clone(), fmt!("Bad path: %s", s))); }
+ Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
Ok(w) => w.write_line("")
}
}
// Tests above should (maybe) be converted to shell out to rustpkg, too
-#[test] #[ignore(cfg(target_arch = "x86"))]
+// FIXME: #7956: temporarily disabled
+#[ignore(cfg(target_arch = "x86"))]
fn test_install_git() {
let sysroot = test_sysroot();
debug!("sysroot = %s", sysroot.to_str());
// should have test, bench, lib, and main
command_line_test([~"install", temp_pkg_id.local_path.to_str()], &repo);
// Check that all files exist
- let ws = repo.push(".rust");
- debug!("Checking for files in %s", ws.to_str());
- let exec = target_executable_in_workspace(&temp_pkg_id, &ws);
+ debug!("Checking for files in %s", repo.to_str());
+ let exec = target_executable_in_workspace(&temp_pkg_id, &repo);
debug!("exec = %s", exec.to_str());
assert!(os::path_exists(&exec));
assert!(is_rwx(&exec));
let _built_lib =
built_library_in_workspace(&temp_pkg_id,
- &ws).expect("test_install_git: built lib should exist");
- let lib = target_library_in_workspace(&temp_pkg_id, &ws);
+ &repo).expect("test_install_git: built lib should exist");
+ let lib = target_library_in_workspace(&temp_pkg_id, &repo);
debug!("lib = %s", lib.to_str());
assert!(os::path_exists(&lib));
assert!(is_rwx(&lib));
let built_test = built_test_in_workspace(&temp_pkg_id,
- &ws).expect("test_install_git: built test should exist");
+ &repo).expect("test_install_git: built test should exist");
assert!(os::path_exists(&built_test));
let built_bench = built_bench_in_workspace(&temp_pkg_id,
- &ws).expect("test_install_git: built bench should exist");
+ &repo).expect("test_install_git: built bench should exist");
assert!(os::path_exists(&built_bench));
// And that the test and bench executables aren't installed
- let test = target_test_in_workspace(&temp_pkg_id, &ws);
+ let test = target_test_in_workspace(&temp_pkg_id, &repo);
assert!(!os::path_exists(&test));
debug!("test = %s", test.to_str());
- let bench = target_bench_in_workspace(&temp_pkg_id, &ws);
+ let bench = target_bench_in_workspace(&temp_pkg_id, &repo);
debug!("bench = %s", bench.to_str());
assert!(!os::path_exists(&bench));
}
}
-#[test] #[ignore(cfg(target_arch = "x86"))]
+// FIXME: #7956: temporarily disabled
+#[ignore(cfg(target_arch = "x86"))]
fn test_package_version() {
let local_path = "mockgithub.com/catamorphism/test_pkg_version";
let repo = init_git_repo(&Path(local_path));
command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg_version"],
&repo);
assert!(match built_library_in_workspace(&temp_pkg_id,
- &repo.push(".rust")) {
+ &repo) {
Some(p) => p.to_str().ends_with(fmt!("0.4%s", os::consts::DLL_SUFFIX)),
None => false
});
- assert!(built_executable_in_workspace(&temp_pkg_id, &repo.push(".rust"))
- == Some(repo.push(".rust").push("build").
+ assert!(built_executable_in_workspace(&temp_pkg_id, &repo)
+ == Some(repo.push("build").
push("mockgithub.com").
push("catamorphism").
push("test_pkg_version").
&temp_dir);
}
-#[test]
+// FIXME: #7956: temporarily disabled
fn rustpkg_library_target() {
let foo_repo = init_git_repo(&Path("foo"));
let package_dir = foo_repo.push("foo");
add_git_tag(&package_dir, ~"1.0");
command_line_test([~"install", ~"foo"], &foo_repo);
- assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0"));
+ assert_lib_exists(&foo_repo, "foo", ExactRevision(~"1.0"));
}
#[test]
assert!(os::path_exists(&dir.push("build").push("fancy_lib").push("generated.rs")));
}
+#[test]
+fn rustpkg_build_no_arg() {
+ let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed");
+ let package_dir = tmp.push("src").push("foo");
+ assert!(os::mkdir_recursive(&package_dir, U_RWX));
+
+ writeFile(&package_dir.push("main.rs"),
+ "fn main() { let _x = (); }");
+ debug!("build_no_arg: dir = %s", package_dir.to_str());
+ command_line_test([~"build"], &package_dir);
+ assert_built_executable_exists(&tmp, "foo");
+}
+
+#[test]
+fn rustpkg_install_no_arg() {
+ let tmp = mkdtemp(&os::tmpdir(),
+ "rustpkg_install_no_arg").expect("rustpkg_build_no_arg failed");
+ let package_dir = tmp.push("src").push("foo");
+ assert!(os::mkdir_recursive(&package_dir, U_RWX));
+ writeFile(&package_dir.push("lib.rs"),
+ "fn main() { let _x = (); }");
+ debug!("install_no_arg: dir = %s", package_dir.to_str());
+ command_line_test([~"install"], &package_dir);
+ assert_lib_exists(&tmp, "foo", NoVersion);
+}
+
+#[test]
+fn rustpkg_clean_no_arg() {
+ let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed");
+ let package_dir = tmp.push("src").push("foo");
+ assert!(os::mkdir_recursive(&package_dir, U_RWX));
+
+ writeFile(&package_dir.push("main.rs"),
+ "fn main() { let _x = (); }");
+ debug!("clean_no_arg: dir = %s", package_dir.to_str());
+ command_line_test([~"build"], &package_dir);
+ assert_built_executable_exists(&tmp, "foo");
+ command_line_test([~"clean"], &package_dir);
+ assert!(!built_executable_in_workspace(&PkgId::new("foo", &package_dir),
+ &tmp).map_default(false, |m| { os::path_exists(m) }));
+}
+
#[test]
#[ignore (reason = "Un-ignore when #7071 is fixed")]
fn rust_path_test() {
let dir_for_path = mkdtemp(&os::tmpdir(), "more_rust").expect("rust_path_test failed");
let dir = mk_workspace(&dir_for_path, &normalize(RemotePath(Path("foo"))), &NoVersion);
debug!("dir = %s", dir.to_str());
- writeFile(&Path("/Users/tjc/more_rust/src/foo-0.1/main.rs"),
- "fn main() { let _x = (); }");
+ writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }");
let cwd = os::getcwd();
debug!("cwd = %s", cwd.to_str());
#[test]
fn rust_path_contents() {
+ use std::unstable::change_dir_locked;
+
let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed");
let abc = &dir.push("A").push("B").push("C");
assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX));
- assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) {
+ assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) {
let p = rust_path();
let cwd = os::getcwd().push(".rust");
let parent = cwd.pop().pop().push(".rust");
let quux = PkgId::new("quux", &dir);
create_local_package_in(&quux, &dir);
+// NOTE Not really great output, though...
+// NOTE do any tests need to be unignored?
command_line_test([~"install", ~"foo"], &dir);
let env_arg = ~[(~"RUST_PATH", dir.to_str())];
+ debug!("RUST_PATH = %s", dir.to_str());
let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
- assert!(list_output.iter().any(|x| x.starts_with("foo-")));
+ assert!(list_output.iter().any(|x| x.starts_with("libfoo_")));
command_line_test([~"install", ~"bar"], &dir);
let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
- assert!(list_output.iter().any(|x| x.starts_with("foo-")));
- assert!(list_output.iter().any(|x| x.starts_with("bar-")));
+ assert!(list_output.iter().any(|x| x.starts_with("libfoo_")));
+ assert!(list_output.iter().any(|x| x.starts_with("libbar_")));
command_line_test([~"install", ~"quux"], &dir);
let list_output = command_line_test_output_with_env([~"list"], env_arg);
- assert!(list_output.iter().any(|x| x.starts_with("foo-")));
- assert!(list_output.iter().any(|x| x.starts_with("bar-")));
- assert!(list_output.iter().any(|x| x.starts_with("quux-")));
+ assert!(list_output.iter().any(|x| x.starts_with("libfoo_")));
+ assert!(list_output.iter().any(|x| x.starts_with("libbar_")));
+ assert!(list_output.iter().any(|x| x.starts_with("libquux_")));
}
#[test]
let mut contents = ~[];
let check_dups = |p: &PkgId| {
if contents.contains(p) {
- fail!("package database contains duplicate ID");
+ fail!("package %s appears in `list` output more than once", p.local_path.to_str());
}
else {
contents.push((*p).clone());
}
pub fn build() {
- io::println("rustpkg [options..] build
+ io::println("rustpkg [options..] build [package-ID]
-Build all targets described in the package script in the current
-directory.
+Build the given package ID if specified. With no package ID argument,
+build the package in the current directory. In that case, the current
+directory must be a direct child of an `src` directory in a workspace.
Options:
-c, --cfg Pass a cfg flag to the package script");
use extra::getopts::groups::getopts;
use syntax::ast_util::*;
use syntax::codemap::{dummy_sp, spanned};
-use syntax::codemap::dummy_spanned;
use syntax::ext::base::ExtCtxt;
use syntax::{ast, attr, codemap, diagnostic, fold};
-use syntax::ast::{meta_name_value, meta_list};
-use syntax::attr::{mk_attr};
+use syntax::attr::AttrMetaMethods;
use rustc::back::link::output_type_exe;
use rustc::driver::driver::compile_upto;
use rustc::driver::session::{lib_crate, bin_crate};
struct ReadyCtx {
sess: session::Session,
- crate: @ast::crate,
+ crate: @ast::Crate,
ext_cx: @ExtCtxt,
path: ~[ast::ident],
fns: ~[ListenerFn]
fn strip_main(item: @ast::item) -> @ast::item {
@ast::item {
attrs: do item.attrs.iter().filter_map |attr| {
- if "main" != attr::get_attr_name(attr) {
+ if "main" != attr.name() {
Some(*attr)
} else {
None
fold: @fold::ast_fold) -> Option<@ast::item> {
ctx.path.push(item.ident);
- let attrs = attr::find_attrs_by_name(item.attrs, "pkg_do");
+ let mut cmds = ~[];
+ let mut had_pkg_do = false;
- if attrs.len() > 0 {
- let mut cmds = ~[];
-
- for attrs.iter().advance |attr| {
+ for item.attrs.iter().advance |attr| {
+ if "pkg_do" == attr.name() {
+ had_pkg_do = true;
match attr.node.value.node {
- ast::meta_list(_, ref mis) => {
+ ast::MetaList(_, ref mis) => {
for mis.iter().advance |mi| {
match mi.node {
- ast::meta_word(cmd) => cmds.push(cmd.to_owned()),
+ ast::MetaWord(cmd) => cmds.push(cmd.to_owned()),
_ => {}
};
}
}
_ => cmds.push(~"build")
- };
+ }
}
+ }
+ if had_pkg_do {
ctx.fns.push(ListenerFn {
cmds: cmds,
span: item.span,
/// Generate/filter main function, add the list of commands, etc.
pub fn ready_crate(sess: session::Session,
- crate: @ast::crate) -> @ast::crate {
+ crate: @ast::Crate) -> @ast::Crate {
let ctx = @mut ReadyCtx {
sess: sess,
crate: crate,
});
// Inject the link attributes so we get the right package name and version
- if attr::find_linkage_metas(crate.node.attrs).is_empty() {
+ if attr::find_linkage_metas(crate.attrs).is_empty() {
let short_name_to_use = match what {
Test => fmt!("%stest", pkg_id.short_name),
Bench => fmt!("%sbench", pkg_id.short_name),
_ => pkg_id.short_name.clone()
};
debug!("Injecting link name: %s", short_name_to_use);
- crate = @codemap::respan(crate.span, ast::crate_ {
- attrs: ~[mk_attr(@dummy_spanned(
- meta_list(@"link",
- ~[@dummy_spanned(meta_name_value(@"name",
- mk_string_lit(short_name_to_use.to_managed()))),
- @dummy_spanned(meta_name_value(@"vers",
- mk_string_lit(pkg_id.version.to_str().to_managed())))])))],
- ..crate.node.clone()});
+ let link_options =
+ ~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()),
+ attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())];
+
+ crate = @ast::Crate {
+ attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))],
+ .. (*crate).clone()
+ };
}
debug!("calling compile_crate_from_input, out_dir = %s,
pub fn compile_crate_from_input(input: &driver::input,
build_dir: &Path,
sess: session::Session,
- crate: @ast::crate,
- cfg: ast::crate_cfg,
+ crate: @ast::Crate,
+ cfg: ast::CrateConfig,
compile_from: driver::compile_phase) {
debug!("Calling build_output_filenames with %s, building library? %?",
build_dir.to_str(), sess.building_library);
// bad copy
let outputs = driver::build_output_filenames(input, &Some((*build_dir).clone()), &None,
- crate.node.attrs, sess);
+ crate.attrs, sess);
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
debug!("additional libraries:");
pub fn find_and_install_dependencies(ctxt: &Ctx,
sess: session::Session,
workspace: &Path,
- c: &ast::crate,
+ c: &ast::Crate,
save: @fn(Path)
) {
// :-(
// rustpkg utilities having to do with workspaces
+use std::os;
+use std::path::Path;
use path_util::{rust_path, workspace_contains_package_id};
use package_id::PkgId;
-use std::path::Path;
pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
// Using the RUST_PATH, find workspaces that contain
.filter(|ws| workspace_contains_package_id(pkgid, ws))
.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) {
+ let cwd = os::getcwd();
+ let ws = cwd.pop().pop();
+ let cwd_ = cwd.clone();
+ let pkgid = cwd_.components.last().to_str();
+ (ws, PkgId::new(pkgid, &cwd))
+}
use cast::transmute_mut;
use prelude::*;
-use util::replace;
/*
A dynamic, mutable location.
Similar to a mutable option type, but friendlier.
*/
-#[mutable] // XXX remove after snap
#[no_freeze]
#[deriving(Clone, DeepClone, Eq)]
#[allow(missing_doc)]
fail!("attempt to take an empty cell");
}
- replace(&mut this.value, None).unwrap()
+ this.value.take_unwrap()
}
/// Returns the value, failing if the cell is full.
false
}
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
pub unsafe fn annihilate() {
use rt::local_heap::local_free;
if !uniq {
let tydesc: *TyDesc = transmute((*box).header.type_desc);
let data = transmute(&(*box).data);
- call_drop_glue(tydesc, data);
+ ((*tydesc).drop_glue)(data);
}
}
use libc::c_void;
#[link_name = "rustrt"]
- pub extern {
+ extern {
#[rust_stack]
// FIXME (#4386): Unable to make following method private.
pub unsafe fn rust_get_task() -> *c_void;
*/
-use core::kinds::Freeze;
+use std::kinds::Freeze;
/// A common trait for cloning an object.
pub trait Clone {
}
// FIXME: #6525: should also be implemented for `T: Send + DeepClone`
-impl<T: Freeze + DeepClone> DeepClone for @T {
+impl<T: Freeze + DeepClone + 'static> DeepClone for @T {
/// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing
/// a deep clone of a potentially cyclical type.
#[inline]
}
// FIXME: #6525: should also be implemented for `T: Send + DeepClone`
-impl<T: Freeze + DeepClone> DeepClone for @mut T {
+impl<T: Freeze + DeepClone + 'static> DeepClone for @mut T {
/// Return a deep copy of the managed box. The `Freeze` trait is required to prevent performing
/// a deep clone of a potentially cyclical type.
#[inline]
unsafe {
let mut xx = Some(x);
do chan.with_imm |chan| {
- let x = replace(&mut xx, None);
- chan.send(x.unwrap())
+ chan.send(xx.take_unwrap())
}
}
}
unsafe {
let mut xx = Some(x);
do chan.with_imm |chan| {
- let x = replace(&mut xx, None);
- chan.try_send(x.unwrap())
+ chan.try_send(xx.take_unwrap())
}
}
}
use pipes::{recv, try_recv, peek, PacketHeader};
use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable};
use cast::transmute_mut;
- use util::replace;
/*proto! oneshot (
Oneshot:send<T:Send> {
#[allow(non_camel_case_types)]
pub mod oneshot {
- priv use core::kinds::Send;
+ priv use std::kinds::Send;
use ptr::to_mut_unsafe_ptr;
pub fn init<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) {
- pub use core::pipes::HasBuffer;
+ pub use std::pipes::HasBuffer;
- let buffer = ~::core::pipes::Buffer {
- header: ::core::pipes::BufferHeader(),
+ let buffer = ~::std::pipes::Buffer {
+ header: ::std::pipes::BufferHeader(),
data: __Buffer {
- Oneshot: ::core::pipes::mk_packet::<Oneshot<T>>()
+ Oneshot: ::std::pipes::mk_packet::<Oneshot<T>>()
},
};
- do ::core::pipes::entangle_buffer(buffer) |buffer, data| {
+ do ::std::pipes::entangle_buffer(buffer) |buffer, data| {
data.Oneshot.set_buffer(buffer);
to_mut_unsafe_ptr(&mut data.Oneshot)
}
pub enum Oneshot<T> { pub send(T), }
#[allow(non_camel_case_types)]
pub struct __Buffer<T> {
- Oneshot: ::core::pipes::Packet<Oneshot<T>>,
+ Oneshot: ::std::pipes::Packet<Oneshot<T>>,
}
#[allow(non_camel_case_types)]
pub mod client {
- priv use core::kinds::Send;
+ priv use std::kinds::Send;
#[allow(non_camel_case_types)]
pub fn try_send<T: Send>(pipe: Oneshot<T>, x_0: T) ->
- ::core::option::Option<()> {
+ ::std::option::Option<()> {
{
use super::send;
let message = send(x_0);
- if ::core::pipes::send(pipe, message) {
- ::core::pipes::rt::make_some(())
- } else { ::core::pipes::rt::make_none() }
+ if ::std::pipes::send(pipe, message) {
+ ::std::pipes::rt::make_some(())
+ } else { ::std::pipes::rt::make_none() }
}
}
{
use super::send;
let message = send(x_0);
- ::core::pipes::send(pipe, message);
+ ::std::pipes::send(pipe, message);
}
}
#[allow(non_camel_case_types)]
pub type Oneshot<T> =
- ::core::pipes::SendPacketBuffered<super::Oneshot<T>,
+ ::std::pipes::SendPacketBuffered<super::Oneshot<T>,
super::__Buffer<T>>;
}
pub mod server {
#[allow(non_camel_case_types)]
pub type Oneshot<T> =
- ::core::pipes::RecvPacketBuffered<super::Oneshot<T>,
+ ::std::pipes::RecvPacketBuffered<super::Oneshot<T>,
super::__Buffer<T>>;
}
}
#[allow(non_camel_case_types)]
pub mod streamp {
- priv use core::kinds::Send;
+ priv use std::kinds::Send;
pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) {
- pub use core::pipes::HasBuffer;
- ::core::pipes::entangle()
+ pub use std::pipes::HasBuffer;
+ ::std::pipes::entangle()
}
#[allow(non_camel_case_types)]
#[allow(non_camel_case_types)]
pub mod client {
- priv use core::kinds::Send;
+ priv use std::kinds::Send;
#[allow(non_camel_case_types)]
pub fn try_data<T: Send>(pipe: Open<T>, x_0: T) ->
- ::core::option::Option<Open<T>> {
+ ::std::option::Option<Open<T>> {
{
use super::data;
- let (s, c) = ::core::pipes::entangle();
+ let (s, c) = ::std::pipes::entangle();
let message = data(x_0, s);
- if ::core::pipes::send(pipe, message) {
- ::core::pipes::rt::make_some(c)
- } else { ::core::pipes::rt::make_none() }
+ if ::std::pipes::send(pipe, message) {
+ ::std::pipes::rt::make_some(c)
+ } else { ::std::pipes::rt::make_none() }
}
}
pub fn data<T: Send>(pipe: Open<T>, x_0: T) -> Open<T> {
{
use super::data;
- let (s, c) = ::core::pipes::entangle();
+ let (s, c) = ::std::pipes::entangle();
let message = data(x_0, s);
- ::core::pipes::send(pipe, message);
+ ::std::pipes::send(pipe, message);
c
}
}
#[allow(non_camel_case_types)]
- pub type Open<T> = ::core::pipes::SendPacket<super::Open<T>>;
+ pub type Open<T> = ::std::pipes::SendPacket<super::Open<T>>;
}
#[allow(non_camel_case_types)]
pub mod server {
#[allow(non_camel_case_types)]
- pub type Open<T> = ::core::pipes::RecvPacket<super::Open<T>>;
+ pub type Open<T> = ::std::pipes::RecvPacket<super::Open<T>>;
}
}
fn send(&self, x: T) {
unsafe {
let self_endp = transmute_mut(&self.endp);
- let endp = replace(self_endp, None);
- *self_endp = Some(streamp::client::data(endp.unwrap(), x))
+ *self_endp = Some(streamp::client::data(self_endp.take_unwrap(), x))
}
}
}
fn try_send(&self, x: T) -> bool {
unsafe {
let self_endp = transmute_mut(&self.endp);
- let endp = replace(self_endp, None);
- match streamp::client::try_data(endp.unwrap(), x) {
+ match streamp::client::try_data(self_endp.take_unwrap(), x) {
Some(next) => {
*self_endp = Some(next);
true
fn recv(&self) -> T {
unsafe {
let self_endp = transmute_mut(&self.endp);
- let endp = replace(self_endp, None);
+ let endp = self_endp.take();
let streamp::data(x, endp) = recv(endp.unwrap());
*self_endp = Some(endp);
x
fn try_recv(&self) -> Option<T> {
unsafe {
let self_endp = transmute_mut(&self.endp);
- let endp = replace(self_endp, None);
+ let endp = self_endp.take();
match try_recv(endp.unwrap()) {
Some(streamp::data(x, endp)) => {
*self_endp = Some(endp);
fn peek(&self) -> bool {
unsafe {
let self_endp = transmute_mut(&self.endp);
- let mut endp = replace(self_endp, None);
+ let mut endp = self_endp.take();
let peek = match endp {
Some(ref mut endp) => peek(endp),
None => fail!("peeking empty stream")
prev: Option<@Handler<T, U>>,
}
-#[cfg(stage0)]
-pub struct Condition<'self, T, U> {
- name: &'static str,
- key: local_data::Key<'self, @Handler<T, U>>
-}
-#[cfg(not(stage0))]
pub struct Condition<T, U> {
name: &'static str,
key: local_data::Key<@Handler<T, U>>
}
-#[cfg(not(stage0))]
impl<T, U> Condition<T, U> {
pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
unsafe {
}
}
}
-#[cfg(stage0)]
-impl<'self, T, U> Condition<'self, T, U> {
- pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
- unsafe {
- let p : *RustClosure = ::cast::transmute(&h);
- let prev = local_data::get(::cast::unsafe_copy(&self.key),
- |k| k.map(|&x| *x));
- let h = @Handler { handle: *p, prev: prev };
- Trap { cond: self, handler: h }
- }
- }
-
- pub fn raise(&self, t: T) -> U {
- let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
- self.raise_default(t, || fail!(msg.clone()))
- }
-
- pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
- unsafe {
- match local_data::pop(::cast::unsafe_copy(&self.key)) {
- None => {
- debug!("Condition.raise: found no handler");
- default()
- }
- Some(handler) => {
- debug!("Condition.raise: found handler");
- match handler.prev {
- None => {}
- Some(hp) => {
- local_data::set(::cast::unsafe_copy(&self.key),
- hp)
- }
- }
- let handle : &fn(T) -> U =
- ::cast::transmute(handler.handle);
- let u = handle(t);
- local_data::set(::cast::unsafe_copy(&self.key), handler);
- u
- }
- }
- }
- }
-}
-#[cfg(stage0)]
-struct Trap<'self, T, U> {
- cond: &'self Condition<'self, T, U>,
- handler: @Handler<T, U>
-}
-#[cfg(not(stage0))]
struct Trap<'self, T, U> {
cond: &'self Condition<T, U>,
handler: @Handler<T, U>
}
}
-#[cfg(stage0)]
-struct Guard<'self, T, U> {
- cond: &'self Condition<'self, T, U>
-}
-#[cfg(not(stage0))]
struct Guard<'self, T, U> {
cond: &'self Condition<T, U>
}
use iterator::IteratorUtil;
use result::Result;
use result;
+use str::StrSlice;
use vec;
use vec::{OwnedVector, ImmutableVector};
}
}
-/// Retrieves the value in the left branch. Fails if the either is Right.
+/// Retrieves the value in the left branch.
+/// Fails with a specified reason if the either is Right.
#[inline]
-pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T {
+pub fn expect_left<T,U>(eith: Either<T,U>, reason: &str) -> T {
match eith {
Left(x) => x,
- Right(_) => fail!("either::unwrap_left Right")
+ Right(_) => fail!(reason.to_owned())
}
}
-/// Retrieves the value in the right branch. Fails if the either is Left.
+/// Retrieves the value in the left branch. Fails if the either is Right.
#[inline]
-pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U {
+pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T {
+ expect_left(eith, "either::unwrap_left Right")
+}
+
+/// Retrieves the value in the right branch.
+/// Fails with a specified reason if the either is Left.
+#[inline]
+pub fn expect_right<T,U>(eith: Either<T,U>, reason: &str) -> U {
match eith {
Right(x) => x,
- Left(_) => fail!("either::unwrap_right Left")
+ Left(_) => fail!(reason.to_owned())
}
}
+/// Retrieves the value in the right branch. Fails if the either is Left.
+pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U {
+ expect_right(eith, "either::unwrap_right Left")
+}
+
impl<T, U> Either<T, U> {
#[inline]
pub fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V {
#[inline]
pub fn is_right(&self) -> bool { is_right(self) }
+ #[inline]
+ pub fn expect_left(self, reason: &str) -> T { expect_left(self, reason) }
+
#[inline]
pub fn unwrap_left(self) -> T { unwrap_left(self) }
+ #[inline]
+ pub fn expect_right(self, reason: &str) -> U { expect_right(self, reason) }
+
#[inline]
pub fn unwrap_right(self) -> U { unwrap_right(self) }
}
use super::StackSegment;
#[link_name = "rustrt"]
- pub extern {
+ extern {
#[rust_stack]
pub unsafe fn rust_gc_metadata() -> *Word;
#[cfg(nogc)]
fn expect_sentinel() -> bool { false }
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
// Entry point for GC-based cleanup. Walks stack looking for exchange
// heap and stack allocations requiring drop, and runs all
// destructors.
// FIXME #4420: Destroy this box
// FIXME #4330: Destroy this box
} else {
- call_drop_glue(tydesc, *root as *i8);
+ ((*tydesc).drop_glue)(*root as *i8);
}
}
}
};
let len_buckets = self.buckets.len();
- let bucket = replace(&mut self.buckets[idx], None);
+ let bucket = self.buckets[idx].take();
- let value = match bucket {
- None => None,
- Some(Bucket{value, _}) => {
- Some(value)
- },
+ let value = do bucket.map_consume |bucket| {
+ bucket.value
};
/* re-inserting buckets may cause changes in size, so remember
let size = self.size - 1;
idx = self.next_bucket(idx, len_buckets);
while self.buckets[idx].is_some() {
- let bucket = replace(&mut self.buckets[idx], None);
+ let bucket = self.buckets[idx].take();
self.insert_opt_bucket(bucket);
idx = self.next_bucket(idx, len_buckets);
}
self.mangle(k, v, |_k,a| a, |k,v,_a| f(k,v))
}
- /// Calls a function on each element of a hash map, destroying the hash
- /// map in the process.
- pub fn consume(&mut self, f: &fn(K, V)) {
- let buckets = replace(&mut self.buckets,
- vec::from_fn(INITIAL_CAPACITY, |_| None));
- self.size = 0;
-
- for buckets.consume_iter().advance |bucket| {
- match bucket {
- None => {},
- Some(Bucket{key, value, _}) => {
- f(key, value)
- }
- }
- }
- }
-
- /// Creates a consuming iterator, that is, one that moves each key-value
- /// pair out of the map in arbitrary order. The map cannot be used after
- /// calling this.
- pub fn consume_iter(self) -> HashMapConsumeIterator<K, V> {
- // `consume_rev_iter` is more efficient than `consume_iter` for vectors
- HashMapConsumeIterator {iter: self.buckets.consume_rev_iter()}
- }
-
/// Retrieves a value for the given key, failing if the key is not
/// present.
pub fn get<'a>(&'a self, k: &K) -> &'a V {
pub fn mut_iter<'a>(&'a mut self) -> HashMapMutIterator<'a, K, V> {
HashMapMutIterator { iter: self.buckets.mut_iter() }
}
+
+ /// Creates a consuming iterator, that is, one that moves each key-value
+ /// pair out of the map in arbitrary order. The map cannot be used after
+ /// calling this.
+ pub fn consume(self) -> HashMapConsumeIterator<K, V> {
+ // `consume_rev_iter` is more efficient than `consume_iter` for vectors
+ HashMapConsumeIterator {iter: self.buckets.consume_rev_iter()}
+ }
}
impl<K: Hash + Eq, V: Clone> HashMap<K, V> {
fn eq(&self, other: &HashMap<K, V>) -> bool {
if self.len() != other.len() { return false; }
- for self.iter().advance |(key, value)| {
+ do self.iter().all |(key, value)| {
match other.find(key) {
- None => return false,
- Some(v) => if value != v { return false },
+ None => false,
+ Some(v) => value == v
}
}
-
- true
}
fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) }
}
/// HashMap iterator
+#[deriving(Clone)]
pub struct HashMapIterator<'self, K, V> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, V>>>,
}
}
/// HashSet iterator
+#[deriving(Clone)]
pub struct HashSetIterator<'self, K> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, ()>>>,
}
self.map.reserve_at_least(n)
}
- /// Consumes all of the elements in the set, emptying it out
- pub fn consume(&mut self, f: &fn(T)) {
- self.map.consume(|k, _| f(k))
- }
-
- /// Creates a consuming iterator, that is, one that moves each value out
- /// of the set in arbitrary order. The set cannot be used after calling
- /// this.
- pub fn consume_iter(self) -> HashSetConsumeIterator<T> {
- // `consume_rev_iter` is more efficient than `consume_iter` for vectors
- HashSetConsumeIterator {iter: self.map.buckets.consume_rev_iter()}
- }
-
/// Returns true if the hash set contains a value equivalent to the
/// given query value.
pub fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool {
HashSetIterator { iter: self.map.buckets.iter() }
}
+ /// Creates a consuming iterator, that is, one that moves each value out
+ /// of the set in arbitrary order. The set cannot be used after calling
+ /// this.
+ pub fn consume(self) -> HashSetConsumeIterator<T> {
+ // `consume_rev_iter` is more efficient than `consume_iter` for vectors
+ HashSetConsumeIterator {iter: self.map.buckets.consume_rev_iter()}
+ }
+
/// Visit the values representing the difference
pub fn difference_iter<'a>(&'a self, other: &'a HashSet<T>)
-> SetAlgebraIter<'a, T> {
#[cfg(test)]
mod test_map {
- use container::{Container, Map, Set};
+ use container::{Container, Map};
use option::{None, Some};
use super::*;
use uint;
#[test]
fn test_consume() {
- let mut m = HashMap::new();
- assert!(m.insert(1, 2));
- assert!(m.insert(2, 3));
- let mut m2 = HashMap::new();
- do m.consume |k, v| {
- m2.insert(k, v);
- }
- assert_eq!(m.len(), 0);
- assert_eq!(m2.len(), 2);
- assert_eq!(m2.get(&1), &2);
- assert_eq!(m2.get(&2), &3);
- }
-
- #[test]
- fn test_consume_still_usable() {
- let mut m = HashMap::new();
- assert!(m.insert(1, 2));
- do m.consume |_, _| {}
- assert!(m.insert(1, 2));
- }
-
- #[test]
- fn test_consume_iter() {
let hm = {
let mut hm = HashMap::new();
hm
};
- let v = hm.consume_iter().collect::<~[(char, int)]>();
+ let v = hm.consume().collect::<~[(char, int)]>();
assert!([('a', 1), ('b', 2)] == v || [('b', 2), ('a', 1)] == v);
}
#[cfg(test)]
mod test_set {
use super::*;
- use container::{Container, Map, Set};
+ use container::Container;
use vec::ImmutableEqVector;
use uint;
}
#[test]
- fn test_consume_iter() {
+ fn test_consume() {
let hs = {
let mut hs = HashSet::new();
hs
};
- let v = hs.consume_iter().collect::<~[char]>();
+ let v = hs.consume().collect::<~[char]>();
assert!(['a', 'b'] == v || ['b', 'a'] == v);
}
}
#[abi = "cdecl"]
#[link_name = "rustrt"]
- pub extern {
- unsafe fn rust_get_stdin() -> *libc::FILE;
- unsafe fn rust_get_stdout() -> *libc::FILE;
- unsafe fn rust_get_stderr() -> *libc::FILE;
+ extern {
+ pub unsafe fn rust_get_stdin() -> *libc::FILE;
+ pub unsafe fn rust_get_stdout() -> *libc::FILE;
+ pub unsafe fn rust_get_stderr() -> *libc::FILE;
}
}
/// An double-ended iterator with the direction inverted
// FIXME #6967: Dummy A parameter to get around type inference bug
+#[deriving(Clone)]
pub struct InvertIterator<A, T> {
priv iter: T
}
}
}
+/// A trait for iterators that are clonable.
+// FIXME #6967: Dummy A parameter to get around type inference bug
+pub trait ClonableIterator<A> {
+ /// Repeats an iterator endlessly
+ ///
+ /// # Example
+ ///
+ /// ~~~ {.rust}
+ /// let a = Counter::new(1,1).take_(1);
+ /// let mut cy = a.cycle();
+ /// assert_eq!(cy.next(), Some(1));
+ /// assert_eq!(cy.next(), Some(1));
+ /// ~~~
+ fn cycle(self) -> CycleIterator<A, Self>;
+}
+
+impl<A, T: Clone + Iterator<A>> ClonableIterator<A> for T {
+ #[inline]
+ fn cycle(self) -> CycleIterator<A, T> {
+ CycleIterator{orig: self.clone(), iter: self}
+ }
+}
+
+/// An iterator that repeats endlessly
+#[deriving(Clone)]
+pub struct CycleIterator<A, T> {
+ priv orig: T,
+ priv iter: T,
+}
+
+impl<A, T: Clone + Iterator<A>> Iterator<A> for CycleIterator<A, T> {
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ match self.iter.next() {
+ None => { self.iter = self.orig.clone(); self.iter.next() }
+ y => y
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ // the cycle iterator is either empty or infinite
+ match self.orig.size_hint() {
+ sz @ (0, Some(0)) => sz,
+ (0, _) => (0, None),
+ _ => (uint::max_value, None)
+ }
+ }
+}
+
/// An iterator which strings two iterators together
// FIXME #6967: Dummy A parameter to get around type inference bug
+#[deriving(Clone)]
pub struct ChainIterator<A, T, U> {
priv a: T,
priv b: U,
}
}
+impl<A, T: DoubleEndedIterator<A>, U: DoubleEndedIterator<A>> DoubleEndedIterator<A>
+for ChainIterator<A, T, U> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ match self.b.next_back() {
+ Some(x) => Some(x),
+ None => self.a.next_back()
+ }
+ }
+}
+
/// An iterator which iterates two other iterators simultaneously
// FIXME #6967: Dummy A & B parameters to get around type inference bug
+#[deriving(Clone)]
pub struct ZipIterator<A, T, B, U> {
priv a: T,
priv b: U
}
}
+impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B>
+for MapIterator<'self, A, B, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<B> {
+ match self.iter.next_back() {
+ Some(a) => Some((self.f)(a)),
+ _ => None
+ }
+ }
+}
+
/// An iterator which filters the elements of `iter` with `predicate`
pub struct FilterIterator<'self, A, T> {
priv iter: T,
}
}
+impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for FilterIterator<'self, A, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ loop {
+ match self.iter.next_back() {
+ None => return None,
+ Some(x) => {
+ if (self.predicate)(&x) {
+ return Some(x);
+ } else {
+ loop
+ }
+ }
+ }
+ }
+ }
+}
+
/// An iterator which uses `f` to both filter and map elements from `iter`
pub struct FilterMapIterator<'self, A, B, T> {
priv iter: T,
}
}
+impl<'self, A, B, T: DoubleEndedIterator<A>> DoubleEndedIterator<B>
+for FilterMapIterator<'self, A, B, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<B> {
+ loop {
+ match self.iter.next_back() {
+ None => return None,
+ Some(x) => {
+ match (self.f)(x) {
+ Some(y) => return Some(y),
+ None => ()
+ }
+ }
+ }
+ }
+ }
+}
+
/// An iterator which yields the current count and the element during iteration
// FIXME #6967: Dummy A parameter to get around type inference bug
+#[deriving(Clone)]
pub struct EnumerateIterator<A, T> {
priv iter: T,
priv count: uint
/// An iterator which skips over `n` elements of `iter`.
// FIXME #6967: Dummy A parameter to get around type inference bug
+#[deriving(Clone)]
pub struct SkipIterator<A, T> {
priv iter: T,
priv n: uint
/// An iterator which only iterates over the first `n` iterations of `iter`.
// FIXME #6967: Dummy A parameter to get around type inference bug
+#[deriving(Clone)]
pub struct TakeIterator<A, T> {
priv iter: T,
priv n: uint
}
}
+impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for PeekIterator<'self, A, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ let next = self.iter.next_back();
+
+ match next {
+ Some(ref a) => (self.f)(a),
+ None => ()
+ }
+
+ next
+ }
+}
+
/// An iterator which just modifies the contained state throughout iteration.
pub struct UnfoldrIterator<'self, A, St> {
priv f: &'self fn(&mut St) -> Option<A>,
/// An infinite iterator starting at `start` and advancing by `step` with each
/// iteration
+#[deriving(Clone)]
pub struct Counter<A> {
/// The current state the counter is at (next value to be yielded)
state: A,
assert_eq!(i, 10);
}
+ #[test]
+ fn test_cycle() {
+ let cycle_len = 3;
+ let it = Counter::new(0u,1).take_(cycle_len).cycle();
+ assert_eq!(it.size_hint(), (uint::max_value, None));
+ for it.take_(100).enumerate().advance |(i, x)| {
+ assert_eq!(i % cycle_len, x);
+ }
+
+ let mut it = Counter::new(0u,1).take_(0).cycle();
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None);
+ }
+
#[test]
fn test_iterator_nth() {
let v = &[0, 1, 2, 3, 4];
it.next();
assert_eq!(it.invert().transform(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]);
}
+
+ #[test]
+ fn test_double_ended_map() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().transform(|&x| x * -1);
+ assert_eq!(it.next(), Some(-1));
+ assert_eq!(it.next(), Some(-2));
+ assert_eq!(it.next_back(), Some(-6));
+ assert_eq!(it.next_back(), Some(-5));
+ assert_eq!(it.next(), Some(-3));
+ assert_eq!(it.next_back(), Some(-4));
+ assert_eq!(it.next(), None);
+ }
+
+ #[test]
+ fn test_double_ended_filter() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().filter(|&x| *x & 1 == 0);
+ assert_eq!(it.next_back().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &4);
+ assert_eq!(it.next().unwrap(), &2);
+ assert_eq!(it.next_back(), None);
+ }
+
+ #[test]
+ fn test_double_ended_filter_map() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None });
+ assert_eq!(it.next_back().unwrap(), 12);
+ assert_eq!(it.next_back().unwrap(), 8);
+ assert_eq!(it.next().unwrap(), 4);
+ assert_eq!(it.next_back(), None);
+ }
+
+ #[test]
+ fn test_double_ended_chain() {
+ let xs = [1, 2, 3, 4, 5];
+ let ys = ~[7, 9, 11];
+ let mut it = xs.iter().chain_(ys.iter()).invert();
+ assert_eq!(it.next().unwrap(), &11)
+ assert_eq!(it.next().unwrap(), &9)
+ assert_eq!(it.next_back().unwrap(), &1)
+ assert_eq!(it.next_back().unwrap(), &2)
+ assert_eq!(it.next_back().unwrap(), &3)
+ assert_eq!(it.next_back().unwrap(), &4)
+ assert_eq!(it.next_back().unwrap(), &5)
+ assert_eq!(it.next_back().unwrap(), &7)
+ assert_eq!(it.next_back(), None)
+ }
}
#[allow(missing_doc)];
-#[cfg(stage0)]
-#[lang="copy"]
-pub trait Copy {
- // Empty.
-}
-
-#[cfg(stage0)]
-#[lang="owned"]
-pub trait Send {
- // empty.
-}
-
-#[cfg(not(stage0))]
#[lang="send"]
pub trait Send {
// empty.
}
-#[cfg(stage0)]
-#[lang="const"]
-pub trait Freeze {
- // empty.
-}
-
-#[cfg(not(stage0))]
#[lang="freeze"]
pub trait Freeze {
// empty.
pub mod ctype {
use libc::types::os::arch::c95::{c_char, c_int};
- pub extern {
- unsafe fn isalnum(c: c_int) -> c_int;
- unsafe fn isalpha(c: c_int) -> c_int;
- unsafe fn iscntrl(c: c_int) -> c_int;
- unsafe fn isdigit(c: c_int) -> c_int;
- unsafe fn isgraph(c: c_int) -> c_int;
- unsafe fn islower(c: c_int) -> c_int;
- unsafe fn isprint(c: c_int) -> c_int;
- unsafe fn ispunct(c: c_int) -> c_int;
- unsafe fn isspace(c: c_int) -> c_int;
- unsafe fn isupper(c: c_int) -> c_int;
- unsafe fn isxdigit(c: c_int) -> c_int;
- unsafe fn tolower(c: c_char) -> c_char;
- unsafe fn toupper(c: c_char) -> c_char;
+ extern {
+ pub unsafe fn isalnum(c: c_int) -> c_int;
+ pub unsafe fn isalpha(c: c_int) -> c_int;
+ pub unsafe fn iscntrl(c: c_int) -> c_int;
+ pub unsafe fn isdigit(c: c_int) -> c_int;
+ pub unsafe fn isgraph(c: c_int) -> c_int;
+ pub unsafe fn islower(c: c_int) -> c_int;
+ pub unsafe fn isprint(c: c_int) -> c_int;
+ pub unsafe fn ispunct(c: c_int) -> c_int;
+ pub unsafe fn isspace(c: c_int) -> c_int;
+ pub unsafe fn isupper(c: c_int) -> c_int;
+ pub unsafe fn isxdigit(c: c_int) -> c_int;
+ pub unsafe fn tolower(c: c_char) -> c_char;
+ pub unsafe fn toupper(c: c_char) -> c_char;
}
}
use libc::types::common::c95::{FILE, c_void, fpos_t};
use libc::types::os::arch::c95::{c_char, c_int, c_long, size_t};
- pub extern {
- unsafe fn fopen(filename: *c_char, mode: *c_char) -> *FILE;
- unsafe fn freopen(filename: *c_char, mode: *c_char,
- file: *FILE) -> *FILE;
- unsafe fn fflush(file: *FILE) -> c_int;
- unsafe fn fclose(file: *FILE) -> c_int;
- unsafe fn remove(filename: *c_char) -> c_int;
- unsafe fn rename(oldname: *c_char, newname: *c_char) -> c_int;
- unsafe fn tmpfile() -> *FILE;
- unsafe fn setvbuf(stream: *FILE, buffer: *c_char,
- mode: c_int, size: size_t) -> c_int;
- unsafe fn setbuf(stream: *FILE, buf: *c_char);
+ extern {
+ pub unsafe fn fopen(filename: *c_char, mode: *c_char)
+ -> *FILE;
+ pub unsafe fn freopen(filename: *c_char,
+ mode: *c_char,
+ file: *FILE)
+ -> *FILE;
+ pub unsafe fn fflush(file: *FILE) -> c_int;
+ pub unsafe fn fclose(file: *FILE) -> c_int;
+ pub unsafe fn remove(filename: *c_char) -> c_int;
+ pub unsafe fn rename(oldname: *c_char, newname: *c_char)
+ -> c_int;
+ pub unsafe fn tmpfile() -> *FILE;
+ pub unsafe fn setvbuf(stream: *FILE,
+ buffer: *c_char,
+ mode: c_int,
+ size: size_t)
+ -> c_int;
+ pub unsafe fn setbuf(stream: *FILE, buf: *c_char);
// Omitted: printf and scanf variants.
- unsafe fn fgetc(stream: *FILE) -> c_int;
+ pub unsafe fn fgetc(stream: *FILE) -> c_int;
#[fast_ffi]
- unsafe fn fgets(buf: *mut c_char, n: c_int,
- stream: *FILE) -> *c_char;
+ pub unsafe fn fgets(buf: *mut c_char,
+ n: c_int,
+ stream: *FILE)
+ -> *c_char;
#[fast_ffi]
- unsafe fn fputc(c: c_int, stream: *FILE) -> c_int;
+ pub unsafe fn fputc(c: c_int, stream: *FILE) -> c_int;
#[fast_ffi]
- unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char;
+ pub unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char;
// Omitted: getc, getchar (might be macros).
// Omitted: gets, so ridiculously unsafe that it should not
// survive.
// Omitted: putc, putchar (might be macros).
- unsafe fn puts(s: *c_char) -> c_int;
- unsafe fn ungetc(c: c_int, stream: *FILE) -> c_int;
+ pub unsafe fn puts(s: *c_char) -> c_int;
+ pub unsafe fn ungetc(c: c_int, stream: *FILE) -> c_int;
#[fast_ffi]
- unsafe fn fread(ptr: *mut c_void, size: size_t,
- nobj: size_t, stream: *FILE) -> size_t;
+ pub unsafe fn fread(ptr: *mut c_void,
+ size: size_t,
+ nobj: size_t,
+ stream: *FILE)
+ -> size_t;
#[fast_ffi]
- unsafe fn fwrite(ptr: *c_void, size: size_t,
- nobj: size_t, stream: *FILE) -> size_t;
- unsafe fn fseek(stream: *FILE, offset: c_long,
- whence: c_int) -> c_int;
- unsafe fn ftell(stream: *FILE) -> c_long;
- unsafe fn rewind(stream: *FILE);
- unsafe fn fgetpos(stream: *FILE, ptr: *fpos_t) -> c_int;
- unsafe fn fsetpos(stream: *FILE, ptr: *fpos_t) -> c_int;
- unsafe fn feof(stream: *FILE) -> c_int;
- unsafe fn ferror(stream: *FILE) -> c_int;
- unsafe fn perror(s: *c_char);
+ pub unsafe fn fwrite(ptr: *c_void,
+ size: size_t,
+ nobj: size_t,
+ stream: *FILE)
+ -> size_t;
+ pub unsafe fn fseek(stream: *FILE,
+ offset: c_long,
+ whence: c_int)
+ -> c_int;
+ pub unsafe fn ftell(stream: *FILE) -> c_long;
+ pub unsafe fn rewind(stream: *FILE);
+ pub unsafe fn fgetpos(stream: *FILE, ptr: *fpos_t) -> c_int;
+ pub unsafe fn fsetpos(stream: *FILE, ptr: *fpos_t) -> c_int;
+ pub unsafe fn feof(stream: *FILE) -> c_int;
+ pub unsafe fn ferror(stream: *FILE) -> c_int;
+ pub unsafe fn perror(s: *c_char);
}
}
use libc::types::os::arch::c95::{c_long, c_uint, c_ulong};
use libc::types::os::arch::c95::{size_t};
- pub extern {
- unsafe fn abs(i: c_int) -> c_int;
- unsafe fn labs(i: c_long) -> c_long;
+ extern {
+ pub unsafe fn abs(i: c_int) -> c_int;
+ pub unsafe fn labs(i: c_long) -> c_long;
// Omitted: div, ldiv (return pub type incomplete).
- unsafe fn atof(s: *c_char) -> c_double;
- unsafe fn atoi(s: *c_char) -> c_int;
- unsafe fn strtod(s: *c_char, endp: **c_char) -> c_double;
- unsafe fn strtol(s: *c_char, endp: **c_char, base: c_int)
- -> c_long;
- unsafe fn strtoul(s: *c_char, endp: **c_char, base: c_int)
- -> c_ulong;
+ pub unsafe fn atof(s: *c_char) -> c_double;
+ pub unsafe fn atoi(s: *c_char) -> c_int;
+ pub unsafe fn strtod(s: *c_char, endp: **c_char) -> c_double;
+ pub unsafe fn strtol(s: *c_char, endp: **c_char, base: c_int)
+ -> c_long;
+ pub unsafe fn strtoul(s: *c_char, endp: **c_char, base: c_int)
+ -> c_ulong;
#[fast_ffi]
- unsafe fn calloc(nobj: size_t, size: size_t) -> *c_void;
+ pub unsafe fn calloc(nobj: size_t, size: size_t) -> *c_void;
#[fast_ffi]
- unsafe fn malloc(size: size_t) -> *c_void;
+ pub unsafe fn malloc(size: size_t) -> *c_void;
#[fast_ffi]
- unsafe fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
+ pub unsafe fn realloc(p: *mut c_void, size: size_t)
+ -> *mut c_void;
#[fast_ffi]
- unsafe fn free(p: *c_void);
- unsafe fn abort() -> !;
- unsafe fn exit(status: c_int) -> !;
+ pub unsafe fn free(p: *c_void);
+ pub unsafe fn abort() -> !;
+ pub unsafe fn exit(status: c_int) -> !;
// Omitted: atexit.
- unsafe fn system(s: *c_char) -> c_int;
- unsafe fn getenv(s: *c_char) -> *c_char;
+ pub unsafe fn system(s: *c_char) -> c_int;
+ pub unsafe fn getenv(s: *c_char) -> *c_char;
// Omitted: bsearch, qsort
- unsafe fn rand() -> c_int;
- unsafe fn srand(seed: c_uint);
+ pub unsafe fn rand() -> c_int;
+ pub unsafe fn srand(seed: c_uint);
}
}
use libc::types::os::arch::c95::{c_char, c_int, size_t};
use libc::types::os::arch::c95::{wchar_t};
- pub extern {
- unsafe fn strcpy(dst: *c_char, src: *c_char) -> *c_char;
- unsafe fn strncpy(dst: *c_char, src: *c_char, n: size_t)
- -> *c_char;
- unsafe fn strcat(s: *c_char, ct: *c_char) -> *c_char;
- unsafe fn strncat(s: *c_char, ct: *c_char, n: size_t)
- -> *c_char;
- unsafe fn strcmp(cs: *c_char, ct: *c_char) -> c_int;
- unsafe fn strncmp(cs: *c_char, ct: *c_char, n: size_t)
- -> c_int;
- unsafe fn strcoll(cs: *c_char, ct: *c_char) -> c_int;
- unsafe fn strchr(cs: *c_char, c: c_int) -> *c_char;
- unsafe fn strrchr(cs: *c_char, c: c_int) -> *c_char;
- unsafe fn strspn(cs: *c_char, ct: *c_char) -> size_t;
- unsafe fn strcspn(cs: *c_char, ct: *c_char) -> size_t;
- unsafe fn strpbrk(cs: *c_char, ct: *c_char) -> *c_char;
- unsafe fn strstr(cs: *c_char, ct: *c_char) -> *c_char;
- unsafe fn strlen(cs: *c_char) -> size_t;
- unsafe fn strerror(n: c_int) -> *c_char;
- unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char;
- unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t)
- -> size_t;
- unsafe fn wcslen(buf: *wchar_t) -> size_t;
+ extern {
+ pub unsafe fn strcpy(dst: *c_char, src: *c_char) -> *c_char;
+ pub unsafe fn strncpy(dst: *c_char, src: *c_char, n: size_t)
+ -> *c_char;
+ pub unsafe fn strcat(s: *c_char, ct: *c_char) -> *c_char;
+ pub unsafe fn strncat(s: *c_char, ct: *c_char, n: size_t)
+ -> *c_char;
+ pub unsafe fn strcmp(cs: *c_char, ct: *c_char) -> c_int;
+ pub unsafe fn strncmp(cs: *c_char, ct: *c_char, n: size_t)
+ -> c_int;
+ pub unsafe fn strcoll(cs: *c_char, ct: *c_char) -> c_int;
+ pub unsafe fn strchr(cs: *c_char, c: c_int) -> *c_char;
+ pub unsafe fn strrchr(cs: *c_char, c: c_int) -> *c_char;
+ pub unsafe fn strspn(cs: *c_char, ct: *c_char) -> size_t;
+ pub unsafe fn strcspn(cs: *c_char, ct: *c_char) -> size_t;
+ pub unsafe fn strpbrk(cs: *c_char, ct: *c_char) -> *c_char;
+ pub unsafe fn strstr(cs: *c_char, ct: *c_char) -> *c_char;
+ pub unsafe fn strlen(cs: *c_char) -> size_t;
+ pub unsafe fn strerror(n: c_int) -> *c_char;
+ pub unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char;
+ pub unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t)
+ -> size_t;
+ pub unsafe fn wcslen(buf: *wchar_t) -> size_t;
// Omitted: memcpy, memmove, memset (provided by LLVM)
// in fact, because LLVM generates calls to them!
#[rust_stack]
#[inline]
- unsafe fn memcmp(cx: *c_void, ct: *c_void, n: size_t)
- -> c_int;
+ pub unsafe fn memcmp(cx: *c_void, ct: *c_void, n: size_t)
+ -> c_int;
#[rust_stack]
#[inline]
- unsafe fn memchr(cx: *c_void, c: c_int, n: size_t) -> *c_void;
+ pub unsafe fn memchr(cx: *c_void, c: c_int, n: size_t)
+ -> *c_void;
}
}
}
use libc::types::os::common::posix01::stat;
use libc::types::os::arch::c95::{c_int, c_char};
- pub extern {
+ extern {
#[link_name = "_chmod"]
- unsafe fn chmod(path: *c_char, mode: c_int) -> c_int;
+ pub unsafe fn chmod(path: *c_char, mode: c_int) -> c_int;
#[link_name = "_mkdir"]
- unsafe fn mkdir(path: *c_char) -> c_int;
+ pub unsafe fn mkdir(path: *c_char) -> c_int;
#[link_name = "_fstat64"]
- unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+ pub unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
#[link_name = "_stat64"]
- unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
+ pub unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
}
}
use libc::types::common::c95::FILE;
use libc::types::os::arch::c95::{c_int, c_char};
- pub extern {
+ extern {
#[link_name = "_popen"]
- unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE;
+ pub unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE;
#[link_name = "_pclose"]
- unsafe fn pclose(stream: *FILE) -> c_int;
+ pub unsafe fn pclose(stream: *FILE) -> c_int;
#[link_name = "_fdopen"]
#[fast_ffi]
- unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
+ pub unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
#[link_name = "_fileno"]
- unsafe fn fileno(stream: *FILE) -> c_int;
+ pub unsafe fn fileno(stream: *FILE) -> c_int;
}
}
#[abi = "cdecl"]
pub mod fcntl {
use libc::types::os::arch::c95::{c_int, c_char};
- pub extern {
+ extern {
#[link_name = "_open"]
- unsafe fn open(path: *c_char, oflag: c_int, mode: c_int)
- -> c_int;
+ pub unsafe fn open(path: *c_char, oflag: c_int, mode: c_int)
+ -> c_int;
#[link_name = "_creat"]
- unsafe fn creat(path: *c_char, mode: c_int) -> c_int;
+ pub unsafe fn creat(path: *c_char, mode: c_int) -> c_int;
}
}
c_long, size_t};
use libc::types::os::arch::c99::intptr_t;
- pub extern {
+ extern {
#[link_name = "_access"]
- unsafe fn access(path: *c_char, amode: c_int) -> c_int;
+ pub unsafe fn access(path: *c_char, amode: c_int) -> c_int;
#[link_name = "_chdir"]
- unsafe fn chdir(dir: *c_char) -> c_int;
+ pub unsafe fn chdir(dir: *c_char) -> c_int;
#[link_name = "_close"]
- unsafe fn close(fd: c_int) -> c_int;
+ pub unsafe fn close(fd: c_int) -> c_int;
#[link_name = "_dup"]
- unsafe fn dup(fd: c_int) -> c_int;
+ pub unsafe fn dup(fd: c_int) -> c_int;
#[link_name = "_dup2"]
- unsafe fn dup2(src: c_int, dst: c_int) -> c_int;
+ pub unsafe fn dup2(src: c_int, dst: c_int) -> c_int;
#[link_name = "_execv"]
- unsafe fn execv(prog: *c_char, argv: **c_char) -> intptr_t;
+ pub unsafe fn execv(prog: *c_char, argv: **c_char)
+ -> intptr_t;
#[link_name = "_execve"]
- unsafe fn execve(prog: *c_char, argv: **c_char,
- envp: **c_char) -> c_int;
+ pub unsafe fn execve(prog: *c_char,
+ argv: **c_char,
+ envp: **c_char)
+ -> c_int;
#[link_name = "_execvp"]
- unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int;
+ pub unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int;
#[link_name = "_execvpe"]
- unsafe fn execvpe(c: *c_char, argv: **c_char,
- envp: **c_char) -> c_int;
+ pub unsafe fn execvpe(c: *c_char,
+ argv: **c_char,
+ envp: **c_char)
+ -> c_int;
#[link_name = "_getcwd"]
- unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char;
+ pub unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char;
#[link_name = "_getpid"]
- unsafe fn getpid() -> c_int;
+ pub unsafe fn getpid() -> c_int;
#[link_name = "_isatty"]
- unsafe fn isatty(fd: c_int) -> c_int;
+ pub unsafe fn isatty(fd: c_int) -> c_int;
#[link_name = "_lseek"]
- unsafe fn lseek(fd: c_int, offset: c_long, origin: c_int)
- -> c_long;
+ pub unsafe fn lseek(fd: c_int, offset: c_long, origin: c_int)
+ -> c_long;
#[link_name = "_pipe"]
- unsafe fn pipe(fds: *mut c_int, psize: c_uint,
- textmode: c_int) -> c_int;
+ pub unsafe fn pipe(fds: *mut c_int,
+ psize: c_uint,
+ textmode: c_int)
+ -> c_int;
#[link_name = "_read"]
#[fast_ffi]
- unsafe fn read(fd: c_int, buf: *mut c_void, count: c_uint)
- -> c_int;
+ pub unsafe fn read(fd: c_int, buf: *mut c_void, count: c_uint)
+ -> c_int;
#[link_name = "_rmdir"]
- unsafe fn rmdir(path: *c_char) -> c_int;
+ pub unsafe fn rmdir(path: *c_char) -> c_int;
#[link_name = "_unlink"]
- unsafe fn unlink(c: *c_char) -> c_int;
+ pub unsafe fn unlink(c: *c_char) -> c_int;
#[link_name = "_write"]
#[fast_ffi]
- unsafe fn write(fd: c_int, buf: *c_void, count: c_uint)
- -> c_int;
+ pub unsafe fn write(fd: c_int, buf: *c_void, count: c_uint)
+ -> c_int;
}
}
#[nolink]
#[abi = "cdecl"]
- pub extern {
- unsafe fn chmod(path: *c_char, mode: mode_t) -> c_int;
- unsafe fn fchmod(fd: c_int, mode: mode_t) -> c_int;
+ extern {
+ pub unsafe fn chmod(path: *c_char, mode: mode_t) -> c_int;
+ pub unsafe fn fchmod(fd: c_int, mode: mode_t) -> c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
- unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+ pub unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
#[link_name = "fstat64"]
- unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
+ pub unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
- unsafe fn mkdir(path: *c_char, mode: mode_t) -> c_int;
- unsafe fn mkfifo(path: *c_char, mode: mode_t) -> c_int;
+ pub unsafe fn mkdir(path: *c_char, mode: mode_t) -> c_int;
+ pub unsafe fn mkfifo(path: *c_char, mode: mode_t) -> c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
- unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
+ pub unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
#[link_name = "stat64"]
- unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
+ pub unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int;
}
}
use libc::types::common::c95::FILE;
use libc::types::os::arch::c95::{c_char, c_int};
- pub extern {
- unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE;
- unsafe fn pclose(stream: *FILE) -> c_int;
- unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
- unsafe fn fileno(stream: *FILE) -> c_int;
+ extern {
+ pub unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE;
+ pub unsafe fn pclose(stream: *FILE) -> c_int;
+ pub unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
+ pub unsafe fn fileno(stream: *FILE) -> c_int;
}
}
use libc::types::os::arch::c95::{c_char, c_int};
use libc::types::os::arch::posix88::mode_t;
- pub extern {
- unsafe fn open(path: *c_char, oflag: c_int, mode: c_int)
- -> c_int;
- unsafe fn creat(path: *c_char, mode: mode_t) -> c_int;
- unsafe fn fcntl(fd: c_int, cmd: c_int) -> c_int;
+ extern {
+ pub unsafe fn open(path: *c_char, oflag: c_int, mode: c_int)
+ -> c_int;
+ pub unsafe fn creat(path: *c_char, mode: mode_t) -> c_int;
+ pub unsafe fn fcntl(fd: c_int, cmd: c_int) -> c_int;
}
}
unsafe fn rust_readdir(dirp: *DIR) -> *dirent_t;
}
- pub extern {
- unsafe fn closedir(dirp: *DIR) -> c_int;
- unsafe fn rewinddir(dirp: *DIR);
- unsafe fn seekdir(dirp: *DIR, loc: c_long);
- unsafe fn telldir(dirp: *DIR) -> c_long;
+ extern {
+ pub unsafe fn closedir(dirp: *DIR) -> c_int;
+ pub unsafe fn rewinddir(dirp: *DIR);
+ pub unsafe fn seekdir(dirp: *DIR, loc: c_long);
+ pub unsafe fn telldir(dirp: *DIR) -> c_long;
}
}
use libc::types::os::arch::posix88::{gid_t, off_t, pid_t};
use libc::types::os::arch::posix88::{ssize_t, uid_t};
- pub extern {
- unsafe fn access(path: *c_char, amode: c_int) -> c_int;
- unsafe fn alarm(seconds: c_uint) -> c_uint;
- unsafe fn chdir(dir: *c_char) -> c_int;
- unsafe fn chown(path: *c_char, uid: uid_t, gid: gid_t)
- -> c_int;
- unsafe fn close(fd: c_int) -> c_int;
- unsafe fn dup(fd: c_int) -> c_int;
- unsafe fn dup2(src: c_int, dst: c_int) -> c_int;
- unsafe fn execv(prog: *c_char, argv: **c_char) -> c_int;
- unsafe fn execve(prog: *c_char,
- argv: **c_char,
- envp: **c_char)
- -> c_int;
- unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int;
- unsafe fn fork() -> pid_t;
- unsafe fn fpathconf(filedes: c_int, name: c_int) -> c_long;
- unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char;
- unsafe fn getegid() -> gid_t;
- unsafe fn geteuid() -> uid_t;
- unsafe fn getgid() -> gid_t ;
- unsafe fn getgroups(ngroups_max: c_int, groups: *mut gid_t)
- -> c_int;
- unsafe fn getlogin() -> *c_char;
- unsafe fn getopt(argc: c_int, argv: **c_char, optstr: *c_char)
- -> c_int;
- unsafe fn getpgrp() -> pid_t;
- unsafe fn getpid() -> pid_t;
- unsafe fn getppid() -> pid_t;
- unsafe fn getuid() -> uid_t;
- unsafe fn isatty(fd: c_int) -> c_int;
- unsafe fn link(src: *c_char, dst: *c_char) -> c_int;
- unsafe fn lseek(fd: c_int, offset: off_t, whence: c_int)
- -> off_t;
- unsafe fn pathconf(path: *c_char, name: c_int) -> c_long;
- unsafe fn pause() -> c_int;
- unsafe fn pipe(fds: *mut c_int) -> c_int;
+ extern {
+ pub unsafe fn access(path: *c_char, amode: c_int) -> c_int;
+ pub unsafe fn alarm(seconds: c_uint) -> c_uint;
+ pub unsafe fn chdir(dir: *c_char) -> c_int;
+ pub unsafe fn chown(path: *c_char, uid: uid_t, gid: gid_t)
+ -> c_int;
+ pub unsafe fn close(fd: c_int) -> c_int;
+ pub unsafe fn dup(fd: c_int) -> c_int;
+ pub unsafe fn dup2(src: c_int, dst: c_int) -> c_int;
+ pub unsafe fn execv(prog: *c_char, argv: **c_char) -> c_int;
+ pub unsafe fn execve(prog: *c_char,
+ argv: **c_char,
+ envp: **c_char)
+ -> c_int;
+ pub unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int;
+ pub unsafe fn fork() -> pid_t;
+ pub unsafe fn fpathconf(filedes: c_int, name: c_int)
+ -> c_long;
+ pub unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char;
+ pub unsafe fn getegid() -> gid_t;
+ pub unsafe fn geteuid() -> uid_t;
+ pub unsafe fn getgid() -> gid_t ;
+ pub unsafe fn getgroups(ngroups_max: c_int,
+ groups: *mut gid_t)
+ -> c_int;
+ pub unsafe fn getlogin() -> *c_char;
+ pub unsafe fn getopt(argc: c_int,
+ argv: **c_char,
+ optstr: *c_char)
+ -> c_int;
+ pub unsafe fn getpgrp() -> pid_t;
+ pub unsafe fn getpid() -> pid_t;
+ pub unsafe fn getppid() -> pid_t;
+ pub unsafe fn getuid() -> uid_t;
+ pub unsafe fn isatty(fd: c_int) -> c_int;
+ pub unsafe fn link(src: *c_char, dst: *c_char) -> c_int;
+ pub unsafe fn lseek(fd: c_int, offset: off_t, whence: c_int)
+ -> off_t;
+ pub unsafe fn pathconf(path: *c_char, name: c_int) -> c_long;
+ pub unsafe fn pause() -> c_int;
+ pub unsafe fn pipe(fds: *mut c_int) -> c_int;
#[fast_ffi]
- unsafe fn read(fd: c_int, buf: *mut c_void,
- count: size_t) -> ssize_t;
- unsafe fn rmdir(path: *c_char) -> c_int;
- unsafe fn setgid(gid: gid_t) -> c_int;
- unsafe fn setpgid(pid: pid_t, pgid: pid_t) -> c_int;
- unsafe fn setsid() -> pid_t;
- unsafe fn setuid(uid: uid_t) -> c_int;
- unsafe fn sleep(secs: c_uint) -> c_uint;
- unsafe fn sysconf(name: c_int) -> c_long;
- unsafe fn tcgetpgrp(fd: c_int) -> pid_t;
- unsafe fn ttyname(fd: c_int) -> *c_char;
- unsafe fn unlink(c: *c_char) -> c_int;
+ pub unsafe fn read(fd: c_int, buf: *mut c_void, count: size_t)
+ -> ssize_t;
+ pub unsafe fn rmdir(path: *c_char) -> c_int;
+ pub unsafe fn setgid(gid: gid_t) -> c_int;
+ pub unsafe fn setpgid(pid: pid_t, pgid: pid_t) -> c_int;
+ pub unsafe fn setsid() -> pid_t;
+ pub unsafe fn setuid(uid: uid_t) -> c_int;
+ pub unsafe fn sleep(secs: c_uint) -> c_uint;
+ pub unsafe fn sysconf(name: c_int) -> c_long;
+ pub unsafe fn tcgetpgrp(fd: c_int) -> pid_t;
+ pub unsafe fn ttyname(fd: c_int) -> *c_char;
+ pub unsafe fn unlink(c: *c_char) -> c_int;
#[fast_ffi]
- unsafe fn write(fd: c_int, buf: *c_void, count: size_t)
- -> ssize_t;
+ pub unsafe fn write(fd: c_int, buf: *c_void, count: size_t)
+ -> ssize_t;
}
}
use libc::types::os::arch::c95::{c_int};
use libc::types::os::arch::posix88::{pid_t};
- pub extern {
- unsafe fn kill(pid: pid_t, sig: c_int) -> c_int;
+ extern {
+ pub unsafe fn kill(pid: pid_t, sig: c_int) -> c_int;
}
}
use libc::types::os::arch::c95::{size_t, c_int, c_char};
use libc::types::os::arch::posix88::{mode_t, off_t};
- pub extern {
- unsafe fn mlock(addr: *c_void, len: size_t) -> c_int;
- unsafe fn munlock(addr: *c_void, len: size_t) -> c_int;
- unsafe fn mlockall(flags: c_int) -> c_int;
- unsafe fn munlockall() -> c_int;
-
- unsafe fn mmap(addr: *c_void,
- len: size_t,
- prot: c_int,
- flags: c_int,
- fd: c_int,
- offset: off_t) -> *mut c_void;
- unsafe fn munmap(addr: *c_void, len: size_t) -> c_int;
-
- unsafe fn mprotect(addr: *c_void, len: size_t, prot: c_int)
- -> c_int;
-
- unsafe fn msync(addr: *c_void, len: size_t, flags: c_int)
- -> c_int;
- unsafe fn shm_open(name: *c_char, oflag: c_int, mode: mode_t)
- -> c_int;
- unsafe fn shm_unlink(name: *c_char) -> c_int;
+ extern {
+ pub unsafe fn mlock(addr: *c_void, len: size_t) -> c_int;
+ pub unsafe fn munlock(addr: *c_void, len: size_t) -> c_int;
+ pub unsafe fn mlockall(flags: c_int) -> c_int;
+ pub unsafe fn munlockall() -> c_int;
+
+ pub unsafe fn mmap(addr: *c_void,
+ len: size_t,
+ prot: c_int,
+ flags: c_int,
+ fd: c_int,
+ offset: off_t)
+ -> *mut c_void;
+ pub unsafe fn munmap(addr: *c_void, len: size_t) -> c_int;
+
+ pub unsafe fn mprotect(addr: *c_void,
+ len: size_t,
+ prot: c_int)
+ -> c_int;
+
+ pub unsafe fn msync(addr: *c_void, len: size_t, flags: c_int)
+ -> c_int;
+ pub unsafe fn shm_open(name: *c_char,
+ oflag: c_int,
+ mode: mode_t)
+ -> c_int;
+ pub unsafe fn shm_unlink(name: *c_char) -> c_int;
}
}
}
use libc::types::os::arch::c95::{c_char, c_int};
use libc::types::os::arch::posix01::stat;
- pub extern {
+ extern {
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
- unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int;
+ pub unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
#[link_name = "lstat64"]
- unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int;
+ pub unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int;
}
}
use libc::types::os::arch::c95::{c_char, c_int, size_t};
use libc::types::os::arch::posix88::{ssize_t};
- pub extern {
- unsafe fn readlink(path: *c_char, buf: *mut c_char,
- bufsz: size_t) -> ssize_t;
+ extern {
+ pub unsafe fn readlink(path: *c_char,
+ buf: *mut c_char,
+ bufsz: size_t)
+ -> ssize_t;
- unsafe fn fsync(fd: c_int) -> c_int;
+ pub unsafe fn fsync(fd: c_int) -> c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
- unsafe fn fdatasync(fd: c_int) -> c_int;
+ pub unsafe fn fdatasync(fd: c_int) -> c_int;
- unsafe fn setenv(name: *c_char, val: *c_char,
- overwrite: c_int) -> c_int;
- unsafe fn unsetenv(name: *c_char) -> c_int;
- unsafe fn putenv(string: *c_char) -> c_int;
+ pub unsafe fn setenv(name: *c_char,
+ val: *c_char,
+ overwrite: c_int)
+ -> c_int;
+ pub unsafe fn unsetenv(name: *c_char) -> c_int;
+ pub unsafe fn putenv(string: *c_char) -> c_int;
- unsafe fn symlink(path1: *c_char, path2: *c_char) -> c_int;
+ pub unsafe fn symlink(path1: *c_char, path2: *c_char)
+ -> c_int;
}
}
use libc::types::os::arch::c95::{c_int};
use libc::types::os::arch::posix88::{pid_t};
- pub extern {
- unsafe fn waitpid(pid: pid_t,
- status: *mut c_int,
- options: c_int)
- -> pid_t;
+ extern {
+ pub unsafe fn waitpid(pid: pid_t,
+ status: *mut c_int,
+ options: c_int)
+ -> pid_t;
}
}
use libc::types::os::arch::c95::{c_char, c_int};
use libc::types::os::common::posix01::{glob_t};
- pub extern {
- unsafe fn glob(pattern: *c_char, flags: c_int,
- errfunc: *c_void, // XXX callback
- pglob: *mut glob_t);
- unsafe fn globfree(pglob: *mut glob_t);
+ extern {
+ pub unsafe fn glob(pattern: *c_char,
+ flags: c_int,
+ errfunc: *c_void, // XXX callback
+ pglob: *mut glob_t);
+ pub unsafe fn globfree(pglob: *mut glob_t);
}
}
use libc::types::common::c95::{c_void};
use libc::types::os::arch::c95::{c_int, size_t};
- pub extern {
- unsafe fn posix_madvise(addr: *c_void,
- len: size_t,
- advice: c_int) -> c_int;
+ extern {
+ pub unsafe fn posix_madvise(addr: *c_void,
+ len: size_t,
+ advice: c_int)
+ -> c_int;
}
}
}
size_t};
#[abi = "cdecl"]
- pub extern {
- unsafe fn sysctl(name: *c_int, namelen: c_uint,
- oldp: *mut c_void, oldlenp: *mut size_t,
- newp: *c_void, newlen: size_t) -> c_int;
+ extern {
+ pub unsafe fn sysctl(name: *c_int,
+ namelen: c_uint,
+ oldp: *mut c_void,
+ oldlenp: *mut size_t,
+ newp: *c_void,
+ newlen: size_t)
+ -> c_int;
- unsafe fn sysctlbyname(name: *c_char,
- oldp: *mut c_void, oldlenp: *mut size_t,
- newp: *c_void, newlen: size_t) -> c_int;
+ pub unsafe fn sysctlbyname(name: *c_char,
+ oldp: *mut c_void,
+ oldlenp: *mut size_t,
+ newp: *c_void,
+ newlen: size_t)
+ -> c_int;
- unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int,
- sizep: *mut size_t) -> c_int;
+ pub unsafe fn sysctlnametomib(name: *c_char,
+ mibp: *mut c_int,
+ sizep: *mut size_t)
+ -> c_int;
- unsafe fn getdtablesize() -> c_int;
+ pub unsafe fn getdtablesize() -> c_int;
- unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int)
- -> c_int;
+ pub unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int)
+ -> c_int;
- unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar)
- -> c_int;
+ pub unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar)
+ -> c_int;
}
}
use libc::types::os::arch::c95::{c_uchar, c_int, size_t};
#[abi = "cdecl"]
- pub extern {
- unsafe fn getdtablesize() -> c_int;
+ extern {
+ pub unsafe fn getdtablesize() -> c_int;
- unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int)
- -> c_int;
+ pub unsafe fn madvise(addr: *c_void, len: size_t, advice: c_int)
+ -> c_int;
- unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar)
- -> c_int;
+ pub unsafe fn mincore(addr: *c_void, len: size_t, vec: *c_uchar)
+ -> c_int;
}
}
use libc::types::os::arch::c95::{c_char, c_int};
#[abi = "cdecl"]
- pub extern {
- unsafe fn _NSGetExecutablePath(buf: *mut c_char,
- bufsize: *mut u32)
- -> c_int;
+ extern {
+ pub unsafe fn _NSGetExecutablePath(buf: *mut c_char,
+ bufsize: *mut u32)
+ -> c_int;
}
}
use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
#[abi = "stdcall"]
- pub extern "stdcall" {
- unsafe fn GetEnvironmentVariableW(n: LPCWSTR,
- v: LPWSTR,
- nsize: DWORD)
- -> DWORD;
- unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
- -> BOOL;
- unsafe fn GetEnvironmentStringsA() -> LPTCH;
- unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
-
- unsafe fn GetModuleFileNameW(hModule: HMODULE,
- lpFilename: LPWSTR,
- nSize: DWORD)
- -> DWORD;
- unsafe fn CreateDirectoryW(lpPathName: LPCWSTR,
- lpSecurityAttributes:
- LPSECURITY_ATTRIBUTES)
+ extern "stdcall" {
+ pub unsafe fn GetEnvironmentVariableW(n: LPCWSTR,
+ v: LPWSTR,
+ nsize: DWORD)
+ -> DWORD;
+ pub unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
+ -> BOOL;
+ pub unsafe fn GetEnvironmentStringsA() -> LPTCH;
+ pub unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;
+
+ pub unsafe fn GetModuleFileNameW(hModule: HMODULE,
+ lpFilename: LPWSTR,
+ nSize: DWORD)
+ -> DWORD;
+ pub unsafe fn CreateDirectoryW(lpPathName: LPCWSTR,
+ lpSecurityAttributes:
+ LPSECURITY_ATTRIBUTES)
+ -> BOOL;
+ pub unsafe fn CopyFileW(lpExistingFileName: LPCWSTR,
+ lpNewFileName: LPCWSTR,
+ bFailIfExists: BOOL)
-> BOOL;
- unsafe fn CopyFileW(lpExistingFileName: LPCWSTR,
- lpNewFileName: LPCWSTR,
- bFailIfExists: BOOL)
- -> BOOL;
- unsafe fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
- unsafe fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
- unsafe fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
-
- unsafe fn GetLastError() -> DWORD;
- unsafe fn FindFirstFileW(fileName: *u16,
- findFileData: HANDLE)
- -> HANDLE;
- unsafe fn FindNextFileW(findFile: HANDLE,
- findFileData: HANDLE)
- -> BOOL;
- unsafe fn FindClose(findFile: HANDLE) -> BOOL;
- unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE,
- hSourceHandle: HANDLE,
- hTargetProcessHandle: HANDLE,
- lpTargetHandle: LPHANDLE,
- dwDesiredAccess: DWORD,
+ pub unsafe fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
+ pub unsafe fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+ pub unsafe fn SetCurrentDirectoryW(lpPathName: LPCWSTR)
+ -> BOOL;
+
+ pub unsafe fn GetLastError() -> DWORD;
+ pub unsafe fn FindFirstFileW(fileName: *u16,
+ findFileData: HANDLE)
+ -> HANDLE;
+ pub unsafe fn FindNextFileW(findFile: HANDLE,
+ findFileData: HANDLE)
+ -> BOOL;
+ pub unsafe fn FindClose(findFile: HANDLE) -> BOOL;
+ pub unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+ hSourceHandle: HANDLE,
+ hTargetProcessHandle: HANDLE,
+ lpTargetHandle: LPHANDLE,
+ dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwOptions: DWORD)
+ -> BOOL;
+ pub unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
+ pub unsafe fn OpenProcess(dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
- dwOptions: DWORD) -> BOOL;
- unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
- unsafe fn OpenProcess(dwDesiredAccess: DWORD,
- bInheritHandle: BOOL,
- dwProcessId: DWORD) -> HANDLE;
- unsafe fn GetCurrentProcess() -> HANDLE;
- unsafe 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;
- unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
- unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
- unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
-
- unsafe fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
- unsafe fn VirtualAlloc(lpAddress: LPVOID,
- dwSize: SIZE_T,
- flAllocationType: DWORD,
- flProtect: DWORD) -> LPVOID;
- unsafe fn VirtualFree(lpAddress: LPVOID,
- dwSize: SIZE_T,
- dwFreeType: DWORD) -> BOOL;
- unsafe fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
- unsafe fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
- unsafe fn VirtualProtect(lpAddress: LPVOID,
- dwSize: SIZE_T,
- flNewProtect: DWORD,
- lpflOldProtect: LPDWORD) -> BOOL;
- unsafe fn VirtualQuery(lpAddress: LPCVOID,
- lpBuffer: LPMEMORY_BASIC_INFORMATION,
- dwLength: SIZE_T) -> SIZE_T;
-
- unsafe fn CreateFileMappingW(hFile: HANDLE,
- lpAttributes: LPSECURITY_ATTRIBUTES,
- flProtect: DWORD,
- dwMaximumSizeHigh: DWORD,
- dwMaximumSizeLow: DWORD,
- lpName: LPCTSTR) -> HANDLE;
- unsafe fn MapViewOfFile(hFileMappingObject: HANDLE,
- dwDesiredAccess: DWORD,
- dwFileOffsetHigh: DWORD,
- dwFileOffsetLow: DWORD,
- dwNumberOfBytesToMap: SIZE_T) -> LPVOID;
- unsafe fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+ dwProcessId: DWORD)
+ -> HANDLE;
+ pub unsafe fn GetCurrentProcess() -> HANDLE;
+ pub unsafe 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 unsafe fn WaitForSingleObject(hHandle: HANDLE,
+ dwMilliseconds: DWORD)
+ -> DWORD;
+ pub unsafe fn TerminateProcess(hProcess: HANDLE,
+ uExitCode: c_uint)
+ -> BOOL;
+ pub unsafe fn GetExitCodeProcess(hProcess: HANDLE,
+ lpExitCode: LPDWORD)
+ -> BOOL;
+
+ pub unsafe fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
+ pub unsafe fn VirtualAlloc(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ flAllocationType: DWORD,
+ flProtect: DWORD)
+ -> LPVOID;
+ pub unsafe fn VirtualFree(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ dwFreeType: DWORD)
+ -> BOOL;
+ pub unsafe fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T)
+ -> BOOL;
+ pub unsafe fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T)
+ -> BOOL;
+ pub unsafe fn VirtualProtect(lpAddress: LPVOID,
+ dwSize: SIZE_T,
+ flNewProtect: DWORD,
+ lpflOldProtect: LPDWORD)
+ -> BOOL;
+ pub unsafe fn VirtualQuery(lpAddress: LPCVOID,
+ lpBuffer:
+ LPMEMORY_BASIC_INFORMATION,
+ dwLength: SIZE_T)
+ -> SIZE_T;
+
+ pub unsafe fn CreateFileMappingW(hFile: HANDLE,
+ lpAttributes:
+ LPSECURITY_ATTRIBUTES,
+ flProtect: DWORD,
+ dwMaximumSizeHigh: DWORD,
+ dwMaximumSizeLow: DWORD,
+ lpName: LPCTSTR)
+ -> HANDLE;
+ pub unsafe fn MapViewOfFile(hFileMappingObject: HANDLE,
+ dwDesiredAccess: DWORD,
+ dwFileOffsetHigh: DWORD,
+ dwFileOffsetLow: DWORD,
+ dwNumberOfBytesToMap: SIZE_T)
+ -> LPVOID;
+ pub unsafe fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
}
}
#[abi = "cdecl"]
#[nolink]
- pub extern {
+ extern {
#[link_name = "_commit"]
- unsafe fn commit(fd: c_int) -> c_int;
+ pub unsafe fn commit(fd: c_int) -> c_int;
#[link_name = "_get_osfhandle"]
- unsafe fn get_osfhandle(fd: c_int) -> c_long;
+ pub unsafe fn get_osfhandle(fd: c_int) -> c_long;
}
}
}
* sections to ensure that each value of the `Key` type points to a unique
* location.
*/
-#[cfg(not(stage0))]
pub type Key<T> = &'static KeyValue<T>;
-#[cfg(stage0)]
-pub type Key<'self,T> = &'self fn(v: T);
pub enum KeyValue<T> { Key }
* Remove a task-local data value from the table, returning the
* reference that was originally created to insert it.
*/
-#[cfg(stage0)]
-pub fn pop<T: 'static>(key: Key<@T>) -> Option<@T> {
- unsafe { local_pop(Handle::new(), key) }
-}
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-#[cfg(not(stage0))]
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.
*/
-#[cfg(stage0)]
-pub fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U {
- unsafe { local_get(Handle::new(), key, f) }
-}
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-#[cfg(not(stage0))]
pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
unsafe { local_get(Handle::new(), key, f) }
}
+
/**
* Retrieve a mutable borrowed pointer to a task-local data value.
*/
-#[cfg(not(stage0))]
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) }
}
+
/**
* Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run).
*/
-#[cfg(stage0)]
-pub fn set<T: 'static>(key: Key<@T>, data: @T) {
- unsafe { local_set(Handle::new(), key, data) }
-}
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-#[cfg(not(stage0))]
pub fn set<T: 'static>(key: Key<T>, data: T) {
unsafe { local_set(Handle::new(), key, data) }
}
+
/**
* Modify a task-local data value. If the function returns 'None', the
* data is removed (and its reference dropped).
*/
-#[cfg(stage0)]
-pub fn modify<T: 'static>(key: Key<@T>, f: &fn(Option<@T>) -> Option<@T>) {
- match f(pop(key)) {
- Some(next) => { set(key, next); }
- None => {}
- }
-}
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-#[cfg(not(stage0))]
pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
unsafe {
match f(pop(::cast::unsafe_copy(&key))) {
pub mod rustrt {
use libc;
- pub extern {
- unsafe fn rust_log_console_on();
- unsafe fn rust_log_console_off();
- unsafe fn rust_log_str(level: u32,
- string: *libc::c_char,
- size: libc::size_t);
+ extern {
+ pub unsafe fn rust_log_console_on();
+ pub unsafe fn rust_log_console_off();
+ pub unsafe fn rust_log_str(level: u32,
+ string: *libc::c_char,
+ size: libc::size_t);
}
}
#[link_name = "m"]
#[abi = "cdecl"]
- pub extern {
+ extern {
// Alpabetically sorted by link_name
- unsafe fn acos(n: c_double) -> c_double;
- unsafe fn asin(n: c_double) -> c_double;
- unsafe fn atan(n: c_double) -> c_double;
- unsafe fn atan2(a: c_double, b: c_double) -> c_double;
- unsafe fn cbrt(n: c_double) -> c_double;
- unsafe fn ceil(n: c_double) -> c_double;
- unsafe fn copysign(x: c_double, y: c_double) -> c_double;
- unsafe fn cos(n: c_double) -> c_double;
- unsafe fn cosh(n: c_double) -> c_double;
- unsafe fn erf(n: c_double) -> c_double;
- unsafe fn erfc(n: c_double) -> c_double;
- unsafe fn exp(n: c_double) -> c_double;
+ pub unsafe fn acos(n: c_double) -> c_double;
+ pub unsafe fn asin(n: c_double) -> c_double;
+ pub unsafe fn atan(n: c_double) -> c_double;
+ pub unsafe fn atan2(a: c_double, b: c_double) -> c_double;
+ pub unsafe fn cbrt(n: c_double) -> c_double;
+ pub unsafe fn ceil(n: c_double) -> c_double;
+ pub unsafe fn copysign(x: c_double, y: c_double) -> c_double;
+ pub unsafe fn cos(n: c_double) -> c_double;
+ pub unsafe fn cosh(n: c_double) -> c_double;
+ pub unsafe fn erf(n: c_double) -> c_double;
+ pub unsafe fn erfc(n: c_double) -> c_double;
+ pub unsafe fn exp(n: c_double) -> c_double;
// rename: for consistency with underscore usage elsewhere
#[link_name="expm1"] unsafe fn exp_m1(n: c_double) -> c_double;
- unsafe fn exp2(n: c_double) -> c_double;
+ pub unsafe fn exp2(n: c_double) -> c_double;
#[link_name="fabs"] unsafe fn abs(n: c_double) -> c_double;
// rename: for clarity and consistency with add/sub/mul/div
#[link_name="fdim"]
- unsafe fn abs_sub(a: c_double, b: c_double) -> c_double;
- unsafe fn floor(n: c_double) -> c_double;
+ pub unsafe fn abs_sub(a: c_double, b: c_double) -> c_double;
+ pub unsafe fn floor(n: c_double) -> c_double;
// rename: for clarity and consistency with add/sub/mul/div
#[link_name="fma"]
- unsafe fn mul_add(a: c_double, b: c_double, c: c_double) -> c_double;
+ pub unsafe fn mul_add(a: c_double, b: c_double, c: c_double)
+ -> c_double;
#[link_name="fmax"]
- unsafe fn fmax(a: c_double, b: c_double) -> c_double;
+ pub unsafe fn fmax(a: c_double, b: c_double) -> c_double;
#[link_name="fmin"]
- unsafe fn fmin(a: c_double, b: c_double) -> c_double;
+ pub unsafe fn fmin(a: c_double, b: c_double) -> c_double;
#[link_name="nextafter"]
- unsafe fn next_after(x: c_double, y: c_double) -> c_double;
- unsafe fn frexp(n: c_double, value: &mut c_int) -> c_double;
- unsafe fn hypot(x: c_double, y: c_double) -> c_double;
- unsafe fn ldexp(x: c_double, n: c_int) -> c_double;
+ pub unsafe fn next_after(x: c_double, y: c_double) -> c_double;
+ pub unsafe fn frexp(n: c_double, value: &mut c_int) -> c_double;
+ pub unsafe fn hypot(x: c_double, y: c_double) -> c_double;
+ pub unsafe fn ldexp(x: c_double, n: c_int) -> c_double;
#[cfg(unix)]
#[link_name="lgamma_r"]
- unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
+ pub unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
#[cfg(windows)]
#[link_name="__lgamma_r"]
- unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
- // renamed: log is a reserved keyword; ln seems more natural, too
- #[link_name="log"] unsafe fn ln(n: c_double) -> c_double;
+ pub unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
+ // renamed: ln seems more natural
+ #[link_name="log"]
+ pub unsafe fn ln(n: c_double) -> c_double;
// renamed: "logb" /often/ is confused for log2 by beginners
- #[link_name="logb"] unsafe fn log_radix(n: c_double) -> c_double;
+ #[link_name="logb"]
+ pub unsafe fn log_radix(n: c_double) -> c_double;
// renamed: to be consitent with log as ln
- #[link_name="log1p"] unsafe fn ln_1p(n: c_double) -> c_double;
- unsafe fn log10(n: c_double) -> c_double;
- unsafe fn log2(n: c_double) -> c_double;
- #[link_name="ilogb"] unsafe fn ilog_radix(n: c_double) -> c_int;
- unsafe fn modf(n: c_double, iptr: &mut c_double) -> c_double;
- unsafe fn pow(n: c_double, e: c_double) -> c_double;
+ #[link_name="log1p"]
+ pub unsafe fn ln_1p(n: c_double) -> c_double;
+ pub unsafe fn log10(n: c_double) -> c_double;
+ pub unsafe fn log2(n: c_double) -> c_double;
+ #[link_name="ilogb"]
+ pub unsafe fn ilog_radix(n: c_double) -> c_int;
+ pub unsafe fn modf(n: c_double, iptr: &mut c_double) -> c_double;
+ pub unsafe fn pow(n: c_double, e: c_double) -> c_double;
// FIXME (#1379): enable when rounding modes become available
// unsafe fn rint(n: c_double) -> c_double;
- unsafe fn round(n: c_double) -> c_double;
+ pub unsafe fn round(n: c_double) -> c_double;
// rename: for consistency with logradix
- #[link_name="scalbn"] unsafe fn ldexp_radix(n: c_double, i: c_int) ->
- c_double;
- unsafe fn sin(n: c_double) -> c_double;
- unsafe fn sinh(n: c_double) -> c_double;
- unsafe fn sqrt(n: c_double) -> c_double;
- unsafe fn tan(n: c_double) -> c_double;
- unsafe fn tanh(n: c_double) -> c_double;
- unsafe fn tgamma(n: c_double) -> c_double;
- unsafe fn trunc(n: c_double) -> c_double;
+ #[link_name="scalbn"]
+ pub unsafe fn ldexp_radix(n: c_double, i: c_int) -> c_double;
+ pub unsafe fn sin(n: c_double) -> c_double;
+ pub unsafe fn sinh(n: c_double) -> c_double;
+ pub unsafe fn sqrt(n: c_double) -> c_double;
+ pub unsafe fn tan(n: c_double) -> c_double;
+ pub unsafe fn tanh(n: c_double) -> c_double;
+ pub unsafe fn tgamma(n: c_double) -> c_double;
+ pub unsafe fn trunc(n: c_double) -> c_double;
// These are commonly only available for doubles
- unsafe fn j0(n: c_double) -> c_double;
- unsafe fn j1(n: c_double) -> c_double;
- unsafe fn jn(i: c_int, n: c_double) -> c_double;
+ pub unsafe fn j0(n: c_double) -> c_double;
+ pub unsafe fn j1(n: c_double) -> c_double;
+ pub unsafe fn jn(i: c_int, n: c_double) -> c_double;
- unsafe fn y0(n: c_double) -> c_double;
- unsafe fn y1(n: c_double) -> c_double;
- unsafe fn yn(i: c_int, n: c_double) -> c_double;
+ pub unsafe fn y0(n: c_double) -> c_double;
+ pub unsafe fn y1(n: c_double) -> c_double;
+ pub unsafe fn yn(i: c_int, n: c_double) -> c_double;
}
}
#[link_name = "m"]
#[abi = "cdecl"]
- pub extern {
+ extern {
// Alpabetically sorted by link_name
- #[link_name="acosf"] unsafe fn acos(n: c_float) -> c_float;
- #[link_name="asinf"] unsafe fn asin(n: c_float) -> c_float;
- #[link_name="atanf"] unsafe fn atan(n: c_float) -> c_float;
+ #[link_name="acosf"]
+ pub unsafe fn acos(n: c_float) -> c_float;
+ #[link_name="asinf"]
+ pub unsafe fn asin(n: c_float) -> c_float;
+ #[link_name="atanf"]
+ pub unsafe fn atan(n: c_float) -> c_float;
#[link_name="atan2f"]
- unsafe fn atan2(a: c_float, b: c_float) -> c_float;
- #[link_name="cbrtf"] unsafe fn cbrt(n: c_float) -> c_float;
- #[link_name="ceilf"] unsafe fn ceil(n: c_float) -> c_float;
- #[link_name="copysignf"] unsafe fn copysign(x: c_float,
- y: c_float) -> c_float;
- #[link_name="cosf"] unsafe fn cos(n: c_float) -> c_float;
- #[link_name="coshf"] unsafe fn cosh(n: c_float) -> c_float;
- #[link_name="erff"] unsafe fn erf(n: c_float) -> c_float;
- #[link_name="erfcf"] unsafe fn erfc(n: c_float) -> c_float;
- #[link_name="expf"] unsafe fn exp(n: c_float) -> c_float;
- #[link_name="expm1f"]unsafe fn exp_m1(n: c_float) -> c_float;
- #[link_name="exp2f"] unsafe fn exp2(n: c_float) -> c_float;
- #[link_name="fabsf"] unsafe fn abs(n: c_float) -> c_float;
+ pub unsafe fn atan2(a: c_float, b: c_float) -> c_float;
+ #[link_name="cbrtf"]
+ pub unsafe fn cbrt(n: c_float) -> c_float;
+ #[link_name="ceilf"]
+ pub unsafe fn ceil(n: c_float) -> c_float;
+ #[link_name="copysignf"]
+ pub unsafe fn copysign(x: c_float, y: c_float) -> c_float;
+ #[link_name="cosf"]
+ pub unsafe fn cos(n: c_float) -> c_float;
+ #[link_name="coshf"]
+ pub unsafe fn cosh(n: c_float) -> c_float;
+ #[link_name="erff"]
+ pub unsafe fn erf(n: c_float) -> c_float;
+ #[link_name="erfcf"]
+ pub unsafe fn erfc(n: c_float) -> c_float;
+ #[link_name="expf"]
+ pub unsafe fn exp(n: c_float) -> c_float;
+ #[link_name="expm1f"]
+ pub unsafe fn exp_m1(n: c_float) -> c_float;
+ #[link_name="exp2f"]
+ pub unsafe fn exp2(n: c_float) -> c_float;
+ #[link_name="fabsf"]
+ pub unsafe fn abs(n: c_float) -> c_float;
#[link_name="fdimf"]
- unsafe fn abs_sub(a: c_float, b: c_float) -> c_float;
- #[link_name="floorf"] unsafe fn floor(n: c_float) -> c_float;
- #[link_name="frexpf"] unsafe fn frexp(n: c_float,
- value: &mut c_int) -> c_float;
+ pub unsafe fn abs_sub(a: c_float, b: c_float) -> c_float;
+ #[link_name="floorf"]
+ pub unsafe fn floor(n: c_float) -> c_float;
+ #[link_name="frexpf"]
+ pub unsafe fn frexp(n: c_float, value: &mut c_int) -> c_float;
#[link_name="fmaf"]
- unsafe fn mul_add(a: c_float, b: c_float, c: c_float) -> c_float;
+ pub unsafe fn mul_add(a: c_float, b: c_float, c: c_float) -> c_float;
#[link_name="fmaxf"]
- unsafe fn fmax(a: c_float, b: c_float) -> c_float;
+ pub unsafe fn fmax(a: c_float, b: c_float) -> c_float;
#[link_name="fminf"]
- unsafe fn fmin(a: c_float, b: c_float) -> c_float;
+ pub unsafe fn fmin(a: c_float, b: c_float) -> c_float;
#[link_name="nextafterf"]
- unsafe fn next_after(x: c_float, y: c_float) -> c_float;
+ pub unsafe fn next_after(x: c_float, y: c_float) -> c_float;
#[link_name="hypotf"]
- unsafe fn hypot(x: c_float, y: c_float) -> c_float;
+ pub unsafe fn hypot(x: c_float, y: c_float) -> c_float;
#[link_name="ldexpf"]
- unsafe fn ldexp(x: c_float, n: c_int) -> c_float;
+ pub unsafe fn ldexp(x: c_float, n: c_int) -> c_float;
#[cfg(unix)]
- #[link_name="lgammaf_r"] unsafe fn lgamma(n: c_float,
- sign: &mut c_int) -> c_float;
+ #[link_name="lgammaf_r"]
+ pub unsafe fn lgamma(n: c_float, sign: &mut c_int) -> c_float;
#[cfg(windows)]
#[link_name="__lgammaf_r"]
- unsafe fn lgamma(n: c_float, sign: &mut c_int) -> c_float;
+ pub unsafe fn lgamma(n: c_float, sign: &mut c_int) -> c_float;
- #[link_name="logf"] unsafe fn ln(n: c_float) -> c_float;
- #[link_name="logbf"] unsafe fn log_radix(n: c_float) -> c_float;
- #[link_name="log1pf"] unsafe fn ln_1p(n: c_float) -> c_float;
- #[link_name="log2f"] unsafe fn log2(n: c_float) -> c_float;
- #[link_name="log10f"] unsafe fn log10(n: c_float) -> c_float;
- #[link_name="ilogbf"] unsafe fn ilog_radix(n: c_float) -> c_int;
- #[link_name="modff"] unsafe fn modf(n: c_float,
- iptr: &mut c_float) -> c_float;
- #[link_name="powf"] unsafe fn pow(n: c_float, e: c_float) -> c_float;
+ #[link_name="logf"]
+ pub unsafe fn ln(n: c_float) -> c_float;
+ #[link_name="logbf"]
+ pub unsafe fn log_radix(n: c_float) -> c_float;
+ #[link_name="log1pf"]
+ pub unsafe fn ln_1p(n: c_float) -> c_float;
+ #[link_name="log2f"]
+ pub unsafe fn log2(n: c_float) -> c_float;
+ #[link_name="log10f"]
+ pub unsafe fn log10(n: c_float) -> c_float;
+ #[link_name="ilogbf"]
+ pub unsafe fn ilog_radix(n: c_float) -> c_int;
+ #[link_name="modff"]
+ pub unsafe fn modf(n: c_float, iptr: &mut c_float) -> c_float;
+ #[link_name="powf"]
+ pub unsafe fn pow(n: c_float, e: c_float) -> c_float;
// FIXME (#1379): enable when rounding modes become available
// #[link_name="rintf"] unsafe fn rint(n: c_float) -> c_float;
- #[link_name="roundf"] unsafe fn round(n: c_float) -> c_float;
- #[link_name="scalbnf"] unsafe fn ldexp_radix(n: c_float, i: c_int)
- -> c_float;
- #[link_name="sinf"] unsafe fn sin(n: c_float) -> c_float;
- #[link_name="sinhf"] unsafe fn sinh(n: c_float) -> c_float;
- #[link_name="sqrtf"] unsafe fn sqrt(n: c_float) -> c_float;
- #[link_name="tanf"] unsafe fn tan(n: c_float) -> c_float;
- #[link_name="tanhf"] unsafe fn tanh(n: c_float) -> c_float;
- #[link_name="tgammaf"] unsafe fn tgamma(n: c_float) -> c_float;
- #[link_name="truncf"] unsafe fn trunc(n: c_float) -> c_float;
+ #[link_name="roundf"]
+ pub unsafe fn round(n: c_float) -> c_float;
+ #[link_name="scalbnf"]
+ pub unsafe fn ldexp_radix(n: c_float, i: c_int) -> c_float;
+ #[link_name="sinf"]
+ pub unsafe fn sin(n: c_float) -> c_float;
+ #[link_name="sinhf"]
+ pub unsafe fn sinh(n: c_float) -> c_float;
+ #[link_name="sqrtf"]
+ pub unsafe fn sqrt(n: c_float) -> c_float;
+ #[link_name="tanf"]
+ pub unsafe fn tan(n: c_float) -> c_float;
+ #[link_name="tanhf"]
+ pub unsafe fn tanh(n: c_float) -> c_float;
+ #[link_name="tgammaf"]
+ pub unsafe fn tgamma(n: c_float) -> c_float;
+ #[link_name="truncf"]
+ pub unsafe fn trunc(n: c_float) -> c_float;
}
}
total
}
-impl<T: Zero> Zero for @mut T {
+impl<T: Zero + 'static> Zero for @mut T {
fn zero() -> @mut T { @mut Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}
-impl<T: Zero> Zero for @T {
+impl<T: Zero + 'static> Zero for @T {
fn zero() -> @T { @Zero::zero() }
fn is_zero(&self) -> bool { (**self).is_zero() }
}
use clone::Clone;
use container::Container;
-use core::cmp::{Ord, Eq};
+use std::cmp::{Ord, Eq};
use ops::{Add, Sub, Mul, Div, Rem, Neg};
use option::{None, Option, Some};
use char;
match *self { Some(ref mut x) => Some(f(x)), None => None }
}
+ /// Maps a `some` value from one type to another by a mutable reference,
+ /// or returns a default value.
+ #[inline]
+ pub fn map_mut_default<'a, U>(&'a mut self, def: U, f: &fn(&'a mut T) -> U) -> U {
+ match *self { Some(ref mut x) => f(x), None => def }
+ }
+
/// As `map`, but consumes the option and gives `f` ownership to avoid
/// copying.
#[inline]
match self { None => def, Some(v) => f(v) }
}
+ /// Take the value out of the option, leaving a `None` in its place.
+ #[inline]
+ pub fn take(&mut self) -> Option<T> {
+ util::replace(self, None)
+ }
+
+ /// As `map_consume`, but swaps a None into the original option rather
+ /// than consuming it by-value.
+ #[inline]
+ pub fn take_map<U>(&mut self, blk: &fn(T) -> U) -> Option<U> {
+ self.take().map_consume(blk)
+ }
+
+ /// As `map_consume_default`, but swaps a None into the original option
+ /// rather than consuming it by-value.
+ #[inline]
+ pub fn take_map_default<U> (&mut self, def: U, blk: &fn(T) -> U) -> U {
+ self.take().map_consume_default(def, blk)
+ }
+
/// Apply a function to the contained value or do nothing
pub fn mutate(&mut self, f: &fn(T) -> T) {
if self.is_some() {
#[inline]
pub fn take_unwrap(&mut self) -> T {
if self.is_none() { fail!("option::take_unwrap none") }
- util::replace(self, None).unwrap()
+ self.take().unwrap()
}
/**
use libc::{c_char, c_int};
use libc;
- pub extern {
- unsafe fn rust_get_argc() -> c_int;
- unsafe fn rust_get_argv() -> **c_char;
- unsafe fn rust_path_is_dir(path: *libc::c_char) -> c_int;
- unsafe fn rust_path_exists(path: *libc::c_char) -> c_int;
- unsafe fn rust_set_exit_status(code: libc::intptr_t);
+ extern {
+ pub unsafe fn rust_get_argc() -> c_int;
+ pub unsafe fn rust_get_argv() -> **c_char;
+ pub unsafe fn rust_path_is_dir(path: *libc::c_char) -> c_int;
+ pub unsafe fn rust_path_exists(path: *libc::c_char) -> c_int;
+ pub unsafe fn rust_set_exit_status(code: libc::intptr_t);
}
}
*
* This version prepends each entry with the directory.
*/
-pub fn list_dir_path(p: &Path) -> ~[~Path] {
- list_dir(p).map(|f| ~p.push(*f))
+pub fn list_dir_path(p: &Path) -> ~[Path] {
+ list_dir(p).map(|f| p.push(*f))
}
/// Removes a directory at the specified path, after removing
}
}
-/// Changes the current working directory to the specified
-/// path while acquiring a global lock, then calls `action`.
-/// If the change is successful, releases the lock and restores the
-/// CWD to what it was before, returning true.
-/// Returns false if the directory doesn't exist or if the directory change
-/// is otherwise unsuccessful.
-pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
- use unstable::global::global_data_clone_create;
- use unstable::sync::{Exclusive, exclusive};
-
- fn key(_: Exclusive<()>) { }
-
- unsafe {
- let result = global_data_clone_create(key, || { ~exclusive(()) });
-
- do result.with_imm() |_| {
- let old_dir = os::getcwd();
- if change_dir(p) {
- action();
- change_dir(&old_dir)
- }
- else {
- false
- }
- }
- }
-}
-
/// Copies a file from one location to another
pub fn copy_file(from: &Path, to: &Path) -> bool {
return do_copy_file(from, to);
val: ~[~str]
}
-#[cfg(stage0)]
-fn overridden_arg_key(_v: @OverriddenArgs) {}
-#[cfg(not(stage0))]
static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key;
/// Returns the arguments which this program was started with (normally passed
use rand;
use run;
use str::StrSlice;
- use vec;
use vec::CopyableVector;
use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
/// Returns `true` if `self` is an absolute path.
fn is_absolute(&self) -> bool;
+
+ /// True if `self` is an ancestor of `other`. See `test_is_ancestor_of` for examples
+ fn is_ancestor_of(&self, (&Self)) -> bool;
}
#[cfg(target_os = "linux")]
fn is_absolute(&self) -> bool {
self.is_absolute
}
+
+ fn is_ancestor_of(&self, other: &PosixPath) -> bool {
+ debug!("%s / %s %? %?", self.to_str(), other.to_str(), self.is_absolute,
+ self.components.len());
+ self == other ||
+ (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) &&
+ self.is_ancestor_of(&other.pop()))
+ }
+
}
fn is_absolute(&self) -> bool {
self.is_absolute
}
-}
+ fn is_ancestor_of(&self, other: &WindowsPath) -> bool {
+ self == other ||
+ (!other.components.is_empty() && !(self.components.is_empty() && !self.is_absolute) &&
+ self.is_ancestor_of(&other.pop()))
+ }
+}
pub fn normalize(components: &[~str]) -> ~[~str] {
let mut cs = ~[];
assert_eq!(WindowsPath("C:\\COM1.TXT").is_restricted(), true);
assert_eq!(WindowsPath("c:\\prn.exe").is_restricted(), true);
}
+
+ #[test]
+ fn test_is_ancestor_of() {
+ assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d")));
+ assert!(!&PosixPath("/a/b/c/d").is_ancestor_of(&PosixPath("/a/b")));
+ assert!(!&PosixPath("/a/b").is_ancestor_of(&PosixPath("/c/d")));
+ assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d")));
+ assert!(&PosixPath("/").is_ancestor_of(&PosixPath("/a/b/c")));
+ assert!(!&PosixPath("/").is_ancestor_of(&PosixPath("")));
+ assert!(!&PosixPath("/a/b/c").is_ancestor_of(&PosixPath("")));
+ assert!(!&PosixPath("").is_ancestor_of(&PosixPath("/a/b/c")));
+
+ assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d")));
+ assert!(!&WindowsPath("C:\\a\\b\\c\\d").is_ancestor_of(&WindowsPath("C:\\a\\b")));
+ assert!(!&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\c\\d")));
+ assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d")));
+ assert!(&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("C:\\a\\b\\c")));
+ assert!(!&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("")));
+ assert!(!&WindowsPath("C:\\a\\b\\c").is_ancestor_of(&WindowsPath("")));
+ assert!(!&WindowsPath("").is_ancestor_of(&WindowsPath("C:\\a\\b\\c")));
+
+ }
+
}
use libc;
use super::rust_task;
- pub extern {
+ extern {
#[rust_stack]
- unsafe fn rust_get_task() -> *rust_task;
+ pub unsafe fn rust_get_task() -> *rust_task;
#[rust_stack]
- unsafe fn rust_task_ref(task: *rust_task);
- unsafe fn rust_task_deref(task: *rust_task);
+ pub unsafe fn rust_task_ref(task: *rust_task);
+ pub unsafe fn rust_task_deref(task: *rust_task);
#[rust_stack]
- unsafe fn task_clear_event_reject(task: *rust_task);
+ pub unsafe fn task_clear_event_reject(task: *rust_task);
- unsafe fn task_wait_event(this: *rust_task,
- killed: &mut *libc::c_void)
- -> bool;
- unsafe fn task_signal_event(target: *rust_task, event: *libc::c_void);
+ pub unsafe fn task_wait_event(this: *rust_task,
+ killed: &mut *libc::c_void)
+ -> bool;
+ pub unsafe fn task_signal_event(target: *rust_task,
+ event: *libc::c_void);
}
}
// optimistic path
match p.header.state {
Full => {
- let payload = replace(&mut p.payload, None);
+ let payload = p.payload.take();
p.header.state = Empty;
return Some(payload.unwrap())
},
fail!("blocking on already blocked packet")
},
Full => {
- let payload = replace(&mut p.payload, None);
+ let payload = p.payload.take();
let old_task = swap_task(&mut p.header.blocked_task, ptr::null());
if !old_task.is_null() {
unsafe {
unsafe {
let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self);
if this.p != None {
- let p = replace(&mut this.p, None);
- sender_terminate(p.unwrap())
+ sender_terminate(this.p.take_unwrap());
}
}
}
impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> {
pub fn unwrap(&mut self) -> *mut Packet<T> {
- replace(&mut self.p, None).unwrap()
+ self.p.take_unwrap()
}
pub fn header(&mut self) -> *mut PacketHeader {
pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
//error!("send reuse_buffer");
- replace(&mut self.buffer, None).unwrap()
+ self.buffer.take_unwrap()
}
}
unsafe {
let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self);
if this.p != None {
- let p = replace(&mut this.p, None);
- receiver_terminate(p.unwrap())
+ receiver_terminate(this.p.take_unwrap())
}
}
}
impl<T:Send,Tbuffer:Send> RecvPacketBuffered<T, Tbuffer> {
pub fn unwrap(&mut self) -> *mut Packet<T> {
- replace(&mut self.p, None).unwrap()
+ self.p.take_unwrap()
}
pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> {
- replace(&mut self.buffer, None).unwrap()
+ self.buffer.take_unwrap()
}
}
use sys;
use unstable::intrinsics;
use util::swap;
-use ops::{Add,Sub};
-use num::Int;
+
+#[cfg(not(test))] use ops::{Add,Sub};
+#[cfg(not(test))] use num::Int;
#[cfg(not(test))] use cmp::{Eq, Ord};
use uint;
#[inline]
#[cfg(target_word_size = "32")]
pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
- use unstable::intrinsics::memmove32;
- memmove32(dst, src as *T, count as u32);
+ intrinsics::memmove32(dst, src as *T, count as u32);
}
/**
#[inline]
#[cfg(target_word_size = "64")]
pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
- use unstable::intrinsics::memmove64;
- memmove64(dst, src as *T, count as u64);
+ intrinsics::memmove64(dst, src as *T, count as u64);
}
/**
#[inline]
#[cfg(target_word_size = "32")]
pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
- use unstable::intrinsics::memcpy32;
- memcpy32(dst, src as *T, count as u32);
+ intrinsics::memcpy32(dst, src as *T, count as u32);
}
/**
#[inline]
#[cfg(target_word_size = "64")]
pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
- use unstable::intrinsics::memcpy64;
- memcpy64(dst, src as *T, count as u64);
+ intrinsics::memcpy64(dst, src as *T, count as u64);
}
/**
#[inline]
#[cfg(target_word_size = "32")]
pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
- use unstable::intrinsics::memset32;
- memset32(dst, c, count as u32);
+ intrinsics::memset32(dst, c, count as u32);
}
/**
#[inline]
#[cfg(target_word_size = "64")]
pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
- use unstable::intrinsics::memset64;
- memset64(dst, c, count as u64);
+ intrinsics::memset64(dst, c, count as u64);
}
/**
* Zeroes out `count * size_of::<T>` bytes of memory at `dst`
*/
#[inline]
-#[cfg(not(stage0))]
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
set_memory(dst, 0, count);
}
-/**
- * Zeroes out `count * size_of::<T>` bytes of memory at `dst`
- */
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
- let mut count = count * sys::size_of::<T>();
- let mut dst = dst as *mut u8;
- while count > 0 {
- *dst = 0;
- dst = mut_offset(dst, 1);
- count -= 1;
- }
-}
-
/**
* Swap the values at two mutable locations of the same type, without
* deinitialising or copying either one.
}
let mut xs_mut = xs.clone();
- let mut m_start = to_mut_ptr(xs_mut);
+ let m_start = to_mut_ptr(xs_mut);
let mut m_ptr = m_start + 9u32;
while m_ptr >= m_start {
fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() }
}
-impl<T: Rand> Rand for @T {
+impl<T: Rand + 'static> Rand for @T {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() }
}
pub mod rustrt {
use libc::size_t;
- pub extern {
- unsafe fn rand_seed_size() -> size_t;
- unsafe fn rand_gen_seed(buf: *mut u8, sz: size_t);
+ extern {
+ pub unsafe fn rand_seed_size() -> size_t;
+ pub unsafe fn rand_gen_seed(buf: *mut u8, sz: size_t);
}
}
}
// used to make space in TLS for a random number generator
-#[cfg(stage0)]
-fn tls_rng_state(_v: @@mut IsaacRng) {}
-#[cfg(not(stage0))]
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
/**
// This is to verify that the implementation of the ISAAC rng is
// correct (i.e. matches the output of the upstream implementation,
// which is in the runtime)
- use vec;
use libc::size_t;
#[abi = "cdecl"]
#[allow(non_camel_case_types)] // runtime type
pub enum rust_rng {}
- pub extern {
- unsafe fn rand_new_seeded(buf: *u8, sz: size_t) -> *rust_rng;
- unsafe fn rand_next(rng: *rust_rng) -> u32;
- unsafe fn rand_free(rng: *rust_rng);
+ extern {
+ pub unsafe fn rand_new_seeded(buf: *u8, sz: size_t)
+ -> *rust_rng;
+ pub unsafe fn rand_next(rng: *rust_rng) -> u32;
+ pub unsafe fn rand_free(rng: *rust_rng);
}
}
#[allow(missing_doc)];
-#[cfg(stage0)]
-use intrinsic::{Opaque, TyDesc, TyVisitor};
-#[cfg(not(stage0))]
use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
use libc::c_void;
use sys;
true
}
- fn visit_str(&self) -> bool {
- self.align_to::<~str>();
- if ! self.inner.visit_str() { return false; }
- self.bump_past::<~str>();
- true
- }
-
fn visit_estr_box(&self) -> bool {
self.align_to::<@str>();
if ! self.inner.visit_estr_box() { return false; }
true
}
- #[cfg(not(stage0))]
fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<~u8>();
if ! self.inner.visit_uniq_managed(mtbl, inner) { return false; }
true
}
- #[cfg(not(stage0))]
fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<~[@u8]>();
if ! self.inner.visit_evec_uniq_managed(mtbl, inner) { return false; }
use vec::raw::{VecRepr, SliceRepr};
use vec;
use vec::{OwnedVector, UnboxedVecRepr};
-#[cfg(stage0)]
-use intrinsic::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
-#[cfg(not(stage0))]
use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
#[cfg(test)] use io;
}
pub fn write_vec_range(&self,
- mtbl: uint,
+ _mtbl: uint,
ptr: *u8,
len: uint,
inner: *TyDesc)
} else {
self.writer.write_str(", ");
}
- self.write_mut_qualifier(mtbl);
self.visit_ptr_inner(p as *c_void, inner);
p = align(ptr::offset(p, sz) as uint, al) as *u8;
left -= dec;
}
}
- // Type no longer exists, vestigial function.
- fn visit_str(&self) -> bool { fail!(); }
-
fn visit_estr_box(&self) -> bool {
do self.get::<@str> |s| {
self.writer.write_char('@');
}
}
- fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write_char('~');
- self.write_mut_qualifier(mtbl);
do self.get::<*c_void> |b| {
self.visit_ptr_inner(*b, inner);
}
}
- #[cfg(not(stage0))]
- fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write_char('~');
- self.write_mut_qualifier(mtbl);
do self.get::<&managed::raw::BoxRepr> |b| {
let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
self.visit_ptr_inner(p, inner);
fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
do self.get::<&VecRepr> |b| {
self.writer.write_char('@');
+ self.write_mut_qualifier(mtbl);
self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner);
}
}
}
}
- #[cfg(not(stage0))]
fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
do self.get::<&VecRepr> |b| {
self.writer.write_char('~');
fn visit_self(&self) -> bool { true }
fn visit_type(&self) -> bool { true }
- #[cfg(not(stage0))]
fn visit_opaque_box(&self) -> bool {
self.writer.write_char('@');
do self.get::<&managed::raw::BoxRepr> |b| {
self.visit_ptr_inner(p, b.header.type_desc);
}
}
- #[cfg(stage0)]
- fn visit_opaque_box(&self) -> bool {
- self.writer.write_char('@');
- do self.get::<&managed::raw::BoxRepr> |b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- unsafe {
- self.visit_ptr_inner(p, transmute(b.header.type_desc));
- }
- }
- }
// Type no longer exists, vestigial function.
fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
exact_test(&(@"hello"), "@\"hello\"");
exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
- // FIXME #4210: the mut fields are a bit off here.
exact_test(&(@10), "@10");
- exact_test(&(@mut 10), "@10");
+ exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
+ exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
exact_test(&(~10), "~10");
exact_test(&(&10), "&10");
let mut x = 10;
exact_test(&(&mut x), "&mut 10");
+ exact_test(&(@mut [1, 2]), "@mut [1, 2]");
exact_test(&(1,), "(1,)");
exact_test(&(@[1,2,3,4,5,6,7,8]),
}
#[cfg(test)]
-#[allow(non_implicitly_copyable_typarams)]
mod tests {
use result::{Err, Ok, Result, chain, get, get_err};
use result;
// except according to those terms.
//! Ports and channels.
-//!
-//! XXX: Carefully consider whether the sequentially consistent
-//! atomics here can be converted to acq/rel. I'm not sure they can,
-//! because there is data being transerred in both directions (the payload
-//! goes from sender to receiver and the task pointer goes the other way).
use option::*;
use cast;
use util;
use ops::Drop;
-use rt::task::Task;
+use rt::kill::BlockedTask;
use kinds::Send;
use rt::sched::Scheduler;
use rt::local::Local;
use cell::Cell;
use clone::Clone;
-/// A combined refcount / ~Task pointer.
+/// A combined refcount / BlockedTask-as-uint pointer.
///
/// Can be equal to the following values:
///
/// * 2 - both endpoints are alive
/// * 1 - either the sender or the receiver is dead, determined by context
-/// * <ptr> - A pointer to a blocked Task that can be transmuted to ~Task
+/// * <ptr> - A pointer to a blocked Task (see BlockedTask::cast_{to,from}_uint)
type State = uint;
static STATE_BOTH: State = 2;
}
task_as_state => {
// Port is blocked. Wake it up.
- let recvr: ~Task = cast::transmute(task_as_state);
- let mut sched = Local::take::<Scheduler>();
- rtdebug!("rendezvous send");
- sched.metrics.rendezvous_sends += 1;
- sched.schedule_task(recvr);
+ let recvr = BlockedTask::cast_from_uint(task_as_state);
+ do recvr.wake().map_consume |woken_task| {
+ let mut sched = Local::take::<Scheduler>();
+ rtdebug!("rendezvous send");
+ sched.metrics.rendezvous_sends += 1;
+ sched.schedule_task(woken_task);
+ };
}
}
}
// an acquire barrier to prevent reordering of the subsequent read
// of the payload. Also issues a release barrier to prevent reordering
// of any previous writes to the task structure.
- let task_as_state: State = cast::transmute(task);
+ let task_as_state = task.cast_to_uint();
let oldstate = (*packet).state.swap(task_as_state, SeqCst);
match oldstate {
STATE_BOTH => {
// NB: We have to drop back into the scheduler event loop here
// instead of switching immediately back or we could end up
// triggering infinite recursion on the scheduler's stack.
- let task: ~Task = cast::transmute(task_as_state);
- sched.enqueue_task(task);
+ let recvr = BlockedTask::cast_from_uint(task_as_state);
+ sched.enqueue_blocked_task(recvr);
}
_ => util::unreachable()
}
task_as_state => {
// The port is blocked waiting for a message we will never send. Wake it.
assert!((*this.packet()).payload.is_none());
- let recvr: ~Task = cast::transmute(task_as_state);
- let sched = Local::take::<Scheduler>();
- sched.schedule_task(recvr);
+ let recvr = BlockedTask::cast_from_uint(task_as_state);
+ do recvr.wake().map_consume |woken_task| {
+ let sched = Local::take::<Scheduler>();
+ sched.schedule_task(woken_task);
+ };
}
}
}
STATE_ONE => {
let _packet: ~Packet<T> = cast::transmute(this.void_packet);
}
- _ => {
- util::unreachable()
+ task_as_state => {
+ // This case occurs during unwinding, when the blocked
+ // receiver was killed awake. The task can't still be
+ // blocked (we are it), but we need to free the handle.
+ let recvr = BlockedTask::cast_from_uint(task_as_state);
+ // FIXME(#7554)(bblum): Make this cfg(test) dependent.
+ // in a later commit.
+ assert!(recvr.wake().is_none());
}
}
}
// XXX: ptr::offset is positive ints only
#[inline]
pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
- use core::sys::size_of;
+ use std::sys::size_of;
(ptr as int + count * (size_of::<T>() as int)) as *mut T
}
p
}
-// FIXME #4942: Make these signatures agree with exchange_alloc's signatures
-#[cfg(stage0, not(test))]
-#[lang="exchange_malloc"]
-#[inline]
-pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
- let td = td as *TyDesc;
- let size = size as uint;
-
- assert!(td.is_not_null());
-
- let total_size = get_box_size(size, (*td).align);
- let p = malloc_raw(total_size as uint);
-
- let box: *mut BoxRepr = p as *mut BoxRepr;
- (*box).header.ref_count = -1;
- (*box).header.type_desc = td;
-
- box as *c_char
-}
-
/// The allocator for unique pointers without contained managed pointers.
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char {
pub use self::stdio::println;
pub use self::file::FileStream;
+pub use self::timer::Timer;
pub use self::net::ip::IpAddr;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
/// Non-I/O things needed by the I/O module
mod support;
+/// Basic Timer
+pub mod timer;
+
/// Thread-blocking implementations
pub mod native {
/// Posix file I/O
}
}
- pub fn recvfrom(&self, buf: &mut [u8]) -> Option<(uint, IpAddr)> {
+ pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, IpAddr)> {
match (**self).recvfrom(buf) {
Ok((nread, src)) => Some((nread, src)),
Err(ioerr) => {
}
}
- pub fn sendto(&self, buf: &[u8], dst: IpAddr) {
+ pub fn sendto(&mut self, buf: &[u8], dst: IpAddr) {
match (**self).sendto(buf, dst) {
Ok(_) => (),
Err(ioerr) => io_error::cond.raise(ioerr),
}
impl UdpStream {
- pub fn as_socket<T>(&self, f: &fn(&UdpSocket) -> T) -> T { f(&self.socket) }
+ pub fn as_socket<T>(&mut self, f: &fn(&mut UdpSocket) -> T) -> T { f(&mut self.socket) }
pub fn disconnect(self) -> UdpSocket { self.socket }
}
impl Reader for UdpStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ let peer = self.connectedTo;
do self.as_socket |sock| {
match sock.recvfrom(buf) {
- Some((_nread, src)) if src != self.connectedTo => Some(0),
+ Some((_nread, src)) if src != peer => Some(0),
Some((nread, _src)) => Some(nread),
None => None,
}
do spawntask_immediately {
match UdpSocket::bind(server_ip) {
- Some(server) => {
+ Some(ref mut server) => {
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
do spawntask_immediately {
match UdpSocket::bind(client_ip) {
- Some(client) => client.sendto([99], server_ip),
+ Some(ref mut client) => client.sendto([99], server_ip),
None => fail!()
}
}
do spawntask_immediately {
match UdpSocket::bind(server_ip) {
- Some(server) => {
+ Some(ref mut server) => {
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
do spawntask_immediately {
match UdpSocket::bind(client_ip) {
- Some(client) => client.sendto([99], server_ip),
+ Some(ref mut client) => client.sendto([99], server_ip),
None => fail!()
}
}
--- /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 option::{Option, Some, None};
+use result::{Ok, Err};
+use rt::io::{io_error};
+use rt::rtio::{IoFactory, IoFactoryObject,
+ RtioTimer, RtioTimerObject};
+use rt::local::Local;
+
+pub struct Timer(~RtioTimerObject);
+
+impl Timer {
+ fn new_on_rt(i: ~RtioTimerObject) -> Timer {
+ Timer(i)
+ }
+
+ pub fn new() -> Option<Timer> {
+ let timer = unsafe {
+ rtdebug!("Timer::init: borrowing io to init timer");
+ let io = Local::unsafe_borrow::<IoFactoryObject>();
+ rtdebug!("about to init timer");
+ (*io).timer_init()
+ };
+ match timer {
+ Ok(t) => Some(Timer::new_on_rt(t)),
+ Err(ioerr) => {
+ rtdebug!("Timer::init: failed to init: %?", ioerr);
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+ }
+}
+
+impl RtioTimer for Timer {
+ fn sleep(&self, msecs: u64) {
+ (**self).sleep(msecs);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use rt::test::*;
+ use option::{Some, None};
+ #[test]
+ fn test_io_timer_sleep_simple() {
+ do run_in_newsched_task {
+ let timer = Timer::new();
+ match timer {
+ Some(t) => t.sleep(1),
+ None => assert!(false)
+ }
+ }
+ }
+}
\ No newline at end of file
+++ /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 JoinLatch is a concurrent type that establishes the task
-//! tree and propagates failure.
-//!
-//! Each task gets a JoinLatch that is derived from the JoinLatch
-//! of its parent task. Every latch must be released by either calling
-//! the non-blocking `release` method or the task-blocking `wait` method.
-//! Releasing a latch does not complete until all of its child latches
-//! complete.
-//!
-//! Latches carry a `success` flag that is set to `false` during task
-//! failure and is propagated both from children to parents and parents
-//! to children. The status af this flag may be queried for the purposes
-//! of linked failure.
-//!
-//! In addition to failure propagation the task tree serves to keep the
-//! default task schedulers alive. The runtime only sends the shutdown
-//! message to schedulers once the root task exits.
-//!
-//! Under this scheme tasks that terminate before their children become
-//! 'zombies' since they may not exit until their children do. Zombie
-//! tasks are 'tombstoned' as `Tombstone(~JoinLatch)` and the tasks
-//! themselves allowed to terminate.
-//!
-//! XXX: Propagate flag from parents to children.
-//! XXX: Tombstoning actually doesn't work.
-//! XXX: This could probably be done in a way that doesn't leak tombstones
-//! longer than the life of the child tasks.
-
-use comm::{GenericPort, Peekable, GenericSmartChan};
-use clone::Clone;
-use container::Container;
-use option::{Option, Some, None};
-use ops::Drop;
-use rt::comm::{SharedChan, Port, stream};
-use rt::local::Local;
-use rt::sched::Scheduler;
-use unstable::atomics::{AtomicUint, SeqCst};
-use util;
-use vec::OwnedVector;
-
-// FIXME #7026: Would prefer this to be an enum
-pub struct JoinLatch {
- priv parent: Option<ParentLink>,
- priv child: Option<ChildLink>,
- closed: bool,
-}
-
-// Shared between parents and all their children.
-struct SharedState {
- /// Reference count, held by a parent and all children.
- count: AtomicUint,
- success: bool
-}
-
-struct ParentLink {
- shared: *mut SharedState,
- // For communicating with the parent.
- chan: SharedChan<Message>
-}
-
-struct ChildLink {
- shared: ~SharedState,
- // For receiving from children.
- port: Port<Message>,
- chan: SharedChan<Message>,
- // Prevents dropping the child SharedState reference counts multiple times.
- dropped_child: bool
-}
-
-// Messages from child latches to parent.
-enum Message {
- Tombstone(~JoinLatch),
- ChildrenTerminated
-}
-
-impl JoinLatch {
- pub fn new_root() -> ~JoinLatch {
- let this = ~JoinLatch {
- parent: None,
- child: None,
- closed: false
- };
- rtdebug!("new root latch %x", this.id());
- return this;
- }
-
- fn id(&self) -> uint {
- unsafe { ::cast::transmute(&*self) }
- }
-
- pub fn new_child(&mut self) -> ~JoinLatch {
- rtassert!(!self.closed);
-
- if self.child.is_none() {
- // This is the first time spawning a child
- let shared = ~SharedState {
- count: AtomicUint::new(1),
- success: true
- };
- let (port, chan) = stream();
- let chan = SharedChan::new(chan);
- let child = ChildLink {
- shared: shared,
- port: port,
- chan: chan,
- dropped_child: false
- };
- self.child = Some(child);
- }
-
- let child_link: &mut ChildLink = self.child.get_mut_ref();
- let shared_state: *mut SharedState = &mut *child_link.shared;
-
- child_link.shared.count.fetch_add(1, SeqCst);
-
- let child = ~JoinLatch {
- parent: Some(ParentLink {
- shared: shared_state,
- chan: child_link.chan.clone()
- }),
- child: None,
- closed: false
- };
- rtdebug!("NEW child latch %x", child.id());
- return child;
- }
-
- pub fn release(~self, local_success: bool) {
- // XXX: This should not block, but there's a bug in the below
- // code that I can't figure out.
- self.wait(local_success);
- }
-
- // XXX: Should not require ~self
- fn release_broken(~self, local_success: bool) {
- rtassert!(!self.closed);
-
- rtdebug!("releasing %x", self.id());
-
- let id = self.id();
- let _ = id; // XXX: `id` is only used in debug statements so appears unused
- let mut this = self;
- let mut child_success = true;
- let mut children_done = false;
-
- if this.child.is_some() {
- rtdebug!("releasing children");
- let child_link: &mut ChildLink = this.child.get_mut_ref();
- let shared: &mut SharedState = &mut *child_link.shared;
-
- if !child_link.dropped_child {
- let last_count = shared.count.fetch_sub(1, SeqCst);
- rtdebug!("child count before sub %u %x", last_count, id);
- if last_count == 1 {
- assert!(child_link.chan.try_send(ChildrenTerminated));
- }
- child_link.dropped_child = true;
- }
-
- // Wait for messages from children
- let mut tombstones = ~[];
- loop {
- if child_link.port.peek() {
- match child_link.port.recv() {
- Tombstone(t) => {
- tombstones.push(t);
- },
- ChildrenTerminated => {
- children_done = true;
- break;
- }
- }
- } else {
- break
- }
- }
-
- rtdebug!("releasing %u tombstones %x", tombstones.len(), id);
-
- // Try to release the tombstones. Those that still have
- // outstanding will be re-enqueued. When this task's
- // parents release their latch we'll end up back here
- // trying them again.
- while !tombstones.is_empty() {
- tombstones.pop().release(true);
- }
-
- if children_done {
- let count = shared.count.load(SeqCst);
- assert!(count == 0);
- // self_count is the acquire-read barrier
- child_success = shared.success;
- }
- } else {
- children_done = true;
- }
-
- let total_success = local_success && child_success;
-
- rtassert!(this.parent.is_some());
-
- unsafe {
- {
- let parent_link: &mut ParentLink = this.parent.get_mut_ref();
- let shared: *mut SharedState = parent_link.shared;
-
- if !total_success {
- // parent_count is the write-wait barrier
- (*shared).success = false;
- }
- }
-
- if children_done {
- rtdebug!("children done");
- do Local::borrow::<Scheduler, ()> |sched| {
- sched.metrics.release_tombstone += 1;
- }
- {
- rtdebug!("RELEASING parent %x", id);
- let parent_link: &mut ParentLink = this.parent.get_mut_ref();
- let shared: *mut SharedState = parent_link.shared;
- let last_count = (*shared).count.fetch_sub(1, SeqCst);
- rtdebug!("count before parent sub %u %x", last_count, id);
- if last_count == 1 {
- assert!(parent_link.chan.try_send(ChildrenTerminated));
- }
- }
- this.closed = true;
- util::ignore(this);
- } else {
- rtdebug!("children not done");
- rtdebug!("TOMBSTONING %x", id);
- do Local::borrow::<Scheduler, ()> |sched| {
- sched.metrics.release_no_tombstone += 1;
- }
- let chan = {
- let parent_link: &mut ParentLink = this.parent.get_mut_ref();
- parent_link.chan.clone()
- };
- assert!(chan.try_send(Tombstone(this)));
- }
- }
- }
-
- // XXX: Should not require ~self
- pub fn wait(~self, local_success: bool) -> bool {
- rtassert!(!self.closed);
-
- rtdebug!("WAITING %x", self.id());
-
- let mut this = self;
- let mut child_success = true;
-
- if this.child.is_some() {
- rtdebug!("waiting for children");
- let child_link: &mut ChildLink = this.child.get_mut_ref();
- let shared: &mut SharedState = &mut *child_link.shared;
-
- if !child_link.dropped_child {
- let last_count = shared.count.fetch_sub(1, SeqCst);
- rtdebug!("child count before sub %u", last_count);
- if last_count == 1 {
- assert!(child_link.chan.try_send(ChildrenTerminated));
- }
- child_link.dropped_child = true;
- }
-
- // Wait for messages from children
- loop {
- match child_link.port.recv() {
- Tombstone(t) => {
- t.wait(true);
- }
- ChildrenTerminated => break
- }
- }
-
- let count = shared.count.load(SeqCst);
- if count != 0 { ::io::println(fmt!("%u", count)); }
- assert!(count == 0);
- // self_count is the acquire-read barrier
- child_success = shared.success;
- }
-
- let total_success = local_success && child_success;
-
- if this.parent.is_some() {
- rtdebug!("releasing parent");
- unsafe {
- let parent_link: &mut ParentLink = this.parent.get_mut_ref();
- let shared: *mut SharedState = parent_link.shared;
-
- if !total_success {
- // parent_count is the write-wait barrier
- (*shared).success = false;
- }
-
- let last_count = (*shared).count.fetch_sub(1, SeqCst);
- rtdebug!("count before parent sub %u", last_count);
- if last_count == 1 {
- assert!(parent_link.chan.try_send(ChildrenTerminated));
- }
- }
- }
-
- this.closed = true;
- util::ignore(this);
-
- return total_success;
- }
-}
-
-impl Drop for JoinLatch {
- fn drop(&self) {
- rtdebug!("DESTROYING %x", self.id());
- rtassert!(self.closed);
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use cell::Cell;
- use container::Container;
- use iter::Times;
- use rt::test::*;
- use rand;
- use rand::RngUtil;
- use vec::{CopyableVector, ImmutableVector};
-
- #[test]
- fn success_immediately() {
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_immediately {
- let child_latch = child_latch.take();
- assert!(child_latch.wait(true));
- }
-
- assert!(latch.wait(true));
- }
- }
-
- #[test]
- fn success_later() {
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_later {
- let child_latch = child_latch.take();
- assert!(child_latch.wait(true));
- }
-
- assert!(latch.wait(true));
- }
- }
-
- #[test]
- fn mt_success() {
- do run_in_mt_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- for 10.times {
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_random {
- let child_latch = child_latch.take();
- assert!(child_latch.wait(true));
- }
- }
-
- assert!(latch.wait(true));
- }
- }
-
- #[test]
- fn mt_failure() {
- do run_in_mt_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- let spawn = |status| {
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_random {
- let child_latch = child_latch.take();
- child_latch.wait(status);
- }
- };
-
- for 10.times { spawn(true) }
- spawn(false);
- for 10.times { spawn(true) }
-
- assert!(!latch.wait(true));
- }
- }
-
- #[test]
- fn mt_multi_level_success() {
- do run_in_mt_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- fn child(latch: &mut JoinLatch, i: int) {
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_random {
- let mut child_latch = child_latch.take();
- if i != 0 {
- child(&mut *child_latch, i - 1);
- child_latch.wait(true);
- } else {
- child_latch.wait(true);
- }
- }
- }
-
- child(&mut *latch, 10);
-
- assert!(latch.wait(true));
- }
- }
-
- #[test]
- fn mt_multi_level_failure() {
- do run_in_mt_newsched_task {
- let mut latch = JoinLatch::new_root();
-
- fn child(latch: &mut JoinLatch, i: int) {
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_random {
- let mut child_latch = child_latch.take();
- if i != 0 {
- child(&mut *child_latch, i - 1);
- child_latch.wait(false);
- } else {
- child_latch.wait(true);
- }
- }
- }
-
- child(&mut *latch, 10);
-
- assert!(!latch.wait(true));
- }
- }
-
- #[test]
- fn release_child() {
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
-
- do spawntask_immediately {
- let latch = child_latch.take();
- latch.release(false);
- }
-
- assert!(!latch.wait(true));
- }
- }
-
- #[test]
- fn release_child_tombstone() {
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
-
- do spawntask_immediately {
- let mut latch = child_latch.take();
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_later {
- let latch = child_latch.take();
- latch.release(false);
- }
- latch.release(true);
- }
-
- assert!(!latch.wait(true));
- }
- }
-
- #[test]
- fn release_child_no_tombstone() {
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
-
- do spawntask_later {
- let mut latch = child_latch.take();
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- do spawntask_immediately {
- let latch = child_latch.take();
- latch.release(false);
- }
- latch.release(true);
- }
-
- assert!(!latch.wait(true));
- }
- }
-
- #[test]
- fn release_child_tombstone_stress() {
- fn rand_orders() -> ~[bool] {
- let mut v = ~[false,.. 5];
- v[0] = true;
- let mut rng = rand::rng();
- return rng.shuffle(v);
- }
-
- fn split_orders(orders: &[bool]) -> (~[bool], ~[bool]) {
- if orders.is_empty() {
- return (~[], ~[]);
- } else if orders.len() <= 2 {
- return (orders.to_owned(), ~[]);
- }
- let mut rng = rand::rng();
- let n = rng.gen_uint_range(1, orders.len());
- let first = orders.slice(0, n).to_owned();
- let last = orders.slice(n, orders.len()).to_owned();
- assert!(first.len() + last.len() == orders.len());
- return (first, last);
- }
-
- for stress_factor().times {
- do run_in_newsched_task {
- fn doit(latch: &mut JoinLatch, orders: ~[bool], depth: uint) {
- let (my_orders, remaining_orders) = split_orders(orders);
- rtdebug!("(my_orders, remaining): %?", (&my_orders, &remaining_orders));
- rtdebug!("depth: %u", depth);
- let mut remaining_orders = remaining_orders;
- let mut num = 0;
- for my_orders.iter().advance |&order| {
- let child_latch = latch.new_child();
- let child_latch = Cell::new(child_latch);
- let (child_orders, remaining) = split_orders(remaining_orders);
- rtdebug!("(child_orders, remaining): %?", (&child_orders, &remaining));
- remaining_orders = remaining;
- let child_orders = Cell::new(child_orders);
- let child_num = num;
- let _ = child_num; // XXX unused except in rtdebug!
- do spawntask_random {
- rtdebug!("depth %u num %u", depth, child_num);
- let mut child_latch = child_latch.take();
- let child_orders = child_orders.take();
- doit(&mut *child_latch, child_orders, depth + 1);
- child_latch.release(order);
- }
-
- num += 1;
- }
- }
-
- let mut latch = JoinLatch::new_root();
- let orders = rand_orders();
- rtdebug!("orders: %?", orders);
-
- doit(&mut *latch, orders, 0);
-
- assert!(!latch.wait(true));
- }
- }
- }
-
- #[deriving(Clone)]
- struct Order {
- immediate: bool,
- succeed: bool,
- orders: ~[Order]
- }
-
- #[test]
- fn whateverman() {
- fn next(latch: &mut JoinLatch, orders: ~[Order]) {
- for orders.iter().advance |order| {
- let suborders = order.orders.clone();
- let child_latch = Cell::new(latch.new_child());
- let succeed = order.succeed;
- if order.immediate {
- do spawntask_immediately {
- let mut child_latch = child_latch.take();
- next(&mut *child_latch, suborders.clone());
- rtdebug!("immediate releasing");
- child_latch.release(succeed);
- }
- } else {
- do spawntask_later {
- let mut child_latch = child_latch.take();
- next(&mut *child_latch, suborders.clone());
- rtdebug!("later releasing");
- child_latch.release(succeed);
- }
- }
- }
- }
-
- do run_in_newsched_task {
- let mut latch = JoinLatch::new_root();
- let orders = ~[ Order { // 0 0
- immediate: true,
- succeed: true,
- orders: ~[ Order { // 1 0
- immediate: true,
- succeed: false,
- orders: ~[ Order { // 2 0
- immediate: false,
- succeed: false,
- orders: ~[ Order { // 3 0
- immediate: true,
- succeed: false,
- orders: ~[]
- }, Order { // 3 1
- immediate: false,
- succeed: false,
- orders: ~[]
- }]
- }]
- }]
- }];
-
- next(&mut *latch, orders);
- assert!(!latch.wait(true));
- }
- }
-}
-
--- /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.
+
+//! Task death: asynchronous killing, linked failure, exit code propagation.
+
+use cast;
+use cell::Cell;
+use either::{Either, Left, Right};
+use option::{Option, Some, None};
+use prelude::*;
+use rt::task::Task;
+use to_bytes::IterBytes;
+use unstable::atomics::{AtomicUint, Acquire, SeqCst};
+use unstable::sync::{UnsafeAtomicRcBox, LittleLock};
+use util;
+
+static KILLED_MSG: &'static str = "killed by linked failure";
+
+// State values for the 'killed' and 'unkillable' atomic flags below.
+static KILL_RUNNING: uint = 0;
+static KILL_KILLED: uint = 1;
+static KILL_UNKILLABLE: uint = 2;
+
+struct KillFlag(AtomicUint);
+type KillFlagHandle = UnsafeAtomicRcBox<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.
+pub enum BlockedTask {
+ Unkillable(~Task),
+ Killable(KillFlagHandle),
+}
+
+// FIXME(#7544)(bblum): think about the cache efficiency of this
+struct KillHandleInner {
+ // Is the task running, blocked, or killed? Possible values:
+ // * KILL_RUNNING - Not unkillable, no kill pending.
+ // * KILL_KILLED - Kill pending.
+ // * <ptr> - A transmuted blocked ~Task pointer.
+ // This flag is refcounted because it may also be referenced by a blocking
+ // concurrency primitive, used to wake the task normally, whose reference
+ // may outlive the handle's if the task is killed.
+ killed: KillFlagHandle,
+ // Has the task deferred kill signals? This flag guards the above one.
+ // Possible values:
+ // * KILL_RUNNING - Not unkillable, no kill pending.
+ // * KILL_KILLED - Kill pending.
+ // * KILL_UNKILLABLE - Kill signals deferred.
+ unkillable: AtomicUint,
+
+ // Shared state between task and children for exit code propagation. These
+ // are here so we can re-use the kill handle to implement watched children
+ // tasks. Using a separate ARClike would introduce extra atomic adds/subs
+ // into common spawn paths, so this is just for speed.
+
+ // Locklessly accessed; protected by the enclosing refcount's barriers.
+ any_child_failed: bool,
+ // A lazy list, consuming which may unwrap() many child tombstones.
+ child_tombstones: Option<~fn() -> bool>,
+ // Protects multiple children simultaneously creating tombstones.
+ graveyard_lock: LittleLock,
+}
+
+/// State shared between tasks used for task killing during linked failure.
+#[deriving(Clone)]
+pub struct KillHandle(UnsafeAtomicRcBox<KillHandleInner>);
+
+/// Per-task state related to task death, killing, failure, etc.
+pub struct Death {
+ // Shared among this task, its watched children, and any linked tasks who
+ // might kill it. This is optional so we can take it by-value at exit time.
+ kill_handle: Option<KillHandle>,
+ // Handle to a watching parent, if we have one, for exit code propagation.
+ watching_parent: Option<KillHandle>,
+ // Action to be done with the exit code. If set, also makes the task wait
+ // until all its watched children exit before collecting the status.
+ on_exit: Option<~fn(bool)>,
+ // nesting level counter for task::unkillable calls (0 == killable).
+ unkillable: int,
+ // nesting level counter for task::atomically calls (0 == can yield).
+ wont_sleep: int,
+ // A "spare" handle to the kill flag inside the kill handle. Used during
+ // blocking/waking as an optimization to avoid two xadds on the refcount.
+ spare_kill_flag: Option<KillFlagHandle>,
+}
+
+impl Drop for KillFlag {
+ // Letting a KillFlag with a task inside get dropped would leak the task.
+ // We could free it here, but the task should get awoken by hand somehow.
+ fn drop(&self) {
+ match self.load(Acquire) {
+ KILL_RUNNING | KILL_KILLED => { },
+ _ => rtabort!("can't drop kill flag with a blocked task inside!"),
+ }
+ }
+}
+
+// Whenever a task blocks, it swaps out its spare kill flag to use as the
+// blocked task handle. So unblocking a task must restore that spare.
+unsafe fn revive_task_ptr(task_ptr: uint, spare_flag: Option<KillFlagHandle>) -> ~Task {
+ let mut task: ~Task = cast::transmute(task_ptr);
+ rtassert!(task.death.spare_kill_flag.is_none());
+ task.death.spare_kill_flag = spare_flag;
+ task
+}
+
+impl BlockedTask {
+ /// Returns Some if the task was successfully woken; None if already killed.
+ pub fn wake(self) -> Option<~Task> {
+ match self {
+ Unkillable(task) => Some(task),
+ Killable(flag_arc) => {
+ let flag = unsafe { &mut **flag_arc.get() };
+ match flag.swap(KILL_RUNNING, SeqCst) {
+ KILL_RUNNING => rtabort!("tried to wake an already-running task"),
+ KILL_KILLED => None, // a killer stole it already
+ task_ptr =>
+ Some(unsafe { revive_task_ptr(task_ptr, Some(flag_arc)) })
+ }
+ }
+ }
+ }
+
+ /// Create a blocked task, unless the task was already killed.
+ pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> {
+ if task.death.unkillable > 0 {
+ Right(Unkillable(task))
+ } else {
+ rtassert!(task.death.kill_handle.is_some());
+ unsafe {
+ // The inverse of 'revive', above, occurs here.
+ // The spare kill flag will usually be Some, unless the task was
+ // already killed, in which case the killer will have deferred
+ // creating a new one until whenever it blocks during unwinding.
+ let flag_arc = match task.death.spare_kill_flag.take() {
+ Some(spare_flag) => spare_flag,
+ None => {
+ // FIXME(#7544): Uncomment this when terminate_current_task
+ // stops being *terrible*. That's the only place that violates
+ // the assumption of "becoming unkillable will fail if the
+ // task was killed".
+ // rtassert!(task.unwinder.unwinding);
+ (*task.death.kill_handle.get_ref().get()).killed.clone()
+ }
+ };
+ let flag = &mut **flag_arc.get();
+ let task_ptr = cast::transmute(task);
+ // Expect flag to contain RUNNING. If KILLED, it should stay KILLED.
+ match flag.compare_and_swap(KILL_RUNNING, task_ptr, SeqCst) {
+ KILL_RUNNING => Right(Killable(flag_arc)),
+ KILL_KILLED => Left(revive_task_ptr(task_ptr, Some(flag_arc))),
+ x => rtabort!("can't block task! kill flag = %?", x),
+ }
+ }
+ }
+ }
+
+ /// Convert to an unsafe uint value. Useful for storing in a pipe's state flag.
+ #[inline]
+ pub unsafe fn cast_to_uint(self) -> uint {
+ // Use the low bit to distinguish the enum variants, to save a second
+ // allocation in the indestructible case.
+ match self {
+ Unkillable(task) => {
+ let blocked_task_ptr: uint = cast::transmute(task);
+ rtassert!(blocked_task_ptr & 0x1 == 0);
+ blocked_task_ptr
+ },
+ Killable(flag_arc) => {
+ let blocked_task_ptr: uint = cast::transmute(~flag_arc);
+ rtassert!(blocked_task_ptr & 0x1 == 0);
+ blocked_task_ptr | 0x1
+ }
+ }
+ }
+
+ /// Convert from an unsafe uint value. Useful for retrieving a pipe's state flag.
+ #[inline]
+ pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
+ if blocked_task_ptr & 0x1 == 0 {
+ Unkillable(cast::transmute(blocked_task_ptr))
+ } else {
+ let ptr: ~KillFlagHandle = cast::transmute(blocked_task_ptr & !0x1);
+ match ptr {
+ ~flag_arc => Killable(flag_arc)
+ }
+ }
+ }
+}
+
+// So that KillHandle can be hashed in the taskgroup bookkeeping code.
+impl IterBytes for KillHandle {
+ fn iter_bytes(&self, lsb0: bool, f: &fn(buf: &[u8]) -> bool) -> bool {
+ self.data.iter_bytes(lsb0, f)
+ }
+}
+impl Eq for KillHandle {
+ #[inline] fn eq(&self, other: &KillHandle) -> bool { self.data.eq(&other.data) }
+ #[inline] fn ne(&self, other: &KillHandle) -> bool { self.data.ne(&other.data) }
+}
+
+impl KillHandle {
+ pub fn new() -> (KillHandle, KillFlagHandle) {
+ let (flag, flag_clone) =
+ UnsafeAtomicRcBox::new2(KillFlag(AtomicUint::new(KILL_RUNNING)));
+ let handle = KillHandle(UnsafeAtomicRcBox::new(KillHandleInner {
+ // Linked failure fields
+ killed: flag,
+ unkillable: AtomicUint::new(KILL_RUNNING),
+ // Exit code propagation fields
+ any_child_failed: false,
+ child_tombstones: None,
+ graveyard_lock: LittleLock(),
+ }));
+ (handle, flag_clone)
+ }
+
+ // Will begin unwinding if a kill signal was received, unless already_failing.
+ // This can't be used recursively, because a task which sees a KILLED
+ // signal must fail immediately, which an already-unkillable task can't do.
+ #[inline]
+ pub fn inhibit_kill(&mut self, already_failing: bool) {
+ let inner = unsafe { &mut *self.get() };
+ // Expect flag to contain RUNNING. If KILLED, it should stay KILLED.
+ // FIXME(#7544)(bblum): is it really necessary to prohibit double kill?
+ match inner.unkillable.compare_and_swap(KILL_RUNNING, KILL_UNKILLABLE, SeqCst) {
+ KILL_RUNNING => { }, // normal case
+ KILL_KILLED => if !already_failing { fail!(KILLED_MSG) },
+ _ => rtabort!("inhibit_kill: task already unkillable"),
+ }
+ }
+
+ // Will begin unwinding if a kill signal was received, unless already_failing.
+ #[inline]
+ pub fn allow_kill(&mut self, already_failing: bool) {
+ let inner = unsafe { &mut *self.get() };
+ // Expect flag to contain UNKILLABLE. If KILLED, it should stay KILLED.
+ // FIXME(#7544)(bblum): is it really necessary to prohibit double kill?
+ match inner.unkillable.compare_and_swap(KILL_UNKILLABLE, KILL_RUNNING, SeqCst) {
+ KILL_UNKILLABLE => { }, // normal case
+ KILL_KILLED => if !already_failing { fail!(KILLED_MSG) },
+ _ => rtabort!("allow_kill: task already killable"),
+ }
+ }
+
+ // Send a kill signal to the handle's owning task. Returns the task itself
+ // if it was blocked and needs punted awake. To be called by other tasks.
+ pub fn kill(&mut self) -> Option<~Task> {
+ let inner = unsafe { &mut *self.get() };
+ if inner.unkillable.swap(KILL_KILLED, SeqCst) == KILL_RUNNING {
+ // Got in. Allowed to try to punt the task awake.
+ let flag = unsafe { &mut *inner.killed.get() };
+ match flag.swap(KILL_KILLED, SeqCst) {
+ // Task either not blocked or already taken care of.
+ KILL_RUNNING | KILL_KILLED => None,
+ // Got ownership of the blocked task.
+ // While the usual 'wake' path can just pass back the flag
+ // handle, we (the slower kill path) haven't an extra one lying
+ // around. The task will wake up without a spare.
+ task_ptr => Some(unsafe { revive_task_ptr(task_ptr, None) }),
+ }
+ } else {
+ // Otherwise it was either unkillable or already killed. Somebody
+ // else was here first who will deal with the kill signal.
+ None
+ }
+ }
+
+ #[inline]
+ pub fn killed(&self) -> bool {
+ // Called every context switch, so shouldn't report true if the task
+ // is unkillable with a kill signal pending.
+ let inner = unsafe { &*self.get() };
+ let flag = unsafe { &*inner.killed.get() };
+ // FIXME(#6598): can use relaxed ordering (i think)
+ flag.load(Acquire) == KILL_KILLED
+ }
+
+ 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
+ // unwrapper/destructor, whichever task may unwrap it.
+ unsafe { (*self.get()).any_child_failed = true; }
+ }
+
+ // For use when a task does not need to collect its children's exit
+ // statuses, but the task has a parent which might want them.
+ pub fn reparent_children_to(self, parent: &mut KillHandle) {
+ // Optimistic path: If another child of the parent's already failed,
+ // we don't need to worry about any of this.
+ if unsafe { (*parent.get()).any_child_failed } {
+ return;
+ }
+
+ // Try to see if all our children are gone already.
+ match unsafe { self.try_unwrap() } {
+ // Couldn't unwrap; children still alive. Reparent entire handle as
+ // our own tombstone, to be unwrapped later.
+ Left(this) => {
+ let this = Cell::new(this); // :(
+ do add_lazy_tombstone(parent) |other_tombstones| {
+ let this = Cell::new(this.take()); // :(
+ let others = Cell::new(other_tombstones); // :(
+ || {
+ // Prefer to check tombstones that were there first,
+ // being "more fair" at the expense of tail-recursion.
+ others.take().map_consume_default(true, |f| f()) && {
+ let mut inner = unsafe { this.take().unwrap() };
+ (!inner.any_child_failed) &&
+ inner.child_tombstones.take_map_default(true, |f| f())
+ }
+ }
+ }
+ }
+ // Whether or not all children exited, one or more already failed.
+ Right(KillHandleInner { any_child_failed: true, _ }) => {
+ parent.notify_immediate_failure();
+ }
+ // All children exited, but some left behind tombstones that we
+ // don't want to wait on now. Give them to our parent.
+ Right(KillHandleInner { any_child_failed: false,
+ child_tombstones: Some(f), _ }) => {
+ let f = Cell::new(f); // :(
+ do add_lazy_tombstone(parent) |other_tombstones| {
+ let f = Cell::new(f.take()); // :(
+ let others = Cell::new(other_tombstones); // :(
+ || {
+ // Prefer fairness to tail-recursion, as in above case.
+ others.take().map_consume_default(true, |f| f()) &&
+ f.take()()
+ }
+ }
+ }
+ // All children exited, none failed. Nothing to do!
+ Right(KillHandleInner { any_child_failed: false,
+ child_tombstones: None, _ }) => { }
+ }
+
+ // NB: Takes a pthread mutex -- 'blk' not allowed to reschedule.
+ #[inline]
+ fn add_lazy_tombstone(parent: &mut KillHandle,
+ blk: &fn(Option<~fn() -> bool>) -> ~fn() -> bool) {
+
+ let inner: &mut KillHandleInner = unsafe { &mut *parent.get() };
+ unsafe {
+ do inner.graveyard_lock.lock {
+ // Update the current "head node" of the lazy list.
+ inner.child_tombstones =
+ Some(blk(util::replace(&mut inner.child_tombstones, None)));
+ }
+ }
+ }
+ }
+}
+
+impl Death {
+ pub fn new() -> Death {
+ let (handle, spare) = KillHandle::new();
+ Death {
+ kill_handle: Some(handle),
+ watching_parent: None,
+ on_exit: None,
+ unkillable: 0,
+ wont_sleep: 0,
+ spare_kill_flag: Some(spare),
+ }
+ }
+
+ pub fn new_child(&self) -> Death {
+ // FIXME(#7327)
+ let (handle, spare) = KillHandle::new();
+ Death {
+ kill_handle: Some(handle),
+ watching_parent: self.kill_handle.clone(),
+ on_exit: None,
+ unkillable: 0,
+ wont_sleep: 0,
+ spare_kill_flag: Some(spare),
+ }
+ }
+
+ /// Collect failure exit codes from children and propagate them to a parent.
+ pub fn collect_failure(&mut self, mut success: bool) {
+ // This may run after the task has already failed, so even though the
+ // task appears to need to be killed, the scheduler should not fail us
+ // when we block to unwrap.
+ // (XXX: Another less-elegant reason for doing this is so that the use
+ // of the LittleLock in reparent_children_to doesn't need to access the
+ // unkillable flag in the kill_handle, since we'll have removed it.)
+ rtassert!(self.unkillable == 0);
+ self.unkillable = 1;
+
+ // Step 1. Decide if we need to collect child failures synchronously.
+ do self.on_exit.take_map |on_exit| {
+ if success {
+ // We succeeded, but our children might not. Need to wait for them.
+ let mut inner = unsafe { self.kill_handle.take_unwrap().unwrap() };
+ if inner.any_child_failed {
+ success = false;
+ } else {
+ // Lockless access to tombstones protected by unwrap barrier.
+ success = inner.child_tombstones.take_map_default(true, |f| f());
+ }
+ }
+ on_exit(success);
+ };
+
+ // Step 2. Possibly alert possibly-watching parent to failure status.
+ // Note that as soon as parent_handle goes out of scope, the parent
+ // can successfully unwrap its handle and collect our reported status.
+ do self.watching_parent.take_map |mut parent_handle| {
+ if success {
+ // Our handle might be None if we had an exit callback, and
+ // already unwrapped it. But 'success' being true means no
+ // child failed, so there's nothing to do (see below case).
+ do self.kill_handle.take_map |own_handle| {
+ own_handle.reparent_children_to(&mut parent_handle);
+ };
+ } else {
+ // Can inform watching parent immediately that we failed.
+ // (Note the importance of non-failing tasks NOT writing
+ // 'false', which could obscure another task's failure.)
+ parent_handle.notify_immediate_failure();
+ }
+ };
+
+ // Can't use allow_kill directly; that would require the kill handle.
+ rtassert!(self.unkillable == 1);
+ self.unkillable = 0;
+ }
+
+ /// Fails if a kill signal was received.
+ #[inline]
+ pub fn check_killed(&self) {
+ match self.kill_handle {
+ Some(ref kill_handle) =>
+ // The task may be both unkillable and killed if it does some
+ // synchronization during unwinding or cleanup (for example,
+ // sending on a notify port). In that case failing won't help.
+ if self.unkillable == 0 && kill_handle.killed() {
+ fail!(KILLED_MSG);
+ },
+ // This may happen during task death (see comments in collect_failure).
+ None => rtassert!(self.unkillable > 0),
+ }
+ }
+
+ /// Enter a possibly-nested unkillable section of code.
+ /// All calls must be paired with a subsequent call to allow_kill.
+ #[inline]
+ pub fn inhibit_kill(&mut self, already_failing: bool) {
+ if self.unkillable == 0 {
+ rtassert!(self.kill_handle.is_some());
+ self.kill_handle.get_mut_ref().inhibit_kill(already_failing);
+ }
+ self.unkillable += 1;
+ }
+
+ /// Exit a possibly-nested unkillable section of code.
+ /// 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);
+ self.unkillable -= 1;
+ if self.unkillable == 0 {
+ rtassert!(self.kill_handle.is_some());
+ self.kill_handle.get_mut_ref().allow_kill(already_failing);
+ }
+ }
+
+ /// Enter a possibly-nested "atomic" section of code. Just for assertions.
+ /// All calls must be paired with a subsequent call to allow_yield.
+ #[inline]
+ pub fn inhibit_yield(&mut self) {
+ self.wont_sleep += 1;
+ }
+
+ /// Exit a possibly-nested "atomic" section of code. Just for assertions.
+ /// All calls must be paired with a preceding call to inhibit_yield.
+ #[inline]
+ pub fn allow_yield(&mut self) {
+ rtassert!(self.wont_sleep != 0);
+ self.wont_sleep -= 1;
+ }
+
+ /// Ensure that the task is allowed to become descheduled.
+ #[inline]
+ pub fn assert_may_sleep(&self) {
+ if self.wont_sleep != 0 {
+ rtabort!("illegal atomic-sleep: can't deschedule inside atomically()");
+ }
+ }
+}
+
+impl Drop for Death {
+ fn drop(&self) {
+ // Mustn't be in an atomic or unkillable section at task death.
+ rtassert!(self.unkillable == 0);
+ rtassert!(self.wont_sleep == 0);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[allow(unused_mut)];
+ use cell::Cell;
+ use rt::test::*;
+ use super::*;
+ use util;
+
+ // Test cases don't care about the spare killed flag.
+ fn make_kill_handle() -> KillHandle { let (h,_) = KillHandle::new(); h }
+
+ #[test]
+ fn no_tombstone_success() {
+ do run_in_newsched_task {
+ // Tests case 4 of the 4-way match in reparent_children.
+ let mut parent = make_kill_handle();
+ let mut child = make_kill_handle();
+
+ // Without another handle to child, the try unwrap should succeed.
+ child.reparent_children_to(&mut parent);
+ let mut parent_inner = unsafe { parent.unwrap() };
+ assert!(parent_inner.child_tombstones.is_none());
+ assert!(parent_inner.any_child_failed == false);
+ }
+ }
+ #[test]
+ fn no_tombstone_failure() {
+ do run_in_newsched_task {
+ // Tests case 2 of the 4-way match in reparent_children.
+ let mut parent = make_kill_handle();
+ let mut child = make_kill_handle();
+
+ child.notify_immediate_failure();
+ // Without another handle to child, the try unwrap should succeed.
+ child.reparent_children_to(&mut parent);
+ let mut parent_inner = unsafe { parent.unwrap() };
+ assert!(parent_inner.child_tombstones.is_none());
+ // Immediate failure should have been propagated.
+ assert!(parent_inner.any_child_failed);
+ }
+ }
+ #[test]
+ fn no_tombstone_because_sibling_already_failed() {
+ do run_in_newsched_task {
+ // Tests "case 0, the optimistic path in reparent_children.
+ let mut parent = make_kill_handle();
+ let mut child1 = make_kill_handle();
+ let mut child2 = make_kill_handle();
+ let mut link = child2.clone();
+
+ // Should set parent's child_failed flag
+ child1.notify_immediate_failure();
+ child1.reparent_children_to(&mut parent);
+ // Should bypass trying to unwrap child2 entirely.
+ // Otherwise, due to 'link', it would try to tombstone.
+ child2.reparent_children_to(&mut parent);
+ // Should successfully unwrap even though 'link' is still alive.
+ let mut parent_inner = unsafe { parent.unwrap() };
+ assert!(parent_inner.child_tombstones.is_none());
+ // Immediate failure should have been propagated by first child.
+ assert!(parent_inner.any_child_failed);
+ util::ignore(link);
+ }
+ }
+ #[test]
+ fn one_tombstone_success() {
+ do run_in_newsched_task {
+ let mut parent = make_kill_handle();
+ let mut child = make_kill_handle();
+ let mut link = child.clone();
+
+ // Creates 1 tombstone. Existence of 'link' makes try-unwrap fail.
+ child.reparent_children_to(&mut parent);
+ // Let parent collect tombstones.
+ util::ignore(link);
+ // Must have created a tombstone
+ let mut parent_inner = unsafe { parent.unwrap() };
+ assert!(parent_inner.child_tombstones.take_unwrap()());
+ assert!(parent_inner.any_child_failed == false);
+ }
+ }
+ #[test]
+ fn one_tombstone_failure() {
+ do run_in_newsched_task {
+ let mut parent = make_kill_handle();
+ let mut child = make_kill_handle();
+ let mut link = child.clone();
+
+ // Creates 1 tombstone. Existence of 'link' makes try-unwrap fail.
+ child.reparent_children_to(&mut parent);
+ // Must happen after tombstone to not be immediately propagated.
+ link.notify_immediate_failure();
+ // Let parent collect tombstones.
+ util::ignore(link);
+ // Must have created a tombstone
+ let mut parent_inner = unsafe { parent.unwrap() };
+ // Failure must be seen in the tombstone.
+ assert!(parent_inner.child_tombstones.take_unwrap()() == false);
+ assert!(parent_inner.any_child_failed == false);
+ }
+ }
+ #[test]
+ fn two_tombstones_success() {
+ do run_in_newsched_task {
+ let mut parent = make_kill_handle();
+ let mut middle = make_kill_handle();
+ let mut child = make_kill_handle();
+ let mut link = child.clone();
+
+ child.reparent_children_to(&mut middle); // case 1 tombstone
+ // 'middle' should try-unwrap okay, but still have to reparent.
+ middle.reparent_children_to(&mut parent); // case 3 tombston
+ // Let parent collect tombstones.
+ util::ignore(link);
+ // Must have created a tombstone
+ let mut parent_inner = unsafe { parent.unwrap() };
+ assert!(parent_inner.child_tombstones.take_unwrap()());
+ assert!(parent_inner.any_child_failed == false);
+ }
+ }
+ #[test]
+ fn two_tombstones_failure() {
+ do run_in_newsched_task {
+ let mut parent = make_kill_handle();
+ let mut middle = make_kill_handle();
+ let mut child = make_kill_handle();
+ let mut link = child.clone();
+
+ child.reparent_children_to(&mut middle); // case 1 tombstone
+ // Must happen after tombstone to not be immediately propagated.
+ link.notify_immediate_failure();
+ // 'middle' should try-unwrap okay, but still have to reparent.
+ middle.reparent_children_to(&mut parent); // case 3 tombstone
+ // Let parent collect tombstones.
+ util::ignore(link);
+ // Must have created a tombstone
+ let mut parent_inner = unsafe { parent.unwrap() };
+ // Failure must be seen in the tombstone.
+ assert!(parent_inner.child_tombstones.take_unwrap()() == false);
+ assert!(parent_inner.any_child_failed == false);
+ }
+ }
+
+ // Task killing tests
+
+ #[test]
+ fn kill_basic() {
+ do run_in_newsched_task {
+ let mut handle = make_kill_handle();
+ assert!(!handle.killed());
+ assert!(handle.kill().is_none());
+ assert!(handle.killed());
+ }
+ }
+
+ #[test]
+ fn double_kill() {
+ do run_in_newsched_task {
+ let mut handle = make_kill_handle();
+ assert!(!handle.killed());
+ assert!(handle.kill().is_none());
+ assert!(handle.killed());
+ assert!(handle.kill().is_none());
+ assert!(handle.killed());
+ }
+ }
+
+ #[test]
+ fn unkillable_after_kill() {
+ do run_in_newsched_task {
+ let mut handle = make_kill_handle();
+ assert!(handle.kill().is_none());
+ assert!(handle.killed());
+ let handle_cell = Cell::new(handle);
+ let result = do spawntask_try {
+ handle_cell.take().inhibit_kill(false);
+ };
+ assert!(result.is_err());
+ }
+ }
+
+ #[test]
+ fn unkillable_during_kill() {
+ do run_in_newsched_task {
+ let mut handle = make_kill_handle();
+ handle.inhibit_kill(false);
+ assert!(handle.kill().is_none());
+ assert!(!handle.killed());
+ let handle_cell = Cell::new(handle);
+ let result = do spawntask_try {
+ handle_cell.take().allow_kill(false);
+ };
+ assert!(result.is_err());
+ }
+ }
+
+ #[test]
+ fn unkillable_before_kill() {
+ do run_in_newsched_task {
+ let mut handle = make_kill_handle();
+ handle.inhibit_kill(false);
+ handle.allow_kill(false);
+ assert!(handle.kill().is_none());
+ assert!(handle.killed());
+ }
+ }
+
+ // Task blocking tests
+
+ #[test]
+ fn block_and_wake() {
+ do with_test_task |mut task| {
+ BlockedTask::try_block(task).unwrap_right().wake().unwrap()
+ }
+ }
+
+ #[test]
+ fn block_and_get_killed() {
+ do with_test_task |mut task| {
+ let mut handle = task.death.kill_handle.get_ref().clone();
+ let result = BlockedTask::try_block(task).unwrap_right();
+ let task = handle.kill().unwrap();
+ assert!(result.wake().is_none());
+ task
+ }
+ }
+
+ #[test]
+ fn block_already_killed() {
+ do with_test_task |mut task| {
+ let mut handle = task.death.kill_handle.get_ref().clone();
+ assert!(handle.kill().is_none());
+ BlockedTask::try_block(task).unwrap_left()
+ }
+ }
+
+ #[test]
+ fn block_unkillably_and_get_killed() {
+ do with_test_task |mut task| {
+ let mut handle = task.death.kill_handle.get_ref().clone();
+ task.death.inhibit_kill(false);
+ let result = BlockedTask::try_block(task).unwrap_right();
+ assert!(handle.kill().is_none());
+ let mut task = result.wake().unwrap();
+ // This call wants to fail, but we can't have that happen since
+ // we're not running in a newsched task, so we can't even use
+ // spawntask_try. But the failing behaviour is already tested
+ // above, in unkillable_during_kill(), so we punt on it here.
+ task.death.allow_kill(true);
+ task
+ }
+ }
+
+ #[test]
+ fn block_on_pipe() {
+ // Tests the "killable" path of casting to/from uint.
+ do run_in_newsched_task {
+ do with_test_task |mut task| {
+ let result = BlockedTask::try_block(task).unwrap_right();
+ let result = unsafe { result.cast_to_uint() };
+ let result = unsafe { BlockedTask::cast_from_uint(result) };
+ result.wake().unwrap()
+ }
+ }
+ }
+
+ #[test]
+ fn block_unkillably_on_pipe() {
+ // Tests the "indestructible" path of casting to/from uint.
+ do run_in_newsched_task {
+ do with_test_task |mut task| {
+ task.death.inhibit_kill(false);
+ let result = BlockedTask::try_block(task).unwrap_right();
+ let result = unsafe { result.cast_to_uint() };
+ let result = unsafe { BlockedTask::cast_from_uint(result) };
+ let mut task = result.wake().unwrap();
+ task.death.allow_kill(false);
+ task
+ }
+ }
+ }
+}
/// Implementations of language-critical runtime features like @.
pub mod task;
+/// Facilities related to task failure, killing, and death.
+mod kill;
+
/// The coroutine task scheduler, built on the `io` event loop.
mod sched;
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;
-/// For waiting on child tasks.
-pub mod join_latch;
-
pub mod metrics;
// FIXME #5248 shouldn't be pub
let main_cell = Cell::new(main);
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
main_cell.take());
- main_task.on_exit = Some(on_exit);
+ main_task.death.on_exit = Some(on_exit);
scheds[0].enqueue_task(main_task);
// Run each scheduler in a thread.
}
}
- pub extern {
+ extern {
#[rust_stack]
- fn rust_try_get_task() -> *rust_task;
+ pub fn rust_try_get_task() -> *rust_task;
}
}
let sched = Local::take::<Scheduler>();
do sched.deschedule_running_task_and_then() |sched, task| {
assert_eq!(context(), SchedulerContext);
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
};
sched.enqueue_task(task);
pub type RtioTcpStreamObject = uvio::UvTcpStream;
pub type RtioTcpListenerObject = uvio::UvTcpListener;
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
+pub type RtioTimerObject = uvio::UvTimer;
pub trait EventLoop {
fn run(&mut self);
fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>;
fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>;
fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError>;
+ fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>;
- fn accept_simultaneously(&self);
- fn dont_accept_simultaneously(&self);
+ fn accept_simultaneously(&mut self);
+ fn dont_accept_simultaneously(&mut self);
}
pub trait RtioTcpStream : RtioSocket {
- fn read(&self, buf: &mut [u8]) -> Result<uint, IoError>;
- fn write(&self, buf: &[u8]) -> Result<(), IoError>;
- fn peer_name(&self) -> IpAddr;
- fn control_congestion(&self);
- fn nodelay(&self);
- fn keepalive(&self, delay_in_seconds: uint);
- fn letdie(&self);
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+ fn peer_name(&mut self) -> IpAddr;
+ fn control_congestion(&mut self);
+ fn nodelay(&mut self);
+ fn keepalive(&mut self, delay_in_seconds: uint);
+ fn letdie(&mut self);
}
pub trait RtioSocket {
- fn socket_name(&self) -> IpAddr;
+ fn socket_name(&mut self) -> IpAddr;
}
pub trait RtioUdpSocket : RtioSocket {
- fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>;
- fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError>;
+ fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError>;
+ fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result<(), IoError>;
- fn join_multicast(&self, multi: IpAddr);
- fn leave_multicast(&self, multi: IpAddr);
+ fn join_multicast(&mut self, multi: IpAddr);
+ fn leave_multicast(&mut self, multi: IpAddr);
- fn loop_multicast_locally(&self);
- fn dont_loop_multicast_locally(&self);
+ fn loop_multicast_locally(&mut self);
+ fn dont_loop_multicast_locally(&mut self);
- fn multicast_time_to_live(&self, ttl: int);
- fn time_to_live(&self, ttl: int);
+ fn multicast_time_to_live(&mut self, ttl: int);
+ fn time_to_live(&mut self, ttl: int);
- fn hear_broadcasts(&self);
- fn ignore_broadcasts(&self);
+ fn hear_broadcasts(&mut self);
+ fn ignore_broadcasts(&mut self);
+}
+
+pub trait RtioTimer {
+ fn sleep(&self, msecs: u64);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use option::*;
+use either::{Left, Right};
+use option::{Option, Some, None};
use sys;
use cast::transmute;
use clone::Clone;
use super::context::Context;
use super::task::{Task, AnySched, Sched};
use super::message_queue::MessageQueue;
+use rt::kill::BlockedTask;
use rt::local_ptr;
use rt::local::Local;
use rt::rtio::RemoteCallback;
};
}
+ /// As enqueue_task, but with the possibility for the blocked task to
+ /// already have been killed.
+ pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) {
+ do blocked_task.wake().map_consume |task| {
+ self.enqueue_task(task);
+ };
+ }
+
// * Scheduler-context operations
fn interpret_message_queue(~self) -> bool {
/// Called by a running task to end execution, after which it will
/// be recycled by the scheduler for reuse in a new task.
pub fn terminate_current_task(~self) {
- assert!(self.in_task_context());
+ let mut this = self;
+ assert!(this.in_task_context());
rtdebug!("ending running task");
- do self.deschedule_running_task_and_then |sched, dead_task| {
- let mut dead_task = dead_task;
- let coroutine = dead_task.coroutine.take_unwrap();
- coroutine.recycle(&mut sched.stack_pool);
+ // This task is post-cleanup, so it must be unkillable. This sequence
+ // of descheduling and recycling must not get interrupted by a kill.
+ // FIXME(#7544): Make this use an inner descheduler, like yield should.
+ this.current_task.get_mut_ref().death.unkillable += 1;
+
+ do this.deschedule_running_task_and_then |sched, dead_task| {
+ match dead_task.wake() {
+ Some(dead_task) => {
+ let mut dead_task = dead_task;
+ dead_task.death.unkillable -= 1; // FIXME(#7544) ugh
+ let coroutine = dead_task.coroutine.take_unwrap();
+ coroutine.recycle(&mut sched.stack_pool);
+ }
+ None => rtabort!("dead task killed before recycle"),
+ }
}
rtabort!("control reached end of task");
// here we know we are home, execute now OR we know we
// aren't homed, and that this sched doesn't care
do this.switch_running_tasks_and_then(task) |sched, last_task| {
- sched.enqueue_task(last_task);
+ sched.enqueue_blocked_task(last_task);
}
} else if !homed && !this.run_anything {
// the task isn't homed, but it can't be run here
// Running tasks may have asked us to do some cleanup
(*sched).run_cleanup_job();
+
+ // Must happen after running the cleanup job (of course).
+ // Might not be running in task context; if not, a later call to
+ // resume_task_immediately will take care of this.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}
+ pub fn resume_blocked_task_immediately(~self, blocked_task: BlockedTask) {
+ match blocked_task.wake() {
+ Some(task) => self.resume_task_immediately(task),
+ None => Local::put(self),
+ };
+ }
+
/// Block a running task, context switch to the scheduler, then pass the
/// blocked task to a closure.
///
/// This passes a Scheduler pointer to the fn after the context switch
/// in order to prevent that fn from performing further scheduling operations.
/// Doing further scheduling could easily result in infinite recursion.
- pub fn deschedule_running_task_and_then(~self, f: &fn(&mut Scheduler, ~Task)) {
+ pub fn deschedule_running_task_and_then(~self, f: &fn(&mut Scheduler, BlockedTask)) {
let mut this = self;
assert!(this.in_task_context());
unsafe {
let blocked_task = this.current_task.take_unwrap();
- let f_fake_region = transmute::<&fn(&mut Scheduler, ~Task),
- &fn(&mut Scheduler, ~Task)>(f);
+ let f_fake_region = transmute::<&fn(&mut Scheduler, BlockedTask),
+ &fn(&mut Scheduler, BlockedTask)>(f);
let f_opaque = ClosureConverter::from_fn(f_fake_region);
this.enqueue_cleanup_job(GiveTask(blocked_task, f_opaque));
}
// We could be executing in a different thread now
let sched = Local::unsafe_borrow::<Scheduler>();
(*sched).run_cleanup_job();
+
+ // As above, must happen after running the cleanup job.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}
/// You would want to think hard about doing this, e.g. if there are
/// pending I/O events it would be a bad idea.
pub fn switch_running_tasks_and_then(~self, next_task: ~Task,
- f: &fn(&mut Scheduler, ~Task)) {
+ f: &fn(&mut Scheduler, BlockedTask)) {
let mut this = self;
assert!(this.in_task_context());
let old_running_task = this.current_task.take_unwrap();
let f_fake_region = unsafe {
- transmute::<&fn(&mut Scheduler, ~Task),
- &fn(&mut Scheduler, ~Task)>(f)
+ transmute::<&fn(&mut Scheduler, BlockedTask),
+ &fn(&mut Scheduler, BlockedTask)>(f)
};
let f_opaque = ClosureConverter::from_fn(f_fake_region);
this.enqueue_cleanup_job(GiveTask(old_running_task, f_opaque));
// We could be executing in a different thread now
let sched = Local::unsafe_borrow::<Scheduler>();
(*sched).run_cleanup_job();
+
+ // As above, must happen after running the cleanup job.
+ (*sched).current_task.map(|t| t.death.check_killed());
}
}
let cleanup_job = self.cleanup_job.take_unwrap();
match cleanup_job {
DoNothing => { }
- GiveTask(task, f) => (f.to_fn())(self, task)
+ GiveTask(task, f) => {
+ let f = f.to_fn();
+ // Task might need to receive a kill signal instead of blocking.
+ // We can call the "and_then" only if it blocks successfully.
+ match BlockedTask::try_block(task) {
+ Left(killed_task) => self.enqueue_task(killed_task),
+ Right(blocked_task) => f(self, blocked_task),
+ }
+ }
}
}
// complaining
type UnsafeTaskReceiver = sys::Closure;
trait ClosureConverter {
- fn from_fn(&fn(&mut Scheduler, ~Task)) -> Self;
- fn to_fn(self) -> &fn(&mut Scheduler, ~Task);
+ fn from_fn(&fn(&mut Scheduler, BlockedTask)) -> Self;
+ fn to_fn(self) -> &fn(&mut Scheduler, BlockedTask);
}
impl ClosureConverter for UnsafeTaskReceiver {
- fn from_fn(f: &fn(&mut Scheduler, ~Task)) -> UnsafeTaskReceiver { unsafe { transmute(f) } }
- fn to_fn(self) -> &fn(&mut Scheduler, ~Task) { unsafe { transmute(self) } }
+ fn from_fn(f: &fn(&mut Scheduler, BlockedTask)) -> UnsafeTaskReceiver {
+ unsafe { transmute(f) }
+ }
+ fn to_fn(self) -> &fn(&mut Scheduler, BlockedTask) { unsafe { transmute(self) } }
}
};
// Context switch directly to the new task
do sched.switch_running_tasks_and_then(task2) |sched, task1| {
- let task1 = Cell::new(task1);
- sched.enqueue_task(task1.take());
+ sched.enqueue_blocked_task(task1);
}
unsafe { *count_ptr = *count_ptr + 1; }
};
let sched = Local::take::<Scheduler>();
assert!(sched.in_task_context());
do sched.deschedule_running_task_and_then() |sched, task| {
- let task = Cell::new(task);
assert!(!sched.in_task_context());
- sched.enqueue_task(task.take());
+ sched.enqueue_blocked_task(task);
}
};
sched.enqueue_task(task);
do sched.event_loop.callback_ms(10) {
rtdebug!("in callback");
let mut sched = Local::take::<Scheduler>();
- sched.enqueue_task(task.take());
+ sched.enqueue_blocked_task(task.take());
Local::put(sched);
}
}
use ptr;
use prelude::*;
use option::{Option, Some, None};
+use rt::kill::Death;
use rt::local::Local;
use rt::logging::StdErrLogger;
use super::local_heap::LocalHeap;
use rt::sched::{Scheduler, SchedHandle};
-use rt::join_latch::JoinLatch;
use rt::stack::{StackSegment, StackPool};
use rt::context::Context;
+use task::spawn::Taskgroup;
use cell::Cell;
pub struct Task {
logger: StdErrLogger,
unwinder: Unwinder,
home: Option<SchedHome>,
- join_latch: Option<~JoinLatch>,
- on_exit: Option<~fn(bool)>,
+ taskgroup: Option<Taskgroup>,
+ death: Death,
destroyed: bool,
coroutine: Option<~Coroutine>
}
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
home: Some(home),
- join_latch: Some(JoinLatch::new_root()),
- on_exit: None,
+ taskgroup: None,
+ death: Death::new(),
destroyed: false,
coroutine: Some(~Coroutine::new(stack_pool, start))
}
logger: StdErrLogger,
home: Some(home),
unwinder: Unwinder { unwinding: false },
- join_latch: Some(self.join_latch.get_mut_ref().new_child()),
- on_exit: None,
+ taskgroup: None,
+ // FIXME(#7544) make watching optional
+ death: self.death.new_child(),
destroyed: false,
coroutine: Some(~Coroutine::new(stack_pool, start))
}
}
self.unwinder.try(f);
+ { let _ = self.taskgroup.take(); }
+ self.death.collect_failure(!self.unwinder.unwinding);
self.destroy();
-
- // Wait for children. Possibly report the exit status.
- let local_success = !self.unwinder.unwinding;
- let join_latch = self.join_latch.take_unwrap();
- match self.on_exit {
- Some(ref on_exit) => {
- let success = join_latch.wait(local_success);
- (*on_exit)(success);
- }
- None => {
- join_latch.release(local_success);
- }
- }
}
/// must be called manually before finalization to clean up
let mut task = ~Task::new_root(&mut sched.stack_pool,
f.take());
rtdebug!("newsched_task: %x", to_uint(task));
- task.on_exit = Some(on_exit);
+ task.death.on_exit = Some(on_exit);
sched.enqueue_task(task);
sched.run();
}
use os;
use from_str::FromStr;
use rt::sched::Shutdown;
- use rt::util;
let f_cell = Cell::new(f);
do run_in_bare_thread {
- let nthreads = match os::getenv("RUST_TEST_THREADS") {
+ let nthreads = match os::getenv("RUST_RT_TEST_THREADS") {
Some(nstr) => FromStr::from_str(nstr).get(),
None => {
- // Using more threads than cores in test code
- // to force the OS to preempt them frequently.
- // Assuming that this help stress test concurrent types.
- util::num_cpus() * 2
+ // A reasonable number of threads for testing
+ // multithreading. NB: It's easy to exhaust OS X's
+ // low maximum fd limit by setting this too high (#7772)
+ 4
}
};
};
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
f_cell.take());
- main_task.on_exit = Some(on_exit);
+ main_task.death.on_exit = Some(on_exit);
scheds[0].enqueue_task(main_task);
let mut threads = ~[];
let sched = Local::take::<Scheduler>();
do sched.switch_running_tasks_and_then(task) |sched, task| {
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
}
if run_now {
do sched.switch_running_tasks_and_then(task) |sched, task| {
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
} else {
sched.enqueue_task(task);
f.take())
}
};
- new_task.on_exit = Some(on_exit);
+ new_task.death.on_exit = Some(on_exit);
let sched = Local::take::<Scheduler>();
do sched.switch_running_tasks_and_then(new_task) |sched, old_task| {
- sched.enqueue_task(old_task);
+ sched.enqueue_blocked_task(old_task);
}
rtdebug!("enqueued the new task, now waiting on exit_status");
if exit_status { Ok(()) } else { Err(()) }
}
-// Spawn a new task in a new scheduler and return a thread handle.
+/// Spawn a new task in a new scheduler and return a thread handle.
pub fn spawntask_thread(f: ~fn()) -> Thread {
use rt::sched::*;
return thread;
}
+/// Get a ~Task for testing purposes other than actually scheduling it.
+pub fn with_test_task(blk: ~fn(~Task) -> ~Task) {
+ do run_in_bare_thread {
+ let mut sched = ~new_test_uv_sched();
+ let task = blk(~Task::new_root(&mut sched.stack_pool, ||{}));
+ sched.enqueue_task(task);
+ sched.run();
+ }
+}
+
/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
use super::rc::RC;
use rt::sched::Scheduler;
use rt::{context, TaskContext, SchedulerContext};
+use rt::kill::BlockedTask;
use rt::local::Local;
-use rt::task::Task;
use vec::OwnedVector;
use container::Container;
struct TubeState<T> {
- blocked_task: Option<~Task>,
+ blocked_task: Option<BlockedTask>,
buf: ~[T]
}
rtdebug!("waking blocked tube");
let task = (*state).blocked_task.take_unwrap();
let sched = Local::take::<Scheduler>();
- sched.resume_task_immediately(task);
+ sched.resume_blocked_task_immediately(task);
}
}
}
do sched.deschedule_running_task_and_then |sched, task| {
let mut tube_clone = tube_clone_cell.take();
tube_clone.send(1);
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
assert!(tube.recv() == 1);
// sending will wake it up.
tube_clone.send(1);
}
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
assert!(tube.recv() == 1);
}
}
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
for int::range(0, MAX) |i| {
}
}
- pub fn bind(&self, address: IpAddr) -> Result<(), UvError> {
+ pub fn bind(&mut self, address: IpAddr) -> Result<(), UvError> {
do ip_as_uv_ip(address) |addr| {
let result = unsafe {
match addr {
}
}
- pub fn recv_start(&self, alloc: AllocCallback, cb: UdpReceiveCallback) {
+ pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
{
- let mut this = *self;
- let data = this.get_watcher_data();
+ let data = self.get_watcher_data();
data.alloc_cb = Some(alloc);
data.udp_recv_cb = Some(cb);
}
}
}
- pub fn recv_stop(&self) {
+ pub fn recv_stop(&mut self) {
unsafe { uvll::udp_recv_stop(self.native_handle()); }
}
- pub fn send(&self, buf: Buf, address: IpAddr, cb: UdpSendCallback) {
+ pub fn send(&mut self, buf: Buf, address: IpAddr, cb: UdpSendCallback) {
{
- let mut this = *self;
- let data = this.get_watcher_data();
+ let data = self.get_watcher_data();
assert!(data.udp_send_cb.is_none());
data.udp_send_cb = Some(cb);
}
fn udp_bind_close_ip4() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
- let udp_watcher = { UdpWatcher::new(&mut loop_) };
+ let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip4();
udp_watcher.bind(addr);
udp_watcher.close(||());
fn udp_bind_close_ip6() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
- let udp_watcher = { UdpWatcher::new(&mut loop_) };
+ let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
let addr = next_test_ip6();
udp_watcher.bind(addr);
udp_watcher.close(||());
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();
- let server = UdpWatcher::new(&loop_);
+ let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
rtdebug!("starting read");
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
- do server.recv_start(alloc) |server, nread, buf, src, flags, status| {
+ do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
rtdebug!("i'm reading!");
assert!(status.is_none());
do Thread::start {
let mut loop_ = Loop::new();
- let client = UdpWatcher::new(&loop_);
+ let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
let server_addr = next_test_ip6();
let client_addr = next_test_ip6();
- let server = UdpWatcher::new(&loop_);
+ let mut server = UdpWatcher::new(&loop_);
assert!(server.bind(server_addr).is_ok());
rtdebug!("starting read");
vec_to_uv_buf(vec::from_elem(size, 0u8))
};
- do server.recv_start(alloc) |server, nread, buf, src, flags, status| {
+ do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
server.recv_stop();
rtdebug!("i'm reading!");
assert!(status.is_none());
do Thread::start {
let mut loop_ = Loop::new();
- let client = UdpWatcher::new(&loop_);
+ let mut client = UdpWatcher::new(&loop_);
assert!(client.bind(client_addr).is_ok());
let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let buf = slice_to_uv_buf(msg);
// Context switch
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
} else {
rtdebug!("status is some");
let task_cell = Cell::new(task_cell.take());
let res = Err(uv_error_to_io_error(status.get()));
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
};
}
let task_cell = Cell::new(task);
do watcher.as_stream().close {
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
Err(uv_error_to_io_error(uverr))
}
fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError> {
- let /*mut*/ watcher = UdpWatcher::new(self.uv_loop());
+ let mut watcher = UdpWatcher::new(self.uv_loop());
match watcher.bind(addr) {
Ok(_) => Ok(~UvUdpSocket(watcher)),
Err(uverr) => {
let task_cell = Cell::new(task);
do watcher.close {
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
Err(uv_error_to_io_error(uverr))
}
}
}
+
+ fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> {
+ Ok(~UvTimer(TimerWatcher::new(self.uv_loop())))
+ }
}
// FIXME #6090: Prefer newtype structs but Drop doesn't work
let task_cell = Cell::new(task);
do watcher.as_stream().close {
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
impl RtioSocket for UvTcpListener {
// XXX implement
- fn socket_name(&self) -> IpAddr { fail!(); }
+ fn socket_name(&mut self) -> IpAddr { fail!(); }
}
impl RtioTcpListener for UvTcpListener {
}
// XXX implement
- fn accept_simultaneously(&self) { fail!(); }
- fn dont_accept_simultaneously(&self) { fail!(); }
+ fn accept_simultaneously(&mut self) { fail!(); }
+ fn dont_accept_simultaneously(&mut self) { fail!(); }
}
// FIXME #6090: Prefer newtype structs but Drop doesn't work
let task_cell = Cell::new(task);
do self.close {
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
impl RtioSocket for UvTcpStream {
// XXX implement
- fn socket_name(&self) -> IpAddr { fail!(); }
+ fn socket_name(&mut self) -> IpAddr { fail!(); }
}
impl RtioTcpStream for UvTcpStream {
- fn read(&self, buf: &mut [u8]) -> Result<uint, IoError> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
return result_cell.take();
}
- fn write(&self, buf: &[u8]) -> Result<(), IoError> {
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
let scheduler = Local::take::<Scheduler>();
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
// XXX implement
- fn peer_name(&self) -> IpAddr { fail!(); }
- fn control_congestion(&self) { fail!(); }
- fn nodelay(&self) { fail!(); }
- fn keepalive(&self, _delay_in_seconds: uint) { fail!(); }
- fn letdie(&self) { fail!(); }
+ fn peer_name(&mut self) -> IpAddr { fail!(); }
+ fn control_congestion(&mut self) { fail!(); }
+ fn nodelay(&mut self) { fail!(); }
+ fn keepalive(&mut self, _delay_in_seconds: uint) { fail!(); }
+ fn letdie(&mut self) { fail!(); }
}
pub struct UvUdpSocket(UdpWatcher);
let task_cell = Cell::new(task);
do self.close {
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
impl RtioSocket for UvUdpSocket {
// XXX implement
- fn socket_name(&self) -> IpAddr { fail!(); }
+ fn socket_name(&mut self) -> IpAddr { fail!(); }
}
impl RtioUdpSocket for UvUdpSocket {
- fn recvfrom(&self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError> {
+ fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, IpAddr), IoError> {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(uint, IpAddr), IoError>> = &result_cell;
assert!(!sched.in_task_context());
let task_cell = Cell::new(task);
let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) };
- do self.recv_start(alloc) |watcher, nread, _buf, addr, flags, status| {
+ do self.recv_start(alloc) |mut watcher, nread, _buf, addr, flags, status| {
let _ = flags; // XXX add handling for partials?
watcher.recv_stop();
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
return result_cell.take();
}
- fn sendto(&self, buf: &[u8], dst: IpAddr) -> Result<(), IoError> {
+ fn sendto(&mut self, buf: &[u8], dst: IpAddr) -> Result<(), IoError> {
let result_cell = Cell::new_empty();
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
let scheduler = Local::take::<Scheduler>();
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
- scheduler.resume_task_immediately(task_cell.take());
+ scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
}
// XXX implement
- fn join_multicast(&self, _multi: IpAddr) { fail!(); }
- fn leave_multicast(&self, _multi: IpAddr) { fail!(); }
+ fn join_multicast(&mut self, _multi: IpAddr) { fail!(); }
+ fn leave_multicast(&mut self, _multi: IpAddr) { fail!(); }
+
+ fn loop_multicast_locally(&mut self) { fail!(); }
+ fn dont_loop_multicast_locally(&mut self) { fail!(); }
- fn loop_multicast_locally(&self) { fail!(); }
- fn dont_loop_multicast_locally(&self) { fail!(); }
+ fn multicast_time_to_live(&mut self, _ttl: int) { fail!(); }
+ fn time_to_live(&mut self, _ttl: int) { fail!(); }
+
+ fn hear_broadcasts(&mut self) { fail!(); }
+ fn ignore_broadcasts(&mut self) { fail!(); }
+}
- fn multicast_time_to_live(&self, _ttl: int) { fail!(); }
- fn time_to_live(&self, _ttl: int) { fail!(); }
+pub struct UvTimer(timer::TimerWatcher);
- fn hear_broadcasts(&self) { fail!(); }
- fn ignore_broadcasts(&self) { fail!(); }
+impl UvTimer {
+ fn new(w: timer::TimerWatcher) -> UvTimer {
+ UvTimer(w)
+ }
+}
+
+impl Drop for UvTimer {
+ fn drop(&self) {
+ rtdebug!("closing UvTimer");
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self.close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+}
+
+impl RtioTimer for UvTimer {
+ fn sleep(&self, msecs: u64) {
+ let scheduler = Local::take::<Scheduler>();
+ assert!(scheduler.in_task_context());
+ do scheduler.deschedule_running_task_and_then |sched, task| {
+ rtdebug!("sleep: entered scheduler context");
+ assert!(!sched.in_task_context());
+ let task_cell = Cell::new(task);
+ let mut watcher = **self;
+ do watcher.start(msecs, 0) |_, status| {
+ assert!(status.is_none());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ let mut w = **self;
+ w.stop();
+ }
}
#[test]
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let mut listener = (*io).tcp_bind(addr).unwrap();
- let stream = listener.accept().unwrap();
+ let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
let nread = stream.read(buf).unwrap();
assert_eq!(nread, 8);
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let stream = (*io).tcp_connect(addr).unwrap();
+ let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
}
}
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let server_socket = (*io).udp_bind(server_addr).unwrap();
+ let mut server_socket = (*io).udp_bind(server_addr).unwrap();
let mut buf = [0, .. 2048];
let (nread,src) = server_socket.recvfrom(buf).unwrap();
assert_eq!(nread, 8);
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let client_socket = (*io).udp_bind(client_addr).unwrap();
+ let mut client_socket = (*io).udp_bind(client_addr).unwrap();
client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
}
}
do spawntask_immediately {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() };
- let stream = listener.accept().unwrap();
+ let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
let expected = 32;
// not ready for it
do scheduler.deschedule_running_task_and_then |sched, task| {
let task = Cell::new(task);
- sched.enqueue_task(task.take());
+ sched.enqueue_blocked_task(task.take());
}
}
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let stream = (*io).tcp_connect(addr).unwrap();
+ 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]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let mut listener = (*io).tcp_bind(addr).unwrap();
- let stream = listener.accept().unwrap();
+ let mut stream = listener.accept().unwrap();
let buf = [1, .. 2048];
let mut total_bytes_written = 0;
while total_bytes_written < MAX {
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let stream = (*io).tcp_connect(addr).unwrap();
+ let mut stream = (*io).tcp_connect(addr).unwrap();
let mut buf = [0, .. 2048];
let mut total_bytes_read = 0;
while total_bytes_read < MAX {
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let client = (*io).udp_bind(client_addr).unwrap();
+ 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_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let server = (*io).udp_bind(server_addr).unwrap();
+ let mut server = (*io).udp_bind(server_addr).unwrap();
let mut buf1 = [0];
let mut buf2 = [0];
let (nread1, src1) = server.recvfrom(buf1).unwrap();
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let server_out = (*io).udp_bind(server_out_addr).unwrap();
- let server_in = (*io).udp_bind(server_in_addr).unwrap();
+ 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];
let mut total_bytes_sent = 0;
let mut buf = [1];
do spawntask_immediately {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
- let client_out = (*io).udp_bind(client_out_addr).unwrap();
- let client_in = (*io).udp_bind(client_in_addr).unwrap();
+ 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;
let mut buf = [0, .. 2048];
while total_bytes_recv < MAX {
}
}
}
+
+fn test_timer_sleep_simple_impl() {
+ unsafe {
+ let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let timer = (*io).timer_init();
+ match timer {
+ Ok(t) => t.sleep(1),
+ Err(_) => assert!(false)
+ }
+ }
+}
+#[test]
+fn test_timer_sleep_simple() {
+ do run_in_newsched_task {
+ test_timer_sleep_simple_impl();
+ }
+}
use libc::c_void;
#[abi = "cdecl"]
- pub extern {
- unsafe fn rust_unset_sigprocmask();
- unsafe fn rust_set_environ(envp: *c_void);
+ extern {
+ pub unsafe fn rust_unset_sigprocmask();
+ pub unsafe fn rust_set_environ(envp: *c_void);
}
}
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
-mod core {
- pub use clone;
- pub use cmp;
- pub use condition;
- pub use option;
- pub use kinds;
- pub use sys;
- pub use pipes;
-}
-#[doc(hidden)]
mod std {
pub use clone;
pub use cmp;
use char;
use char::Char;
use clone::Clone;
-use container::Container;
+use container::{Container, Mutable};
use iter::Times;
use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator, MapIterator};
use libc;
/// An iterator over the substrings of a string, separated by `sep`.
+#[deriving(Clone)]
pub struct StrCharSplitIterator<'self,Sep> {
priv string: &'self str,
priv position: uint,
/// An iterator over the start and end indicies of the matches of a
/// substring within a larger string
+#[deriving(Clone)]
pub struct StrMatchesIndexIterator<'self> {
priv haystack: &'self str,
priv needle: &'self str,
/// An iterator over the substrings of a string separated by a given
/// search string
+#[deriving(Clone)]
pub struct StrStrSplitIterator<'self> {
priv it: StrMatchesIndexIterator<'self>,
priv last_end: uint,
/// Sets the length of the string and adds the null terminator
#[inline]
- #[cfg(stage0)]
- pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
- let v: **mut vec::raw::VecRepr = cast::transmute(v);
- let repr: *mut vec::raw::VecRepr = *v;
- (*repr).unboxed.fill = new_len + 1u;
- let null = ptr::mut_offset(cast::transmute(&((*repr).unboxed.data)),
- new_len);
- *null = 0u8;
- }
-
- /// Sets the length of the string and adds the null terminator
- #[inline]
- #[cfg(not(stage0))]
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **mut vec::UnboxedVecRepr = cast::transmute(v);
let repr: *mut vec::UnboxedVecRepr = *v;
}
}
+impl Container for ~str {
+ #[inline]
+ fn len(&self) -> uint { self.as_slice().len() }
+ #[inline]
+ fn is_empty(&self) -> bool { self.len() == 0 }
+}
+
+impl Container for @str {
+ #[inline]
+ fn len(&self) -> uint { self.as_slice().len() }
+ #[inline]
+ fn is_empty(&self) -> bool { self.len() == 0 }
+}
+
+impl Mutable for ~str {
+ /// Remove all content, make the string empty
+ #[inline]
+ fn clear(&mut self) {
+ unsafe {
+ raw::set_len(self, 0)
+ }
+ }
+}
+
+
#[allow(missing_doc)]
pub trait StrSlice<'self> {
fn contains<'a>(&self, needle: &'a str) -> bool;
/// External iterator for a string's characters. Use with the `std::iterator`
/// module.
+#[deriving(Clone)]
pub struct StrCharIterator<'self> {
priv index: uint,
priv string: &'self str,
}
/// External iterator for a string's characters in reverse order. Use
/// with the `std::iterator` module.
+#[deriving(Clone)]
pub struct StrCharRevIterator<'self> {
priv index: uint,
priv string: &'self str,
/// External iterator for a string's bytes. Use with the `std::iterator`
/// module.
+#[deriving(Clone)]
pub struct StrBytesIterator<'self> {
priv it: vec::VecIterator<'self, u8>
}
/// External iterator for a string's bytes in reverse order. Use with
/// the `std::iterator` module.
+#[deriving(Clone)]
pub struct StrBytesRevIterator<'self> {
priv it: vec::VecRevIterator<'self, u8>
}
assert_eq!(~"华ประเทศไทย中", data);
}
+ #[test]
+ fn test_clear() {
+ let mut empty = ~"";
+ empty.clear();
+ assert_eq!("", empty.as_slice());
+ let mut data = ~"ประเทศไทย中";
+ data.clear();
+ assert_eq!("", data.as_slice());
+ data.push_char('华');
+ assert_eq!("华", data.as_slice());
+ }
+
#[test]
fn test_split_within() {
fn t(s: &str, i: uint, u: &[~str]) {
t::<@str>();
t::<~str>();
}
+
+ #[test]
+ fn test_str_container() {
+ fn sum_len<S: Container>(v: &[S]) -> uint {
+ v.iter().transform(|x| x.len()).sum()
+ }
+
+ let s = ~"01234";
+ assert_eq!(5, sum_len(["012", "", "34"]));
+ assert_eq!(5, sum_len([@"01", @"2", @"34", @""]));
+ assert_eq!(5, sum_len([~"01", ~"2", ~"34", ~""]));
+ assert_eq!(5, sum_len([s.as_slice()]));
+ }
}
pub mod rustrt {
use libc::{c_char, size_t};
- pub extern {
+ extern {
#[rust_stack]
- unsafe fn rust_upcall_fail(expr: *c_char,
- file: *c_char,
- line: size_t);
+ pub unsafe fn rust_upcall_fail(expr: *c_char,
+ file: *c_char,
+ line: size_t);
}
}
+++ /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 cmp::Eq;
-use libc;
-use local_data;
-use prelude::*;
-use sys;
-use task::rt;
-
-use super::rt::rust_task;
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
- OldHandle(*rust_task),
- NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
- pub fn new() -> Handle {
- use rt::{context, OldTaskContext};
- use rt::local::Local;
- unsafe {
- match context() {
- OldTaskContext => {
- OldHandle(rt::rust_get_task())
- }
- _ => {
- let task = Local::unsafe_borrow::<Task>();
- NewHandle(&mut (*task).storage)
- }
- }
- }
- }
-}
-
-pub trait LocalData { }
-impl<T: 'static> LocalData for @T { }
-
-impl Eq for @LocalData {
- fn eq(&self, other: &@LocalData) -> bool {
- unsafe {
- let ptr_a: &(uint, uint) = cast::transmute(self);
- let ptr_b: &(uint, uint) = cast::transmute(other);
- return ptr_a == ptr_b;
- }
- }
- fn ne(&self, other: &@LocalData) -> bool { !(*self).eq(other) }
-}
-
-// If TLS is used heavily in future, this could be made more efficient with a
-// proper map.
-type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData);
-// Has to be a pointer at outermost layer; the foreign call returns void *.
-type TaskLocalMap = ~[Option<TaskLocalElement>];
-
-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 {
- match handle {
- OldHandle(task) => get_task_local_map(task),
- NewHandle(local_storage) => get_newsched_local_map(local_storage)
- }
-}
-
-unsafe fn get_task_local_map(task: *rust_task) -> &mut TaskLocalMap {
-
- extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) {
- cleanup_task_local_map(map_ptr);
- }
-
- // Relies on the runtime initialising the pointer to null.
- // Note: the map is an owned pointer and is "owned" by TLS. It is moved
- // into the tls slot for this task, and then mutable loans are taken from
- // this slot to modify the map.
- let map_ptr = rt::rust_get_task_local_data(task);
- if (*map_ptr).is_null() {
- // First time TLS is used, create a new map and set up the necessary
- // TLS information for its safe destruction
- let map: TaskLocalMap = ~[];
- *map_ptr = cast::transmute(map);
- rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb);
- }
- return cast::transmute(map_ptr);
-}
-
-unsafe fn get_newsched_local_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);
- }
- }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<@T>) -> *libc::c_void {
- let pair: sys::Closure = cast::transmute(key);
- return pair.code as *libc::c_void;
-}
-
-// If returning Some(..), returns with @T with the map's reference. Careful!
-unsafe fn local_data_lookup<T: 'static>(
- map: &mut TaskLocalMap, key: local_data::Key<@T>)
- -> Option<(uint, *libc::c_void)> {
-
- let key_value = key_to_key_value(key);
- for map.iter().enumerate().advance |(i, entry)| {
- match *entry {
- Some((k, data, _)) if k == key_value => { return Some((i, data)); }
- _ => {}
- }
- }
- return None;
-}
-
-unsafe fn local_get_helper<T: 'static>(
- handle: Handle, key: local_data::Key<@T>,
- do_pop: bool) -> Option<@T> {
-
- let map = get_local_map(handle);
- // Interpreturn our findings from the map
- do local_data_lookup(map, key).map |result| {
- // A reference count magically appears on 'data' out of thin air. It
- // was referenced in the local_data box, though, not here, so before
- // overwriting the local_data_box we need to give an extra reference.
- // We must also give an extra reference when not removing.
- let (index, data_ptr) = *result;
- let data: @T = cast::transmute(data_ptr);
- cast::bump_box_refcount(data);
- if do_pop {
- map[index] = None;
- }
- data
- }
-}
-
-
-pub unsafe fn local_pop<T: 'static>(
- handle: Handle,
- key: local_data::Key<@T>) -> Option<@T> {
-
- local_get_helper(handle, key, true)
-}
-
-pub unsafe fn local_get<T: 'static, U>(
- handle: Handle,
- key: local_data::Key<@T>,
- f: &fn(Option<&@T>) -> U) -> U {
-
- match local_get_helper(handle, key, false) {
- Some(ref x) => f(Some(x)),
- None => f(None)
- }
-}
-
-pub unsafe fn local_set<T: 'static>(
- handle: Handle, key: local_data::Key<@T>, data: @T) {
-
- let map = get_local_map(handle);
- // Store key+data as *voids. Data is invisibly referenced once; key isn't.
- let keyval = key_to_key_value(key);
- // We keep the data in two forms: one as an unsafe pointer, so we can get
- // it back by casting; another in an existential box, so the reference we
- // own on it can be dropped when the box is destroyed. The unsafe pointer
- // does not have a reference associated with it, so it may become invalid
- // when the box is destroyed.
- let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data);
- let data_box = @data as @LocalData;
- // Construct new entry to store in the map.
- let new_entry = Some((keyval, data_ptr, data_box));
- // Find a place to put it.
- match local_data_lookup(map, key) {
- Some((index, _old_data_ptr)) => {
- // Key already had a value set, _old_data_ptr, whose reference
- // will get dropped when the local_data box is overwritten.
- map[index] = new_entry;
- }
- None => {
- // Find an empty slot. If not, grow the vector.
- match map.iter().position(|x| x.is_none()) {
- Some(empty_index) => { map[empty_index] = new_entry; }
- None => { map.push(new_entry); }
- }
- }
- }
-}
-
-pub unsafe fn local_modify<T: 'static>(
- handle: Handle, key: local_data::Key<@T>,
- modify_fn: &fn(Option<@T>) -> Option<@T>) {
-
- // Could be more efficient by doing the lookup work, but this is easy.
- let newdata = modify_fn(local_pop(handle, key));
- if newdata.is_some() {
- local_set(handle, key, newdata.unwrap());
- }
-}
use comm::{stream, Chan, GenericChan, GenericPort, Port};
use result::Result;
use result;
-use rt::{context, OldTaskContext};
+use rt::{context, OldTaskContext, TaskContext};
+use rt::local::Local;
use task::rt::{task_id, sched_id};
use unstable::finally::Finally;
-use util::replace;
use util;
#[cfg(test)] use cast;
#[cfg(test)] use ptr;
#[cfg(test)] use task;
-#[cfg(stage0)]
-#[path="local_data_priv_stage0.rs"]
-mod local_data_priv;
-#[cfg(not(stage0))]
mod local_data_priv;
pub mod rt;
pub mod spawn;
/// All tasks run in the same OS thread
SingleThreaded,
/// Tasks are distributed among available CPUs
- ThreadPerCore,
- /// Each task runs in its own OS thread
ThreadPerTask,
/// Tasks are distributed among a fixed number of OS threads
ManualThreads(uint),
* * supervised - Propagate failure unidirectionally from parent to child,
* but not from child to parent. False by default.
*
+ * * watched - Make parent task collect exit status notifications from child
+ * before reporting its own exit status. (This delays the parent
+ * task's death and cleanup until after all transitively watched
+ * children also exit.) True by default.
+ *
+ * * indestructible - Configures the task to ignore kill signals received from
+ * linked failure. This may cause process hangs during
+ * failure if not used carefully, but causes task blocking
+ * code paths (e.g. port recv() calls) to be faster by 2
+ * atomic operations. False by default.
+ *
* * notify_chan - Enable lifecycle notifications on the given channel
*
* * sched - Specify the configuration of a new scheduler to create the task
pub struct TaskOpts {
linked: bool,
supervised: bool,
+ watched: bool,
+ indestructible: bool,
notify_chan: Option<Chan<TaskResult>>,
sched: SchedOpts
}
fail!("Cannot copy a task_builder"); // Fake move mode on self
}
self.consumed = true;
- let gen_body = replace(&mut self.gen_body, None);
- let notify_chan = replace(&mut self.opts.notify_chan, None);
+ let gen_body = self.gen_body.take();
+ let notify_chan = self.opts.notify_chan.take();
TaskBuilder {
opts: TaskOpts {
linked: self.opts.linked,
supervised: self.opts.supervised,
+ watched: self.opts.watched,
+ indestructible: self.opts.indestructible,
notify_chan: notify_chan,
sched: self.opts.sched
},
/// the other will not be killed.
pub fn unlinked(&mut self) {
self.opts.linked = false;
+ self.opts.watched = false;
}
/// Unidirectionally link the child task's failure with the parent's. The
pub fn supervised(&mut self) {
self.opts.supervised = true;
self.opts.linked = false;
+ self.opts.watched = false;
}
/// Link the child task's and parent task's failures. If either fails, the
pub fn linked(&mut self) {
self.opts.linked = true;
self.opts.supervised = false;
+ self.opts.watched = true;
+ }
+
+ /// Cause the parent task to collect the child's exit status (and that of
+ /// all transitively-watched grandchildren) before reporting its own.
+ pub fn watched(&mut self) {
+ self.opts.watched = true;
+ }
+
+ /// Allow the child task to outlive the parent task, at the possible cost
+ /// of the parent reporting success even if the child task fails later.
+ pub fn unwatched(&mut self) {
+ self.opts.watched = false;
+ }
+
+ /// Cause the child task to ignore any kill signals received from linked
+ /// failure. This optimizes context switching, at the possible expense of
+ /// process hangs in the case of unexpected failure.
+ pub fn indestructible(&mut self) {
+ self.opts.indestructible = true;
}
/**
* existing body generator to the new body generator.
*/
pub fn add_wrapper(&mut self, wrapper: ~fn(v: ~fn()) -> ~fn()) {
- let prev_gen_body = replace(&mut self.gen_body, None);
+ let prev_gen_body = self.gen_body.take();
let prev_gen_body = match prev_gen_body {
Some(gen) => gen,
None => {
* must be greater than zero.
*/
pub fn spawn(&mut self, f: ~fn()) {
- let gen_body = replace(&mut self.gen_body, None);
- let notify_chan = replace(&mut self.opts.notify_chan, None);
+ let gen_body = self.gen_body.take();
+ let notify_chan = self.opts.notify_chan.take();
let x = self.consume();
let opts = TaskOpts {
linked: x.opts.linked,
supervised: x.opts.supervised,
+ watched: x.opts.watched,
+ indestructible: x.opts.indestructible,
notify_chan: notify_chan,
sched: x.opts.sched
};
TaskOpts {
linked: true,
supervised: false,
+ watched: true,
+ indestructible: false,
notify_chan: None,
sched: SchedOpts {
mode: DefaultScheduler,
task.spawn(f)
}
+/// Creates a child task that cannot be killed by linked failure. This causes
+/// its context-switch path to be faster by 2 atomic swap operations.
+/// (Note that this convenience wrapper still uses linked-failure, so the
+/// child's children will still be killable by the parent. For the fastest
+/// possible spawn mode, use task::task().unlinked().indestructible().spawn.)
+pub fn spawn_indestructible(f: ~fn()) {
+ let mut task = task();
+ task.indestructible();
+ task.spawn(f)
+}
+
pub fn spawn_with<A:Send>(arg: A, f: ~fn(v: A)) {
/*!
* Runs a task, while transfering ownership of one argument to the
}
_ => {
// XXX: What does yield really mean in newsched?
+ // FIXME(#7544): Optimize this, since we know we won't block.
let sched = Local::take::<Scheduler>();
do sched.deschedule_running_task_and_then |sched, task| {
- sched.enqueue_task(task);
+ sched.enqueue_blocked_task(task);
}
}
}
pub fn failing() -> bool {
//! True if the running task has failed
- use rt::{context, OldTaskContext};
- use rt::local::Local;
use rt::task::Task;
match context() {
* ~~~
*/
pub unsafe fn unkillable<U>(f: &fn() -> U) -> U {
- if context() == OldTaskContext {
- let t = rt::rust_get_task();
- do (|| {
- rt::rust_task_inhibit_kill(t);
- f()
- }).finally {
- rt::rust_task_allow_kill(t);
+ use rt::task::Task;
+
+ match context() {
+ OldTaskContext => {
+ let t = rt::rust_get_task();
+ do (|| {
+ rt::rust_task_inhibit_kill(t);
+ f()
+ }).finally {
+ rt::rust_task_allow_kill(t);
+ }
+ }
+ TaskContext => {
+ // The inhibits/allows might fail and need to borrow the task.
+ let t = Local::unsafe_borrow::<Task>();
+ do (|| {
+ (*t).death.inhibit_kill((*t).unwinder.unwinding);
+ f()
+ }).finally {
+ (*t).death.allow_kill((*t).unwinder.unwinding);
+ }
}
- } else {
- // FIXME #6377
- f()
+ // FIXME(#3095): This should be an rtabort as soon as the scheduler
+ // no longer uses a workqueue implemented with an Exclusive.
+ _ => f()
}
}
/// The inverse of unkillable. Only ever to be used nested in unkillable().
pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
- if context() == OldTaskContext {
- let t = rt::rust_get_task();
- do (|| {
- rt::rust_task_allow_kill(t);
- f()
- }).finally {
- rt::rust_task_inhibit_kill(t);
+ use rt::task::Task;
+
+ match context() {
+ OldTaskContext => {
+ let t = rt::rust_get_task();
+ do (|| {
+ rt::rust_task_allow_kill(t);
+ f()
+ }).finally {
+ rt::rust_task_inhibit_kill(t);
+ }
+ }
+ TaskContext => {
+ let t = Local::unsafe_borrow::<Task>();
+ do (|| {
+ (*t).death.allow_kill((*t).unwinder.unwinding);
+ f()
+ }).finally {
+ (*t).death.inhibit_kill((*t).unwinder.unwinding);
+ }
}
- } else {
- // FIXME #6377
- f()
+ // FIXME(#3095): As in unkillable().
+ _ => f()
}
}
* For use with exclusive ARCs, which use pthread mutexes directly.
*/
pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
- if context() == OldTaskContext {
- let t = rt::rust_get_task();
- do (|| {
- rt::rust_task_inhibit_kill(t);
- rt::rust_task_inhibit_yield(t);
- f()
- }).finally {
- rt::rust_task_allow_yield(t);
- rt::rust_task_allow_kill(t);
+ use rt::task::Task;
+
+ match context() {
+ OldTaskContext => {
+ let t = rt::rust_get_task();
+ do (|| {
+ rt::rust_task_inhibit_kill(t);
+ rt::rust_task_inhibit_yield(t);
+ f()
+ }).finally {
+ rt::rust_task_allow_yield(t);
+ rt::rust_task_allow_kill(t);
+ }
}
- } else {
- // FIXME #6377
- f()
+ TaskContext => {
+ let t = Local::unsafe_borrow::<Task>();
+ do (|| {
+ // It's important to inhibit kill after inhibiting yield, because
+ // inhibit-kill might fail if we were already killed, and the
+ // inhibit-yield must happen to match the finally's allow-yield.
+ (*t).death.inhibit_yield();
+ (*t).death.inhibit_kill((*t).unwinder.unwinding);
+ f()
+ }).finally {
+ (*t).death.allow_kill((*t).unwinder.unwinding);
+ (*t).death.allow_yield();
+ }
+ }
+ // FIXME(#3095): As in unkillable().
+ _ => f()
}
}
// !!! These tests are dangerous. If Something is buggy, they will hang, !!!
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
+#[cfg(test)]
+fn block_forever() { let (po, _ch) = stream::<()>(); po.recv(); }
+
#[test] #[ignore(cfg(windows))]
fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port
let (po, ch) = stream();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_spawn_unlinked_sup_fail_down() {
- do spawn_supervised { loop { task::yield(); } }
+ do spawn_supervised { block_forever(); }
fail!(); // Shouldn't leave a child hanging around.
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_spawn_linked_sup_fail_up() { // child fails; parent fails
- let (po, _ch) = stream::<()>();
-
// Unidirectional "parenting" shouldn't override bidirectional linked.
// We have to cheat with opts - the interface doesn't support them because
// they don't make sense (redundant with task().supervised()).
do b0.spawn {
fail!();
}
- po.recv(); // We should get punted awake
+ block_forever(); // We should get punted awake
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_spawn_linked_sup_fail_down() { // parent fails; child fails
let mut b0 = task();
b0.opts.linked = true;
b0.opts.supervised = true;
- do b0.spawn {
- loop {
- task::yield();
- }
- }
+ do b0.spawn { block_forever(); }
fail!(); // *both* mechanisms would be wrong if this didn't kill the child
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails
- let (po, _ch) = stream::<()>();
// Default options are to spawn linked & unsupervised.
do spawn { fail!(); }
- po.recv(); // We should get punted awake
+ block_forever(); // We should get punted awake
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails
// Default options are to spawn linked & unsupervised.
- do spawn { loop { task::yield(); } }
+ do spawn { block_forever(); }
fail!();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
// Make sure the above test is the same as this one.
let mut builder = task();
builder.linked();
- do builder.spawn {
- loop {
- task::yield();
- }
- }
+ do builder.spawn { block_forever(); }
fail!();
}
fn test_spawn_failure_propagate_grandchild() {
// Middle task exits; does grandparent's failure propagate across the gap?
do spawn_supervised {
- do spawn_supervised {
- loop { task::yield(); }
- }
+ do spawn_supervised { block_forever(); }
}
for 16.times { task::yield(); }
fail!();
fn test_spawn_failure_propagate_secondborn() {
// First-born child exits; does parent's failure propagate to sibling?
do spawn_supervised {
- do spawn { // linked
- loop { task::yield(); }
- }
+ do spawn { block_forever(); } // linked
}
for 16.times { task::yield(); }
fail!();
fn test_spawn_failure_propagate_nephew_or_niece() {
// Our sibling exits; does our failure propagate to sibling's child?
do spawn { // linked
- do spawn_supervised {
- loop { task::yield(); }
- }
+ do spawn_supervised { block_forever(); }
}
for 16.times { task::yield(); }
fail!();
fn test_spawn_linked_sup_propagate_sibling() {
// Middle sibling exits - does eldest's failure propagate to youngest?
do spawn { // linked
- do spawn { // linked
- loop { task::yield(); }
- }
+ do spawn { block_forever(); } // linked
}
for 16.times { task::yield(); }
fail!();
use libc;
#[nolink]
- pub extern {
- unsafe fn rust_dbg_lock_create() -> *libc::c_void;
- unsafe fn rust_dbg_lock_destroy(lock: *libc::c_void);
- unsafe fn rust_dbg_lock_lock(lock: *libc::c_void);
- unsafe fn rust_dbg_lock_unlock(lock: *libc::c_void);
- unsafe fn rust_dbg_lock_wait(lock: *libc::c_void);
- unsafe fn rust_dbg_lock_signal(lock: *libc::c_void);
+ extern {
+ pub unsafe fn rust_dbg_lock_create() -> *libc::c_void;
+ pub unsafe fn rust_dbg_lock_destroy(lock: *libc::c_void);
+ pub unsafe fn rust_dbg_lock_lock(lock: *libc::c_void);
+ pub unsafe fn rust_dbg_lock_unlock(lock: *libc::c_void);
+ pub unsafe fn rust_dbg_lock_wait(lock: *libc::c_void);
+ pub unsafe fn rust_dbg_lock_signal(lock: *libc::c_void);
}
}
task::spawn(child_no(0));
}
-#[test]
-fn test_sched_thread_per_core() {
- let (port, chan) = comm::stream();
-
- do spawn_sched(ThreadPerCore) || {
- unsafe {
- let cores = rt::rust_num_threads();
- let reported_threads = rt::rust_sched_threads();
- assert_eq!(cores as uint, reported_threads as uint);
- chan.send(());
- }
- }
-
- port.recv();
-}
-
#[test]
fn test_spawn_thread_on_demand() {
let (port, chan) = comm::stream();
}
}
+#[test] #[ignore(cfg(windows))]
+fn test_spawn_watched() {
+ use rt::test::{run_in_newsched_task, spawntask_try};
+ do run_in_newsched_task {
+ let result = do spawntask_try {
+ let mut t = task();
+ t.unlinked();
+ t.watched();
+ do t.spawn {
+ let mut t = task();
+ t.unlinked();
+ t.watched();
+ do t.spawn {
+ task::yield();
+ fail!();
+ }
+ }
+ };
+ assert!(result.is_err());
+ }
+}
+
+#[test] #[ignore(cfg(windows))]
+fn test_indestructible() {
+ use rt::test::{run_in_newsched_task, spawntask_try};
+ do run_in_newsched_task {
+ let result = do spawntask_try {
+ let mut t = task();
+ t.watched();
+ t.supervised();
+ t.indestructible();
+ do t.spawn {
+ let (p1, _c1) = stream::<()>();
+ let (p2, c2) = stream::<()>();
+ let (p3, c3) = stream::<()>();
+ let mut t = task();
+ t.unwatched();
+ do t.spawn {
+ do (|| {
+ p1.recv(); // would deadlock if not killed
+ }).finally {
+ c2.send(());
+ };
+ }
+ let mut t = task();
+ t.unwatched();
+ do t.spawn {
+ p3.recv();
+ task::yield();
+ fail!();
+ }
+ c3.send(());
+ p2.recv();
+ }
+ };
+ assert!(result.is_ok());
+ }
+}
#[allow(non_camel_case_types)] // runtime type
pub type rust_closure = libc::c_void;
-pub extern {
+extern {
#[rust_stack]
- fn rust_task_yield(task: *rust_task) -> bool;
+ pub fn rust_task_yield(task: *rust_task) -> bool;
- fn rust_get_sched_id() -> sched_id;
- fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id;
- fn rust_sched_threads() -> libc::size_t;
- fn rust_sched_current_nonlazy_threads() -> libc::size_t;
- fn rust_num_threads() -> libc::uintptr_t;
+ pub fn rust_get_sched_id() -> sched_id;
+ pub fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id;
+ pub fn rust_sched_threads() -> libc::size_t;
+ pub fn rust_sched_current_nonlazy_threads() -> libc::size_t;
- fn get_task_id() -> task_id;
+ pub fn get_task_id() -> task_id;
#[rust_stack]
- fn rust_get_task() -> *rust_task;
+ pub fn rust_get_task() -> *rust_task;
- fn new_task() -> *rust_task;
- fn rust_new_task_in_sched(id: sched_id) -> *rust_task;
+ pub fn new_task() -> *rust_task;
+ pub fn rust_new_task_in_sched(id: sched_id) -> *rust_task;
- fn start_task(task: *rust_task, closure: *rust_closure);
+ pub fn start_task(task: *rust_task, closure: *rust_closure);
- fn rust_task_is_unwinding(task: *rust_task) -> bool;
- fn rust_osmain_sched_id() -> sched_id;
+ pub fn rust_task_is_unwinding(task: *rust_task) -> bool;
+ pub fn rust_osmain_sched_id() -> sched_id;
#[rust_stack]
- fn rust_task_inhibit_kill(t: *rust_task);
+ pub fn rust_task_inhibit_kill(t: *rust_task);
#[rust_stack]
- fn rust_task_allow_kill(t: *rust_task);
+ pub fn rust_task_allow_kill(t: *rust_task);
#[rust_stack]
- fn rust_task_inhibit_yield(t: *rust_task);
+ pub fn rust_task_inhibit_yield(t: *rust_task);
#[rust_stack]
- fn rust_task_allow_yield(t: *rust_task);
- fn rust_task_kill_other(task: *rust_task);
- fn rust_task_kill_all(task: *rust_task);
+ pub fn rust_task_allow_yield(t: *rust_task);
+ pub fn rust_task_kill_other(task: *rust_task);
+ pub fn rust_task_kill_all(task: *rust_task);
#[rust_stack]
- fn rust_get_task_local_data(task: *rust_task) -> *mut *libc::c_void;
+ pub fn rust_get_task_local_data(task: *rust_task) -> *mut *libc::c_void;
#[rust_stack]
- fn rust_task_local_data_atexit(task: *rust_task, cleanup_fn: *u8);
+ pub fn rust_task_local_data_atexit(task: *rust_task, cleanup_fn: *u8);
}
use cell::Cell;
use container::MutableMap;
use comm::{Chan, GenericChan};
-use hashmap::HashSet;
+use hashmap::{HashSet, HashSetConsumeIterator};
use local_data;
use task::local_data_priv::{local_get, local_set, OldHandle};
use task::rt::rust_task;
use task::rt;
use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded};
-use task::{Success, TaskOpts, TaskResult, ThreadPerCore, ThreadPerTask};
+use task::{Success, TaskOpts, TaskResult, ThreadPerTask};
use task::{ExistingScheduler, SchedulerHandle};
use task::unkillable;
+use to_bytes::IterBytes;
use uint;
use util;
use unstable::sync::{Exclusive, exclusive};
+use rt::{OldTaskContext, TaskContext, SchedulerContext, GlobalContext, context};
use rt::local::Local;
use rt::task::Task;
+use rt::kill::KillHandle;
+use rt::sched::Scheduler;
use iterator::IteratorUtil;
#[cfg(test)] use task::default_task_opts;
#[cfg(test)] use comm;
#[cfg(test)] use task;
-type TaskSet = HashSet<*rust_task>;
-
-fn new_taskset() -> TaskSet {
- HashSet::new()
+// Transitionary.
+#[deriving(Eq)]
+enum TaskHandle {
+ OldTask(*rust_task),
+ NewTask(KillHandle),
}
-fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
- let didnt_overwrite = tasks.insert(task);
- assert!(didnt_overwrite);
+
+impl Clone for TaskHandle {
+ fn clone(&self) -> TaskHandle {
+ match *self {
+ OldTask(x) => OldTask(x),
+ NewTask(ref x) => NewTask(x.clone()),
+ }
+ }
}
-fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) {
- let was_present = tasks.remove(&task);
- assert!(was_present);
+
+impl IterBytes for TaskHandle {
+ fn iter_bytes(&self, lsb0: bool, f: &fn(buf: &[u8]) -> bool) -> bool {
+ match *self {
+ OldTask(ref x) => x.iter_bytes(lsb0, f),
+ NewTask(ref x) => x.iter_bytes(lsb0, f),
+ }
+ }
}
-pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) -> bool {
- tasks.iter().advance(|k| blk(*k))
+
+struct TaskSet(HashSet<TaskHandle>);
+
+impl TaskSet {
+ #[inline]
+ fn new() -> TaskSet {
+ TaskSet(HashSet::new())
+ }
+ #[inline]
+ fn insert(&mut self, task: TaskHandle) {
+ let didnt_overwrite = (**self).insert(task);
+ assert!(didnt_overwrite);
+ }
+ #[inline]
+ fn remove(&mut self, task: &TaskHandle) {
+ let was_present = (**self).remove(task);
+ assert!(was_present);
+ }
+ #[inline]
+ fn consume(self) -> HashSetConsumeIterator<TaskHandle> {
+ (*self).consume()
+ }
}
// One of these per group of linked-failure tasks.
// circular references arise, deadlock and memory leaks are imminent).
// Hence we assert that this counter monotonically decreases as we
// approach the tail of the list.
- // FIXME(#3068): Make the generation counter togglable with #[cfg(debug)].
generation: uint,
- // Should really be a non-option. This way appeases borrowck.
- parent_group: Option<TaskGroupArc>,
+ // Handle to the tasks in the group of the current generation.
+ parent_group: TaskGroupArc,
// Recursive rest of the list.
ancestors: AncestorList,
}
}
}
+#[inline] #[cfg(test)]
+fn check_generation(younger: uint, older: uint) { assert!(younger > older); }
+#[inline] #[cfg(not(test))]
+fn check_generation(_younger: uint, _older: uint) { }
+
+#[inline] #[cfg(test)]
+fn incr_generation(ancestors: &AncestorList) -> uint {
+ ancestors.map_default(0, |arc| access_ancestors(arc, |a| a.generation+1))
+}
+#[inline] #[cfg(not(test))]
+fn incr_generation(_ancestors: &AncestorList) -> uint { 0 }
+
// Iterates over an ancestor list.
// (1) Runs forward_blk on each ancestral taskgroup in the list
// (2) If forward_blk "break"s, runs optional bail_blk on all ancestral
// taskgroups that forward_blk already ran on successfully (Note: bail_blk
// is NOT called on the block that forward_blk broke on!).
// (3) As a bonus, coalesces away all 'dead' taskgroup nodes in the list.
-// FIXME(#2190): Change Option<@fn(...)> to Option<&fn(...)>, to save on
-// allocations. Once that bug is fixed, changing the sigil should suffice.
fn each_ancestor(list: &mut AncestorList,
- bail_opt: Option<@fn(TaskGroupInner)>,
+ bail_blk: &fn(TaskGroupInner),
forward_blk: &fn(TaskGroupInner) -> bool)
-> bool {
// "Kickoff" call - there was no last generation.
- return !coalesce(list, bail_opt, forward_blk, uint::max_value);
+ return !coalesce(list, bail_blk, forward_blk, uint::max_value);
// Recursively iterates, and coalesces afterwards if needed. Returns
// whether or not unwinding is needed (i.e., !successful iteration).
fn coalesce(list: &mut AncestorList,
- bail_opt: Option<@fn(TaskGroupInner)>,
+ bail_blk: &fn(TaskGroupInner),
forward_blk: &fn(TaskGroupInner) -> bool,
last_generation: uint) -> bool {
- // Need to swap the list out to use it, to appease borrowck.
- let tmp_list = util::replace(&mut *list, AncestorList(None));
let (coalesce_this, early_break) =
- iterate(&tmp_list, bail_opt, forward_blk, last_generation);
+ iterate(list, bail_blk, forward_blk, last_generation);
// What should our next ancestor end up being?
if coalesce_this.is_some() {
// Needed coalesce. Our next ancestor becomes our old
// ancestor's next ancestor. ("next = old_next->next;")
*list = coalesce_this.unwrap();
- } else {
- // No coalesce; restore from tmp. ("next = old_next;")
- *list = tmp_list;
}
return early_break;
}
// bool:
// True if the supplied block did 'break', here or in any recursive
// calls. If so, must call the unwinder on all previous nodes.
- fn iterate(ancestors: &AncestorList,
- bail_opt: Option<@fn(TaskGroupInner)>,
+ fn iterate(ancestors: &mut AncestorList,
+ bail_blk: &fn(TaskGroupInner),
forward_blk: &fn(TaskGroupInner) -> bool,
last_generation: uint)
-> (Option<AncestorList>, bool) {
// The map defaults to None, because if ancestors is None, we're at
// the end of the list, which doesn't make sense to coalesce.
- return do (**ancestors).map_default((None,false)) |ancestor_arc| {
+ do ancestors.map_default((None,false)) |ancestor_arc| {
// NB: Takes a lock! (this ancestor node)
do access_ancestors(ancestor_arc) |nobe| {
// Argh, but we couldn't give it to coalesce() otherwise.
let forward_blk = forward_blk.take();
// Check monotonicity
- assert!(last_generation > nobe.generation);
+ check_generation(last_generation, nobe.generation);
/*##########################################################*
* Step 1: Look at this ancestor group (call iterator block).
*##########################################################*/
let mut nobe_is_dead = false;
let do_continue =
// NB: Takes a lock! (this ancestor node's parent group)
- do with_parent_tg(&mut nobe.parent_group) |tg_opt| {
+ do access_group(&nobe.parent_group) |tg_opt| {
// Decide whether this group is dead. Note that the
// group being *dead* is disjoint from it *failing*.
nobe_is_dead = match *tg_opt {
None => nobe_is_dead
};
// Call iterator block. (If the group is dead, it's
- // safe to skip it. This will leave our *rust_task
+ // safe to skip it. This will leave our TaskHandle
// hanging around in the group even after it's freed,
// but that's ok because, by virtue of the group being
// dead, nobody will ever kill-all (foreach) over it.)
let mut need_unwind = false;
if do_continue {
// NB: Takes many locks! (ancestor nodes & parent groups)
- need_unwind = coalesce(&mut nobe.ancestors, bail_opt,
+ need_unwind = coalesce(&mut nobe.ancestors, |tg| bail_blk(tg),
forward_blk, nobe.generation);
}
/*##########################################################*
* Step 3: Maybe unwind; compute return info for our caller.
*##########################################################*/
if need_unwind && !nobe_is_dead {
- for bail_opt.iter().advance |bail_blk| {
- do with_parent_tg(&mut nobe.parent_group) |tg_opt| {
- (*bail_blk)(tg_opt)
- }
+ do access_group(&nobe.parent_group) |tg_opt| {
+ bail_blk(tg_opt)
}
}
// Decide whether our caller should unwind.
(None, need_unwind)
}
}
- };
-
- // Wrapper around exclusive::with that appeases borrowck.
- fn with_parent_tg<U>(parent_group: &mut Option<TaskGroupArc>,
- blk: &fn(TaskGroupInner) -> U) -> U {
- // If this trips, more likely the problem is 'blk' failed inside.
- let tmp_arc = parent_group.take_unwrap();
- let result = do access_group(&tmp_arc) |tg_opt| { blk(tg_opt) };
- *parent_group = Some(tmp_arc);
- result
}
}
}
// One of these per task.
-struct TCB {
- me: *rust_task,
+pub struct Taskgroup {
// List of tasks with whose fates this one's is intertwined.
tasks: TaskGroupArc, // 'none' means the group has failed.
// Lists of tasks who will kill us if they fail, but whom we won't kill.
notifier: Option<AutoNotify>,
}
-impl Drop for TCB {
+impl Drop for Taskgroup {
// Runs on task exit.
fn drop(&self) {
unsafe {
// FIXME(#4330) Need self by value to get mutability.
- let this: &mut TCB = transmute(self);
+ let this: &mut Taskgroup = transmute(self);
// If we are failing, the whole taskgroup needs to die.
- if rt::rust_task_is_unwinding(self.me) {
- for this.notifier.mut_iter().advance |x| {
- x.failed = true;
- }
- // Take everybody down with us.
- do access_group(&self.tasks) |tg| {
- kill_taskgroup(tg, self.me, self.is_main);
- }
- } else {
- // Remove ourselves from the group(s).
- do access_group(&self.tasks) |tg| {
- leave_taskgroup(tg, self.me, true);
+ do RuntimeGlue::with_task_handle_and_failing |me, failing| {
+ if failing {
+ for this.notifier.mut_iter().advance |x| {
+ x.failed = true;
+ }
+ // Take everybody down with us.
+ do access_group(&self.tasks) |tg| {
+ kill_taskgroup(tg, &me, self.is_main);
+ }
+ } else {
+ // Remove ourselves from the group(s).
+ do access_group(&self.tasks) |tg| {
+ leave_taskgroup(tg, &me, true);
+ }
}
+ // It doesn't matter whether this happens before or after dealing
+ // with our own taskgroup, so long as both happen before we die.
+ // We remove ourself from every ancestor we can, so no cleanup; no
+ // break.
+ for each_ancestor(&mut this.ancestors, |_| {}) |ancestor_group| {
+ leave_taskgroup(ancestor_group, &me, false);
+ };
}
- // It doesn't matter whether this happens before or after dealing
- // with our own taskgroup, so long as both happen before we die.
- // We remove ourself from every ancestor we can, so no cleanup; no
- // break.
- for each_ancestor(&mut this.ancestors, None) |ancestor_group| {
- leave_taskgroup(ancestor_group, self.me, false);
- };
}
}
}
-fn TCB(me: *rust_task,
- tasks: TaskGroupArc,
+pub fn Taskgroup(tasks: TaskGroupArc,
ancestors: AncestorList,
is_main: bool,
- mut notifier: Option<AutoNotify>) -> TCB {
+ mut notifier: Option<AutoNotify>) -> Taskgroup {
for notifier.mut_iter().advance |x| {
x.failed = false;
}
- TCB {
- me: me,
+ Taskgroup {
tasks: tasks,
ancestors: ancestors,
is_main: is_main,
}
}
-fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task,
+fn enlist_in_taskgroup(state: TaskGroupInner, me: TaskHandle,
is_member: bool) -> bool {
- let newstate = util::replace(&mut *state, None);
+ let me = Cell::new(me); // :(
// If 'None', the group was failing. Can't enlist.
- if newstate.is_some() {
- let mut group = newstate.unwrap();
- taskset_insert(if is_member {
+ do state.map_mut_default(false) |group| {
+ (if is_member {
&mut group.members
} else {
&mut group.descendants
- }, me);
- *state = Some(group);
+ }).insert(me.take());
true
- } else {
- false
}
}
// NB: Runs in destructor/post-exit context. Can't 'fail'.
-fn leave_taskgroup(state: TaskGroupInner, me: *rust_task,
+fn leave_taskgroup(state: TaskGroupInner, me: &TaskHandle,
is_member: bool) {
- let newstate = util::replace(&mut *state, None);
+ let me = Cell::new(me); // :(
// If 'None', already failing and we've already gotten a kill signal.
- if newstate.is_some() {
- let mut group = newstate.unwrap();
- taskset_remove(if is_member {
+ do state.map_mut |group| {
+ (if is_member {
&mut group.members
} else {
&mut group.descendants
- }, me);
- *state = Some(group);
- }
+ }).remove(me.take());
+ };
}
// NB: Runs in destructor/post-exit context. Can't 'fail'.
-fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) {
+fn kill_taskgroup(state: TaskGroupInner, me: &TaskHandle, is_main: bool) {
unsafe {
// NB: We could do the killing iteration outside of the group arc, by
// having "let mut newstate" here, swapping inside, and iterating
// That's ok; only one task needs to do the dirty work. (Might also
// see 'None' if Somebody already failed and we got a kill signal.)
if newstate.is_some() {
- let group = newstate.unwrap();
- for taskset_each(&group.members) |sibling| {
+ let TaskGroupData { members: members, descendants: descendants } =
+ newstate.unwrap();
+ for members.consume().advance |sibling| {
// Skip self - killing ourself won't do much good.
- if sibling != me {
- rt::rust_task_kill_other(sibling);
+ if &sibling != me {
+ RuntimeGlue::kill_task(sibling);
}
}
- for taskset_each(&group.descendants) |child| {
- assert!(child != me);
- rt::rust_task_kill_other(child);
+ for descendants.consume().advance |child| {
+ assert!(&child != me);
+ RuntimeGlue::kill_task(child);
}
// Only one task should ever do this.
if is_main {
- rt::rust_task_kill_all(me);
+ RuntimeGlue::kill_all_tasks(me);
}
// Do NOT restore state to Some(..)! It stays None to indicate
// that the whole taskgroup is failing, to forbid new spawns.
// FIXME (#2912): Work around core-vs-coretest function duplication. Can't use
// a proper closure because the #[test]s won't understand. Have to fake it.
-#[cfg(not(stage0))]
-fn taskgroup_key() -> local_data::Key<@@mut TCB> {
+fn taskgroup_key() -> local_data::Key<@@mut Taskgroup> {
unsafe { cast::transmute(-2) }
}
-#[cfg(stage0)]
-fn taskgroup_key() -> local_data::Key<@@mut TCB> {
- unsafe { cast::transmute((-2, 0)) }
-}
-fn gen_child_taskgroup(linked: bool, supervised: bool)
- -> (TaskGroupArc, AncestorList, bool) {
- unsafe {
- let spawner = rt::rust_get_task();
- /*##################################################################*
- * Step 1. Get spawner's taskgroup info.
- *##################################################################*/
- let spawner_group: @@mut TCB =
- do local_get(OldHandle(spawner), taskgroup_key()) |group| {
- match group {
+// Transitionary.
+struct RuntimeGlue;
+impl RuntimeGlue {
+ unsafe fn kill_task(task: TaskHandle) {
+ match task {
+ OldTask(ptr) => rt::rust_task_kill_other(ptr),
+ NewTask(handle) => {
+ let mut handle = handle;
+ do handle.kill().map_consume |killed_task| {
+ let killed_task = Cell::new(killed_task);
+ do Local::borrow::<Scheduler, ()> |sched| {
+ sched.enqueue_task(killed_task.take());
+ }
+ };
+ }
+ }
+ }
+
+ unsafe fn kill_all_tasks(task: &TaskHandle) {
+ match *task {
+ OldTask(ptr) => rt::rust_task_kill_all(ptr),
+ NewTask(ref _handle) => rtabort!("unimplemented"), // FIXME(#7544)
+ }
+ }
+
+ fn with_task_handle_and_failing(blk: &fn(TaskHandle, bool)) {
+ match context() {
+ OldTaskContext => unsafe {
+ let me = rt::rust_get_task();
+ blk(OldTask(me), rt::rust_task_is_unwinding(me))
+ },
+ TaskContext => 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>();
+ // FIXME(#7544): Get rid of this clone by passing by-ref.
+ // Will probably have to wait until the old rt is gone.
+ blk(NewTask((*me).death.kill_handle.get_ref().clone()),
+ (*me).unwinder.unwinding)
+ },
+ SchedulerContext | GlobalContext => rtabort!("task dying in bad context"),
+ }
+ }
+
+ fn with_my_taskgroup<U>(blk: &fn(&Taskgroup) -> U) -> U {
+ match context() {
+ OldTaskContext => unsafe {
+ let me = rt::rust_get_task();
+ do local_get(OldHandle(me), taskgroup_key()) |g| {
+ match g {
+ None => {
+ // Main task, doing first spawn ever. Lazily initialise here.
+ let mut members = TaskSet::new();
+ members.insert(OldTask(me));
+ let tasks = exclusive(Some(TaskGroupData {
+ members: members,
+ descendants: TaskSet::new(),
+ }));
+ // Main task/group has no ancestors, no notifier, etc.
+ let group = @@mut Taskgroup(tasks, AncestorList(None),
+ true, None);
+ local_set(OldHandle(me), taskgroup_key(), group);
+ blk(&**group)
+ }
+ Some(&group) => blk(&**group)
+ }
+ }
+ },
+ TaskContext => 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>();
+ blk(match (*me).taskgroup {
None => {
- // Main task, doing first spawn ever. Lazily initialise
- // here.
- let mut members = new_taskset();
- taskset_insert(&mut members, spawner);
+ // Main task, doing first spawn ever. Lazily initialize.
+ let mut members = TaskSet::new();
+ let my_handle = (*me).death.kill_handle.get_ref().clone();
+ members.insert(NewTask(my_handle));
let tasks = exclusive(Some(TaskGroupData {
members: members,
- descendants: new_taskset(),
+ descendants: TaskSet::new(),
}));
- // Main task/group has no ancestors, no notifier, etc.
- let group = @@mut TCB(spawner,
- tasks,
- AncestorList(None),
- true,
- None);
- local_set(OldHandle(spawner), taskgroup_key(), group);
- group
+ let group = Taskgroup(tasks, AncestorList(None), true, None);
+ (*me).taskgroup = Some(group);
+ (*me).taskgroup.get_ref()
}
- Some(&group) => group
- }
- };
- let spawner_group: &mut TCB = *spawner_group;
+ Some(ref group) => group,
+ })
+ },
+ SchedulerContext | GlobalContext => rtabort!("spawning in bad context"),
+ }
+ }
+}
- /*##################################################################*
- * Step 2. Process spawn options for child.
- *##################################################################*/
- return if linked {
+fn gen_child_taskgroup(linked: bool, supervised: bool)
+ -> (TaskGroupArc, AncestorList, bool) {
+ do RuntimeGlue::with_my_taskgroup |spawner_group| {
+ let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone()));
+ if linked {
// Child is in the same group as spawner.
- let g = spawner_group.tasks.clone();
// Child's ancestors are spawner's ancestors.
- let a = share_ancestors(&mut spawner_group.ancestors);
// Propagate main-ness.
- (g, a, spawner_group.is_main)
+ (spawner_group.tasks.clone(), ancestors, spawner_group.is_main)
} else {
// Child is in a separate group from spawner.
let g = exclusive(Some(TaskGroupData {
- members: new_taskset(),
- descendants: new_taskset(),
+ members: TaskSet::new(),
+ descendants: TaskSet::new(),
}));
let a = if supervised {
- // Child's ancestors start with the spawner.
- let old_ancestors =
- share_ancestors(&mut spawner_group.ancestors);
- // FIXME(#3068) - The generation counter is only used for a
- // debug assertion, but initialising it requires locking a
- // mutex. Hence it should be enabled only in debug builds.
- let new_generation =
- match *old_ancestors {
- Some(ref arc) => {
- access_ancestors(arc, |a| a.generation+1)
- }
- None => 0 // the actual value doesn't really matter.
- };
+ let new_generation = incr_generation(&ancestors);
assert!(new_generation < uint::max_value);
+ // Child's ancestors start with the spawner.
// Build a new node in the ancestor list.
AncestorList(Some(exclusive(AncestorNode {
generation: new_generation,
- parent_group: Some(spawner_group.tasks.clone()),
- ancestors: old_ancestors,
+ parent_group: spawner_group.tasks.clone(),
+ ancestors: ancestors,
})))
} else {
// Child has no ancestors.
AncestorList(None)
};
(g, a, false)
- };
+ }
}
+}
- fn share_ancestors(ancestors: &mut AncestorList) -> AncestorList {
- // Appease the borrow-checker. Really this wants to be written as:
- // match ancestors
- // Some(ancestor_arc) { ancestor_list(Some(ancestor_arc.clone())) }
- // None { ancestor_list(None) }
- let tmp = util::replace(&mut **ancestors, None);
- if tmp.is_some() {
- let ancestor_arc = tmp.unwrap();
- let result = ancestor_arc.clone();
- **ancestors = Some(ancestor_arc);
- AncestorList(Some(result))
- } else {
- AncestorList(None)
+// Set up membership in taskgroup and descendantship in all ancestor
+// groups. If any enlistment fails, Some task was already failing, so
+// don't let the child task run, and undo every successful enlistment.
+fn enlist_many(child: TaskHandle, child_arc: &TaskGroupArc,
+ ancestors: &mut AncestorList) -> bool {
+ // Join this taskgroup.
+ let mut result = do access_group(child_arc) |child_tg| {
+ enlist_in_taskgroup(child_tg, child.clone(), true) // member
+ };
+ if result {
+ // Unwinding function in case any ancestral enlisting fails
+ let bail: &fn(TaskGroupInner) = |tg| { leave_taskgroup(tg, &child, false) };
+ // Attempt to join every ancestor group.
+ result = do each_ancestor(ancestors, bail) |ancestor_tg| {
+ // Enlist as a descendant, not as an actual member.
+ // Descendants don't kill ancestor groups on failure.
+ enlist_in_taskgroup(ancestor_tg, child.clone(), false)
+ };
+ // If any ancestor group fails, need to exit this group too.
+ if !result {
+ do access_group(child_arc) |child_tg| {
+ leave_taskgroup(child_tg, &child, true); // member
+ }
}
}
+ result
}
pub fn spawn_raw(opts: TaskOpts, f: ~fn()) {
- use rt::*;
-
match context() {
OldTaskContext => {
spawn_raw_oldsched(opts, f)
}
fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
- use rt::sched::*;
-
- let f = Cell::new(f);
+ let child_data = Cell::new(gen_child_taskgroup(opts.linked, opts.supervised));
+ let indestructible = opts.indestructible;
+
+ let child_wrapper: ~fn() = || {
+ // Child task runs this code.
+ let child_data = Cell::new(child_data.take()); // :(
+ let enlist_success = do Local::borrow::<Task, bool> |me| {
+ let (child_tg, ancestors, is_main) = child_data.take();
+ let mut ancestors = ancestors;
+ // FIXME(#7544): Optimize out the xadd in this clone, somehow.
+ let handle = me.death.kill_handle.get_ref().clone();
+ // Atomically try to get into all of our taskgroups.
+ if enlist_many(NewTask(handle), &child_tg, &mut ancestors) {
+ // Got in. We can run the provided child body, and can also run
+ // the taskgroup's exit-time-destructor afterward.
+ me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None));
+ true
+ } else {
+ false
+ }
+ };
+ // Should be run after the local-borrowed task is returned.
+ if enlist_success {
+ if indestructible {
+ unsafe { do unkillable { f() } }
+ } else {
+ f()
+ }
+ }
+ };
let mut task = unsafe {
let sched = Local::unsafe_borrow::<Scheduler>();
rtdebug!("unsafe borrowed sched");
- if opts.linked {
+ if opts.watched {
+ let child_wrapper = Cell::new(child_wrapper);
do Local::borrow::<Task, ~Task>() |running_task| {
- ~running_task.new_child(&mut (*sched).stack_pool, f.take())
+ ~running_task.new_child(&mut (*sched).stack_pool, child_wrapper.take())
}
} else {
- // An unlinked task is a new root in the task tree
- ~Task::new_root(&mut (*sched).stack_pool, f.take())
+ // An unwatched task is a new root in the exit-code propagation tree
+ ~Task::new_root(&mut (*sched).stack_pool, child_wrapper)
}
};
if success { Success } else { Failure }
)
};
- task.on_exit = Some(on_exit);
+ task.death.on_exit = Some(on_exit);
}
rtdebug!("spawn about to take scheduler");
let child_data = Cell::new((child_tg, ancestors, f));
// Being killed with the unsafe task/closure pointers would leak them.
do unkillable {
- // Agh. Get move-mode items into the closure. FIXME (#2829)
- let (child_tg, ancestors, f) = child_data.take();
+ let (child_tg, ancestors, f) = child_data.take(); // :(
// Create child task.
let new_task = match opts.sched.mode {
DefaultScheduler => rt::new_task(),
};
assert!(!new_task.is_null());
// Getting killed after here would leak the task.
- let notify_chan = if opts.notify_chan.is_none() {
- None
- } else {
- Some(opts.notify_chan.take_unwrap())
- };
-
let child_wrapper = make_child_wrapper(new_task, child_tg,
- ancestors, is_main, notify_chan, f);
+ ancestors, is_main, opts.notify_chan.take(), f);
let closure = cast::transmute(&child_wrapper);
-> ~fn() {
let child_data = Cell::new((notify_chan, child_arc, ancestors));
let result: ~fn() = || {
- // Agh. Get move-mode items into the closure. FIXME (#2829)
- let (notify_chan, child_arc, ancestors) = child_data.take();
+ let (notify_chan, child_arc, ancestors) = child_data.take(); // :(
let mut ancestors = ancestors;
// Child task runs this code.
let notifier = notify_chan.map_consume(|c| AutoNotify(c));
- if enlist_many(child, &child_arc, &mut ancestors) {
- let group = @@mut TCB(child,
- child_arc,
- ancestors,
- is_main,
- notifier);
+ if enlist_many(OldTask(child), &child_arc, &mut ancestors) {
+ let group = @@mut Taskgroup(child_arc, ancestors, is_main, notifier);
unsafe {
local_set(OldHandle(child), taskgroup_key(), group);
}
// unsafe { cleanup::annihilate(); }
};
return result;
-
- // Set up membership in taskgroup and descendantship in all ancestor
- // groups. If any enlistment fails, Some task was already failing, so
- // don't let the child task run, and undo every successful enlistment.
- fn enlist_many(child: *rust_task, child_arc: &TaskGroupArc,
- ancestors: &mut AncestorList) -> bool {
- // Join this taskgroup.
- let mut result =
- do access_group(child_arc) |child_tg| {
- enlist_in_taskgroup(child_tg, child, true) // member
- };
- if result {
- // Unwinding function in case any ancestral enlisting fails
- let bail: @fn(TaskGroupInner) = |tg| {
- leave_taskgroup(tg, child, false)
- };
- // Attempt to join every ancestor group.
- result =
- each_ancestor(ancestors, Some(bail), |ancestor_tg| {
- // Enlist as a descendant, not as an actual member.
- // Descendants don't kill ancestor groups on failure.
- enlist_in_taskgroup(ancestor_tg, child, false)
- });
- // If any ancestor group fails, need to exit this group too.
- if !result {
- do access_group(child_arc) |child_tg| {
- leave_taskgroup(child_tg, child, true); // member
- }
- }
- }
- result
- }
}
fn new_task_in_sched(opts: SchedOpts) -> *rust_task {
| ExistingScheduler(*)
| PlatformThread => 0u, /* Won't be used */
SingleThreaded => 1u,
- ThreadPerCore => unsafe { rt::rust_num_threads() },
ThreadPerTask => {
fail!("ThreadPerTask scheduling mode unimplemented")
}
fn test_spawn_raw_unsupervise() {
let opts = task::TaskOpts {
linked: false,
+ watched: false,
notify_chan: None,
.. default_task_opts()
};
let opts = task::TaskOpts {
linked: false,
+ watched: false,
notify_chan: Some(notify_ch),
.. default_task_opts()
};
mod tests {
use hashmap::HashMap;
use hashmap::HashSet;
- use container::{Set, Map, MutableSet, MutableMap};
+ use container::{MutableSet, MutableMap};
#[test]
fn test_simple_types() {
assert_eq!(1i.to_str(), ~"1");
#[cfg(test)]
mod test_map {
use super::*;
- use core::option::{Some, None};
+ use option::{Some, None};
use uint;
#[test]
}
#[test]
- #[allow(non_implicitly_copyable_typarams)]
fn test_tuple() {
assert_eq!((948, 4039.48).first(), 948);
assert_eq!((34.5, ~"foo").second(), ~"foo");
+++ /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 cast;
-use libc::size_t;
-use rand::RngUtil;
-use rand;
-use sys;
-use task;
-use vec;
-
-#[cfg(test)] use uint;
-
-/**
-Register a function to be run during runtime shutdown.
-
-After all non-weak tasks have exited, registered exit functions will
-execute, in random order, on the primary scheduler. Each function runs
-in its own unsupervised task.
-*/
-pub fn at_exit(f: ~fn()) {
- unsafe {
- let runner: &fn(*ExitFunctions) = exit_runner;
- let runner_pair: sys::Closure = cast::transmute(runner);
- let runner_ptr = runner_pair.code;
- let runner_ptr = cast::transmute(runner_ptr);
- rustrt::rust_register_exit_function(runner_ptr, ~f);
- }
-}
-
-// NB: The double pointer indirection here is because ~fn() is a fat
-// pointer and due to FFI problems I am more comfortable making the
-// interface use a normal pointer
-mod rustrt {
- use libc::c_void;
-
- pub extern {
- fn rust_register_exit_function(runner: *c_void, f: ~~fn());
- }
-}
-
-struct ExitFunctions {
- // The number of exit functions
- count: size_t,
- // The buffer of exit functions
- start: *~~fn()
-}
-
-fn exit_runner(exit_fns: *ExitFunctions) {
- let exit_fns = unsafe { &*exit_fns };
- let count = (*exit_fns).count;
- let start = (*exit_fns).start;
-
- // NB: from_buf memcpys from the source, which will
- // give us ownership of the array of functions
- let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) };
- // Let's not make any promises about execution order
- let mut rng = rand::rng();
- rng.shuffle_mut(exit_fns_vec);
-
- debug!("running %u exit functions", exit_fns_vec.len());
-
- while !exit_fns_vec.is_empty() {
- match exit_fns_vec.pop() {
- ~f => {
- let mut task = task::task();
- task.supervised();
- task.spawn(f);
- }
- }
- }
-}
-
-#[test]
-fn test_at_exit() {
- let i = 10;
- do at_exit {
- debug!("at_exit1");
- assert_eq!(i, 10);
- }
-}
-
-#[test]
-fn test_at_exit_many() {
- let i = 10;
- for uint::range(20, 100) |j| {
- do at_exit {
- debug!("at_exit2");
- assert_eq!(i, 10);
- assert!(j > i);
- }
- }
-}
self.swap(cast::transmute(0), order)
}
}
+
+ /// A compare-and-swap. Succeeds if the option is 'None' and returns 'None'
+ /// if so. If the option was already 'Some', returns 'Some' of the rejected
+ /// value.
+ #[inline]
+ pub fn fill(&mut self, val: ~T, order: Ordering) -> Option<~T> {
+ unsafe {
+ let val = cast::transmute(val);
+ let expected = cast::transmute(0);
+ let oldval = atomic_compare_and_swap(&mut self.p, expected, val, order);
+ if oldval == expected {
+ None
+ } else {
+ Some(cast::transmute(val))
+ }
+ }
+ }
+
+ /// Be careful: The caller must have some external method of ensuring the
+ /// result does not get invalidated by another task after this returns.
+ #[inline]
+ pub fn is_empty(&mut self, order: Ordering) -> bool {
+ unsafe { atomic_load(&self.p, order) == cast::transmute(0) }
+ }
}
#[unsafe_destructor]
assert!(!flg.test_and_set(SeqCst));
}
+ #[test]
+ fn option_empty() {
+ assert!(AtomicOption::empty::<()>().is_empty(SeqCst));
+ }
+
#[test]
fn option_swap() {
let mut p = AtomicOption::new(~1);
assert_eq!(p.take(SeqCst), Some(~2));
}
+ #[test]
+ fn option_fill() {
+ let mut p = AtomicOption::new(~1);
+ assert!(p.fill(~2, SeqCst).is_some()); // should fail; shouldn't leak!
+ assert_eq!(p.take(SeqCst), Some(~1));
+
+ assert!(p.fill(~2, SeqCst).is_none()); // shouldn't fail
+ assert_eq!(p.take(SeqCst), Some(~2));
+ }
}
+++ /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.
-
-/*!
-Global data
-
-An interface for creating and retrieving values with global
-(per-runtime) scope.
-
-Global values are stored in a map and protected by a single global
-mutex. Operations are provided for accessing and cloning the value
-under the mutex.
-
-Because all globals go through a single mutex, they should be used
-sparingly. The interface is intended to be used with clonable,
-atomically reference counted synchronization types, like ARCs, in
-which case the value should be cached locally whenever possible to
-avoid hitting the mutex.
-*/
-
-use cast::{transmute};
-use clone::Clone;
-use kinds::Send;
-use libc::{c_void, intptr_t};
-use option::{Option, Some, None};
-use ops::Drop;
-use unstable::sync::{Exclusive, exclusive};
-use unstable::at_exit::at_exit;
-use unstable::intrinsics::atomic_cxchg;
-use hashmap::HashMap;
-use sys::Closure;
-
-#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox};
-#[cfg(test)] use task::spawn;
-#[cfg(test)] use uint;
-
-pub type GlobalDataKey<'self,T> = &'self fn(v: T);
-
-pub unsafe fn global_data_clone_create<T:Send + Clone>(
- key: GlobalDataKey<T>, create: &fn() -> ~T) -> T {
- /*!
- * Clone a global value or, if it has not been created,
- * first construct the value then return a clone.
- *
- * # Safety note
- *
- * Both the clone operation and the constructor are
- * called while the global lock is held. Recursive
- * use of the global interface in either of these
- * operations will result in deadlock.
- */
- global_data_clone_create_(key_ptr(key), create)
-}
-
-unsafe fn global_data_clone_create_<T:Send + Clone>(
- key: uint, create: &fn() -> ~T) -> T {
-
- let mut clone_value: Option<T> = None;
- do global_data_modify_(key) |value: Option<~T>| {
- match value {
- None => {
- let value = create();
- clone_value = Some((*value).clone());
- Some(value)
- }
- Some(value) => {
- clone_value = Some((*value).clone());
- Some(value)
- }
- }
- }
- return clone_value.unwrap();
-}
-
-unsafe fn global_data_modify<T:Send>(
- key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) {
-
- global_data_modify_(key_ptr(key), op)
-}
-
-unsafe fn global_data_modify_<T:Send>(
- key: uint, op: &fn(Option<~T>) -> Option<~T>) {
-
- let mut old_dtor = None;
- do get_global_state().with |gs| {
- let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) {
- Some((ptr, dtor)) => {
- let value: ~T = transmute(ptr);
- (op(Some(value)), Some(dtor))
- }
- None => {
- (op(None), None)
- }
- };
- match maybe_new_value {
- Some(value) => {
- let data: *c_void = transmute(value);
- let dtor: ~fn() = match maybe_dtor {
- Some(dtor) => dtor,
- None => {
- let dtor: ~fn() = || {
- let _destroy_value: ~T = transmute(data);
- };
- dtor
- }
- };
- let value = (data, dtor);
- gs.map.insert(key, value);
- }
- None => {
- match maybe_dtor {
- Some(dtor) => old_dtor = Some(dtor),
- None => ()
- }
- }
- }
- }
-}
-
-pub unsafe fn global_data_clone<T:Send + Clone>(
- key: GlobalDataKey<T>) -> Option<T> {
- let mut maybe_clone: Option<T> = None;
- do global_data_modify(key) |current| {
- match ¤t {
- &Some(~ref value) => {
- maybe_clone = Some(value.clone());
- }
- &None => ()
- }
- current
- }
- return maybe_clone;
-}
-
-// GlobalState is a map from keys to unique pointers and a
-// destructor. Keys are pointers derived from the type of the
-// global value. There is a single GlobalState instance per runtime.
-struct GlobalState {
- map: HashMap<uint, (*c_void, ~fn())>
-}
-
-impl Drop for GlobalState {
- fn drop(&self) {
- for self.map.each_value |v| {
- match v {
- &(_, ref dtor) => (*dtor)()
- }
- }
- }
-}
-
-fn get_global_state() -> Exclusive<GlobalState> {
-
- static POISON: int = -1;
-
- // FIXME #4728: Doing atomic_cxchg to initialize the global state
- // lazily, which wouldn't be necessary with a runtime written
- // in Rust
- let global_ptr = unsafe { rust_get_global_data_ptr() };
-
- if unsafe { *global_ptr } == 0 {
- // Global state doesn't exist yet, probably
-
- // The global state object
- let state = GlobalState {
- map: HashMap::new()
- };
-
- // It's under a reference-counted mutex
- let state = ~exclusive(state);
-
- // Convert it to an integer
- let state_i: int = unsafe {
- let state_ptr: &Exclusive<GlobalState> = state;
- transmute(state_ptr)
- };
-
- // Swap our structure into the global pointer
- let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) };
-
- // Sanity check that we're not trying to reinitialize after shutdown
- assert!(prev_i != POISON);
-
- if prev_i == 0 {
- // Successfully installed the global pointer
-
- // Take a handle to return
- let clone = (*state).clone();
-
- // Install a runtime exit function to destroy the global object
- do at_exit {
- // Poison the global pointer
- let prev_i = unsafe {
- atomic_cxchg(&mut *global_ptr, state_i, POISON)
- };
- assert_eq!(prev_i, state_i);
-
- // Capture the global state object in the at_exit closure
- // so that it is destroyed at the right time
- let _capture_global_state = &state;
- };
- return clone;
- } else {
- // Somebody else initialized the globals first
- let state: &Exclusive<GlobalState> = unsafe { transmute(prev_i) };
- return state.clone();
- }
- } else {
- let state: &Exclusive<GlobalState> = unsafe {
- transmute(*global_ptr)
- };
- return state.clone();
- }
-}
-
-fn key_ptr<T:Send>(key: GlobalDataKey<T>) -> uint {
- unsafe {
- let closure: Closure = transmute(key);
- return transmute(closure.code);
- }
-}
-
-extern {
- fn rust_get_global_data_ptr() -> *mut intptr_t;
-}
-
-#[test]
-fn test_clone_rc() {
- fn key(_v: UnsafeAtomicRcBox<int>) { }
-
- for uint::range(0, 100) |_| {
- do spawn {
- unsafe {
- let val = do global_data_clone_create(key) {
- ~UnsafeAtomicRcBox::new(10)
- };
-
- assert!(val.get() == &10);
- }
- }
- }
-}
-
-#[test]
-fn test_modify() {
- fn key(_v: UnsafeAtomicRcBox<int>) { }
-
- unsafe {
- do global_data_modify(key) |v| {
- match v {
- None => { Some(~UnsafeAtomicRcBox::new(10)) }
- _ => fail!()
- }
- }
-
- do global_data_modify(key) |v| {
- match v {
- Some(sms) => {
- let v = sms.get();
- assert!(*v == 10);
- None
- },
- _ => fail!()
- }
- }
-
- do global_data_modify(key) |v| {
- match v {
- None => { Some(~UnsafeAtomicRcBox::new(10)) }
- _ => fail!()
- }
- }
- }
-}
#[cfg(test)]
pub use realstd::unstable::intrinsics::{TyDesc, Opaque, TyVisitor};
-#[cfg(not(stage0))]
pub type GlueFn = extern "Rust" fn(*i8);
-#[cfg(stage0)]
-pub type GlueFn = extern "Rust" fn(**TyDesc, *i8);
-
// NB: this has to be kept in sync with the Rust ABI.
#[lang="ty_desc"]
#[cfg(not(test))]
fn visit_f64(&self) -> bool;
fn visit_char(&self) -> bool;
- fn visit_str(&self) -> bool;
fn visit_estr_box(&self) -> bool;
fn visit_estr_uniq(&self) -> bool;
}
#[abi = "rust-intrinsic"]
-pub extern "rust-intrinsic" {
+extern "rust-intrinsic" {
/// Atomic compare and exchange, sequentially consistent.
pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
pub fn pref_align_of<T>() -> uint;
/// Get a static pointer to a type descriptor.
- #[cfg(not(stage0))]
pub fn get_tydesc<T>() -> *TyDesc;
- #[cfg(stage0)]
- pub fn get_tydesc<T>() -> *();
/// Create a value initialized to zero.
///
pub fn needs_drop<T>() -> bool;
/// Returns `true` if a type is managed (will be allocated on the local heap)
- #[cfg(not(stage0))]
pub fn contains_managed<T>() -> bool;
- #[cfg(not(stage0))]
pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor);
pub fn frame_address(f: &once fn(*u8));
use unstable::lang::rust_task;
use libc::{c_char, uintptr_t};
- pub extern {
+ extern {
#[rust_stack]
- unsafe fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char;
+ pub unsafe fn rust_upcall_malloc(td: *c_char, size: uintptr_t)
+ -> *c_char;
#[rust_stack]
- unsafe fn rust_upcall_free(ptr: *c_char);
+ pub unsafe fn rust_upcall_free(ptr: *c_char);
#[fast_ffi]
- unsafe fn rust_upcall_malloc_noswitch(td: *c_char,
- size: uintptr_t)
- -> *c_char;
+ pub unsafe fn rust_upcall_malloc_noswitch(td: *c_char,
+ size: uintptr_t)
+ -> *c_char;
#[rust_stack]
- fn rust_try_get_task() -> *rust_task;
+ pub fn rust_try_get_task() -> *rust_task;
- fn rust_dbg_breakpoint();
+ pub fn rust_dbg_breakpoint();
}
}
use prelude::*;
use task;
-pub mod at_exit;
-
pub mod dynamic_lib;
-pub mod global;
pub mod finally;
-pub mod weak_task;
pub mod intrinsics;
pub mod simd;
pub mod extfmt;
fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
fn rust_raw_thread_join_delete(thread: *raw_thread);
}
+
+
+/// Changes the current working directory to the specified
+/// path while acquiring a global lock, then calls `action`.
+/// If the change is successful, releases the lock and restores the
+/// CWD to what it was before, returning true.
+/// Returns false if the directory doesn't exist or if the directory change
+/// is otherwise unsuccessful.
+///
+/// This is used by test cases to avoid cwd races.
+///
+/// # Safety Note
+///
+/// This uses a pthread mutex so descheduling in the action callback
+/// can lead to deadlock. Calling change_dir_locked recursively will
+/// also deadlock.
+pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+ use os;
+ use os::change_dir;
+ use task;
+ use unstable::finally::Finally;
+
+ unsafe {
+ // This is really sketchy. Using a pthread mutex so descheduling
+ // in the `action` callback can cause deadlock. Doing it in
+ // `task::atomically` to try to avoid that, but ... I don't know
+ // this is all bogus.
+ return do task::atomically {
+ rust_take_change_dir_lock();
+
+ do (||{
+ let old_dir = os::getcwd();
+ if change_dir(p) {
+ action();
+ change_dir(&old_dir)
+ }
+ else {
+ false
+ }
+ }).finally {
+ rust_drop_change_dir_lock();
+ }
+ }
+ }
+
+ extern {
+ fn rust_take_change_dir_lock();
+ fn rust_drop_change_dir_lock();
+ }
+}
// except according to those terms.
use cast;
+use cell::Cell;
+use comm;
use libc;
+use ptr;
use option::*;
+use either::{Either, Left, Right};
use task;
use task::atomically;
+use unstable::atomics::{AtomicOption,AtomicUint,Acquire,Release,SeqCst};
use unstable::finally::Finally;
-use unstable::intrinsics;
use ops::Drop;
use clone::Clone;
use kinds::Send;
}
struct AtomicRcBoxData<T> {
- count: int,
+ 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
+ // pipe protocol because the unwrapper has to access both stages at once.
+ // FIXME(#7544): Maybe use AtomicPtr instead (to avoid xchg in take() later)?
+ unwrapper: AtomicOption<(comm::ChanOne<()>, comm::PortOne<bool>)>,
+ // FIXME(#3224) should be able to make this non-option to save memory
data: Option<T>,
}
impl<T: Send> UnsafeAtomicRcBox<T> {
pub fn new(data: T) -> UnsafeAtomicRcBox<T> {
unsafe {
- let data = ~AtomicRcBoxData { count: 1, data: Some(data) };
+ let data = ~AtomicRcBoxData { count: AtomicUint::new(1),
+ unwrapper: AtomicOption::empty(),
+ data: Some(data) };
let ptr = cast::transmute(data);
return UnsafeAtomicRcBox { data: ptr };
}
}
+ /// As new(), but returns an extra pre-cloned handle.
+ pub fn new2(data: T) -> (UnsafeAtomicRcBox<T>, UnsafeAtomicRcBox<T>) {
+ unsafe {
+ let data = ~AtomicRcBoxData { count: AtomicUint::new(2),
+ unwrapper: AtomicOption::empty(),
+ data: Some(data) };
+ let ptr = cast::transmute(data);
+ return (UnsafeAtomicRcBox { data: ptr },
+ UnsafeAtomicRcBox { data: ptr });
+ }
+ }
+
#[inline]
pub unsafe fn get(&self) -> *mut T
{
let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- assert!(data.count > 0);
+ assert!(data.count.load(Acquire) > 0); // no barrier is really needed
let r: *mut T = data.data.get_mut_ref();
cast::forget(data);
return r;
#[inline]
pub unsafe fn get_immut(&self) -> *T
{
- let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- assert!(data.count > 0);
- let r: *T = cast::transmute_immut(data.data.get_mut_ref());
+ let data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
+ assert!(data.count.load(Acquire) > 0); // no barrier is really needed
+ let r: *T = data.data.get_ref();
cast::forget(data);
return r;
}
+
+ /// Wait until all other handles are dropped, then retrieve the enclosed
+ /// data. See extra::arc::ARC for specific semantics documentation.
+ /// If called when the task is already unkillable, unwrap will unkillably
+ /// block; otherwise, an unwrapping task can be killed by linked failure.
+ pub unsafe fn unwrap(self) -> T {
+ let this = Cell::new(self); // argh
+ do task::unkillable {
+ let mut this = this.take();
+ let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
+ // Set up the unwrap protocol.
+ let (p1,c1) = comm::oneshot(); // ()
+ let (p2,c2) = comm::oneshot(); // bool
+ // Try to put our server end in the unwrapper slot.
+ // This needs no barrier -- it's protected by the release barrier on
+ // the xadd, and the acquire+release barrier in the destructor's xadd.
+ // FIXME(#6598) Change Acquire to Relaxed.
+ if data.unwrapper.fill(~(c1,p2), Acquire).is_none() {
+ // Got in. Tell this handle's destructor not to run (we are now it).
+ this.data = ptr::mut_null();
+ // Drop our own reference.
+ let old_count = data.count.fetch_sub(1, Release);
+ assert!(old_count >= 1);
+ if old_count == 1 {
+ // 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;
+ // user_data
+ data.data.take_unwrap()
+ } else {
+ // The *next* person who sees the refcount hit 0 will wake us.
+ let p1 = Cell::new(p1); // argh
+ // Unlike the above one, this cell is necessary. It will get
+ // taken either in the do block or in the finally block.
+ let c2_and_data = Cell::new((c2,data));
+ do (|| {
+ do task::rekillable { p1.take().recv(); }
+ // Got here. Back in the 'unkillable' without getting killed.
+ let (c2, data) = c2_and_data.take();
+ c2.send(true);
+ // FIXME(#3224): it should be like this
+ // let ~AtomicRcBoxData { data: user_data, _ } = data;
+ // user_data
+ let mut data = data;
+ data.data.take_unwrap()
+ }).finally {
+ if task::failing() {
+ // Killed during wait. Because this might happen while
+ // someone else still holds a reference, we can't free
+ // the data now; the "other" last refcount will free it.
+ let (c2, data) = c2_and_data.take();
+ c2.send(false);
+ cast::forget(data);
+ } else {
+ assert!(c2_and_data.is_empty());
+ }
+ }
+ }
+ } else {
+ // If 'put' returns the server end back to us, we were rejected;
+ // someone else was trying to unwrap. Avoid guaranteed deadlock.
+ cast::forget(data);
+ fail!("Another task is already unwrapping this ARC!");
+ }
+ }
+ }
+
+ /// As unwrap above, but without blocking. Returns 'Left(self)' if this is
+ /// not the last reference; 'Right(unwrapped_data)' if so.
+ pub unsafe fn try_unwrap(self) -> Either<UnsafeAtomicRcBox<T>, T> {
+ let mut this = self; // FIXME(#4330) mutable self
+ let mut data: ~AtomicRcBoxData<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.
+ let count = data.count.load(Acquire);
+ assert!(count >= 1);
+ // The more interesting race is one with an unwrapper. They may have
+ // already dropped their count -- but if so, the unwrapper pointer
+ // will have been set first, which the barriers ensure we will see.
+ // (Note: using is_empty(), not take(), to not free the unwrapper.)
+ if count == 1 && data.unwrapper.is_empty(Acquire) {
+ // Tell this handle's destructor not to run (we are now it).
+ this.data = ptr::mut_null();
+ // FIXME(#3224) as above
+ Right(data.data.take_unwrap())
+ } else {
+ cast::forget(data);
+ Left(this)
+ }
+ }
}
impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
fn clone(&self) -> UnsafeAtomicRcBox<T> {
unsafe {
let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1;
- assert!(new_count >= 2);
+ // This barrier might be unnecessary, but I'm not sure...
+ let old_count = data.count.fetch_add(1, Acquire);
+ assert!(old_count >= 1);
cast::forget(data);
return UnsafeAtomicRcBox { data: self.data };
}
impl<T> Drop for UnsafeAtomicRcBox<T>{
fn drop(&self) {
unsafe {
+ if self.data.is_null() {
+ return; // Happens when destructing an unwrapper's handle.
+ }
do task::unkillable {
let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data);
- let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1;
- assert!(new_count >= 0);
- if new_count == 0 {
- // drop glue takes over.
+ // 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);
+ assert!(old_count >= 1);
+ if old_count == 1 {
+ // Were we really last, or should we hand off to an
+ // unwrapper? It's safe to not xchg because the unwrapper
+ // will set the unwrap lock *before* dropping his/her
+ // reference. In effect, being here means we're the only
+ // *awake* task with the data.
+ match data.unwrapper.take(Acquire) {
+ Some(~(message,response)) => {
+ // Send 'ready' and wait for a response.
+ message.send(());
+ // Unkillable wait. Message guaranteed to come.
+ if response.recv() {
+ // Other task got the data.
+ cast::forget(data);
+ } else {
+ // Other task was killed. drop glue takes over.
+ }
+ }
+ None => {
+ // drop glue takes over.
+ }
+ }
} else {
cast::forget(data);
}
/****************************************************************************/
#[allow(non_camel_case_types)] // runtime type
-pub type rust_little_lock = *libc::c_void;
+type rust_little_lock = *libc::c_void;
-struct LittleLock {
+pub struct LittleLock {
l: rust_little_lock,
}
}
}
-fn LittleLock() -> LittleLock {
+pub fn LittleLock() -> LittleLock {
unsafe {
LittleLock {
l: rust_create_little_lock()
/**
* An arc over mutable data that is protected by a lock. For library use only.
+ *
+ * # Safety note
+ *
+ * This uses a pthread mutex, not one that's aware of the userspace scheduler.
+ * The user of an exclusive must be careful not to invoke any functions that may
+ * reschedule the task while holding the lock, or deadlock may result. If you
+ * need to block or yield while accessing shared state, use extra::sync::RWARC.
*/
pub struct Exclusive<T> {
x: UnsafeAtomicRcBox<ExData<T>>
f(cast::transmute_immut(x))
}
}
-}
-fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
- unsafe {
- let old = intrinsics::atomic_cxchg(address, oldval, newval);
- old == oldval
+ pub fn unwrap(self) -> T {
+ let Exclusive { x: x } = self;
+ // Someday we might need to unkillably unwrap an exclusive, but not today.
+ let inner = unsafe { x.unwrap() };
+ let ExData { data: user_data, _ } = inner; // will destroy the LittleLock
+ user_data
}
}
fn rust_unlock_little_lock(lock: rust_little_lock);
}
-/* *********************************************************************/
-
-//FIXME: #5042 This should be replaced by proper atomic type
-pub struct AtomicUint {
- priv inner: uint
-}
-
-impl AtomicUint {
- pub fn new(val: uint) -> AtomicUint { AtomicUint { inner: val } }
- pub fn load(&self) -> uint {
- unsafe { intrinsics::atomic_load(cast::transmute(self)) as uint }
- }
- pub fn store(&mut self, val: uint) {
- unsafe { intrinsics::atomic_store(cast::transmute(self), val as int); }
- }
- pub fn add(&mut self, val: int) -> uint {
- unsafe { intrinsics::atomic_xadd(cast::transmute(self), val as int) as uint }
- }
- pub fn cas(&mut self, old:uint, new: uint) -> uint {
- unsafe { intrinsics::atomic_cxchg(cast::transmute(self), old as int, new as int) as uint }
- }
-}
-
-pub struct AtomicInt {
- priv inner: int
-}
-
-impl AtomicInt {
- pub fn new(val: int) -> AtomicInt { AtomicInt { inner: val } }
- pub fn load(&self) -> int {
- unsafe { intrinsics::atomic_load(&self.inner) }
- }
- pub fn store(&mut self, val: int) {
- unsafe { intrinsics::atomic_store(&mut self.inner, val); }
- }
- pub fn add(&mut self, val: int) -> int {
- unsafe { intrinsics::atomic_xadd(&mut self.inner, val) }
- }
- pub fn cas(&mut self, old: int, new: int) -> int {
- unsafe { intrinsics::atomic_cxchg(&mut self.inner, old, new) }
- }
-}
-
-
#[cfg(test)]
mod tests {
- use super::*;
+ use cell::Cell;
use comm;
- use super::exclusive;
+ use option::*;
+ use super::{exclusive, UnsafeAtomicRcBox};
use task;
use uint;
+ use util;
#[test]
fn exclusive_arc() {
}
#[test]
- fn atomic_int_smoke_test() {
- let mut i = AtomicInt::new(0);
- i.store(10);
- assert!(i.load() == 10);
- assert!(i.add(1) == 10);
- assert!(i.load() == 11);
- assert!(i.cas(11, 12) == 11);
- assert!(i.cas(11, 13) == 12);
- assert!(i.load() == 12);
+ fn arclike_unwrap_basic() {
+ unsafe {
+ let x = UnsafeAtomicRcBox::new(~~"hello");
+ assert!(x.unwrap() == ~~"hello");
+ }
}
#[test]
- fn atomic_uint_smoke_test() {
- let mut i = AtomicUint::new(0);
- i.store(10);
- assert!(i.load() == 10);
- assert!(i.add(1) == 10);
- assert!(i.load() == 11);
- assert!(i.cas(11, 12) == 11);
- assert!(i.cas(11, 13) == 12);
- assert!(i.load() == 12);
+ fn arclike_try_unwrap() {
+ unsafe {
+ let x = UnsafeAtomicRcBox::new(~~"hello");
+ assert!(x.try_unwrap().expect_right("try_unwrap failed") == ~~"hello");
+ }
+ }
+
+ #[test]
+ fn arclike_try_unwrap_fail() {
+ unsafe {
+ let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x2 = x.clone();
+ let left_x = x.try_unwrap();
+ assert!(left_x.is_left());
+ util::ignore(left_x);
+ assert!(x2.try_unwrap().expect_right("try_unwrap none") == ~~"hello");
+ }
+ }
+
+ #[test]
+ fn arclike_try_unwrap_unwrap_race() {
+ // When an unwrap and a try_unwrap race, the unwrapper should always win.
+ unsafe {
+ let x = UnsafeAtomicRcBox::new(~~"hello");
+ let x2 = Cell::new(x.clone());
+ let (p,c) = comm::stream();
+ do task::spawn {
+ c.send(());
+ assert!(x2.take().unwrap() == ~~"hello");
+ c.send(());
+ }
+ p.recv();
+ task::yield(); // Try to make the unwrapper get blocked first.
+ let left_x = x.try_unwrap();
+ assert!(left_x.is_left());
+ util::ignore(left_x);
+ p.recv();
+ }
+ }
+
+ #[test]
+ fn exclusive_unwrap_basic() {
+ // Unlike the above, also tests no double-freeing of the LittleLock.
+ let x = exclusive(~~"hello");
+ assert!(x.unwrap() == ~~"hello");
+ }
+
+ #[test]
+ fn exclusive_unwrap_contended() {
+ let x = exclusive(~~"hello");
+ let x2 = Cell::new(x.clone());
+ do task::spawn {
+ let x2 = x2.take();
+ unsafe { do x2.with |_hello| { } }
+ task::yield();
+ }
+ assert!(x.unwrap() == ~~"hello");
+
+ // Now try the same thing, but with the child task blocking.
+ let x = exclusive(~~"hello");
+ let x2 = Cell::new(x.clone());
+ let mut res = None;
+ let mut builder = task::task();
+ builder.future_result(|r| res = Some(r));
+ do builder.spawn {
+ let x2 = x2.take();
+ assert!(x2.unwrap() == ~~"hello");
+ }
+ // Have to get rid of our reference before blocking.
+ util::ignore(x);
+ res.unwrap().recv();
+ }
+
+ #[test] #[should_fail] #[ignore(cfg(windows))]
+ fn exclusive_unwrap_conflict() {
+ let x = exclusive(~~"hello");
+ let x2 = Cell::new(x.clone());
+ let mut res = None;
+ let mut builder = task::task();
+ builder.future_result(|r| res = Some(r));
+ do builder.spawn {
+ let x2 = x2.take();
+ assert!(x2.unwrap() == ~~"hello");
+ }
+ assert!(x.unwrap() == ~~"hello");
+ // See #4689 for why this can't be just "res.recv()".
+ assert!(res.unwrap().recv() == task::Success);
+ }
+
+ #[test] #[ignore(cfg(windows))]
+ fn exclusive_unwrap_deadlock() {
+ // This is not guaranteed to get to the deadlock before being killed,
+ // but it will show up sometimes, and if the deadlock were not there,
+ // the test would nondeterministically fail.
+ let result = do task::try {
+ // a task that has two references to the same exclusive will
+ // deadlock when it unwraps. nothing to be done about that.
+ let x = exclusive(~~"hello");
+ let x2 = x.clone();
+ do task::spawn {
+ for 10.times { task::yield(); } // try to let the unwrapper go
+ fail!(); // punt it awake from its deadlock
+ }
+ let _z = x.unwrap();
+ unsafe { do x2.with |_hello| { } }
+ };
+ assert!(result.is_err());
}
}
+++ /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.
-
-/*!
-Weak tasks
-
-Weak tasks are a runtime feature for building global services that
-do not keep the runtime alive. Normally the runtime exits when all
-tasks exits, but if a task is weak then the runtime may exit while
-it is running, sending a notification to the task that the runtime
-is trying to shut down.
-*/
-
-use cell::Cell;
-use comm::{GenericSmartChan, stream};
-use comm::{Port, Chan, SharedChan, GenericChan, GenericPort};
-use hashmap::HashMap;
-use option::{Some, None};
-use unstable::at_exit::at_exit;
-use unstable::finally::Finally;
-use unstable::global::global_data_clone_create;
-use task::rt::{task_id, get_task_id};
-use task::task;
-
-#[cfg(test)] use task::spawn;
-
-type ShutdownMsg = ();
-
-// FIXME #4729: This could be a PortOne but I've experienced bugginess
-// with oneshot pipes and try_send
-pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
- let service = global_data_clone_create(global_data_key,
- create_global_service);
- let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
- let shutdown_port = Cell::new(shutdown_port);
- let task = get_task_id();
- // Expect the weak task service to be alive
- assert!(service.try_send(RegisterWeakTask(task, shutdown_chan)));
- rust_dec_kernel_live_count();
- do (|| {
- f(shutdown_port.take())
- }).finally || {
- rust_inc_kernel_live_count();
- // Service my have already exited
- service.send(UnregisterWeakTask(task));
- }
-}
-
-type WeakTaskService = SharedChan<ServiceMsg>;
-type TaskHandle = task_id;
-
-fn global_data_key(_v: WeakTaskService) { }
-
-enum ServiceMsg {
- RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>),
- UnregisterWeakTask(TaskHandle),
- Shutdown
-}
-
-fn create_global_service() -> ~WeakTaskService {
-
- debug!("creating global weak task service");
- let (port, chan) = stream::<ServiceMsg>();
- let port = Cell::new(port);
- let chan = SharedChan::new(chan);
- let chan_clone = chan.clone();
-
- let mut task = task();
- task.unlinked();
- do task.spawn {
- debug!("running global weak task service");
- let port = Cell::new(port.take());
- do (|| {
- let port = port.take();
- // The weak task service is itself a weak task
- debug!("weakening the weak service task");
- unsafe { rust_dec_kernel_live_count(); }
- run_weak_task_service(port);
- }).finally {
- debug!("unweakening the weak service task");
- unsafe { rust_inc_kernel_live_count(); }
- }
- }
-
- do at_exit {
- debug!("shutting down weak task service");
- chan.send(Shutdown);
- }
-
- return ~chan_clone;
-}
-
-fn run_weak_task_service(port: Port<ServiceMsg>) {
-
- let mut shutdown_map = HashMap::new();
-
- loop {
- match port.recv() {
- RegisterWeakTask(task, shutdown_chan) => {
- let previously_unregistered =
- shutdown_map.insert(task, shutdown_chan);
- assert!(previously_unregistered);
- }
- UnregisterWeakTask(task) => {
- match shutdown_map.pop(&task) {
- Some(shutdown_chan) => {
- // Oneshot pipes must send, even though
- // nobody will receive this
- shutdown_chan.send(());
- }
- None => fail!()
- }
- }
- Shutdown => break
- }
- }
-
- do shutdown_map.consume |_, shutdown_chan| {
- // Weak task may have already exited
- shutdown_chan.send(());
- }
-}
-
-extern {
- unsafe fn rust_inc_kernel_live_count();
- unsafe fn rust_dec_kernel_live_count();
-}
-
-#[test]
-fn test_simple() {
- let (port, chan) = stream();
- do spawn {
- unsafe {
- do weaken_task |_signal| {
- }
- }
- chan.send(());
- }
- port.recv();
-}
-
-#[test]
-fn test_weak_weak() {
- let (port, chan) = stream();
- do spawn {
- unsafe {
- do weaken_task |_signal| {
- }
- do weaken_task |_signal| {
- }
- }
- chan.send(());
- }
- port.recv();
-}
-
-#[test]
-fn test_wait_for_signal() {
- do spawn {
- unsafe {
- do weaken_task |signal| {
- signal.recv();
- }
- }
- }
-}
-
-#[test]
-fn test_wait_for_signal_many() {
- use uint;
- for uint::range(0, 100) |_| {
- do spawn {
- unsafe {
- do weaken_task |signal| {
- signal.recv();
- }
- }
- }
- }
-}
-
-#[test]
-fn test_select_stream_and_oneshot() {
- use comm::select2i;
- use either::{Left, Right};
-
- let (port, chan) = stream();
- let port = Cell::new(port);
- let (waitport, waitchan) = stream();
- do spawn {
- unsafe {
- do weaken_task |mut signal| {
- let mut port = port.take();
- match select2i(&mut port, &mut signal) {
- Left(*) => (),
- Right(*) => fail!()
- }
- }
- }
- waitchan.send(());
- }
- chan.send(());
- waitport.recv();
-}
// verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct
- // NOTE: uncomment after snapshot, will not parse yet
- //static mut did_run: bool = false;
+ static mut did_run: bool = false;
struct Foo { five: int }
impl Drop for Foo {
fn drop(&self) {
assert_eq!(self.five, 5);
- // NOTE: uncomment after snapshot, will not parse yet
- //unsafe {
- //did_run = true;
- //}
+ unsafe {
+ did_run = true;
+ }
}
}
let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
}
- // NOTE: uncomment after snapshot, will not parse yet
- //unsafe { assert_eq!(did_run, true); }
+ unsafe { assert_eq!(did_run, true); }
}
}
use cast;
use clone::Clone;
use container::{Container, Mutable};
-use cmp::{Eq, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
+use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
use cmp;
use iterator::*;
use libc::c_void;
use ptr::to_unsafe_ptr;
use ptr;
use ptr::RawPtr;
-#[cfg(not(stage0))]
use rt::global_heap::malloc_raw;
use rt::global_heap::realloc_raw;
use sys;
use sys::size_of;
use uint;
use unstable::intrinsics;
-#[cfg(stage0)]
-use intrinsic::{get_tydesc};
-#[cfg(not(stage0))]
use unstable::intrinsics::{get_tydesc, contains_managed};
use vec;
use util;
}
/// Creates a new vector with a capacity of `capacity`
-#[cfg(stage0)]
-pub fn with_capacity<T>(capacity: uint) -> ~[T] {
- let mut vec = ~[];
- vec.reserve(capacity);
- vec
-}
-
-/// Creates a new vector with a capacity of `capacity`
-#[cfg(not(stage0))]
pub fn with_capacity<T>(capacity: uint) -> ~[T] {
unsafe {
if contains_managed::<T>() {
#[allow(missing_doc)]
pub trait ImmutableVector<'self, T> {
fn slice(&self, start: uint, end: uint) -> &'self [T];
+ fn slice_from(&self, start: uint) -> &'self [T];
+ fn slice_to(&self, end: uint) -> &'self [T];
fn iter(self) -> VecIterator<'self, T>;
fn rev_iter(self) -> VecRevIterator<'self, T>;
fn split_iter(self, pred: &'self fn(&T) -> bool) -> VecSplitIterator<'self, T>;
/// Extension methods for vectors
impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
- /// Return a slice that points into another slice.
+
+ /**
+ * Returns a slice of self between `start` and `end`.
+ *
+ * Fails when `start` or `end` point outside the bounds of self,
+ * or when `start` > `end`.
+ */
#[inline]
fn slice(&self, start: uint, end: uint) -> &'self [T] {
- assert!(start <= end);
- assert!(end <= self.len());
+ assert!(start <= end);
+ assert!(end <= self.len());
do self.as_imm_buf |p, _len| {
unsafe {
transmute((ptr::offset(p, start),
}
}
+ /**
+ * Returns a slice of self from `start` to the end of the vec.
+ *
+ * Fails when `start` points outside the bounds of self.
+ */
+ #[inline]
+ fn slice_from(&self, start: uint) -> &'self [T] {
+ self.slice(start, self.len())
+ }
+
+ /**
+ * Returns a slice of self from the start of the vec to `end`.
+ *
+ * Fails when `end` points outside the bounds of self.
+ */
+ #[inline]
+ fn slice_to(&self, end: uint) -> &'self [T] {
+ self.slice(0, end)
+ }
+
#[inline]
fn iter(self) -> VecIterator<'self, T> {
unsafe {
*
* * n - The number of elements to reserve space for
*/
- #[cfg(stage0)]
- fn reserve(&mut self, n: uint) {
- // Only make the (slow) call into the runtime if we have to
- use managed;
- if self.capacity() < n {
- unsafe {
- let ptr: *mut *mut raw::VecRepr = cast::transmute(self);
- let td = get_tydesc::<T>();
- if ((**ptr).box_header.ref_count ==
- managed::raw::RC_MANAGED_UNIQUE) {
- // XXX transmute shouldn't be necessary
- let td = cast::transmute(td);
- ::at_vec::raw::reserve_raw(td, ptr, n);
- } else {
- let alloc = n * sys::nonzero_size_of::<T>();
- *ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::<raw::VecRepr>())
- as *mut raw::VecRepr;
- (**ptr).unboxed.alloc = alloc;
- }
- }
- }
- }
-
- /**
- * Reserves capacity for exactly `n` elements in the given vector.
- *
- * If the capacity for `self` is already equal to or greater than the requested
- * capacity, then no action is taken.
- *
- * # Arguments
- *
- * * n - The number of elements to reserve space for
- */
- #[cfg(not(stage0))]
fn reserve(&mut self, n: uint) {
// Only make the (slow) call into the runtime if we have to
if self.capacity() < n {
/// Returns the number of elements the vector can hold without reallocating.
#[inline]
- #[cfg(stage0)]
- fn capacity(&self) -> uint {
- unsafe {
- let repr: **raw::VecRepr = transmute(self);
- (**repr).unboxed.alloc / sys::nonzero_size_of::<T>()
- }
- }
-
- /// Returns the number of elements the vector can hold without reallocating.
- #[inline]
- #[cfg(not(stage0))]
fn capacity(&self) -> uint {
unsafe {
if contains_managed::<T>() {
/// Append an element to a vector
#[inline]
- #[cfg(stage0)]
- fn push(&mut self, t: T) {
- unsafe {
- let repr: **raw::VecRepr = transmute(&mut *self);
- let fill = (**repr).unboxed.fill;
- if (**repr).unboxed.alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
- }
-
- self.push_fast(t);
- }
- }
-
- /// Append an element to a vector
- #[inline]
- #[cfg(not(stage0))]
fn push(&mut self, t: T) {
unsafe {
if contains_managed::<T>() {
// This doesn't bother to make sure we have space.
#[inline] // really pretty please
- #[cfg(stage0)]
- unsafe fn push_fast(&mut self, t: T) {
- let repr: **mut raw::VecRepr = transmute(self);
- let fill = (**repr).unboxed.fill;
- (**repr).unboxed.fill += sys::nonzero_size_of::<T>();
- let p = to_unsafe_ptr(&((**repr).unboxed.data));
- let p = ptr::offset(p, fill) as *mut T;
- intrinsics::move_val_init(&mut(*p), t);
- }
-
- // This doesn't bother to make sure we have space.
- #[inline] // really pretty please
- #[cfg(not(stage0))]
unsafe fn push_fast(&mut self, t: T) {
if contains_managed::<T>() {
let repr: **mut raw::VecRepr = transmute(self);
use cast::transmute;
use clone::Clone;
use managed;
- use option::{None, Some};
+ use option::Some;
use ptr;
use sys;
use unstable::intrinsics;
use vec::{UnboxedVecRepr, with_capacity, ImmutableVector, MutableVector};
- use util;
- #[cfg(not(stage0))]
use unstable::intrinsics::contains_managed;
/// The internal representation of a (boxed) vector
* the vector is actually the specified size.
*/
#[inline]
- #[cfg(stage0)]
- pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
- let repr: **mut VecRepr = transmute(v);
- (**repr).unboxed.fill = new_len * sys::nonzero_size_of::<T>();
- }
-
- /**
- * Sets the length of a vector
- *
- * This will explicitly set the size of the vector, without actually
- * modifing its buffers, so it is up to the caller to ensure that
- * the vector is actually the specified size.
- */
- #[inline]
- #[cfg(not(stage0))]
pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
if contains_managed::<T>() {
let repr: **mut VecRepr = transmute(v);
pub unsafe fn init_elem<T>(v: &mut [T], i: uint, val: T) {
let mut box = Some(val);
do v.as_mut_buf |p, _len| {
- let box2 = util::replace(&mut box, None);
intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)),
- box2.unwrap());
+ box.take_unwrap());
}
}
double_ended_iterator!{impl VecIterator -> &'self T}
pub type VecRevIterator<'self, T> = InvertIterator<&'self T, VecIterator<'self, T>>;
+impl<'self, T> Clone for VecIterator<'self, T> {
+ fn clone(&self) -> VecIterator<'self, T> { *self }
+}
+
//iterator!{struct VecMutIterator -> *mut T, &'self mut T}
/// An iterator for mutating the elements of a vector.
pub struct VecMutIterator<'self, T> {
pub type VecMutRevIterator<'self, T> = InvertIterator<&'self mut T, VecMutIterator<'self, T>>;
/// An iterator that moves out of a vector.
+#[deriving(Clone)]
pub struct VecConsumeIterator<T> {
priv v: ~[T],
priv idx: uint,
}
/// An iterator that moves out of a vector in reverse order.
+#[deriving(Clone)]
pub struct VecConsumeRevIterator<T> {
priv v: ~[T]
}
}
}
-#[cfg(stage0)]
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- pub fn from_iterator(iterator: &mut T) -> ~[A] {
- let mut xs = ~[];
- for iterator.advance |x| {
- xs.push(x);
- }
- xs
- }
-}
-
-
-#[cfg(not(stage0))]
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
pub fn from_iterator(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
assert_eq!(v_d[4], 6);
}
+ #[test]
+ fn test_slice_from() {
+ let vec = &[1, 2, 3, 4];
+ assert_eq!(vec.slice_from(0), vec);
+ assert_eq!(vec.slice_from(2), &[3, 4]);
+ assert_eq!(vec.slice_from(4), &[]);
+ }
+
+ #[test]
+ fn test_slice_to() {
+ let vec = &[1, 2, 3, 4];
+ assert_eq!(vec.slice_to(4), vec);
+ assert_eq!(vec.slice_to(2), &[1, 2]);
+ assert_eq!(vec.slice_to(0), &[]);
+ }
+
#[test]
fn test_pop() {
// Test on-heap pop.
assert_eq!(xs.mut_rev_iter().size_hint(), (5, Some(5)));
}
+ #[test]
+ fn test_iter_clone() {
+ let xs = [1, 2, 5];
+ let mut it = xs.iter();
+ it.next();
+ let mut jt = it.clone();
+ assert_eq!(it.next(), jt.next());
+ assert_eq!(it.next(), jt.next());
+ assert_eq!(it.next(), jt.next());
+ }
+
#[test]
fn test_mut_iterator() {
use iterator::*;
/// Construct an identifier with the given name and an empty context:
pub fn new_ident(name: Name) -> ident { ident {name: name, ctxt: empty_ctxt}}
-// a SyntaxContext represents a chain of macro-expandings
-// and renamings. Each macro expansion corresponds to
-// a fresh uint
+/// A SyntaxContext represents a chain of macro-expandings
+/// and renamings. Each macro expansion corresponds to
+/// a fresh uint
// I'm representing this syntax context as an index into
// a table, in order to work around a compiler bug
IllegalCtxt()
}
-// a name is a part of an identifier, representing a string
-// or gensym. It's the result of interning.
+/// A name is a part of an identifier, representing a string or gensym. It's
+/// the result of interning.
pub type Name = uint;
-// a mark represents a unique id associated
-// with a macro expansion
+/// A mark represents a unique id associated with a macro expansion
pub type Mrk = uint;
impl<S:Encoder> Encodable<S> for ident {
}
}
-// Functions may or may not have names.
+/// Function name (not all functions have names)
pub type fn_ident = Option<ident>;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct Path {
span: span,
+ /// 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],
}
-pub type crate_num = int;
+pub type CrateNum = int;
pub type node_id = int;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct def_id {
- crate: crate_num,
+ crate: CrateNum,
node: node_id,
}
-pub static local_crate: crate_num = 0;
+pub static local_crate: CrateNum = 0;
pub static crate_node_id: node_id = 0;
// The AST represents all type param bounds as types.
}
-// The set of meta_items that define the compilation environment of the crate,
+// The set of MetaItems that define the compilation environment of the crate,
// used to drive conditional compilation
-pub type crate_cfg = ~[@meta_item];
-
-pub type crate = spanned<crate_>;
+pub type CrateConfig = ~[@MetaItem];
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub struct crate_ {
+pub struct Crate {
module: _mod,
- attrs: ~[attribute],
- config: crate_cfg,
+ attrs: ~[Attribute],
+ config: CrateConfig,
+ span: span,
}
-pub type meta_item = spanned<meta_item_>;
+pub type MetaItem = spanned<MetaItem_>;
-#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub enum meta_item_ {
- meta_word(@str),
- meta_list(@str, ~[@meta_item]),
- meta_name_value(@str, lit),
+#[deriving(Clone, Encodable, Decodable, IterBytes)]
+pub enum MetaItem_ {
+ MetaWord(@str),
+ MetaList(@str, ~[@MetaItem]),
+ MetaNameValue(@str, lit),
}
-//pub type blk = spanned<blk_>;
+// can't be derived because the MetaList requires an unordered comparison
+impl Eq for MetaItem_ {
+ fn eq(&self, other: &MetaItem_) -> bool {
+ match *self {
+ MetaWord(ref ns) => match *other {
+ MetaWord(ref no) => (*ns) == (*no),
+ _ => false
+ },
+ MetaNameValue(ref ns, ref vs) => match *other {
+ MetaNameValue(ref no, ref vo) => {
+ (*ns) == (*no) && vs.node == vo.node
+ }
+ _ => false
+ },
+ MetaList(ref ns, ref miss) => match *other {
+ MetaList(ref no, ref miso) => {
+ ns == no &&
+ miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node))
+ }
+ _ => false
+ }
+ }
+ }
+}
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub struct blk {
+pub struct Block {
view_items: ~[view_item],
stmts: ~[@stmt],
expr: Option<@expr>,
// FIXME (pending discussion of #1697, #2178...): local should really be
// a refinement on pat.
#[deriving(Eq, Encodable, Decodable,IterBytes)]
-pub struct local_ {
+pub struct Local {
is_mutbl: bool,
ty: Ty,
pat: @pat,
init: Option<@expr>,
id: node_id,
+ span: span,
}
-pub type local = spanned<local_>;
-
pub type decl = spanned<decl_>;
#[deriving(Eq, Encodable, Decodable,IterBytes)]
pub enum decl_ {
// a local (let) binding:
- decl_local(@local),
+ decl_local(@Local),
// an item binding:
decl_item(@item),
}
pub struct arm {
pats: ~[@pat],
guard: Option<@expr>,
- body: blk,
+ body: Block,
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub struct field_ {
+pub struct Field {
ident: ident,
expr: @expr,
+ span: span,
}
-pub type field = spanned<field_>;
-
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum blk_check_mode {
default_blk,
expr_unary(node_id, unop, @expr),
expr_lit(@lit),
expr_cast(@expr, Ty),
- expr_if(@expr, blk, Option<@expr>),
- expr_while(@expr, blk),
+ expr_if(@expr, Block, Option<@expr>),
+ expr_while(@expr, Block),
/* Conditionless loop (can be exited with break, cont, or ret)
Same semantics as while(true) { body }, but typestate knows that the
(implicit) condition is always true. */
- expr_loop(blk, Option<ident>),
+ expr_loop(Block, Option<ident>),
expr_match(@expr, ~[arm]),
- expr_fn_block(fn_decl, blk),
+ expr_fn_block(fn_decl, Block),
// Inner expr is always an expr_fn_block. We need the wrapping node to
// easily type this (a function returning nil on the inside but bool on
// the outside).
expr_loop_body(@expr),
// Like expr_loop_body but for 'do' blocks
expr_do_body(@expr),
- expr_block(blk),
+ expr_block(Block),
expr_assign(@expr, @expr),
expr_assign_op(node_id, binop, @expr, @expr),
expr_mac(mac),
// A struct literal expression.
- expr_struct(Path, ~[field], Option<@expr>),
+ expr_struct(Path, ~[Field], Option<@expr>),
// A vector literal constructed from one repeated element.
expr_repeat(@expr /* element */, @expr /* count */, mutability),
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct ty_method {
ident: ident,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
purity: purity,
decl: fn_decl,
generics: Generics,
#[deriving(Eq, Encodable, Decodable,IterBytes)]
pub struct method {
ident: ident,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
generics: Generics,
explicit_self: explicit_self,
purity: purity,
decl: fn_decl,
- body: blk,
+ body: Block,
id: node_id,
span: span,
self_id: node_id,
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct variant_ {
name: ident,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
kind: variant_kind,
id: node_id,
disr_expr: Option<@expr>,
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct view_item {
node: view_item_,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
vis: visibility,
span: span,
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum view_item_ {
- view_item_extern_mod(ident, ~[@meta_item], node_id),
+ view_item_extern_mod(ident, ~[@MetaItem], node_id),
view_item_use(~[@view_path]),
}
// Meta-data associated with an item
-pub type attribute = spanned<attribute_>;
+pub type Attribute = spanned<Attribute_>;
-// Distinguishes between attributes that decorate items and attributes that
+// Distinguishes between Attributes that decorate items and Attributes that
// are contained as statements within items. These two cases need to be
// distinguished for pretty-printing.
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub enum attr_style {
- attr_outer,
- attr_inner,
+pub enum AttrStyle {
+ AttrOuter,
+ AttrInner,
}
// doc-comments are promoted to attributes that have is_sugared_doc = true
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub struct attribute_ {
- style: attr_style,
- value: @meta_item,
+pub struct Attribute_ {
+ style: AttrStyle,
+ value: @MetaItem,
is_sugared_doc: bool,
}
kind: struct_field_kind,
id: node_id,
ty: Ty,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
}
pub type struct_field = spanned<struct_field_>;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct item {
ident: ident,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
id: node_id,
node: item_,
vis: visibility,
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum item_ {
item_static(Ty, mutability, @expr),
- item_fn(fn_decl, purity, AbiSet, Generics, blk),
+ item_fn(fn_decl, purity, AbiSet, Generics, Block),
item_mod(_mod),
item_foreign_mod(foreign_mod),
item_ty(Ty, Generics),
#[deriving(Eq, Encodable, Decodable,IterBytes)]
pub struct foreign_item {
ident: ident,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
node: foreign_item_,
id: node_id,
span: span,
use visit;
use syntax::parse::token::special_idents;
-use std::cmp;
use std::hashmap::HashMap;
use std::vec;
node_stmt(@stmt),
node_arg,
node_local(ident),
- node_block(blk),
+ node_block(Block),
node_struct_ctor(@struct_def, @item, @path),
node_callee_scope(@expr)
}
});
}
-pub fn map_crate(diag: @span_handler, c: &crate) -> map {
+pub fn map_crate(diag: @span_handler, c: &Crate) -> map {
let cx = @mut Ctx {
map: @mut HashMap::new(),
path: ~[],
pub fn map_fn(
fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: codemap::span,
id: node_id,
(cx,v): (@mut Ctx,
visit::visit_fn(fk, decl, body, sp, id, (cx, v));
}
-pub fn map_block(b: &blk, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
+pub fn map_block(b: &Block, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
cx.map.insert(b.id, node_block(/* FIXME (#2543) */ (*b).clone()));
visit::visit_block(b, (cx, v));
}
use parse::token;
use visit;
-use std::cast::unsafe_copy;
-use std::cast;
use std::hashmap::HashMap;
use std::int;
use std::local_data;
match e.node { expr_call(*) => true, _ => false }
}
-pub fn block_from_expr(e: @expr) -> blk {
+pub fn block_from_expr(e: @expr) -> Block {
let mut blk = default_block(~[], option::Some::<@expr>(e), e.id);
blk.span = e.span;
return blk;
stmts1: ~[@stmt],
expr1: Option<@expr>,
id1: node_id
-) -> blk {
- ast::blk {
+) -> Block {
+ ast::Block {
view_items: ~[],
stmts: stmts1,
expr: expr1,
},
visit_local: |l, (t, vt)| {
- vfn(l.node.id, t.clone());
+ vfn(l.id, t.clone());
visit::visit_local(l, (t, vt));
},
visit_block: |b, (t, vt)| {
pub fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool;
}
-impl EachViewItem for ast::crate {
+impl EachViewItem for ast::Crate {
fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool {
let broke = @mut false;
let vtor: visit::vt<()> = visit::mk_simple_visitor(@visit::SimpleVisitor {
// fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_sctable() -> @mut SCTable {
- #[cfg(not(stage0))]
static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
- #[cfg(stage0)]
- fn sctable_key(_: @@mut SCTable) {}
match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
None => {
let new_table = @@mut new_sctable_internal();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Functions dealing with attributes and meta_items
+// Functions dealing with attributes and meta items
use extra;
use ast;
+use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
use codemap::{spanned, dummy_spanned};
-use attr;
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
use std::hashmap::HashSet;
-/* Constructors */
-
-pub fn mk_name_value_item_str(name: @str, value: @str)
- -> @ast::meta_item {
- let value_lit = dummy_spanned(ast::lit_str(value));
- mk_name_value_item(name, value_lit)
-}
-
-pub fn mk_name_value_item(name: @str, value: ast::lit)
- -> @ast::meta_item {
- @dummy_spanned(ast::meta_name_value(name, value))
-}
-
-pub fn mk_list_item(name: @str, items: ~[@ast::meta_item]) ->
- @ast::meta_item {
- @dummy_spanned(ast::meta_list(name, items))
-}
-pub fn mk_word_item(name: @str) -> @ast::meta_item {
- @dummy_spanned(ast::meta_word(name))
+pub trait AttrMetaMethods {
+ // This could be changed to `fn check_name(&self, name: @str) ->
+ // bool` which would facilitate a side table recording which
+ // attributes/meta items are used/unused.
+
+ /// Retrieve the name of the meta item, e.g. foo in #[foo],
+ /// #[foo="bar"] and #[foo(bar)]
+ fn name(&self) -> @str;
+
+ /**
+ * Gets the string value if self is a MetaNameValue variant
+ * containing a string, otherwise None.
+ */
+ fn value_str(&self) -> Option<@str>;
+ /// Gets a list of inner meta items from a list MetaItem type.
+ fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]>;
+
+ /**
+ * If the meta item is a name-value type with a string value then returns
+ * a tuple containing the name and string value, otherwise `None`
+ */
+ fn name_str_pair(&self) -> Option<(@str, @str)>;
}
-pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
- dummy_spanned(ast::attribute_ { style: ast::attr_inner,
- value: item,
- is_sugared_doc: false })
+impl AttrMetaMethods for Attribute {
+ fn name(&self) -> @str { self.meta().name() }
+ fn value_str(&self) -> Option<@str> { self.meta().value_str() }
+ fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+ self.node.value.meta_item_list()
+ }
+ fn name_str_pair(&self) -> Option<(@str, @str)> { self.meta().name_str_pair() }
}
-pub fn mk_sugared_doc_attr(text: @str,
- lo: BytePos, hi: BytePos) -> ast::attribute {
- let style = doc_comment_style(text);
- let lit = spanned(lo, hi, ast::lit_str(text));
- let attr = ast::attribute_ {
- style: style,
- value: @spanned(lo, hi, ast::meta_name_value(@"doc", lit)),
- is_sugared_doc: true
- };
- spanned(lo, hi, attr)
-}
+impl AttrMetaMethods for MetaItem {
+ fn name(&self) -> @str {
+ match self.node {
+ MetaWord(n) => n,
+ MetaNameValue(n, _) => n,
+ MetaList(n, _) => n
+ }
+ }
-/* Conversion */
+ fn value_str(&self) -> Option<@str> {
+ match self.node {
+ MetaNameValue(_, ref v) => {
+ match v.node {
+ ast::lit_str(s) => Some(s),
+ _ => None,
+ }
+ },
+ _ => None
+ }
+ }
-pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
- attr.node.value
-}
+ fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+ match self.node {
+ MetaList(_, ref l) => Some(l.as_slice()),
+ _ => None
+ }
+ }
-// Get the meta_items from inside a vector of attributes
-pub fn attr_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
- do attrs.map |a| { attr_meta(*a) }
+ pub fn name_str_pair(&self) -> Option<(@str, @str)> {
+ self.value_str().map_consume(|s| (self.name(), s))
+ }
}
-pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
- if attr.node.is_sugared_doc {
- let comment = get_meta_item_value_str(attr.node.value).get();
- let meta = mk_name_value_item_str(@"doc",
- strip_doc_comment_decoration(comment).to_managed());
- mk_attr(meta)
- } else {
- *attr
+// Annoying, but required to get test_cfg to work
+impl AttrMetaMethods for @MetaItem {
+ fn name(&self) -> @str { (**self).name() }
+ fn value_str(&self) -> Option<@str> { (**self).value_str() }
+ fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+ (**self).meta_item_list()
}
+ fn name_str_pair(&self) -> Option<(@str, @str)> { (**self).name_str_pair() }
}
-/* Accessors */
-pub fn get_attr_name(attr: &ast::attribute) -> @str {
- get_meta_item_name(attr.node.value)
+pub trait AttributeMethods {
+ fn meta(&self) -> @MetaItem;
+ fn desugar_doc(&self) -> Attribute;
}
-pub fn get_meta_item_name(meta: @ast::meta_item) -> @str {
- match meta.node {
- ast::meta_word(n) => n,
- ast::meta_name_value(n, _) => n,
- ast::meta_list(n, _) => n,
+impl AttributeMethods for Attribute {
+ /// Extract the MetaItem from inside this Attribute.
+ pub fn meta(&self) -> @MetaItem {
+ self.node.value
}
-}
-/**
- * Gets the string value if the meta_item is a meta_name_value variant
- * containing a string, otherwise none
- */
-pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<@str> {
- match meta.node {
- ast::meta_name_value(_, v) => {
- match v.node {
- ast::lit_str(s) => Some(s),
- _ => None,
- }
- },
- _ => None
+ /// Convert self to a normal #[doc="foo"] comment, if it is a
+ /// comment like `///` or `/** */`. (Returns self unchanged for
+ /// non-sugared doc attributes.)
+ pub fn desugar_doc(&self) -> Attribute {
+ if self.node.is_sugared_doc {
+ let comment = self.value_str().get();
+ let meta = mk_name_value_item_str(@"doc",
+ strip_doc_comment_decoration(comment).to_managed());
+ mk_attr(meta)
+ } else {
+ *self
+ }
}
}
-/// Gets a list of inner meta items from a list meta_item type
-pub fn get_meta_item_list(meta: @ast::meta_item)
- -> Option<~[@ast::meta_item]> {
- match meta.node {
- ast::meta_list(_, ref l) => Some(/* FIXME (#2543) */ (*l).clone()),
- _ => None
- }
-}
+/* Constructors */
-/**
- * If the meta item is a nam-value type with a string value then returns
- * a tuple containing the name and string value, otherwise `none`
- */
-pub fn get_name_value_str_pair(item: @ast::meta_item)
- -> Option<(@str, @str)> {
- match attr::get_meta_item_value_str(item) {
- Some(value) => {
- let name = attr::get_meta_item_name(item);
- Some((name, value))
- }
- None => None
- }
+pub fn mk_name_value_item_str(name: @str, value: @str) -> @MetaItem {
+ let value_lit = dummy_spanned(ast::lit_str(value));
+ mk_name_value_item(name, value_lit)
}
-
-/* Searching */
-
-/// Search a list of attributes and return only those with a specific name
-pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
- ~[ast::attribute] {
- do attrs.iter().filter_map |a| {
- if name == get_attr_name(a) {
- Some(*a)
- } else {
- None
- }
- }.collect()
+pub fn mk_name_value_item(name: @str, value: ast::lit) -> @MetaItem {
+ @dummy_spanned(MetaNameValue(name, value))
}
-/// Search a list of meta items and return only those with a specific name
-pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
- ~[@ast::meta_item] {
- let mut rs = ~[];
- for metas.iter().advance |mi| {
- if name == get_meta_item_name(*mi) {
- rs.push(*mi)
- }
- }
- rs
+pub fn mk_list_item(name: @str, items: ~[@MetaItem]) -> @MetaItem {
+ @dummy_spanned(MetaList(name, items))
}
-/**
- * Returns true if a list of meta items contains another meta item. The
- * comparison is performed structurally.
- */
-pub fn contains(haystack: &[@ast::meta_item],
- needle: @ast::meta_item) -> bool {
- for haystack.iter().advance |item| {
- if eq(*item, needle) { return true; }
- }
- return false;
+pub fn mk_word_item(name: @str) -> @MetaItem {
+ @dummy_spanned(MetaWord(name))
}
-fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
- match a.node {
- ast::meta_word(ref na) => match b.node {
- ast::meta_word(ref nb) => (*na) == (*nb),
- _ => false
- },
- ast::meta_name_value(ref na, va) => match b.node {
- ast::meta_name_value(ref nb, vb) => {
- (*na) == (*nb) && va.node == vb.node
- }
- _ => false
- },
- ast::meta_list(ref na, ref misa) => match b.node {
- ast::meta_list(ref nb, ref misb) => {
- if na != nb { return false; }
- for misa.iter().advance |mi| {
- if !misb.iter().any(|x| x == mi) { return false; }
- }
- true
- }
- _ => false
- }
- }
+pub fn mk_attr(item: @MetaItem) -> Attribute {
+ dummy_spanned(Attribute_ {
+ style: ast::AttrInner,
+ value: item,
+ is_sugared_doc: false,
+ })
}
-pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
- let matches = find_meta_items_by_name(metas, name);
- matches.len() > 0u
+pub fn mk_sugared_doc_attr(text: @str, lo: BytePos, hi: BytePos) -> Attribute {
+ let style = doc_comment_style(text);
+ let lit = spanned(lo, hi, ast::lit_str(text));
+ let attr = Attribute_ {
+ style: style,
+ value: @spanned(lo, hi, MetaNameValue(@"doc", lit)),
+ is_sugared_doc: true
+ };
+ spanned(lo, hi, attr)
}
-pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
- !find_attrs_by_name(attrs, name).is_empty()
+/* Searching */
+/// Check if `needle` occurs in `haystack` by a structural
+/// comparison. This is slightly subtle, and relies on ignoring the
+/// span included in the `==` comparison a plain MetaItem.
+pub fn contains(haystack: &[@ast::MetaItem],
+ needle: @ast::MetaItem) -> bool {
+ debug!("attr::contains (name=%s)", needle.name());
+ do haystack.iter().any |item| {
+ debug!(" testing: %s", item.name());
+ item.node == needle.node
+ }
}
-pub fn first_attr_value_str_by_name(attrs: &[ast::attribute], name: &str)
- -> Option<@str> {
-
- let mattrs = find_attrs_by_name(attrs, name);
- if mattrs.len() > 0 {
- get_meta_item_value_str(attr_meta(mattrs[0]))
- } else {
- None
+pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
+ debug!("attr::contains_name (name=%s)", name);
+ do metas.iter().any |item| {
+ debug!(" testing: %s", item.name());
+ name == item.name()
}
}
-fn last_meta_item_by_name(items: &[@ast::meta_item], name: &str)
- -> Option<@ast::meta_item> {
-
- let items = attr::find_meta_items_by_name(items, name);
- items.last_opt().map(|item| **item)
+pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str)
+ -> Option<@str> {
+ attrs.iter()
+ .find_(|at| name == at.name())
+ .chain(|at| at.value_str())
}
-pub fn last_meta_item_value_str_by_name(items: &[@ast::meta_item], name: &str)
+pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str)
-> Option<@str> {
-
- match last_meta_item_by_name(items, name) {
- Some(item) => {
- match attr::get_meta_item_value_str(item) {
- Some(value) => Some(value),
- None => None
- }
- },
- None => None
- }
+ items.rev_iter().find_(|mi| name == mi.name()).chain(|i| i.value_str())
}
-pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str)
- -> Option<~[@ast::meta_item]> {
-
- match last_meta_item_by_name(items, name) {
- Some(item) => attr::get_meta_item_list(item),
- None => None
- }
-}
-
-
/* Higher-level applications */
-pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] {
- // This is sort of stupid here, converting to a vec of mutables and back
- let mut v = items.to_owned();
- do extra::sort::quick_sort(v) |ma, mb| {
- get_meta_item_name(*ma) <= get_meta_item_name(*mb)
+pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] {
+ // This is sort of stupid here, but we need to sort by
+ // human-readable strings.
+ let mut v = items.iter()
+ .transform(|&mi| (mi.name(), mi))
+ .collect::<~[(@str, @MetaItem)]>();
+
+ do extra::sort::quick_sort(v) |&(a, _), &(b, _)| {
+ a <= b
}
// There doesn't seem to be a more optimal way to do this
- do v.map |m| {
+ do v.consume_iter().transform |(_, m)| {
match m.node {
- ast::meta_list(n, ref mis) => {
+ MetaList(n, ref mis) => {
@spanned {
- node: ast::meta_list(n, sort_meta_items(*mis)),
- .. /*bad*/ (**m).clone()
+ node: MetaList(n, sort_meta_items(*mis)),
+ .. /*bad*/ (*m).clone()
}
}
- _ => *m
+ _ => m
}
- }
-}
-
-pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: &str) ->
- ~[@ast::meta_item] {
- items.consume_iter().filter(|item| name != get_meta_item_name(*item)).collect()
+ }.collect()
}
/**
* From a list of crate attributes get only the meta_items that affect crate
* linkage
*/
-pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
- do find_attrs_by_name(attrs, "link").flat_map |attr| {
- match attr.node.value.node {
- ast::meta_list(_, ref items) => {
- /* FIXME (#2543) */ (*items).clone()
- }
- _ => ~[]
+pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] {
+ let mut result = ~[];
+ for attrs.iter().filter(|at| "link" == at.name()).advance |attr| {
+ match attr.meta().node {
+ MetaList(_, ref items) => result.push_all(*items),
+ _ => ()
}
}
+ result
}
#[deriving(Eq)]
-pub enum inline_attr {
- ia_none,
- ia_hint,
- ia_always,
- ia_never,
+pub enum InlineAttr {
+ InlineNone,
+ InlineHint,
+ InlineAlways,
+ InlineNever,
}
/// True if something like #[inline] is found in the list of attrs.
-pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
+pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
// FIXME (#2809)---validate the usage of #[inline] and #[inline]
- do attrs.iter().fold(ia_none) |ia,attr| {
+ do attrs.iter().fold(InlineNone) |ia,attr| {
match attr.node.value.node {
- ast::meta_word(s) if "inline" == s => ia_hint,
- ast::meta_list(s, ref items) if "inline" == s => {
- if !find_meta_items_by_name(*items, "always").is_empty() {
- ia_always
- } else if !find_meta_items_by_name(*items, "never").is_empty() {
- ia_never
+ MetaWord(n) if "inline" == n => InlineHint,
+ MetaList(n, ref items) if "inline" == n => {
+ if contains_name(*items, "always") {
+ InlineAlways
+ } else if contains_name(*items, "never") {
+ InlineNever
} else {
- ia_hint
+ InlineHint
}
}
_ => ia
}
}
+/// Tests if any `cfg(...)` meta items in `metas` match `cfg`. e.g.
+///
+/// test_cfg(`[foo="a", bar]`, `[cfg(foo), cfg(bar)]`) == true
+/// test_cfg(`[foo="a", bar]`, `[cfg(not(bar))]`) == false
+/// test_cfg(`[foo="a", bar]`, `[cfg(bar, foo="a")]`) == true
+/// test_cfg(`[foo="a", bar]`, `[cfg(bar, foo="b")]`) == false
+pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
+ (cfg: &[@MetaItem], mut metas: It) -> bool {
+ // having no #[cfg(...)] attributes counts as matching.
+ let mut no_cfgs = true;
+
+ // this would be much nicer as a chain of iterator adaptors, but
+ // this doesn't work.
+ let some_cfg_matches = do metas.any |mi| {
+ debug!("testing name: %s", mi.name());
+ if "cfg" == mi.name() { // it is a #[cfg()] attribute
+ debug!("is cfg");
+ no_cfgs = false;
+ // only #[cfg(...)] ones are understood.
+ match mi.meta_item_list() {
+ Some(cfg_meta) => {
+ debug!("is cfg(...)");
+ do cfg_meta.iter().all |cfg_mi| {
+ debug!("cfg(%s[...])", cfg_mi.name());
+ match cfg_mi.node {
+ ast::MetaList(s, ref not_cfgs) if "not" == s => {
+ debug!("not!");
+ // inside #[cfg(not(...))], so these need to all
+ // not match.
+ not_cfgs.iter().all(|mi| {
+ debug!("cfg(not(%s[...]))", mi.name());
+ !contains(cfg, *mi)
+ })
+ }
+ _ => contains(cfg, *cfg_mi)
+ }
+ }
+ }
+ None => false
+ }
+ } else {
+ false
+ }
+ };
+ debug!("test_cfg (no_cfgs=%?, some_cfg_matches=%?)", no_cfgs, some_cfg_matches);
+ no_cfgs || some_cfg_matches
+}
pub fn require_unique_names(diagnostic: @span_handler,
- metas: &[@ast::meta_item]) {
+ metas: &[@MetaItem]) {
let mut set = HashSet::new();
for metas.iter().advance |meta| {
- let name = get_meta_item_name(*meta);
+ let name = meta.name();
// FIXME: How do I silence the warnings? --pcw (#2619)
if !set.insert(name) {
}
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
- #[cfg(not(stage0))]
static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
- #[cfg(stage0)]
- fn tls_terminal(_: @Option<term::Terminal>) {}
let stderr = io::stderr();
pub fn expand_auto_encode(
cx: @ExtCtxt,
span: span,
- _mitem: @ast::meta_item,
+ _mitem: @ast::MetaItem,
in_items: ~[@ast::item]
) -> ~[@ast::item] {
cx.span_err(span, "`#[auto_encode]` is deprecated, use `#[deriving(Encodable)]` instead");
pub fn expand_auto_decode(
cx: @ExtCtxt,
span: span,
- _mitem: @ast::meta_item,
+ _mitem: @ast::MetaItem,
in_items: ~[@ast::item]
) -> ~[@ast::item] {
cx.span_err(span, "`#[auto_decode]` is deprecated, use `#[deriving(Decodable)]` instead");
pub type ItemDecorator = @fn(@ExtCtxt,
span,
- @ast::meta_item,
+ @ast::MetaItem,
~[@ast::item])
-> ~[@ast::item];
// -> expn_info of their expansion context stored into their span.
pub struct ExtCtxt {
parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
backtrace: @mut Option<@ExpnInfo>,
// These two @mut's should really not be here,
}
impl ExtCtxt {
- pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg)
+ pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::CrateConfig)
-> @ExtCtxt {
@ExtCtxt {
parse_sess: parse_sess,
pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
pub fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess }
- pub fn cfg(&self) -> ast::crate_cfg { self.cfg.clone() }
+ pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
pub fn call_site(&self) -> span {
match *self.backtrace {
Some(@ExpnInfo {call_site: cs, _}) => cs,
// get the map from an env frame
-impl <K: Eq + Hash + IterBytes, V> MapChain<K,V>{
-
+impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
// Constructor. I don't think we need a zero-arg one.
fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
@mut BaseMapChain(init)
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt;
// blocks
- fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::blk;
- fn blk_expr(&self, expr: @ast::expr) -> ast::blk;
+ fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block;
+ fn blk_expr(&self, expr: @ast::expr) -> ast::Block;
fn blk_all(&self, span: span,
view_items: ~[ast::view_item],
stmts: ~[@ast::stmt],
- expr: Option<@ast::expr>) -> ast::blk;
+ expr: Option<@ast::expr>) -> ast::Block;
// expressions
fn expr(&self, span: span, node: ast::expr_) -> @ast::expr;
fn expr_method_call(&self, span: span,
expr: @ast::expr, ident: ast::ident,
args: ~[@ast::expr]) -> @ast::expr;
- fn expr_blk(&self, b: ast::blk) -> @ast::expr;
+ fn expr_blk(&self, b: ast::Block) -> @ast::expr;
- fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::field;
- fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::field]) -> @ast::expr;
- fn expr_struct_ident(&self, span: span, id: ast::ident, fields: ~[ast::field]) -> @ast::expr;
+ fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::Field;
+ fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::Field]) -> @ast::expr;
+ fn expr_struct_ident(&self, span: span, id: ast::ident, fields: ~[ast::Field]) -> @ast::expr;
fn expr_lit(&self, sp: span, lit: ast::lit_) -> @ast::expr;
fn expr_if(&self, span: span,
cond: @ast::expr, then: @ast::expr, els: Option<@ast::expr>) -> @ast::expr;
- fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::blk) -> @ast::expr;
+ fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::Block) -> @ast::expr;
- fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::blk) -> @ast::expr;
- fn lambda0(&self, span: span, blk: ast::blk) -> @ast::expr;
- fn lambda1(&self, span: span, blk: ast::blk, ident: ast::ident) -> @ast::expr;
+ fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::Block) -> @ast::expr;
+ fn lambda0(&self, span: span, blk: ast::Block) -> @ast::expr;
+ fn lambda1(&self, span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr;
fn lambda_expr(&self, span: span, ids: ~[ast::ident], blk: @ast::expr) -> @ast::expr;
fn lambda_expr_0(&self, span: span, expr: @ast::expr) -> @ast::expr;
// items
fn item(&self, span: span,
- name: ident, attrs: ~[ast::attribute], node: ast::item_) -> @ast::item;
+ name: ident, attrs: ~[ast::Attribute], node: ast::item_) -> @ast::item;
fn arg(&self, span: span, name: ident, ty: ast::Ty) -> ast::arg;
// XXX unused self
inputs: ~[ast::arg],
output: ast::Ty,
generics: Generics,
- body: ast::blk) -> @ast::item;
+ body: ast::Block) -> @ast::item;
fn item_fn(&self,
span: span,
name: ident,
inputs: ~[ast::arg],
output: ast::Ty,
- body: ast::blk) -> @ast::item;
+ body: ast::Block) -> @ast::item;
fn variant(&self, span: span, name: ident, tys: ~[ast::Ty]) -> ast::variant;
fn item_enum_poly(&self,
fn item_struct(&self, span: span, name: ident, struct_def: ast::struct_def) -> @ast::item;
fn item_mod(&self, span: span,
- name: ident, attrs: ~[ast::attribute],
+ name: ident, attrs: ~[ast::Attribute],
vi: ~[ast::view_item], items: ~[@ast::item]) -> @ast::item;
fn item_ty_poly(&self,
generics: Generics) -> @ast::item;
fn item_ty(&self, span: span, name: ident, ty: ast::Ty) -> @ast::item;
- fn attribute(&self, sp: span, mi: @ast::meta_item) -> ast::attribute;
+ fn attribute(&self, sp: span, mi: @ast::MetaItem) -> ast::Attribute;
- fn meta_word(&self, sp: span, w: @str) -> @ast::meta_item;
- fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::meta_item]) -> @ast::meta_item;
- fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::meta_item;
+ fn meta_word(&self, sp: span, w: @str) -> @ast::MetaItem;
+ fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem;
+ fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::MetaItem;
fn view_use(&self, sp: span,
vis: ast::visibility, vp: ~[@ast::view_path]) -> ast::view_item;
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt {
let pat = self.pat_ident(sp, ident);
- let local = @respan(sp,
- ast::local_ {
- is_mutbl: mutbl,
- ty: self.ty_infer(sp),
- pat: pat,
- init: Some(ex),
- id: self.next_id(),
- });
+ let local = @ast::Local {
+ is_mutbl: mutbl,
+ ty: self.ty_infer(sp),
+ 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 blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::blk {
+ fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block {
self.blk_all(span, ~[], stmts, expr)
}
- fn blk_expr(&self, expr: @ast::expr) -> ast::blk {
+ fn blk_expr(&self, expr: @ast::expr) -> ast::Block {
self.blk_all(expr.span, ~[], ~[], Some(expr))
}
fn blk_all(&self,
span: span,
view_items: ~[ast::view_item],
stmts: ~[@ast::stmt],
- expr: Option<@ast::expr>) -> ast::blk {
- ast::blk {
+ expr: Option<@ast::expr>) -> ast::Block {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: expr,
self.expr(span,
ast::expr_method_call(self.next_id(), expr, ident, ~[], args, ast::NoSugar))
}
- fn expr_blk(&self, b: ast::blk) -> @ast::expr {
+ fn expr_blk(&self, b: ast::Block) -> @ast::expr {
self.expr(b.span, ast::expr_block(b))
}
- fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::field {
- respan(span, ast::field_ { ident: name, expr: e })
+ fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::Field {
+ ast::Field { ident: name, expr: e, span: span }
}
- fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::field]) -> @ast::expr {
+ fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::Field]) -> @ast::expr {
self.expr(span, ast::expr_struct(path, fields, None))
}
fn expr_struct_ident(&self, span: span,
- id: ast::ident, fields: ~[ast::field]) -> @ast::expr {
+ id: ast::ident, fields: ~[ast::Field]) -> @ast::expr {
self.expr_struct(span, self.path_ident(span, id), fields)
}
self.expr(span, ast::expr_if(cond, self.blk_expr(then), els))
}
- fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::blk) -> @ast::expr {
+ fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::Block) -> @ast::expr {
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
- fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::blk) -> @ast::expr {
+ fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::Block) -> @ast::expr {
let fn_decl = self.fn_decl(
ids.map(|id| self.arg(span, *id, self.ty_infer(span))),
self.ty_infer(span));
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
- fn lambda0(&self, _span: span, blk: ast::blk) -> @ast::expr {
+ fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|| $blk_e )
}
- fn lambda1(&self, _span: span, blk: ast::blk, ident: ast::ident) -> @ast::expr {
+ fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|$ident| $blk_e )
}
fn item(&self, span: span,
- name: ident, attrs: ~[ast::attribute], node: ast::item_) -> @ast::item {
+ name: ident, attrs: ~[ast::Attribute], node: ast::item_) -> @ast::item {
// XXX: Would be nice if our generated code didn't violate
// Rust coding conventions
@ast::item { ident: name,
inputs: ~[ast::arg],
output: ast::Ty,
generics: Generics,
- body: ast::blk) -> @ast::item {
+ body: ast::Block) -> @ast::item {
self.item(span,
name,
~[],
name: ident,
inputs: ~[ast::arg],
output: ast::Ty,
- body: ast::blk
+ body: ast::Block
) -> @ast::item {
self.item_fn_poly(
span,
}
fn item_mod(&self, span: span, name: ident,
- attrs: ~[ast::attribute],
+ attrs: ~[ast::Attribute],
vi: ~[ast::view_item],
items: ~[@ast::item]) -> @ast::item {
self.item(
self.item_ty_poly(span, name, ty, ast_util::empty_generics())
}
- fn attribute(&self, sp: span, mi: @ast::meta_item) -> ast::attribute {
- respan(sp,
- ast::attribute_ {
- style: ast::attr_outer,
- value: mi,
- is_sugared_doc: false
- })
+ fn attribute(&self, sp: span, mi: @ast::MetaItem) -> ast::Attribute {
+ respan(sp, ast::Attribute_ {
+ style: ast::AttrOuter,
+ value: mi,
+ is_sugared_doc: false,
+ })
}
- fn meta_word(&self, sp: span, w: @str) -> @ast::meta_item {
- @respan(sp, ast::meta_word(w))
+ fn meta_word(&self, sp: span, w: @str) -> @ast::MetaItem {
+ @respan(sp, ast::MetaWord(w))
}
- fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::meta_item]) -> @ast::meta_item {
- @respan(sp, ast::meta_list(name, mis))
+ fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem {
+ @respan(sp, ast::MetaList(name, mis))
}
- fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::meta_item {
- @respan(sp, ast::meta_name_value(name, respan(sp, value)))
+ fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::MetaItem {
+ @respan(sp, ast::MetaNameValue(name, respan(sp, value)))
}
fn view_use(&self, sp: span,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_clone(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
}
pub fn expand_deriving_deep_clone(cx: @ExtCtxt,
- span: span,
- mitem: @meta_item,
- in_items: ~[@item])
+ span: span,
+ mitem: @MetaItem,
+ in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~["std", "clone", "DeepClone"]),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_eq(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
// structures are equal if all fields are equal, and non equal, if
// any fields are not equal or if the enum variants are different
// except according to those terms.
use ast;
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_ord(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
macro_rules! md (
($name:expr, $op:expr, $equal:expr) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
pub fn expand_deriving_totaleq(cx: @ExtCtxt,
- span: span,
- mitem: @meta_item,
- in_items: ~[@item]) -> ~[@item] {
-
+ span: span,
+ mitem: @MetaItem,
+ in_items: ~[@item]) -> ~[@item] {
fn cs_equals(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
cs_and(|cx, span, _, _| cx.expr_bool(span, false),
cx, span, substr)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_totalord(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~["std", "cmp", "TotalOrd"]),
use std::vec;
use std::uint;
-use ast::{meta_item, item, expr, m_mutbl};
+use ast::{MetaItem, item, expr, m_mutbl};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_decodable(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: Path::new_(~["extra", "serialize", "Decodable"], None,
}
*/
-use ast::{meta_item, item, expr, m_imm, m_mutbl};
+use ast::{MetaItem, item, expr, m_imm, m_mutbl};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_encodable(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: Path::new_(~["extra", "serialize", "Encodable"], None,
impl<'self> TraitDef<'self> {
pub fn expand(&self, cx: @ExtCtxt,
span: span,
- _mitem: @ast::meta_item,
+ _mitem: @ast::MetaItem,
in_items: ~[@ast::item]) -> ~[@ast::item] {
let mut result = ~[];
for in_items.iter().advance |item| {
let doc_attr = cx.attribute(
span,
cx.meta_name_value(span,
- @"doc", ast::lit_str(@"Automatically derived.")));
+ @"doc",
+ ast::lit_str(@"Automatically derived.")));
cx.item(
span,
::parse::token::special_idents::clownshoes_extensions,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr, and};
+use ast::{MetaItem, item, expr, and};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_iter_bytes(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item]) -> ~[@item] {
let trait_def = TraitDef {
path: Path::new(~["std", "to_bytes", "IterBytes"]),
*/
-use ast::{enum_def, ident, item, Generics, meta_item, struct_def};
+use ast::{enum_def, ident, item, Generics, struct_def};
+use ast::{MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use codemap::span;
pub fn expand_meta_deriving(cx: @ExtCtxt,
_span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item])
-> ~[@item] {
- use ast::{meta_list, meta_name_value, meta_word};
-
match mitem.node {
- meta_name_value(_, ref l) => {
+ MetaNameValue(_, ref l) => {
cx.span_err(l.span, "unexpected value in `deriving`");
in_items
}
- meta_word(_) | meta_list(_, []) => {
+ MetaWord(_) | MetaList(_, []) => {
cx.span_warn(mitem.span, "empty trait list in `deriving`");
in_items
}
- meta_list(_, ref titems) => {
+ MetaList(_, ref titems) => {
do titems.rev_iter().fold(in_items) |in_items, &titem| {
match titem.node {
- meta_name_value(tname, _) |
- meta_list(tname, _) |
- meta_word(tname) => {
+ MetaNameValue(tname, _) |
+ MetaList(tname, _) |
+ MetaWord(tname) => {
macro_rules! expand(($func:path) => ($func(cx, titem.span,
titem, in_items)));
match tname.as_slice() {
// except according to those terms.
use ast;
-use ast::{meta_item, item, expr, ident};
+use ast::{MetaItem, item, expr, ident};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::{AstBuilder, Duplicate};
pub fn expand_deriving_rand(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
// except according to those terms.
use ast;
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_to_str(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
pub fn expand_deriving_zero(cx: @ExtCtxt,
span: span,
- mitem: @meta_item,
+ mitem: @MetaItem,
in_items: ~[@item])
-> ~[@item] {
let trait_def = TraitDef {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{blk, crate, expr_, expr_mac, mac_invoc_tt};
+use ast::{Block, Crate, expr_, expr_mac, mac_invoc_tt};
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
use ast::{illegal_ctxt};
use ast;
use ast_util::{new_rename, new_mark, resolve};
use attr;
+use attr::AttrMetaMethods;
use codemap;
use codemap::{span, ExpnInfo, NameAndSpan};
use ext::base::*;
// the item into a new set of items.
let new_items = do vec::flat_map(module_.items) |item| {
do item.attrs.rev_iter().fold(~[*item]) |items, attr| {
- let mname = attr::get_attr_name(attr);
+ let mname = attr.name();
match (*extsbox).find(&intern(mname)) {
Some(@SE(ItemDecorator(dec_fn))) => {
}
// does this attribute list contain "macro_escape" ?
-pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool {
- attrs.iter().any(|attr| "macro_escape" == attr::get_attr_name(attr))
+pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "macro_escape")
}
// Support for item-position macro invocations, exactly the same
pub fn expand_block(extsbox: @mut SyntaxEnv,
_cx: @ExtCtxt,
- blk: &blk,
+ blk: &Block,
fld: @ast_fold,
- orig: @fn(&blk, @ast_fold) -> blk)
- -> blk {
+ orig: @fn(&Block, @ast_fold) -> Block)
+ -> Block {
// see note below about treatment of exts table
with_exts_frame!(extsbox,false,orig(blk,fld))
}
// add a bunch of macros as though they were placed at the head of the
// program (ick). This should run before cfg stripping.
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg, c: &crate) -> @crate {
+ cfg: ast::CrateConfig, c: &Crate) -> @Crate {
let sm = match parse_item_from_source_str(@"<std-macros>",
std_macros(),
cfg.clone(),
}
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg, c: &crate) -> @crate {
+ cfg: ast::CrateConfig, c: &Crate) -> @Crate {
// adding *another* layer of indirection here so that the block
// visitor can swap out one exts table for another for the duration
// of the block. The cleaner alternative would be to thread the
mod test {
use super::*;
use ast;
- use ast::{attribute_, attr_outer, meta_word, empty_ctxt};
+ use ast::{Attribute_, AttrOuter, MetaWord, empty_ctxt};
use codemap;
use codemap::spanned;
use parse;
assert_eq!(contains_macro_escape (attrs2),false);
}
- // make a "meta_word" outer attribute with the given name
- fn make_dummy_attr(s: @str) -> ast::attribute {
+ // make a MetaWord outer attribute with the given name
+ fn make_dummy_attr(s: @str) -> ast::Attribute {
spanned {
span:codemap::dummy_sp(),
- node: attribute_ {
- style: attr_outer,
+ node: Attribute_ {
+ style: AttrOuter,
value: @spanned {
- node: meta_word(s),
+ node: MetaWord(s),
span: codemap::dummy_sp(),
},
is_sugared_doc: false,
}
}
- impl ToSource for ast::blk {
+ impl ToSource for ast::Block {
fn to_source(&self) -> @str {
pprust::block_to_str(self, get_ident_interner()).to_managed()
}
}
}
- impl ToTokens for ast::blk {
+ impl ToTokens for ast::Block {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
pub fn parse_or_else(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader,
ms: ~[matcher]
) -> HashMap<ident, @named_match> {
pub fn parse(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader,
ms: &[matcher]
) -> parse_result {
use opt_vec::OptVec;
pub trait ast_fold {
- fn fold_crate(@self, &crate) -> crate;
+ fn fold_crate(@self, &Crate) -> Crate;
fn fold_view_item(@self, &view_item) -> view_item;
fn fold_foreign_item(@self, @foreign_item) -> @foreign_item;
fn fold_item(@self, @item) -> Option<@item>;
fn fold_struct_field(@self, @struct_field) -> @struct_field;
fn fold_item_underscore(@self, &item_) -> item_;
fn fold_method(@self, @method) -> @method;
- fn fold_block(@self, &blk) -> blk;
+ fn fold_block(@self, &Block) -> Block;
fn fold_stmt(@self, &stmt) -> Option<@stmt>;
fn fold_arm(@self, &arm) -> arm;
fn fold_pat(@self, @pat) -> @pat;
fn fold_variant(@self, &variant) -> variant;
fn fold_ident(@self, ident) -> ident;
fn fold_path(@self, &Path) -> Path;
- fn fold_local(@self, @local) -> @local;
+ fn fold_local(@self, @Local) -> @Local;
fn map_exprs(@self, @fn(@expr) -> @expr, &[@expr]) -> ~[@expr];
fn new_id(@self, node_id) -> node_id;
fn new_span(@self, span) -> span;
pub struct AstFoldFns {
//unlike the others, item_ is non-trivial
- fold_crate: @fn(&crate_, span, @ast_fold) -> (crate_, span),
+ fold_crate: @fn(&Crate, @ast_fold) -> Crate,
fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_,
fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item,
fold_item: @fn(@item, @ast_fold) -> Option<@item>,
fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field,
fold_item_underscore: @fn(&item_, @ast_fold) -> item_,
fold_method: @fn(@method, @ast_fold) -> @method,
- fold_block: @fn(&blk, @ast_fold) -> blk,
+ fold_block: @fn(&Block, @ast_fold) -> Block,
fold_stmt: @fn(&stmt_, span, @ast_fold) -> (Option<stmt_>, span),
fold_arm: @fn(&arm, @ast_fold) -> arm,
fold_pat: @fn(&pat_, span, @ast_fold) -> (pat_, span),
fold_variant: @fn(&variant_, span, @ast_fold) -> (variant_, span),
fold_ident: @fn(ident, @ast_fold) -> ident,
fold_path: @fn(&Path, @ast_fold) -> Path,
- fold_local: @fn(&local_, span, @ast_fold) -> (local_, span),
+ fold_local: @fn(@Local, @ast_fold) -> @Local,
map_exprs: @fn(@fn(@expr) -> @expr, &[@expr]) -> ~[@expr],
new_id: @fn(node_id) -> node_id,
new_span: @fn(span) -> span
/* some little folds that probably aren't useful to have in ast_fold itself*/
//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
-fn fold_meta_item_(mi: @meta_item, fld: @ast_fold) -> @meta_item {
+fn fold_meta_item_(mi: @MetaItem, fld: @ast_fold) -> @MetaItem {
@spanned {
node:
match mi.node {
- meta_word(id) => meta_word(id),
- meta_list(id, ref mis) => {
+ MetaWord(id) => MetaWord(id),
+ MetaList(id, ref mis) => {
let fold_meta_item = |x| fold_meta_item_(x, fld);
- meta_list(
+ MetaList(
id,
mis.map(|e| fold_meta_item(*e))
)
}
- meta_name_value(id, s) => {
- meta_name_value(id, s)
- }
+ MetaNameValue(id, s) => MetaNameValue(id, s)
},
span: fld.new_span(mi.span) }
}
//used in noop_fold_item and noop_fold_crate
-fn fold_attribute_(at: attribute, fld: @ast_fold) -> attribute {
+fn fold_attribute_(at: Attribute, fld: @ast_fold) -> Attribute {
spanned {
- node: ast::attribute_ {
+ span: fld.new_span(at.span),
+ node: ast::Attribute_ {
style: at.node.style,
value: fold_meta_item_(at.node.value, fld),
- is_sugared_doc: at.node.is_sugared_doc,
- },
- span: fld.new_span(at.span),
+ is_sugared_doc: at.node.is_sugared_doc
+ }
}
}
+
//used in noop_fold_foreign_item and noop_fold_fn_decl
fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
ast::arg {
lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
}
-pub fn noop_fold_crate(c: &crate_, fld: @ast_fold) -> crate_ {
+pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
let fold_meta_item = |x| fold_meta_item_(x, fld);
let fold_attribute = |x| fold_attribute_(x, fld);
- crate_ {
+ Crate {
module: fld.fold_mod(&c.module),
attrs: c.attrs.map(|x| fold_attribute(*x)),
config: c.config.map(|x| fold_meta_item(*x)),
+ span: fld.new_span(c.span),
}
}
}
-pub fn noop_fold_block(b: &blk, fld: @ast_fold) -> blk {
+pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
let view_items = b.view_items.map(|x| fld.fold_view_item(x));
let mut stmts = ~[];
for b.stmts.iter().advance |stmt| {
Some(stmt) => stmts.push(stmt)
}
}
- ast::blk {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: b.expr.map(|x| fld.fold_expr(*x)),
}
pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
- fn fold_field_(field: field, fld: @ast_fold) -> field {
- spanned {
- node: ast::field_ {
- ident: fld.fold_ident(field.node.ident),
- expr: fld.fold_expr(field.node.expr),
- },
+ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
+ ast::Field {
+ ident: fld.fold_ident(field.ident),
+ expr: fld.fold_expr(field.expr),
span: fld.new_span(field.span),
}
}
}
}
-fn noop_fold_local(l: &local_, fld: @ast_fold) -> local_ {
- local_ {
+fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
+ @Local {
is_mutbl: l.is_mutbl,
ty: fld.fold_ty(&l.ty),
pat: fld.fold_pat(l.pat),
init: l.init.map(|e| fld.fold_expr(*e)),
id: fld.new_id(l.id),
+ span: fld.new_span(l.span),
}
}
pub fn default_ast_fold() -> ast_fold_fns {
@AstFoldFns {
- fold_crate: wrap(noop_fold_crate),
+ fold_crate: noop_fold_crate,
fold_view_item: noop_fold_view_item,
fold_foreign_item: noop_fold_foreign_item,
fold_item: noop_fold_item,
fold_variant: wrap(noop_fold_variant),
fold_ident: noop_fold_ident,
fold_path: noop_fold_path,
- fold_local: wrap(noop_fold_local),
+ fold_local: noop_fold_local,
map_exprs: noop_map_exprs,
new_id: noop_id,
new_span: noop_span,
impl ast_fold for AstFoldFns {
/* naturally, a macro to write these would be nice */
- fn fold_crate(@self, c: &crate) -> crate {
- let (n, s) = (self.fold_crate)(&c.node, c.span, self as @ast_fold);
- spanned { node: n, span: (self.new_span)(s) }
+ fn fold_crate(@self, c: &Crate) -> Crate {
+ (self.fold_crate)(c, self as @ast_fold)
}
fn fold_view_item(@self, x: &view_item) -> view_item {
ast::view_item {
fn fold_method(@self, x: @method) -> @method {
(self.fold_method)(x, self as @ast_fold)
}
- fn fold_block(@self, x: &blk) -> blk {
+ fn fold_block(@self, x: &Block) -> Block {
(self.fold_block)(x, self as @ast_fold)
}
fn fold_stmt(@self, x: &stmt) -> Option<@stmt> {
fn fold_path(@self, x: &Path) -> Path {
(self.fold_path)(x, self as @ast_fold)
}
- fn fold_local(@self, x: @local) -> @local {
- let (n, s) = (self.fold_local)(&x.node, x.span, self as @ast_fold);
- @spanned { node: n, span: (self.new_span)(s) }
+ fn fold_local(@self, x: @Local) -> @Local {
+ (self.fold_local)(x, self as @ast_fold)
}
fn map_exprs(@self,
f: @fn(@expr) -> @expr,
}
pub trait AstFoldExtensions {
- fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute];
+ fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute];
}
impl AstFoldExtensions for @ast_fold {
- fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute] {
+ fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute] {
attrs.map(|x| fold_attribute_(*x, *self))
}
}
}
// this version doesn't care about getting comments or docstrings in.
- fn fake_print_crate(s: @pprust::ps, crate: &ast::crate) {
- pprust::print_mod(s, &crate.node.module, crate.node.attrs);
+ fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
+ pprust::print_mod(s, &crate.module, crate.attrs);
}
// change every identifier to "zz"
// a parser that can parse attributes.
pub trait parser_attr {
- fn parse_outer_attributes(&self) -> ~[ast::attribute];
- fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute;
+ fn parse_outer_attributes(&self) -> ~[ast::Attribute];
+ fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute;
fn parse_attribute_naked(
&self,
- style: ast::attr_style,
+ style: ast::AttrStyle,
lo: BytePos
- ) -> ast::attribute;
+ ) -> ast::Attribute;
fn parse_inner_attrs_and_next(&self) ->
- (~[ast::attribute], ~[ast::attribute]);
- fn parse_meta_item(&self) -> @ast::meta_item;
- fn parse_meta_seq(&self) -> ~[@ast::meta_item];
- fn parse_optional_meta(&self) -> ~[@ast::meta_item];
+ (~[ast::Attribute], ~[ast::Attribute]);
+ fn parse_meta_item(&self) -> @ast::MetaItem;
+ fn parse_meta_seq(&self) -> ~[@ast::MetaItem];
+ fn parse_optional_meta(&self) -> ~[@ast::MetaItem];
}
impl parser_attr for Parser {
// Parse attributes that appear before an item
- fn parse_outer_attributes(&self) -> ~[ast::attribute] {
- let mut attrs: ~[ast::attribute] = ~[];
+ fn parse_outer_attributes(&self) -> ~[ast::Attribute] {
+ let mut attrs: ~[ast::Attribute] = ~[];
loop {
match *self.token {
token::POUND => {
if self.look_ahead(1, |t| *t != token::LBRACKET) {
break;
}
- attrs.push(self.parse_attribute(ast::attr_outer));
+ attrs.push(self.parse_attribute(ast::AttrOuter));
}
token::DOC_COMMENT(s) => {
let attr = ::attr::mk_sugared_doc_attr(
self.span.lo,
self.span.hi
);
- if attr.node.style != ast::attr_outer {
+ if attr.node.style != ast::AttrOuter {
self.fatal("expected outer comment");
}
attrs.push(attr);
}
// matches attribute = # attribute_naked
- fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute {
+ fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute {
let lo = self.span.lo;
self.expect(&token::POUND);
return self.parse_attribute_naked(style, lo);
}
// matches attribute_naked = [ meta_item ]
- fn parse_attribute_naked(&self, style: ast::attr_style, lo: BytePos) ->
- ast::attribute {
+ fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) ->
+ ast::Attribute {
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
self.expect(&token::RBRACKET);
let hi = self.span.hi;
- return spanned(lo, hi, ast::attribute_ { style: style,
+ return spanned(lo, hi, ast::Attribute_ { style: style,
value: meta_item, is_sugared_doc: false }); }
// Parse attributes that appear after the opening of an item, each
// you can make the 'next' field an Option, but the result is going to be
// more useful as a vector.
fn parse_inner_attrs_and_next(&self) ->
- (~[ast::attribute], ~[ast::attribute]) {
- let mut inner_attrs: ~[ast::attribute] = ~[];
- let mut next_outer_attrs: ~[ast::attribute] = ~[];
+ (~[ast::Attribute], ~[ast::Attribute]) {
+ let mut inner_attrs: ~[ast::Attribute] = ~[];
+ let mut next_outer_attrs: ~[ast::Attribute] = ~[];
loop {
match *self.token {
token::POUND => {
// This is an extension
break;
}
- let attr = self.parse_attribute(ast::attr_inner);
+ let attr = self.parse_attribute(ast::AttrInner);
if *self.token == token::SEMI {
self.bump();
inner_attrs.push(attr);
// It's not really an inner attribute
let outer_attr =
spanned(attr.span.lo, attr.span.hi,
- ast::attribute_ { style: ast::attr_outer,
+ ast::Attribute_ { style: ast::AttrOuter,
value: attr.node.value,
is_sugared_doc: false });
next_outer_attrs.push(outer_attr);
self.span.hi
);
self.bump();
- if attr.node.style == ast::attr_inner {
+ if attr.node.style == ast::AttrInner {
inner_attrs.push(attr);
} else {
next_outer_attrs.push(attr);
// matches meta_item = IDENT
// | IDENT = lit
// | IDENT meta_seq
- fn parse_meta_item(&self) -> @ast::meta_item {
+ fn parse_meta_item(&self) -> @ast::MetaItem {
let lo = self.span.lo;
let name = self.id_to_str(self.parse_ident());
match *self.token {
self.bump();
let lit = self.parse_lit();
let hi = self.span.hi;
- @spanned(lo, hi, ast::meta_name_value(name, lit))
+ @spanned(lo, hi, ast::MetaNameValue(name, lit))
}
token::LPAREN => {
let inner_items = self.parse_meta_seq();
let hi = self.span.hi;
- @spanned(lo, hi, ast::meta_list(name, inner_items))
+ @spanned(lo, hi, ast::MetaList(name, inner_items))
}
_ => {
let hi = self.last_span.hi;
- @spanned(lo, hi, ast::meta_word(name))
+ @spanned(lo, hi, ast::MetaWord(name))
}
}
}
// matches meta_seq = ( COMMASEP(meta_item) )
- fn parse_meta_seq(&self) -> ~[@ast::meta_item] {
+ fn parse_meta_seq(&self) -> ~[@ast::MetaItem] {
self.parse_seq(&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_meta_item()).node
}
- fn parse_optional_meta(&self) -> ~[@ast::meta_item] {
+ fn parse_optional_meta(&self) -> ~[@ast::MetaItem] {
match *self.token {
token::LPAREN => self.parse_meta_seq(),
_ => ~[]
pub fn expr_is_simple_block(e: @ast::expr) -> bool {
match e.node {
ast::expr_block(
- ast::blk { rules: ast::default_blk, _ }
+ ast::Block { rules: ast::default_blk, _ }
) => true,
_ => false
}
s.starts_with("/*!")
}
-pub fn doc_comment_style(comment: &str) -> ast::attr_style {
+pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
assert!(is_doc_comment(comment));
if comment.starts_with("//!") || comment.starts_with("/*!") {
- ast::attr_inner
+ ast::AttrInner
} else {
- ast::attr_outer
+ ast::AttrOuter
}
}
pub fn parse_crate_from_file(
input: &Path,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
-) -> @ast::crate {
+) -> @ast::Crate {
new_parser_from_file(sess, /*bad*/ cfg.clone(), input).parse_crate_mod()
// why is there no p.abort_if_errors here?
}
pub fn parse_crate_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
-) -> @ast::crate {
+) -> @ast::Crate {
let p = new_parser_from_source_str(sess,
/*bad*/ cfg.clone(),
name,
pub fn parse_expr_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> @ast::expr {
let p = new_parser_from_source_str(
pub fn parse_item_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
- attrs: ~[ast::attribute],
+ cfg: ast::CrateConfig,
+ attrs: ~[ast::Attribute],
sess: @mut ParseSess
) -> Option<@ast::item> {
let p = new_parser_from_source_str(
pub fn parse_meta_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
-) -> @ast::meta_item {
+) -> @ast::MetaItem {
let p = new_parser_from_source_str(
sess,
cfg,
pub fn parse_stmt_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
- attrs: ~[ast::attribute],
+ cfg: ast::CrateConfig,
+ attrs: ~[ast::Attribute],
sess: @mut ParseSess
) -> @ast::stmt {
let p = new_parser_from_source_str(
pub fn parse_tts_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> ~[ast::token_tree] {
let p = new_parser_from_source_str(
f: &fn(&Parser) -> T,
name: @str, ss: codemap::FileSubstr,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> T {
let p = new_parser_from_source_substr(
// Create a new parser from a source string
pub fn new_parser_from_source_str(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
name: @str,
source: @str)
-> Parser {
// Create a new parser from a source string where the origin
// is specified as a substring of another file.
pub fn new_parser_from_source_substr(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
name: @str,
ss: codemap::FileSubstr,
source: @str)
/// if the file doesn't exist
pub fn new_parser_from_file(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
path: &Path
) -> Parser {
filemap_to_parser(sess,file_to_filemap(sess,path,None),cfg)
/// On an error, use the given span as the source of the problem.
pub fn new_sub_parser_from_file(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
path: &Path,
sp: span
) -> Parser {
/// Given a filemap and config, return a parser
pub fn filemap_to_parser(sess: @mut ParseSess,
filemap: @FileMap,
- cfg: ast::crate_cfg) -> Parser {
+ cfg: ast::CrateConfig) -> Parser {
tts_to_parser(sess,filemap_to_tts(sess,filemap),cfg)
}
// must preserve old name for now, because quote! from the *existing*
// compiler expands into it
pub fn new_parser_from_tts(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
tts: ~[ast::token_tree]) -> Parser {
tts_to_parser(sess,tts,cfg)
}
// given tts and cfg, produce a parser
pub fn tts_to_parser(sess: @mut ParseSess,
tts: ~[ast::token_tree],
- cfg: ast::crate_cfg) -> Parser {
+ cfg: ast::CrateConfig) -> Parser {
let trdr = lexer::new_tt_reader(sess.span_diagnostic, None, tts);
Parser(sess, cfg, trdr as @reader)
}
lifetimes: opt_vec::Empty,
ty_params: opt_vec::Empty,
},
- ast::blk {
+ ast::Block {
view_items: ~[],
stmts: ~[@spanned{
node: ast::stmt_semi(@ast::expr{
removed.
*/
-use ast::{expr, expr_lit, lit_nil, attribute};
+use ast::{expr, expr_lit, lit_nil, Attribute};
use ast;
use codemap::{span, respan};
use parse::parser::Parser;
ObsoleteNamedExternModule,
ObsoleteMultipleLocalDecl,
ObsoleteMutWithMultipleBindings,
+ ObsoleteExternVisibility,
}
impl to_bytes::IterBytes for ObsoleteSyntax {
fn eat_obsolete_ident(&self, ident: &str) -> bool;
fn try_parse_obsolete_struct_ctor(&self) -> bool;
fn try_parse_obsolete_with(&self) -> bool;
- fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool;
+ fn try_parse_obsolete_priv_section(&self, attrs: &[Attribute]) -> bool;
}
impl ParserObsoleteMethods for Parser {
"use multiple local declarations instead of e.g. `let mut \
(x, y) = ...`."
),
+ ObsoleteExternVisibility => (
+ "`pub extern` or `priv extern`",
+ "place the `pub` or `priv` on the individual external items \
+ instead"
+ )
};
self.report(sp, kind, kind_str, desc);
}
}
- pub fn try_parse_obsolete_priv_section(&self, attrs: &[attribute])
+ pub fn try_parse_obsolete_priv_section(&self, attrs: &[Attribute])
-> bool {
if self.is_keyword(keywords::Priv) &&
self.look_ahead(1, |t| *t == token::LBRACE) {
use ast::{TyBareFn, TyClosure};
use ast::{RegionTyParamBound, TraitTyParamBound};
use ast::{provided, public, purity};
-use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer};
-use ast::{bitand, bitor, bitxor, blk};
+use ast::{_mod, add, arg, arm, Attribute, bind_by_ref, bind_infer};
+use ast::{bitand, bitor, bitxor, Block};
use ast::{blk_check_mode, box};
-use ast::{crate, crate_cfg, decl, decl_item};
+use ast::{Crate, CrateConfig, decl, decl_item};
use ast::{decl_local, default_blk, deref, div, enum_def, explicit_self};
use ast::{expr, expr_, expr_addr_of, expr_match, expr_again};
use ast::{expr_assign, expr_assign_op, expr_binary, expr_block};
use ast::{expr_ret, expr_self, expr_struct, expr_tup, expr_unary};
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
use ast::{expr_vstore_slice, expr_vstore_box};
-use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
+use ast::{expr_vstore_mut_slice, expr_while, extern_fn, Field, fn_decl};
use ast::{expr_vstore_uniq, Onceness, Once, Many};
use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod};
use ast::{ident, impure_fn, inherited, item, item_, item_static};
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, m_const};
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, node_id, noreturn, not, pat, pat_box, pat_enum};
use parse::obsolete::{ObsoleteConstItem, ObsoleteFixedLengthVectorType};
use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl};
use parse::obsolete::{ObsoleteMutWithMultipleBindings};
-use parse::obsolete::{ParserObsoleteMethods};
+use parse::obsolete::{ObsoleteExternVisibility, ParserObsoleteMethods};
use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident};
use parse::token::{is_ident_or_path};
use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents};
}
type arg_or_capture_item = Either<arg, ()>;
-type item_info = (ident, item_, Option<~[attribute]>);
+type item_info = (ident, item_, Option<~[Attribute]>);
pub enum item_or_view_item {
// Indicates a failure to parse any kind of item. The attributes are
// returned.
- iovi_none(~[attribute]),
+ iovi_none(~[Attribute]),
iovi_item(@item),
iovi_foreign_item(@foreign_item),
iovi_view_item(view_item)
)
-fn maybe_append(lhs: ~[attribute], rhs: Option<~[attribute]>)
- -> ~[attribute] {
+fn maybe_append(lhs: ~[Attribute], rhs: Option<~[Attribute]>)
+ -> ~[Attribute] {
match rhs {
None => lhs,
Some(ref attrs) => vec::append(lhs, (*attrs))
struct ParsedItemsAndViewItems {
- attrs_remaining: ~[attribute],
+ attrs_remaining: ~[Attribute],
view_items: ~[view_item],
items: ~[@item],
foreign_items: ~[@foreign_item]
/* ident is handled by common.rs */
pub fn Parser(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader)
-> Parser {
let tok0 = rdr.next_token();
// ooh, nasty mutable fields everywhere....
pub struct Parser {
sess: @mut ParseSess,
- cfg: crate_cfg,
+ cfg: CrateConfig,
// the current token:
token: @mut token::Token,
// the span of the current token:
// consume token 'tok' if it exists. Returns true if the given
// token was present, false otherwise.
pub fn eat(&self, tok: &token::Token) -> bool {
- return if *self.token == *tok { self.bump(); true } else { false };
+ let is_present = *self.token == *tok;
+ if is_present { self.bump() }
+ is_present
}
pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
// with a single > and continue. If a GT is not seen,
// signal an error.
pub fn expect_gt(&self) {
- if *self.token == token::GT {
- self.bump();
- } else if *self.token == token::BINOP(token::SHR) {
- self.replace_token(
+ match *self.token {
+ token::GT => self.bump(),
+ token::BINOP(token::SHR) => self.replace_token(
token::GT,
self.span.lo + BytePos(1u),
self.span.hi
- );
- } else {
- let mut s: ~str = ~"expected `";
- s.push_str(self.token_to_str(&token::GT));
- s.push_str("`, found `");
- s.push_str(self.this_token_to_str());
- s.push_str("`");
- self.fatal(s);
+ ),
+ _ => self.fatal(fmt!("expected `%s`, found `%s`",
+ self.token_to_str(&token::GT),
+ self.this_token_to_str()))
}
}
}
pub fn is_named_argument(&self) -> bool {
- let offset = if *self.token == token::BINOP(token::AND) {
- 1
- } else if *self.token == token::BINOP(token::MINUS) {
- 1
- } else if *self.token == token::ANDAND {
- 1
- } else if *self.token == token::BINOP(token::PLUS) {
- if self.look_ahead(1, |t| *t == token::BINOP(token::PLUS)) {
- 2
- } else {
- 1
- }
- } else { 0 };
+ let offset = match *self.token {
+ token::BINOP(token::AND) => 1,
+ token::BINOP(token::MINUS) => 1,
+ token::ANDAND => 1,
+ token::BINOP(token::PLUS) => {
+ if self.look_ahead(1, |t| *t == token::BINOP(token::PLUS)) {
+ 2
+ } else {
+ 1
+ }
+ },
+ _ => 0
+ };
+
if offset == 0 {
is_plain_ident(&*self.token)
&& self.look_ahead(1, |t| *t == token::COLON)
}
// parse ident COLON expr
- pub fn parse_field(&self) -> field {
+ pub fn parse_field(&self) -> Field {
let lo = self.span.lo;
let i = self.parse_ident();
self.expect(&token::COLON);
let e = self.parse_expr();
- spanned(lo, e.span.hi, ast::field_ {
+ ast::Field {
ident: i,
- expr: e
- })
+ expr: e,
+ span: mk_sp(lo, e.span.hi),
+ }
}
pub fn mk_expr(&self, lo: BytePos, hi: BytePos, node: expr_) -> @expr {
// parse an optional separator followed by a kleene-style
// repetition token (+ or *).
pub fn parse_sep_and_zerok(&self) -> (Option<token::Token>, bool) {
- if *self.token == token::BINOP(token::STAR)
- || *self.token == token::BINOP(token::PLUS) {
- let zerok = *self.token == token::BINOP(token::STAR);
- self.bump();
- (None, zerok)
- } else {
- let sep = self.bump_and_get();
- if *self.token == token::BINOP(token::STAR)
- || *self.token == token::BINOP(token::PLUS) {
- let zerok = *self.token == token::BINOP(token::STAR);
- self.bump();
- (Some(sep), zerok)
- } else {
- self.fatal("expected `*` or `+`");
+ fn parse_zerok(parser: &Parser) -> Option<bool> {
+ match *parser.token {
+ token::BINOP(token::STAR) | token::BINOP(token::PLUS) => {
+ let zerok = *parser.token == token::BINOP(token::STAR);
+ parser.bump();
+ Some(zerok)
+ },
+ _ => None
}
+ };
+
+ match parse_zerok(self) {
+ Some(zerok) => return (None, zerok),
+ None => {}
+ }
+
+ let separator = self.bump_and_get();
+ match parse_zerok(self) {
+ Some(zerok) => (Some(separator), zerok),
+ None => self.fatal("expected `*` or `+`")
}
}
// parse an expression of binops of at least min_prec precedence
pub fn parse_more_binops(&self, lhs: @expr, min_prec: uint) -> @expr {
if self.expr_is_complete(lhs) { return lhs; }
- if token::BINOP(token::OR) == *self.token &&
- (*self.restriction == RESTRICT_NO_BAR_OP ||
- *self.restriction == RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) {
- lhs
- } else if token::OROR == *self.token &&
- *self.restriction == RESTRICT_NO_BAR_OR_DOUBLEBAR_OP {
- lhs
- } else {
- let cur_opt = token_to_binop(self.token);
- match cur_opt {
- Some(cur_op) => {
- let cur_prec = operator_prec(cur_op);
- if cur_prec > min_prec {
- self.bump();
- let expr = self.parse_prefix_expr();
- let rhs = self.parse_more_binops(expr, cur_prec);
- let bin = self.mk_expr(lhs.span.lo, rhs.span.hi,
- self.mk_binary(cur_op, lhs, rhs));
- self.parse_more_binops(bin, min_prec)
- } else {
- lhs
- }
+
+ // Prevent dynamic borrow errors later on by limiting the
+ // scope of the borrows.
+ {
+ let token: &token::Token = self.token;
+ let restriction: &restriction = self.restriction;
+ match (token, restriction) {
+ (&token::BINOP(token::OR), &RESTRICT_NO_BAR_OP) => return lhs,
+ (&token::BINOP(token::OR),
+ &RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs,
+ (&token::OROR, &RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs,
+ _ => { }
+ }
+ }
+
+ let cur_opt = token_to_binop(self.token);
+ match cur_opt {
+ Some(cur_op) => {
+ let cur_prec = operator_prec(cur_op);
+ if cur_prec > min_prec {
+ self.bump();
+ let expr = self.parse_prefix_expr();
+ let rhs = self.parse_more_binops(expr, cur_prec);
+ let bin = self.mk_expr(lhs.span.lo, rhs.span.hi,
+ self.mk_binary(cur_op, lhs, rhs));
+ self.parse_more_binops(bin, min_prec)
+ } else {
+ lhs
}
- None => {
- if as_prec > min_prec && self.eat_keyword(keywords::As) {
- let rhs = self.parse_ty(true);
- let _as = self.mk_expr(lhs.span.lo,
- rhs.span.hi,
- expr_cast(lhs, rhs));
- self.parse_more_binops(_as, min_prec)
- } else {
- lhs
- }
+ }
+ None => {
+ if as_prec > min_prec && self.eat_keyword(keywords::As) {
+ let rhs = self.parse_ty(true);
+ let _as = self.mk_expr(lhs.span.lo,
+ rhs.span.hi,
+ expr_cast(lhs, rhs));
+ self.parse_more_binops(_as, min_prec)
+ } else {
+ lhs
}
}
}
token::BINOPEQ(op) => {
self.bump();
let rhs = self.parse_expr();
- let aop;
- match op {
- token::PLUS => aop = add,
- token::MINUS => aop = subtract,
- token::STAR => aop = mul,
- token::SLASH => aop = div,
- token::PERCENT => aop = rem,
- token::CARET => aop = bitxor,
- token::AND => aop = bitand,
- token::OR => aop = bitor,
- token::SHL => aop = shl,
- token::SHR => aop = shr
- }
+ let aop = match op {
+ token::PLUS => add,
+ token::MINUS => subtract,
+ token::STAR => mul,
+ token::SLASH => div,
+ token::PERCENT => rem,
+ token::CARET => bitxor,
+ token::AND => bitand,
+ token::OR => bitor,
+ token::SHL => shl,
+ token::SHR => shr
+ };
self.mk_expr(lo, rhs.span.hi,
self.mk_assign_op(aop, lhs, rhs))
}
let lo = self.last_span.lo;
let decl = parse_decl();
let body = parse_body();
- let fakeblock = ast::blk {
+ let fakeblock = ast::Block {
view_items: ~[],
stmts: ~[],
expr: Some(body),
self.eat(&token::COMMA);
}
- let blk = ast::blk {
+ let blk = ast::Block {
view_items: ~[],
stmts: ~[],
expr: Some(expr),
token::LBRACE => {
self.bump();
let (_, _) = self.parse_pat_fields();
- hi = self.span.hi;
self.bump();
self.obsolete(*self.span, ObsoleteRecordPattern);
pat = pat_wild;
}
}
if fields.len() == 1 { self.expect(&token::COMMA); }
- hi = self.span.hi;
self.expect(&token::RPAREN);
pat = pat_tup(fields);
}
self.bump();
let (before, slice, after) =
self.parse_pat_vec_elements();
- hi = self.span.hi;
+
self.expect(&token::RBRACKET);
pat = ast::pat_vec(before, slice, after);
hi = self.last_span.hi;
}
// parse a local variable declaration
- fn parse_local(&self, is_mutbl: bool) -> @local {
+ fn parse_local(&self, is_mutbl: bool) -> @Local {
let lo = self.span.lo;
let pat = self.parse_pat();
};
if self.eat(&token::COLON) { ty = self.parse_ty(false); }
let init = self.parse_initializer();
- @spanned(
- lo,
- self.last_span.hi,
- ast::local_ {
- is_mutbl: is_mutbl,
- ty: ty,
- pat: pat,
- init: init,
- id: self.get_id(),
- }
- )
+ @ast::Local {
+ is_mutbl: is_mutbl,
+ ty: ty,
+ pat: pat,
+ init: init,
+ id: self.get_id(),
+ span: mk_sp(lo, self.last_span.hi),
+ }
}
// parse a "let" stmt
// parse a structure field
fn parse_name_and_ty(&self,
pr: visibility,
- attrs: ~[attribute]) -> @struct_field {
+ attrs: ~[Attribute]) -> @struct_field {
let lo = self.span.lo;
if !is_plain_ident(&*self.token) {
self.fatal("expected ident");
// parse a statement. may include decl.
// precondition: any attributes are parsed already
- pub fn parse_stmt(&self, item_attrs: ~[attribute]) -> @stmt {
+ pub fn parse_stmt(&self, item_attrs: ~[Attribute]) -> @stmt {
maybe_whole!(self, nt_stmt);
fn check_expected_item(p: &Parser, found_attrs: bool) {
}
// parse a block. No inner attrs are allowed.
- pub fn parse_block(&self) -> blk {
+ pub fn parse_block(&self) -> Block {
maybe_whole!(self, nt_block);
let lo = self.span.lo;
// parse a block. Inner attrs are allowed.
fn parse_inner_attrs_and_block(&self)
- -> (~[attribute], blk) {
+ -> (~[Attribute], Block) {
maybe_whole!(pair_empty self, nt_block);
// I guess that also means "already parsed the 'impure'" if
// necessary, and this should take a qualifier.
// some blocks start with "#{"...
- fn parse_block_tail(&self, lo: BytePos, s: blk_check_mode) -> blk {
+ fn parse_block_tail(&self, lo: BytePos, s: blk_check_mode) -> Block {
self.parse_block_tail_(lo, s, ~[])
}
// parse the rest of a block expression or function body
fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode,
- first_item_attrs: ~[attribute]) -> blk {
+ first_item_attrs: ~[Attribute]) -> Block {
let mut stmts = ~[];
let mut expr = None;
let hi = self.span.hi;
self.bump();
- ast::blk {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: expr,
}
// parse a generic use site
- fn parse_generic_values(
- &self) -> (OptVec<ast::Lifetime>, ~[Ty])
- {
+ fn parse_generic_values(&self) -> (OptVec<ast::Lifetime>, ~[Ty]) {
if !self.eat(&token::LT) {
(opt_vec::Empty, ~[])
} else {
}
}
- fn parse_generic_values_after_lt(
- &self) -> (OptVec<ast::Lifetime>, ~[Ty])
- {
+ fn parse_generic_values_after_lt(&self) -> (OptVec<ast::Lifetime>, ~[Ty]) {
let lifetimes = self.parse_lifetimes();
let result = self.parse_seq_to_gt(
Some(token::COMMA),
}
fn is_self_ident(&self) -> bool {
- match *self.token {
- token::IDENT(id, false) if id == special_idents::self_
- => true,
- _ => false
- }
+ *self.token == token::IDENT(special_idents::self_, false)
}
fn expect_self_ident(&self) {
fn mk_item(&self, lo: BytePos, hi: BytePos, ident: ident,
node: item_, vis: visibility,
- attrs: ~[attribute]) -> @item {
+ attrs: ~[Attribute]) -> @item {
@ast::item { ident: ident,
attrs: attrs,
id: self.get_id(),
// parse a structure field declaration
pub fn parse_single_struct_field(&self,
vis: visibility,
- attrs: ~[attribute])
+ attrs: ~[Attribute])
-> @struct_field {
if self.eat_obsolete_ident("let") {
self.obsolete(*self.last_span, ObsoleteLet);
// attributes (of length 0 or 1), parse all of the items in a module
fn parse_mod_items(&self,
term: token::Token,
- first_item_attrs: ~[attribute])
+ first_item_attrs: ~[Attribute])
-> _mod {
// parse all of the items up to closing or an attribute.
// view items are legal here.
}
// parse a `mod <foo> { ... }` or `mod <foo>;` item
- fn parse_item_mod(&self, outer_attrs: &[ast::attribute]) -> item_info {
+ fn parse_item_mod(&self, outer_attrs: &[Attribute]) -> item_info {
let id_span = *self.span;
let id = self.parse_ident();
if *self.token == token::SEMI {
}
}
- fn push_mod_path(&self, id: ident, attrs: &[ast::attribute]) {
+ fn push_mod_path(&self, id: ident, attrs: &[Attribute]) {
let default_path = token::interner_get(id.name);
- let file_path = match ::attr::first_attr_value_str_by_name(
- attrs, "path") {
-
+ let file_path = match ::attr::first_attr_value_str_by_name(attrs,
+ "path") {
Some(d) => d,
None => default_path
};
// read a module from a source file.
fn eval_src_mod(&self,
id: ast::ident,
- outer_attrs: &[ast::attribute],
+ outer_attrs: &[ast::Attribute],
id_sp: span)
- -> (ast::item_, ~[ast::attribute]) {
+ -> (ast::item_, ~[ast::Attribute]) {
let prefix = Path(self.sess.cm.span_to_filename(*self.span));
let prefix = prefix.dir_path();
let mod_path_stack = &*self.mod_path_stack;
let mod_path = Path(".").push_many(*mod_path_stack);
- let default_path = token::interner_get(id.name).to_owned() + ".rs";
+ let dir_path = prefix.push_many(mod_path.components);
let file_path = match ::attr::first_attr_value_str_by_name(
outer_attrs, "path") {
Some(d) => {
let path = Path(d);
if !path.is_absolute {
- mod_path.push(d)
+ dir_path.push(d)
} else {
path
}
}
- None => mod_path.push(default_path)
+ None => {
+ let mod_name = token::interner_get(id.name).to_owned();
+ let default_path_str = mod_name + ".rs";
+ let secondary_path_str = mod_name + "/mod.rs";
+ let default_path = dir_path.push(default_path_str);
+ let secondary_path = dir_path.push(secondary_path_str);
+ let default_exists = default_path.exists();
+ let secondary_exists = secondary_path.exists();
+ match (default_exists, secondary_exists) {
+ (true, false) => default_path,
+ (false, true) => secondary_path,
+ (false, false) => {
+ self.span_fatal(id_sp, fmt!("file not found for module `%s`", mod_name));
+ }
+ (true, true) => {
+ self.span_fatal(id_sp,
+ fmt!("file for module `%s` found at both %s and %s",
+ mod_name, default_path_str, secondary_path_str));
+ }
+ }
+ }
};
- self.eval_src_mod_from_path(prefix,
- file_path,
+ self.eval_src_mod_from_path(file_path,
outer_attrs.to_owned(),
id_sp)
}
fn eval_src_mod_from_path(&self,
- prefix: Path,
path: Path,
- outer_attrs: ~[ast::attribute],
- id_sp: span) -> (ast::item_, ~[ast::attribute]) {
-
- let full_path = if path.is_absolute {
- path
- } else {
- prefix.push_many(path.components)
- };
- let full_path = full_path.normalize();
+ outer_attrs: ~[ast::Attribute],
+ id_sp: span) -> (ast::item_, ~[ast::Attribute]) {
+ let full_path = path.normalize();
let maybe_i = do self.sess.included_mod_stack.iter().position |p| { *p == full_path };
match maybe_i {
let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs);
self.sess.included_mod_stack.pop();
return (ast::item_mod(m0), mod_attrs);
-
- fn cdir_path_opt(default: @str, attrs: ~[ast::attribute]) -> @str {
- match ::attr::first_attr_value_str_by_name(attrs, "path") {
- Some(d) => d,
- None => default
- }
- }
}
// parse a function declaration from a foreign module
- fn parse_item_foreign_fn(&self, attrs: ~[attribute]) -> @foreign_item {
+ fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item {
let lo = self.span.lo;
let vis = self.parse_visibility();
let purity = self.parse_fn_purity();
// parse a const definition from a foreign module
fn parse_item_foreign_const(&self, vis: ast::visibility,
- attrs: ~[attribute]) -> @foreign_item {
+ attrs: ~[Attribute]) -> @foreign_item {
let lo = self.span.lo;
// XXX: Obsolete; remove after snap.
fn parse_foreign_mod_items(&self,
sort: ast::foreign_mod_sort,
abis: AbiSet,
- first_item_attrs: ~[attribute])
+ first_item_attrs: ~[Attribute])
-> foreign_mod {
let ParsedItemsAndViewItems {
attrs_remaining: attrs_remaining,
lo: BytePos,
opt_abis: Option<AbiSet>,
visibility: visibility,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
items_allowed: bool)
-> item_or_view_item {
let mut must_be_named_mod = false;
self.obsolete(*self.last_span, ObsoleteNamedExternModule);
}
+ // Do not allow visibility to be specified.
+ if visibility != ast::inherited {
+ self.obsolete(*self.span, ObsoleteExternVisibility);
+ }
+
let abis = opt_abis.get_or_default(AbiSet::C());
let (inner, next) = self.parse_inner_attrs_and_next();
let m = self.parse_foreign_mod_items(sort, abis, next);
self.expect(&token::RBRACE);
- return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
- item_foreign_mod(m), visibility,
- maybe_append(attrs,
- Some(inner))));
+ return iovi_item(self.mk_item(lo,
+ self.last_span.hi,
+ ident,
+ item_foreign_mod(m),
+ public,
+ maybe_append(attrs, Some(inner))));
}
if opt_abis.is_some() {
// NB: this function no longer parses the items inside an
// extern mod.
fn parse_item_or_view_item(&self,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
macros_allowed: bool)
-> item_or_view_item {
maybe_whole!(iovi self, nt_item);
// parse a foreign item; on failure, return iovi_none.
fn parse_foreign_item(&self,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
macros_allowed: bool)
-> item_or_view_item {
maybe_whole!(iovi self, nt_item);
// this is the fall-through for parsing items.
fn parse_macro_use_or_failure(
&self,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
macros_allowed: bool,
lo : BytePos,
visibility : visibility
return iovi_none(attrs);
}
- pub fn parse_item(&self, attrs: ~[attribute]) -> Option<@ast::item> {
+ pub fn parse_item(&self, attrs: ~[Attribute]) -> Option<@ast::item> {
match self.parse_item_or_view_item(attrs, true) {
- iovi_none(attrs) =>
- None,
+ iovi_none(_) => None,
iovi_view_item(_) =>
self.fatal("view items are not allowed here"),
iovi_foreign_item(_) =>
self.fatal("foreign items are not allowed here"),
- iovi_item(item) =>
- Some(item)
+ iovi_item(item) => Some(item)
}
}
// parse a view item.
fn parse_view_item(
&self,
- attrs: ~[attribute],
+ attrs: ~[Attribute],
vis: visibility
) -> view_item {
let lo = self.span.lo;
// - mod_items uses extern_mod_allowed = true
// - block_tail_ uses extern_mod_allowed = false
fn parse_items_and_view_items(&self,
- first_item_attrs: ~[attribute],
+ first_item_attrs: ~[Attribute],
mut extern_mod_allowed: bool,
macros_allowed: bool)
-> ParsedItemsAndViewItems {
// First, parse view items.
let mut view_items : ~[ast::view_item] = ~[];
let mut items = ~[];
- let mut done = false;
+
// I think this code would probably read better as a single
// loop with a mutable three-state-variable (for extern mods,
// view items, and regular items) ... except that because
// Parses a sequence of foreign items. Stops when it finds program
// text that can't be parsed as an item
- fn parse_foreign_items(&self, first_item_attrs: ~[attribute],
+ fn parse_foreign_items(&self, first_item_attrs: ~[Attribute],
macros_allowed: bool)
-> ParsedItemsAndViewItems {
let mut attrs = vec::append(first_item_attrs,
// Parses a source module as a crate. This is the main
// entry point for the parser.
- pub fn parse_crate_mod(&self) -> @crate {
+ pub fn parse_crate_mod(&self) -> @Crate {
let lo = self.span.lo;
// parse the crate's inner attrs, maybe (oops) one
// of the attrs of an item:
let first_item_outer_attrs = next;
// parse the items inside the crate:
let m = self.parse_mod_items(token::EOF, first_item_outer_attrs);
- @spanned(lo, self.span.lo,
- ast::crate_ { module: m,
- attrs: inner,
- config: self.cfg.clone() })
+
+ @ast::Crate {
+ module: m,
+ attrs: inner,
+ config: self.cfg.clone(),
+ span: mk_sp(lo, self.span.lo)
+ }
}
pub fn parse_str(&self) -> @str {
/// For interpolation during macro expansion.
pub enum nonterminal {
nt_item(@ast::item),
- nt_block(ast::blk),
+ nt_block(ast::Block),
nt_stmt(@ast::stmt),
nt_pat( @ast::pat),
nt_expr(@ast::expr),
// if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one.
pub fn get_ident_interner() -> @ident_interner {
- #[cfg(not(stage0))]
static key: local_data::Key<@@::parse::token::ident_interner> =
&local_data::Key;
- #[cfg(stage0)]
- fn key(_: @@::parse::token::ident_interner) {}
match local_data::get(key, |k| k.map(|&k| *k)) {
Some(interner) => *interner,
None => {
use ast_util;
use opt_vec::OptVec;
use opt_vec;
-use attr;
+use attr::{AttrMetaMethods, AttributeMethods};
use codemap::{CodeMap, BytePos};
use codemap;
use diagnostic;
// The @ps is stored here to prevent recursive type.
pub enum ann_node<'self> {
- node_block(@ps, &'self ast::blk),
+ node_block(@ps, &'self ast::Block),
node_item(@ps, &'self ast::item),
node_expr(@ps, &'self ast::expr),
node_pat(@ps, &'self ast::pat),
pub fn print_crate(cm: @CodeMap,
intr: @ident_interner,
span_diagnostic: @diagnostic::span_handler,
- crate: &ast::crate,
+ crate: &ast::Crate,
filename: @str,
in: @io::Reader,
out: @io::Writer,
print_crate_(s, crate);
}
-pub fn print_crate_(s: @ps, crate: &ast::crate) {
- print_mod(s, &crate.node.module, crate.node.attrs);
+pub fn print_crate_(s: @ps, crate: &ast::Crate) {
+ print_mod(s, &crate.module, crate.attrs);
print_remaining_comments(s);
eof(s.s);
}
}
}
-pub fn block_to_str(blk: &ast::blk, intr: @ident_interner) -> ~str {
+pub fn block_to_str(blk: &ast::Block, intr: @ident_interner) -> ~str {
do io::with_str_writer |wr| {
let s = rust_printer(wr, intr);
// containing cbox, will be closed by print-block at }
}
}
-pub fn meta_item_to_str(mi: &ast::meta_item, intr: @ident_interner) -> ~str {
+pub fn meta_item_to_str(mi: &ast::MetaItem, intr: @ident_interner) -> ~str {
to_str(mi, print_meta_item, intr)
}
-pub fn attribute_to_str(attr: &ast::attribute, intr: @ident_interner) -> ~str {
+pub fn attribute_to_str(attr: &ast::Attribute, intr: @ident_interner) -> ~str {
to_str(attr, print_attribute, intr)
}
commasep_cmnt(s, b, exprs, |p, &e| print_expr(p, e), |e| e.span);
}
-pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::attribute]) {
+pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::Attribute]) {
print_inner_attributes(s, attrs);
for _mod.view_items.iter().advance |vitem| {
print_view_item(s, vitem);
}
pub fn print_foreign_mod(s: @ps, nmod: &ast::foreign_mod,
- attrs: &[ast::attribute]) {
+ attrs: &[ast::Attribute]) {
print_inner_attributes(s, attrs);
for nmod.view_items.iter().advance |vitem| {
print_view_item(s, vitem);
match item.node {
ast::foreign_item_fn(ref decl, purity, ref generics) => {
print_fn(s, decl, Some(purity), AbiSet::Rust(), item.ident, generics, None,
- ast::inherited);
+ item.vis);
end(s); // end head-ibox
word(s.s, ";");
end(s); // end the outer fn box
}
ast::foreign_item_static(ref t, m) => {
- head(s, "static");
+ head(s, visibility_qualified(item.vis, "static"));
if m {
word_space(s, "mut");
}
bclose(s, item.span);
}
ast::item_foreign_mod(ref nmod) => {
- head(s, visibility_qualified(item.vis, "extern"));
+ head(s, "extern");
word_nbsp(s, nmod.abis.to_str());
match nmod.sort {
ast::named => {
print_block_with_attrs(s, &meth.body, meth.attrs);
}
-pub fn print_outer_attributes(s: @ps, attrs: &[ast::attribute]) {
+pub fn print_outer_attributes(s: @ps, attrs: &[ast::Attribute]) {
let mut count = 0;
for attrs.iter().advance |attr| {
match attr.node.style {
- ast::attr_outer => { print_attribute(s, attr); count += 1; }
+ ast::AttrOuter => { print_attribute(s, attr); count += 1; }
_ => {/* fallthrough */ }
}
}
if count > 0 { hardbreak_if_not_bol(s); }
}
-pub fn print_inner_attributes(s: @ps, attrs: &[ast::attribute]) {
+pub fn print_inner_attributes(s: @ps, attrs: &[ast::Attribute]) {
let mut count = 0;
for attrs.iter().advance |attr| {
match attr.node.style {
- ast::attr_inner => {
+ ast::AttrInner => {
print_attribute(s, attr);
if !attr.node.is_sugared_doc {
word(s.s, ";");
if count > 0 { hardbreak_if_not_bol(s); }
}
-pub fn print_attribute(s: @ps, attr: &ast::attribute) {
+pub fn print_attribute(s: @ps, attr: &ast::Attribute) {
hardbreak_if_not_bol(s);
maybe_print_comment(s, attr.span.lo);
if attr.node.is_sugared_doc {
- let meta = attr::attr_meta(*attr);
- let comment = attr::get_meta_item_value_str(meta).get();
+ let comment = attr.value_str().get();
word(s.s, comment);
} else {
word(s.s, "#[");
- print_meta_item(s, attr.node.value);
+ print_meta_item(s, attr.meta());
word(s.s, "]");
}
}
maybe_print_trailing_comment(s, st.span, None);
}
-pub fn print_block(s: @ps, blk: &ast::blk) {
+pub fn print_block(s: @ps, blk: &ast::Block) {
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
}
-pub fn print_block_unclosed(s: @ps, blk: &ast::blk) {
+pub fn print_block_unclosed(s: @ps, blk: &ast::Block) {
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, &[],
false);
}
-pub fn print_block_unclosed_indent(s: @ps, blk: &ast::blk, indented: uint) {
+pub fn print_block_unclosed_indent(s: @ps, blk: &ast::Block, indented: uint) {
print_possibly_embedded_block_(s, blk, block_normal, indented, &[],
false);
}
pub fn print_block_with_attrs(s: @ps,
- blk: &ast::blk,
- attrs: &[ast::attribute]) {
+ blk: &ast::Block,
+ attrs: &[ast::Attribute]) {
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
true);
}
pub enum embed_type { block_block_fn, block_normal, }
pub fn print_possibly_embedded_block(s: @ps,
- blk: &ast::blk,
+ blk: &ast::Block,
embedded: embed_type,
indented: uint) {
print_possibly_embedded_block_(
}
pub fn print_possibly_embedded_block_(s: @ps,
- blk: &ast::blk,
+ blk: &ast::Block,
embedded: embed_type,
indented: uint,
- attrs: &[ast::attribute],
+ attrs: &[ast::Attribute],
close_box: bool) {
match blk.rules {
ast::unsafe_blk => word_space(s, "unsafe"),
(s.ann.post)(ann_node);
}
-pub fn print_if(s: @ps, test: &ast::expr, blk: &ast::blk,
+pub fn print_if(s: @ps, test: &ast::expr, blk: &ast::Block,
elseopt: Option<@ast::expr>, chk: bool) {
head(s, "if");
if chk { word_nbsp(s, "check"); }
}
pub fn print_expr(s: @ps, expr: &ast::expr) {
- fn print_field(s: @ps, field: &ast::field) {
+ fn print_field(s: @ps, field: &ast::Field) {
ibox(s, indent_unit);
- print_ident(s, field.node.ident);
+ print_ident(s, field.ident);
word_space(s, ":");
- print_expr(s, field.node.expr);
+ print_expr(s, field.expr);
end(s);
}
- fn get_span(field: &ast::field) -> codemap::span { return field.span; }
+ fn get_span(field: &ast::Field) -> codemap::span { return field.span; }
maybe_print_comment(s, expr.span.lo);
ibox(s, indent_unit);
end(s);
}
-pub fn print_local_decl(s: @ps, loc: &ast::local) {
- print_pat(s, loc.node.pat);
- match loc.node.ty.node {
+pub fn print_local_decl(s: @ps, loc: &ast::Local) {
+ print_pat(s, loc.pat);
+ match loc.ty.node {
ast::ty_infer => (),
- _ => { word_space(s, ":"); print_type(s, &loc.node.ty); }
+ _ => { word_space(s, ":"); print_type(s, &loc.ty); }
}
}
ibox(s, indent_unit);
word_nbsp(s, "let");
- if loc.node.is_mutbl {
+ if loc.is_mutbl {
word_nbsp(s, "mut");
}
- fn print_local(s: @ps, loc: &ast::local) {
+ fn print_local(s: @ps, loc: &ast::Local) {
ibox(s, indent_unit);
print_local_decl(s, loc);
end(s);
- match loc.node.init {
+ match loc.init {
Some(init) => {
nbsp(s);
word_space(s, "=");
word(s.s, ident_to_str(&ident));
}
-pub fn print_for_decl(s: @ps, loc: &ast::local, coll: &ast::expr) {
+pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::expr) {
print_local_decl(s, loc);
space(s.s);
word_space(s, "in");
}
}
-pub fn print_meta_item(s: @ps, item: &ast::meta_item) {
+pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
ibox(s, indent_unit);
match item.node {
- ast::meta_word(name) => word(s.s, name),
- ast::meta_name_value(name, value) => {
+ ast::MetaWord(name) => word(s.s, name),
+ ast::MetaNameValue(name, value) => {
word_space(s, name);
word_space(s, "=");
print_literal(s, @value);
}
- ast::meta_list(name, ref items) => {
+ ast::MetaList(name, ref items) => {
word(s.s, name);
popen(s);
commasep(s,
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
-#[deny(deprecated_pattern)];
-
extern mod extra;
pub mod util {
}
// when traits can extend traits, we should extend index<uint,T> to get []
-impl<T:Eq + IterBytes + Hash + Freeze + Clone> Interner<T> {
+impl<T:Eq + IterBytes + Hash + Freeze + Clone + 'static> Interner<T> {
pub fn new() -> Interner<T> {
Interner {
map: @mut HashMap::new(),
p
}
-pub fn string_to_crate (source_str : @str) -> @ast::crate {
+pub fn string_to_crate (source_str : @str) -> @ast::Crate {
string_to_parser(source_str).parse_crate_mod()
}
visit_view_item: @fn(&view_item, (E, vt<E>)),
visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
visit_item: @fn(@item, (E, vt<E>)),
- visit_local: @fn(@local, (E, vt<E>)),
- visit_block: @fn(&blk, (E, vt<E>)),
+ visit_local: @fn(@Local, (E, vt<E>)),
+ visit_block: @fn(&Block, (E, vt<E>)),
visit_stmt: @fn(@stmt, (E, vt<E>)),
visit_arm: @fn(&arm, (E, vt<E>)),
visit_pat: @fn(@pat, (E, vt<E>)),
visit_expr_post: @fn(@expr, (E, vt<E>)),
visit_ty: @fn(&Ty, (E, vt<E>)),
visit_generics: @fn(&Generics, (E, vt<E>)),
- visit_fn: @fn(&fn_kind, &fn_decl, &blk, span, node_id, (E, vt<E>)),
+ visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, node_id, (E, vt<E>)),
visit_ty_method: @fn(&ty_method, (E, vt<E>)),
visit_trait_method: @fn(&trait_method, (E, vt<E>)),
visit_struct_def: @fn(@struct_def, ident, &Generics, node_id, (E, vt<E>)),
};
}
-pub fn visit_crate<E:Clone>(c: &crate, (e, v): (E, vt<E>)) {
- (v.visit_mod)(&c.node.module, c.span, crate_node_id, (e, v));
+pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
+ (v.visit_mod)(&c.module, c.span, crate_node_id, (e, v));
}
pub fn visit_mod<E:Clone>(m: &_mod,
pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
-pub fn visit_local<E:Clone>(loc: &local, (e, v): (E, vt<E>)) {
- (v.visit_pat)(loc.node.pat, (e.clone(), v));
- (v.visit_ty)(&loc.node.ty, (e.clone(), v));
- match loc.node.init {
+pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
+ (v.visit_pat)(loc.pat, (e.clone(), v));
+ (v.visit_ty)(&loc.ty, (e.clone(), v));
+ match loc.init {
None => (),
Some(ex) => (v.visit_expr)(ex, (e, v))
}
(e, v));
}
-pub fn visit_fn<E:Clone>(fk: &fn_kind, decl: &fn_decl, body: &blk, _sp: span,
+pub fn visit_fn<E:Clone>(fk: &fn_kind, decl: &fn_decl, body: &Block, _sp: span,
_id: node_id, (e, v): (E, vt<E>)) {
visit_fn_decl(decl, (e.clone(), v));
let generics = generics_of_fn(fk);
(v.visit_ty)(&sf.node.ty, (e, v));
}
-pub fn visit_block<E:Clone>(b: &blk, (e, v): (E, vt<E>)) {
+pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
for b.view_items.iter().advance |vi| {
(v.visit_view_item)(vi, (e.clone(), v));
}
expr_struct(ref p, ref flds, base) => {
visit_path(p, (e.clone(), v));
for flds.iter().advance |f| {
- (v.visit_expr)(f.node.expr, (e.clone(), v));
+ (v.visit_expr)(f.expr, (e.clone(), v));
}
visit_expr_opt(base, (e.clone(), v));
}
visit_view_item: @fn(&view_item),
visit_foreign_item: @fn(@foreign_item),
visit_item: @fn(@item),
- visit_local: @fn(@local),
- visit_block: @fn(&blk),
+ visit_local: @fn(@Local),
+ visit_block: @fn(&Block),
visit_stmt: @fn(@stmt),
visit_arm: @fn(&arm),
visit_pat: @fn(@pat),
visit_expr_post: @fn(@expr),
visit_ty: @fn(&Ty),
visit_generics: @fn(&Generics),
- visit_fn: @fn(&fn_kind, &fn_decl, &blk, span, node_id),
+ visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, node_id),
visit_ty_method: @fn(&ty_method),
visit_trait_method: @fn(&trait_method),
visit_struct_def: @fn(@struct_def, ident, &Generics, node_id),
f(i);
visit_item(i, (e, v));
}
- fn v_local(f: @fn(@local), l: @local, (e, v): ((), vt<()>)) {
+ fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
f(l);
visit_local(l, (e, v));
}
- fn v_block(f: @fn(&ast::blk), bl: &ast::blk, (e, v): ((), vt<()>)) {
+ fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
f(bl);
visit_block(bl, (e, v));
}
visit_generics(ps, (e, v));
}
fn v_fn(
- f: @fn(&fn_kind, &fn_decl, &blk, span, node_id),
+ f: @fn(&fn_kind, &fn_decl, &Block, span, node_id),
fk: &fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(e, v): ((), vt<()>)
return (void*)((char *)ptr + HEADER_SIZE);
}
+inline void memory_region::maybe_print_backtrace(const alloc_header *header) const {
+# if RUSTRT_TRACK_ALLOCATIONS >= 3
+ if (_detailed_leaks) {
+ backtrace_symbols_fd(header->bt + 1, header->btframes - 1, 2);
+ }
+# endif
+}
+
memory_region::memory_region(bool synchronized,
bool detailed_leaks,
bool poison_on_free) :
header->tag,
(uintptr_t) get_data(header));
++leak_count;
-
-# if RUSTRT_TRACK_ALLOCATIONS >= 3
- if (_detailed_leaks) {
- backtrace_symbols_fd(header->bt + 1,
- header->btframes - 1, 2);
- }
-# endif
+ maybe_print_backtrace(header);
}
}
assert(leak_count == _live_allocations);
# 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());
+ maybe_print_backtrace(alloc);
+ assert(false && "index beyond allocation_list");
+ }
if (_allocation_list[alloc->index] != alloc) {
printf("free: ptr 0x%" PRIxPTR " (%s) is not in allocation_list\n",
(uintptr_t) get_data(alloc), alloc->tag);
+ maybe_print_backtrace(alloc);
assert(false && "not in allocation_list");
}
else {
void release_alloc(void *mem);
void claim_alloc(void *mem);
+ void maybe_print_backtrace(const alloc_header *) const;
+
private:
// private and undefined to disable copying
memory_region(const memory_region& rhs);
return task->sched->get_id();
}
-extern "C" CDECL uintptr_t
-rust_num_threads() {
- rust_task *task = rust_get_current_task();
- return task->kernel->env->num_sched_threads;
-}
-
extern "C" CDECL int
rust_get_argc() {
rust_task *task = rust_get_current_task();
delete thread;
}
-extern "C" void
-rust_register_exit_function(spawn_fn runner, fn_env_pair *f) {
- rust_task *task = rust_get_current_task();
- task->kernel->register_exit_function(runner, f);
-}
-
-extern "C" intptr_t*
-rust_get_global_data_ptr() {
- rust_task *task = rust_get_current_task();
- return &task->kernel->global_data;
-}
-
-extern "C" void
-rust_inc_kernel_live_count() {
- rust_task *task = rust_get_current_task();
- task->kernel->inc_live_count();
-}
-
-extern "C" void
-rust_dec_kernel_live_count() {
- rust_task *task = rust_get_current_task();
- task->kernel->dec_live_count();
-}
-
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
return exit_status;
}
+static lock_and_signal change_dir_lock;
+
+extern "C" CDECL void
+rust_take_change_dir_lock() {
+ global_args_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_change_dir_lock() {
+ global_args_lock.unlock();
+}
+
//
// Local Variables:
// mode: C++
sched_reaper(this),
osmain_driver(NULL),
non_weak_tasks(0),
- at_exit_runner(NULL),
- at_exit_started(false),
- env(env),
- global_data(0)
+ env(env)
{
// Create the single threaded scheduler that will run on the platform's
// main thread
}
}
- run_exit_functions();
allow_scheduler_exit();
}
-void
-rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "registering at_exit function after exit");
-
- if (at_exit_runner) {
- // FIXME #2912 Would be very nice to assert this but we can't because
- // of the way coretest works (the test case ends up using its own
- // function)
- //assert(runner == at_exit_runner
- // && "there can be only one at_exit_runner");
- }
-
- at_exit_runner = runner;
- at_exit_fns.push_back(f);
-}
-
-void
-rust_kernel::run_exit_functions() {
- rust_task *task;
-
- {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "running exit functions twice?");
-
- at_exit_started = true;
-
- if (at_exit_runner == NULL) {
- return;
- }
-
- rust_scheduler *sched = get_scheduler_by_id(main_sched_id());
- assert(sched);
- task = sched->create_task(NULL, "at_exit");
-
- final_exit_fns.count = at_exit_fns.size();
- final_exit_fns.start = at_exit_fns.data();
- }
-
- task->start(at_exit_runner, NULL, &final_exit_fns);
-}
-
//
// Local Variables:
// mode: C++
typedef std::map<rust_sched_id, rust_scheduler*> sched_map;
-// This is defined as a struct only because we need a single pointer to pass
-// to the Rust function that runs the at_exit functions
-struct exit_functions {
- size_t count;
- fn_env_pair **start;
-};
-
class rust_kernel {
rust_exchange_alloc exchange_alloc;
rust_log _log;
void allow_scheduler_exit();
void begin_shutdown();
- lock_and_signal at_exit_lock;
- spawn_fn at_exit_runner;
- bool at_exit_started;
- std::vector<fn_env_pair*> at_exit_fns;
- exit_functions final_exit_fns;
-
- void run_exit_functions();
-
public:
struct rust_env *env;
- intptr_t global_data;
rust_kernel(rust_env *env);
void inc_live_count();
void dec_live_count();
- void register_exit_function(spawn_fn runner, fn_env_pair *f);
};
template <typename T> struct kernel_owned {
// free the environment (which should be a unique closure).
const type_desc *td = env->td;
td->drop_glue(NULL,
-#ifdef _RUST_STAGE0
- NULL,
-#endif
box_body(env));
task->kernel->region()->free(env);
}
struct type_desc;
typedef void CDECL (glue_fn)(void *,
-#ifdef _RUST_STAGE0
- const type_desc **,
-#endif
void *);
// Corresponds to the boxed data in the @ region. The body follows the
rust_get_argv
rust_new_sched
rust_new_task_in_sched
-rust_num_threads
rust_path_is_dir
rust_path_exists
rust_get_stdin
linenoiseHistoryLoad
rust_raw_thread_start
rust_raw_thread_join_delete
-rust_register_exit_function
-rust_get_global_data_ptr
-rust_inc_kernel_live_count
-rust_dec_kernel_live_count
rust_get_rt_tls_key
swap_registers
rust_readdir
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
\ No newline at end of file
typedef DIBuilder* DIBuilderRef;
template<typename DIT>
-DIT unwrapDI(LLVMValueRef ref) {
- return DIT(ref ? unwrap<MDNode>(ref) : NULL);
+DIT unwrapDI(LLVMValueRef ref) {
+ return DIT(ref ? unwrap<MDNode>(ref) : NULL);
}
extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) {
extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType(
DIBuilderRef Builder,
- LLVMValueRef File,
+ LLVMValueRef File,
LLVMValueRef ParameterTypes) {
return wrap(Builder->createSubroutineType(
- unwrapDI<DIFile>(File),
+ unwrapDI<DIFile>(File),
unwrapDI<DIArray>(ParameterTypes)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateFunction(
DIBuilderRef Builder,
- LLVMValueRef Scope,
+ LLVMValueRef Scope,
const char* Name,
const char* LinkageName,
- LLVMValueRef File,
+ LLVMValueRef File,
unsigned LineNo,
- LLVMValueRef Ty,
+ LLVMValueRef Ty,
bool isLocalToUnit,
bool isDefinition,
unsigned ScopeLine,
LLVMValueRef TParam,
LLVMValueRef Decl) {
return wrap(Builder->createFunction(
- unwrapDI<DIScope>(Scope), Name, LinkageName,
- unwrapDI<DIFile>(File), LineNo,
- unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
+ unwrapDI<DIScope>(Scope), Name, LinkageName,
+ unwrapDI<DIFile>(File), LineNo,
+ unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
Flags, isOptimized,
- unwrap<Function>(Fn),
+ unwrap<Function>(Fn),
unwrapDI<MDNode*>(TParam),
unwrapDI<MDNode*>(Decl)));
}
uint64_t AlignInBits,
unsigned Encoding) {
return wrap(Builder->createBasicType(
- Name, SizeInBits,
+ Name, SizeInBits,
AlignInBits, Encoding));
}
-
+
extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType(
DIBuilderRef Builder,
LLVMValueRef PointeeTy,
unsigned RunTimeLang,
LLVMValueRef VTableHolder) {
return wrap(Builder->createStructType(
- unwrapDI<DIDescriptor>(Scope), Name,
- unwrapDI<DIFile>(File), LineNumber,
- SizeInBits, AlignInBits, Flags,
- unwrapDI<DIType>(DerivedFrom),
- unwrapDI<DIArray>(Elements), RunTimeLang,
+ unwrapDI<DIDescriptor>(Scope), Name,
+ unwrapDI<DIFile>(File), LineNumber,
+ SizeInBits, AlignInBits, Flags,
+ unwrapDI<DIType>(DerivedFrom),
+ unwrapDI<DIArray>(Elements), RunTimeLang,
unwrapDI<MDNode*>(VTableHolder)));
}
unsigned Flags,
LLVMValueRef Ty) {
return wrap(Builder->createMemberType(
- unwrapDI<DIDescriptor>(Scope), Name,
+ unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File), LineNo,
- SizeInBits, AlignInBits, OffsetInBits, Flags,
+ SizeInBits, AlignInBits, OffsetInBits, Flags,
unwrapDI<DIType>(Ty)));
}
-
+
extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock(
DIBuilderRef Builder,
LLVMValueRef Scope,
unsigned Line,
unsigned Col) {
return wrap(Builder->createLexicalBlock(
- unwrapDI<DIDescriptor>(Scope),
+ unwrapDI<DIDescriptor>(Scope),
unwrapDI<DIFile>(File), Line, Col));
}
-
+
extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable(
DIBuilderRef Builder,
unsigned Tag,
bool AlwaysPreserve,
unsigned Flags,
unsigned ArgNo) {
- return wrap(Builder->createLocalVariable(Tag,
- unwrapDI<DIDescriptor>(Scope), Name,
- unwrapDI<DIFile>(File),
- LineNo,
+ return wrap(Builder->createLocalVariable(Tag,
+ unwrapDI<DIDescriptor>(Scope), Name,
+ unwrapDI<DIFile>(File),
+ LineNo,
unwrapDI<DIType>(Ty), AlwaysPreserve, Flags, ArgNo));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType(
DIBuilderRef Builder,
- uint64_t Size,
- uint64_t AlignInBits,
- LLVMValueRef Ty,
+ uint64_t Size,
+ uint64_t AlignInBits,
+ LLVMValueRef Ty,
LLVMValueRef Subscripts) {
return wrap(Builder->createArrayType(Size, AlignInBits,
- unwrapDI<DIType>(Ty),
+ unwrapDI<DIType>(Ty),
unwrapDI<DIArray>(Subscripts)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType(
DIBuilderRef Builder,
- uint64_t Size,
- uint64_t AlignInBits,
- LLVMValueRef Ty,
+ uint64_t Size,
+ uint64_t AlignInBits,
+ LLVMValueRef Ty,
LLVMValueRef Subscripts) {
return wrap(Builder->createVectorType(Size, AlignInBits,
- unwrapDI<DIType>(Ty),
+ unwrapDI<DIType>(Ty),
unwrapDI<DIArray>(Subscripts)));
}
extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange(
- DIBuilderRef Builder,
- int64_t Lo,
+ DIBuilderRef Builder,
+ int64_t Lo,
int64_t Count) {
return wrap(Builder->getOrCreateSubrange(Lo, Count));
}
extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray(
DIBuilderRef Builder,
- LLVMValueRef* Ptr,
+ LLVMValueRef* Ptr,
unsigned Count) {
return wrap(Builder->getOrCreateArray(
ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count)));
LLVMValueRef VarInfo,
LLVMBasicBlockRef InsertAtEnd) {
return wrap(Builder->insertDeclare(
- unwrap(Val),
- unwrapDI<DIVariable>(VarInfo),
+ unwrap(Val),
+ unwrapDI<DIVariable>(VarInfo),
unwrap(InsertAtEnd)));
}
LLVMValueRef VarInfo,
LLVMValueRef InsertBefore) {
return wrap(Builder->insertDeclare(
- unwrap(Val),
- unwrapDI<DIVariable>(VarInfo),
+ unwrap(Val),
+ unwrapDI<DIVariable>(VarInfo),
unwrap<Instruction>(InsertBefore)));
}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerator(
+ DIBuilderRef Builder,
+ const char* Name,
+ uint64_t Val)
+{
+ return wrap(Builder->createEnumerator(Name, Val));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType(
+ DIBuilderRef Builder,
+ LLVMValueRef Scope,
+ const char* Name,
+ LLVMValueRef File,
+ unsigned LineNumber,
+ uint64_t SizeInBits,
+ uint64_t AlignInBits,
+ LLVMValueRef Elements,
+ LLVMValueRef ClassType)
+{
+ return wrap(Builder->createEnumerationType(
+ unwrapDI<DIDescriptor>(Scope),
+ Name,
+ unwrapDI<DIFile>(File),
+ LineNumber,
+ SizeInBits,
+ AlignInBits,
+ unwrapDI<DIArray>(Elements),
+ unwrapDI<DIType>(ClassType)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
+ DIBuilderRef Builder,
+ LLVMValueRef Scope,
+ const char* Name,
+ LLVMValueRef File,
+ unsigned LineNumber,
+ uint64_t SizeInBits,
+ uint64_t AlignInBits,
+ unsigned Flags,
+ LLVMValueRef Elements,
+ unsigned RunTimeLang)
+{
+ return wrap(Builder->createUnionType(
+ unwrapDI<DIDescriptor>(Scope),
+ Name,
+ unwrapDI<DIFile>(File),
+ LineNumber,
+ SizeInBits,
+ AlignInBits,
+ Flags,
+ unwrapDI<DIArray>(Elements),
+ RunTimeLang));
+}
\ No newline at end of file
LLVMInsertBasicBlockInContext
LLVMInsertIntoBuilder
LLVMInsertIntoBuilderWithName
+LLVMInstructionEraseFromParent
LLVMInt16Type
LLVMInt16TypeInContext
LLVMInt1Type
LLVMDIBuilderGetOrCreateArray
LLVMDIBuilderInsertDeclareAtEnd
LLVMDIBuilderInsertDeclareBefore
+LLVMDIBuilderCreateEnumerator
+LLVMDIBuilderCreateEnumerationType
+LLVMDIBuilderCreateUnionType
+S 2013-07-21 e336cbf
+ macos-i386 d9666dccc1040ebe298a54acb378902a7472ad0f
+ macos-x86_64 808f68916444e3857ef2aab20f8db9db8f4b0b4a
+ winnt-i386 f9a5f891fd24e9446acb2a1b5d697461665c4388
+ freebsd-x86_64 8e79f6e970bc33ea6a3b9329bc4526d89ca63d47
+ linux-i386 054a0229b9cbdadf013868ba01a8277883f83a6d
+ linux-x86_64 2c53a72e9c9bb547df248a2d4b857d480ce0b910
+
S 2013-06-23 f827561
macos-i386 63ffbcf99b6853d7840bdfe01380068518d0e466
macos-x86_64 b34fdf3845f8ef4760817007d8ef820cd32f2e07
pub mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
- fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
- fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
- fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
+ extern "rust-intrinsic" {
+ pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
+ pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
+ pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
- fn atomic_xchg(dst: &mut int, src: int) -> int;
- fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
- fn atomic_xchg_rel(dst: &mut int, src: int) -> int;
+ pub fn atomic_xchg(dst: &mut int, src: int) -> int;
+ pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int;
+ pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int;
- fn atomic_xadd(dst: &mut int, src: int) -> int;
- fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
- fn atomic_xadd_rel(dst: &mut int, src: int) -> int;
+ pub fn atomic_xadd(dst: &mut int, src: int) -> int;
+ pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int;
+ pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int;
- fn atomic_xsub(dst: &mut int, src: int) -> int;
- fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
- fn atomic_xsub_rel(dst: &mut int, src: int) -> int;
+ pub fn atomic_xsub(dst: &mut int, src: int) -> int;
+ pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int;
+ pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int;
}
}
data: @mut ~[Entry<A,B>]
}
-pub fn alist_add<A,B>(lst: &alist<A,B>, k: A, v: B) {
+pub fn alist_add<A:'static,B:'static>(lst: &alist<A,B>, k: A, v: B) {
lst.data.push(Entry{key:k, value:v});
}
-pub fn alist_get<A:Clone,B:Clone>(lst: &alist<A,B>, k: A) -> B {
+pub fn alist_get<A:Clone + 'static,
+ B:Clone + 'static>(
+ lst: &alist<A,B>,
+ k: A)
+ -> B {
let eq_fn = lst.eq_fn;
for lst.data.iter().advance |entry| {
if eq_fn(entry.key.clone(), k.clone()) {
}
#[inline]
-pub fn new_int_alist<B>() -> alist<int, B> {
+pub fn new_int_alist<B:'static>() -> alist<int, B> {
fn eq_int(a: int, b: int) -> bool { a == b }
return alist {eq_fn: eq_int, data: @mut ~[]};
}
#[inline]
-pub fn new_int_alist_2<B>() -> alist<int, B> {
+pub fn new_int_alist_2<B:'static>() -> alist<int, B> {
#[inline]
fn eq_int(a: int, b: int) -> bool { a == b }
return alist {eq_fn: eq_int, data: @mut ~[]};
pub mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
pub mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_get_argc() -> libc::c_int;
}
}
--- /dev/null
+// aux-build:trait_default_method_xc_aux.rs
+
+extern mod aux(name = "trait_default_method_xc_aux");
+use aux::A;
+
+pub struct a_struct { x: int }
+
+impl A for a_struct {
+ fn f(&self) -> int { 10 }
+}
+
+// This function will need to get inlined, and badness may result.
+pub fn welp<A>(x: A) -> A {
+ let a = a_struct { x: 0 };
+ a.g();
+ x
+}
fn main() {
let argv = os::args();
- let tests = argv.slice(1, argv.len());
+ let _tests = argv.slice(1, argv.len());
bench!(shift_push);
bench!(read_line);
fn maybe_run_test(argv: &[~str], name: ~str, test: &fn()) {
let mut run_test = false;
- if os::getenv(~"RUST_BENCH").is_some() {
+ if os::getenv("RUST_BENCH").is_some() {
run_test = true
} else if argv.len() > 0 {
run_test = argv.iter().any(|x| x == &~"all") || argv.iter().any(|x| x == &name)
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"10000000"]
} else if args.len() <= 1u {
~[~"", ~"100000"]
}
}
- do graph.consume_iter().transform |mut v| {
+ do graph.consume_iter().transform |v| {
let mut vec = ~[];
- do v.consume |i| {
+ for v.consume().advance |i| {
vec.push(i);
}
vec
}
}
let mut vec = ~[];
- do keys.consume |i| {
+ for keys.consume().advance |i| {
vec.push(i);
}
return vec;
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"15", ~"48"]
} else if args.len() <= 1 {
~[~"", ~"10", ~"16"]
let graph_arc = arc::ARC(graph.clone());
do gen_search_keys(graph, num_keys).map() |root| {
- io::stdout().write_line(~"");
+ io::stdout().write_line("");
io::stdout().write_line(fmt!("Search key: %?", root));
if do_sequential {
}
};
- io::stdout().write_line(~"");
+ io::stdout().write_line("");
io::stdout().write_line(
fmt!("Total sequential: %? \t Total Parallel: %? \t Speedup: %?x",
total_seq, total_par, total_seq / total_par));
use std::comm::{Port, Chan, SharedChan};
use std::comm;
-use std::io::{Writer, WriterUtil};
use std::io;
use std::os;
use std::task;
-use std::ptr;
use std::uint;
-use std::vec;
-fn move_out<T>(x: T) {}
+fn move_out<T>(_x: T) {}
enum request {
get_count,
stop
}
-fn server(requests: &Port<request>, responses: &comm::Chan<uint>) {
+fn server(requests: &Port<request>, responses: &Chan<uint>) {
let mut count = 0u;
let mut done = false;
while !done {
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"1000000", ~"10000"]
} else if args.len() <= 1u {
~[~"", ~"10000", ~"4"]
extern mod extra;
-use std::comm::{Port, PortSet, Chan, stream};
-use std::io::{Writer, WriterUtil};
+use std::comm::{PortSet, Chan, stream};
use std::io;
use std::os;
-use std::ptr;
use std::task;
use std::uint;
-use std::vec;
-fn move_out<T>(x: T) {}
+fn move_out<T>(_x: T) {}
enum request {
get_count,
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"1000000", ~"8"]
} else if args.len() <= 1u {
~[~"", ~"10000", ~"4"]
use std::io;
use std::os;
use std::uint;
-use std::vec;
// A poor man's pipe.
type pipe = arc::MutexARC<~[uint]>;
// Send/Receive lots of messages.
for uint::range(0u, count) |j| {
//error!("task %?, iter %?", i, j);
- let mut num_chan2 = num_chan.take_unwrap();
- let mut num_port2 = num_port.take_unwrap();
+ let num_chan2 = num_chan.take_unwrap();
+ let num_port2 = num_port.take_unwrap();
send(&num_chan2, i * j);
num_chan = Some(num_chan2);
let _n = recv(&num_port2);
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100", ~"10000"]
} else if args.len() <= 1u {
~[~"", ~"10", ~"100"]
let msg_per_task = uint::from_str(args[2]).get();
let (num_chan, num_port) = init();
- let mut num_chan = Cell::new(num_chan);
+ let num_chan = Cell::new(num_chan);
let start = time::precise_time_s();
use std::io;
use std::os;
use std::pipes::recv;
-use std::ptr;
use std::uint;
use std::util;
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100", ~"10000"]
} else if args.len() <= 1u {
~[~"", ~"100", ~"1000"]
let msg_per_task = uint::from_str(args[2]).get();
let (num_port, num_chan) = ring::init();
- let mut num_chan = Cell::new(num_chan);
+ let num_chan = Cell::new(num_chan);
let start = time::precise_time_s();
use std::io;
use std::os;
use std::uint;
-use std::vec;
// A poor man's pipe.
type pipe = arc::RWARC<~[uint]>;
// Send/Receive lots of messages.
for uint::range(0u, count) |j| {
//error!("task %?, iter %?", i, j);
- let mut num_chan2 = num_chan.take_unwrap();
- let mut num_port2 = num_port.take_unwrap();
+ let num_chan2 = num_chan.take_unwrap();
+ let num_port2 = num_port.take_unwrap();
send(&num_chan2, i * j);
num_chan = Some(num_chan2);
let _n = recv(&num_port2);
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100", ~"10000"]
} else if args.len() <= 1u {
~[~"", ~"10", ~"100"]
let msg_per_task = uint::from_str(args[2]).get();
let (num_chan, num_port) = init();
- let mut num_chan = Cell::new(num_chan);
+ let num_chan = Cell::new(num_chan);
let start = time::precise_time_s();
}
fn main() {
- let count = if os::getenv(~"RUST_BENCH").is_some() {
+ let count = if os::getenv("RUST_BENCH").is_some() {
250000
} else {
100
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"12"]
} else if args.len() <= 1u {
~[~"", ~"8"]
use std::os;
use std::int;
let args = std::os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"17"]
} else if args.len() <= 1u {
~[~"", ~"8"]
extern mod extra;
-use extra::sort;
use std::cell::Cell;
use std::comm::*;
use std::io;
use std::os;
use std::task;
use std::uint;
-use std::vec;
fn print_complements() {
let all = [Blue, Red, Yellow];
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"200000"]
} else if args.len() <= 1u {
~[~"", ~"600"]
let nn = uint::from_str(args[1]).get();
print_complements();
- io::println(~"");
+ io::println("");
rendezvous(nn, ~[Blue, Red, Yellow]);
- io::println(~"");
+ io::println("");
rendezvous(nn,
~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]);
use std::from_str::FromStr;
use std::libc::{FILE, STDOUT_FILENO, c_int, fdopen, fputc, fputs, fwrite, size_t};
use std::os;
-use std::str;
use std::uint::{min, range};
use std::vec::bytes::copy_memory;
use std::vec;
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"40"]
} else if args.len() <= 1u {
~[~"", ~"30"]
}
fn make_sequence_processor(sz: uint,
- from_parent: &comm::Port<~[u8]>,
- to_parent: &comm::Chan<~str>) {
+ from_parent: &Port<~[u8]>,
+ to_parent: &Chan<~str>) {
let mut freqs: HashMap<~[u8], uint> = HashMap::new();
let mut carry: ~[u8] = ~[];
let mut total: uint = 0u;
let buffer = match sz {
1u => { sort_and_fmt(&freqs, total) }
2u => { sort_and_fmt(&freqs, total) }
- 3u => { fmt!("%u\t%s", find(&freqs, ~"GGT"), ~"GGT") }
- 4u => { fmt!("%u\t%s", find(&freqs, ~"GGTA"), ~"GGTA") }
- 6u => { fmt!("%u\t%s", find(&freqs, ~"GGTATT"), ~"GGTATT") }
- 12u => { fmt!("%u\t%s", find(&freqs, ~"GGTATTTTAATT"), ~"GGTATTTTAATT") }
- 18u => { fmt!("%u\t%s", find(&freqs, ~"GGTATTTTAATTTATAGT"), ~"GGTATTTTAATTTATAGT") }
+ 3u => { fmt!("%u\t%s", find(&freqs, ~"GGT"), "GGT") }
+ 4u => { fmt!("%u\t%s", find(&freqs, ~"GGTA"), "GGTA") }
+ 6u => { fmt!("%u\t%s", find(&freqs, ~"GGTATT"), "GGTATT") }
+ 12u => { fmt!("%u\t%s", find(&freqs, ~"GGTATTTTAATT"), "GGTATTTTAATT") }
+ 18u => { fmt!("%u\t%s", find(&freqs, ~"GGTATTTTAATTTATAGT"), "GGTATTTTAATTTATAGT") }
_ => { ~"" }
};
// given a FASTA file on stdin, process sequence THREE
fn main() {
- let args = os::args();
- let rdr = if os::getenv(~"RUST_BENCH").is_some() {
+ let rdr = if os::getenv("RUST_BENCH").is_some() {
// FIXME: Using this compile-time env variable is a crummy way to
// get to this massive data set, but include_bin! chokes on it (#2598)
let path = Path(env!("CFG_SRC_DIR"))
// start processing if this is the one
('>', false) => {
- match line.slice_from(1).find_str(~"THREE") {
+ match line.slice_from(1).find_str("THREE") {
option::Some(_) => { proc_mode = true; }
option::None => { }
}
let line_bytes = line.as_bytes();
for sizes.iter().enumerate().advance |(ii, _sz)| {
- let mut lb = line_bytes.to_owned();
+ let lb = line_bytes.to_owned();
to_child[ii].send(lb);
}
}
use std::from_str::FromStr;
use std::os;
use std::uint::range;
-use std::vec;
static PI: f64 = 3.141592653589793;
static SOLAR_MASS: f64 = 4.0 * PI * PI;
use std::io;
use std::os;
use std::result::{Ok, Err};
-use std::str;
use std::task;
use std::u64;
use std::uint;
}
fn parse_opts(argv: ~[~str]) -> Config {
- let opts = ~[getopts::optflag(~"stress")];
+ let opts = ~[getopts::optflag("stress")];
let opt_args = argv.slice(1, argv.len());
match getopts::getopts(opt_args, opts) {
Ok(ref m) => {
- return Config {stress: getopts::opt_present(m, ~"stress")}
+ return Config {stress: getopts::opt_present(m, "stress")}
}
Err(_) => { fail!(); }
}
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"20"]
} else if args.len() <= 1u {
~[~"", ~"8"]
use std::libc::{STDOUT_FILENO, c_int, fdopen, fgets, fopen, fputc, fwrite};
use std::libc::{size_t};
use std::ptr::null;
-use std::vec::raw::set_len;
static LINE_LEN: u32 = 80;
fn start(n_tasks: int, token: int) {
let (p, ch1) = stream();
let mut p = p;
- let mut ch1 = ch1;
+ let ch1 = ch1;
ch1.send(token);
// XXX could not get this to work with a range closure
let mut i = 2;
}
fn main() {
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"2000000", ~"503"]
}
else {
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100000", ~"100"]
} else if args.len() <= 1u {
~[~"", ~"10000", ~"50"]
use std::io::{ReaderUtil, WriterUtil};
use std::io;
use std::os;
-use std::str;
use std::u8;
use std::uint;
use std::unstable::intrinsics::cttz16;
}
pub fn from_vec(vec: &[[u8, ..9], ..9]) -> Sudoku {
- let mut g = do vec::from_fn(9u) |i| {
+ let g = do vec::from_fn(9u) |i| {
do vec::from_fn(9u) |j| { vec[i][j] }
};
return Sudoku::new(g)
// Stores available colors as simple bitfield, bit 0 is always unset
struct Colors(u16);
-static heads: u16 = (1u16 << 10) - 1; /* bits 9..0 */
+static HEADS: u16 = (1u16 << 10) - 1; /* bits 9..0 */
impl Colors {
fn new(start_color: u8) -> Colors {
// Sets bits 9..start_color
let tails = !0u16 << start_color;
- return Colors(heads & tails);
+ return Colors(HEADS & tails);
}
fn next(&self) -> u8 {
- let val = **self & heads;
+ let val = **self & HEADS;
if (0u16 == val) {
return 0u8;
} else {
}
}
-static default_sudoku: [[u8, ..9], ..9] = [
+static DEFAULT_SUDOKU: [[u8, ..9], ..9] = [
/* 0 1 2 3 4 5 6 7 8 */
/* 0 */ [0u8, 4u8, 0u8, 6u8, 0u8, 0u8, 0u8, 3u8, 2u8],
/* 1 */ [0u8, 0u8, 8u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8],
];
#[cfg(test)]
-static default_solution: [[u8, ..9], ..9] = [
+static DEFAULT_SOLUTION: [[u8, ..9], ..9] = [
/* 0 1 2 3 4 5 6 7 8 */
/* 0 */ [1u8, 4u8, 9u8, 6u8, 7u8, 5u8, 8u8, 3u8, 2u8],
/* 1 */ [5u8, 3u8, 8u8, 1u8, 2u8, 9u8, 7u8, 4u8, 6u8],
}
#[test]
-fn check_default_sudoku_solution() {
+fn check_DEFAULT_SUDOKU_solution() {
// GIVEN
- let mut sudoku = Sudoku::from_vec(&default_sudoku);
- let solution = Sudoku::from_vec(&default_solution);
+ let mut sudoku = Sudoku::from_vec(&DEFAULT_SUDOKU);
+ let solution = Sudoku::from_vec(&DEFAULT_SOLUTION);
// WHEN
sudoku.solve();
let args = os::args();
let use_default = args.len() == 1u;
let mut sudoku = if use_default {
- Sudoku::from_vec(&default_sudoku)
+ Sudoku::from_vec(&DEFAULT_SUDOKU)
} else {
Sudoku::read(io::stdin())
};
}
fn main() {
- let (repeat, depth) = if os::getenv(~"RUST_BENCH").is_some() {
+ let (repeat, depth) = if os::getenv("RUST_BENCH").is_some() {
(50, 1000)
} else {
(10, 10)
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100000"]
} else if args.len() <= 1 {
~[~"", ~"100"]
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"100000"]
} else if args.len() <= 1u {
~[~"", ~"100"]
// xfail-test OOM on linux-32 without opts
-use std::comm::*;
use std::os;
use std::task;
use std::uint;
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"30"]
} else if args.len() <= 1u {
~[~"", ~"10"]
fn main() {
let args = os::args();
- let args = if os::getenv(~"RUST_BENCH").is_some() {
+ let args = if os::getenv("RUST_BENCH").is_some() {
~[~"", ~"400"]
} else if args.len() <= 1u {
~[~"", ~"10"]
--- /dev/null
+fn f<T>(x: T) -> @T {
+ @x //~ ERROR value may contain borrowed pointers
+}
+
+fn g<T:'static>(x: T) -> @T {
+ @x // ok
+}
+
+fn main() {}
+
mod test {
#[abi = "cdecl"]
- pub extern {
+ extern {
pub unsafe fn free();
}
}
--- /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::io;
+
+struct Struct {
+ r: io::Reader //~ ERROR reference to trait `io::Reader` where a type is expected
+}
+
+fn new_struct(r: io::Reader) -> Struct { //~ ERROR reference to trait `io::Reader` where a type is expected
+ Struct { r: r }
+}
+
+trait Curve {}
+enum E {X(Curve)} //~ ERROR reference to trait `Curve` where a type is expected
+fn main() {}
@t as @foo
//~^ ERROR value may contain borrowed pointers; add `'static` bound
//~^^ ERROR cannot pack type
+ //~^^^ ERROR value may contain borrowed pointers
}
fn to_foo2<T:Clone + foo + 'static>(t: T) -> @foo {
copy2(&x); //~ ERROR does not fulfill `'static`
copy2(@3);
- copy2(@&x); //~ ERROR does not fulfill `'static`
+ copy2(@&x); //~ ERROR value may contain borrowed pointers
+ //~^ ERROR does not fulfill `'static`
}
#[deny(unused_unsafe)];
mod foo {
- pub extern {
+ extern {
pub fn bar();
}
}
+++ /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.
-
-// error-pattern:error opening
-
-mod doesnotexist;
\ 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.
+
+mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` found at both
+
+fn main() {
+ assert_eq!(mod_file_aux::bar(), 10);
+}
--- /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.
+
+// xfail-test not a test. aux 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.
+
+// xfail-test not a test. aux file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-mod not_a_real_file; //~ ERROR not_a_real_file.rs
+mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file`
fn main() {
assert_eq!(mod_file_aux::bar(), 10);
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
use syntax::print::*;
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
//error-pattern:libc::c_int or libc::c_long should be used
mod xx {
- pub extern {
+ extern {
pub fn strlen(str: *u8) -> uint;
pub fn foo(x: int, y: uint);
}
--- /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.
+
+// 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.
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+// debugger:print *bool_ref
+// check:$1 = true
+
+// debugger:print *int_ref
+// check:$2 = -1
+
+// debugger:print *char_ref
+// check:$3 = 97
+
+// debugger:print *i8_ref
+// check:$4 = 68 'D'
+
+// debugger:print *i16_ref
+// check:$5 = -16
+
+// debugger:print *i32_ref
+// check:$6 = -32
+
+// debugger:print *i64_ref
+// check:$7 = -64
+
+// debugger:print *uint_ref
+// check:$8 = 1
+
+// debugger:print *u8_ref
+// check:$9 = 100 'd'
+
+// debugger:print *u16_ref
+// check:$10 = 16
+
+// debugger:print *u32_ref
+// check:$11 = 32
+
+// debugger:print *u64_ref
+// check:$12 = 64
+
+// debugger:print *float_ref
+// check:$13 = 1.5
+
+// debugger:print *f32_ref
+// check:$14 = 2.5
+
+// debugger:print *f64_ref
+// check:$15 = 3.5
+
+fn main() {
+ let bool_val: bool = true;
+ let bool_ref: &bool = &bool_val;
+
+ let int_val: int = -1;
+ let int_ref: &int = &int_val;
+
+ let char_val: char = 'a';
+ let char_ref: &char = &char_val;
+
+ let i8_val: i8 = 68;
+ let i8_ref: &i8 = &i8_val;
+
+ let i16_val: i16 = -16;
+ let i16_ref: &i16 = &i16_val;
+
+ let i32_val: i32 = -32;
+ let i32_ref: &i32 = &i32_val;
+
+ let uint_val: i64 = -64;
+ let i64_ref: &i64 = &uint_val;
+
+ let uint_val: uint = 1;
+ let uint_ref: &uint = &uint_val;
+
+ let u8_val: u8 = 100;
+ let u8_ref: &u8 = &u8_val;
+
+ let u16_val: u16 = 16;
+ let u16_ref: &u16 = &u16_val;
+
+ let u32_val: u32 = 32;
+ let u32_ref: &u32 = &u32_val;
+
+ let u64_val: u64 = 64;
+ let u64_ref: &u64 = &u64_val;
+
+ let float_val: float = 1.5;
+ let float_ref: &float = &float_val;
+
+ let f32_val: f32 = 2.5;
+ let f32_ref: &f32 = &f32_val;
+
+ let f64_val: f64 = 3.5;
+ let f64_ref: &f64 = &f64_val;
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print *the_a_ref
+// check:$1 = TheA
+
+// debugger:print *the_b_ref
+// check:$2 = TheB
+
+// debugger:print *the_c_ref
+// check:$3 = TheC
+
+enum ABC { TheA, TheB, TheC }
+
+fn main() {
+ let the_a = TheA;
+ let the_a_ref: &ABC = &the_a;
+
+ let the_b = TheB;
+ let the_b_ref: &ABC = &the_b;
+
+ let the_c = TheC;
+ let the_c_ref: &ABC = &the_c;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print *the_a_ref
+// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}}
+
+// debugger:print *the_b_ref
+// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
+
+// debugger:print *univariant_ref
+// check:$3 = {4820353753753434}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum ABC {
+ TheA { x: i64, y: i64 },
+ TheB (i64, i32, i32),
+}
+
+// This is a special case since it does not have the implicit discriminant field.
+enum Univariant {
+ TheOnlyCase(i64)
+}
+
+fn main() {
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let the_a = TheA { x: 0, y: 8970181431921507452 };
+ let the_a_ref: &ABC = &the_a;
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let the_b = TheB (0, 286331153, 286331153);
+ let the_b_ref: &ABC = &the_b;
+
+ let univariant = TheOnlyCase(4820353753753434);
+ let univariant_ref: &Univariant = &univariant;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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.
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+// debugger:print *bool_ref
+// check:$1 = true
+
+// debugger:print *int_ref
+// check:$2 = -1
+
+// debugger:print *char_ref
+// check:$3 = 97
+
+// debugger:print/d *i8_ref
+// check:$4 = 68
+
+// debugger:print *i16_ref
+// check:$5 = -16
+
+// debugger:print *i32_ref
+// check:$6 = -32
+
+// debugger:print *i64_ref
+// check:$7 = -64
+
+// debugger:print *uint_ref
+// check:$8 = 1
+
+// debugger:print/d *u8_ref
+// check:$9 = 100
+
+// debugger:print *u16_ref
+// check:$10 = 16
+
+// debugger:print *u32_ref
+// check:$11 = 32
+
+// debugger:print *u64_ref
+// check:$12 = 64
+
+// debugger:print *float_ref
+// check:$13 = 1.5
+
+// debugger:print *f32_ref
+// check:$14 = 2.5
+
+// debugger:print *f64_ref
+// check:$15 = 3.5
+
+
+fn main() {
+ let bool_box: @bool = @true;
+ let bool_ref: &bool = bool_box;
+
+ let int_box: @int = @-1;
+ let int_ref: &int = int_box;
+
+ let char_box: @char = @'a';
+ let char_ref: &char = char_box;
+
+ let i8_box: @i8 = @68;
+ let i8_ref: &i8 = i8_box;
+
+ let i16_box: @i16 = @-16;
+ let i16_ref: &i16 = i16_box;
+
+ let i32_box: @i32 = @-32;
+ let i32_ref: &i32 = i32_box;
+
+ let i64_box: @i64 = @-64;
+ let i64_ref: &i64 = i64_box;
+
+ let uint_box: @uint = @1;
+ let uint_ref: &uint = uint_box;
+
+ let u8_box: @u8 = @100;
+ let u8_ref: &u8 = u8_box;
+
+ let u16_box: @u16 = @16;
+ let u16_ref: &u16 = u16_box;
+
+ let u32_box: @u32 = @32;
+ let u32_ref: &u32 = u32_box;
+
+ let u64_box: @u64 = @64;
+ let u64_ref: &u64 = u64_box;
+
+ let float_box: @float = @1.5;
+ let float_ref: &float = float_box;
+
+ let f32_box: @f32 = @2.5;
+ let f32_ref: &f32 = f32_box;
+
+ let f64_box: @f64 = @3.5;
+ let f64_ref: &f64 = f64_box;
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print *stack_val_ref
+// check:$1 = {x = 10, y = 23.5}
+
+// debugger:print *stack_val_interior_ref_1
+// check:$2 = 10
+
+// debugger:print *stack_val_interior_ref_2
+// check:$3 = 23.5
+
+// debugger:print *ref_to_unnamed
+// check:$4 = {x = 11, y = 24.5}
+
+// debugger:print *managed_val_ref
+// check:$5 = {x = 12, y = 25.5}
+
+// debugger:print *managed_val_interior_ref_1
+// check:$6 = 12
+
+// debugger:print *managed_val_interior_ref_2
+// check:$7 = 25.5
+
+// debugger:print *unique_val_ref
+// check:$8 = {x = 13, y = 26.5}
+
+// debugger:print *unique_val_interior_ref_1
+// check:$9 = 13
+
+// debugger:print *unique_val_interior_ref_2
+// check:$10 = 26.5
+
+
+
+struct SomeStruct {
+ x: int,
+ y: f64
+}
+
+fn main() {
+ let stack_val: SomeStruct = SomeStruct { x: 10, y: 23.5 };
+ let stack_val_ref: &SomeStruct = &stack_val;
+ let stack_val_interior_ref_1: &int = &stack_val.x;
+ let stack_val_interior_ref_2: &f64 = &stack_val.y;
+ let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 };
+
+ let managed_val = @SomeStruct { x: 12, y: 25.5 };
+ let managed_val_ref: &SomeStruct = managed_val;
+ let managed_val_interior_ref_1: &int = &managed_val.x;
+ let managed_val_interior_ref_2: &f64 = &managed_val.y;
+
+ let unique_val = ~SomeStruct { x: 13, y: 26.5 };
+ let unique_val_ref: &SomeStruct = unique_val;
+ let unique_val_interior_ref_1: &int = &unique_val.x;
+ let unique_val_interior_ref_2: &f64 = &unique_val.y;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print *stack_val_ref
+// check:$1 = {-14, -19}
+
+// debugger:print *ref_to_unnamed
+// check:$2 = {-15, -20}
+
+// debugger:print *managed_val_ref
+// check:$3 = {-16, -21}
+
+// debugger:print *unique_val_ref
+// check:$4 = {-17, -22}
+
+fn main() {
+ let stack_val: (i16, f32) = (-14, -19f32);
+ let stack_val_ref: &(i16, f32) = &stack_val;
+ let ref_to_unnamed: &(i16, f32) = &(-15, -20f32);
+
+ let managed_val: @(i16, f32) = @(-16, -21f32);
+ let managed_val_ref: &(i16, f32) = managed_val;
+
+ let unique_val: ~(i16, f32) = ~(-17, -22f32);
+ let unique_val_ref: &(i16, f32) = unique_val;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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.
+
+// compile-flags:-Z extra-debug-info
+// debugger:break zzz
+// debugger:run
+// debugger:finish
+// debugger:print *bool_ref
+// check:$1 = true
+
+// debugger:print *int_ref
+// check:$2 = -1
+
+// debugger:print *char_ref
+// check:$3 = 97
+
+// debugger:print/d *i8_ref
+// check:$4 = 68
+
+// debugger:print *i16_ref
+// check:$5 = -16
+
+// debugger:print *i32_ref
+// check:$6 = -32
+
+// debugger:print *i64_ref
+// check:$7 = -64
+
+// debugger:print *uint_ref
+// check:$8 = 1
+
+// debugger:print/d *u8_ref
+// check:$9 = 100
+
+// debugger:print *u16_ref
+// check:$10 = 16
+
+// debugger:print *u32_ref
+// check:$11 = 32
+
+// debugger:print *u64_ref
+// check:$12 = 64
+
+// debugger:print *float_ref
+// check:$13 = 1.5
+
+// debugger:print *f32_ref
+// check:$14 = 2.5
+
+// debugger:print *f64_ref
+// check:$15 = 3.5
+
+
+fn main() {
+ let bool_box: ~bool = ~true;
+ let bool_ref: &bool = bool_box;
+
+ let int_box: ~int = ~-1;
+ let int_ref: &int = int_box;
+
+ let char_box: ~char = ~'a';
+ let char_ref: &char = char_box;
+
+ let i8_box: ~i8 = ~68;
+ let i8_ref: &i8 = i8_box;
+
+ let i16_box: ~i16 = ~-16;
+ let i16_ref: &i16 = i16_box;
+
+ let i32_box: ~i32 = ~-32;
+ let i32_ref: &i32 = i32_box;
+
+ let i64_box: ~i64 = ~-64;
+ let i64_ref: &i64 = i64_box;
+
+ let uint_box: ~uint = ~1;
+ let uint_ref: &uint = uint_box;
+
+ let u8_box: ~u8 = ~100;
+ let u8_ref: &u8 = u8_box;
+
+ let u16_box: ~u16 = ~16;
+ let u16_ref: &u16 = u16_box;
+
+ let u32_box: ~u32 = ~32;
+ let u32_ref: &u32 = u32_box;
+
+ let u64_box: ~u64 = ~64;
+ let u64_ref: &u64 = u64_box;
+
+ let float_box: ~float = ~1.5;
+ let float_ref: &float = float_box;
+
+ let f32_box: ~f32 = ~2.5;
+ let f32_ref: &f32 = f32_box;
+
+ let f64_box: ~f64 = ~3.5;
+ let f64_ref: &f64 = f64_box;
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-test
+// 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
// debugger:run
// debugger:finish
-// debugger:print a->boxed
+// debugger:print *a
// check:$1 = 1
-// debugger:print b->boxed
+// debugger:print *b
// check:$2 = {2, 3.5}
-// debugger:print c->boxed
+// debugger:print c->val
// check:$3 = 4
-// debugger:print d->boxed
+// debugger:print d->val
// check:$4 = false
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.
+
+// 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
+// debugger:finish
+
+// debugger:print *unique
+// check:$1 = {x = 99, y = 999, z = 9999, w = 99999}
+
+// debugger:print managed->val
+// check:$2 = {x = 88, y = 888, z = 8888, w = 88888}
+
+// debugger:print *unique_dtor
+// check:$3 = {x = 77, y = 777, z = 7777, w = 77777}
+
+// debugger:print managed_dtor->val
+// check:$4 = {x = 33, y = 333, z = 3333, w = 33333}
+
+struct StructWithSomePadding {
+ x: i16,
+ y: i32,
+ z: i32,
+ w: i64
+}
+
+struct StructWithDestructor {
+ x: i16,
+ y: i32,
+ z: i32,
+ w: i64
+}
+
+impl Drop for StructWithDestructor {
+ fn drop(&self) {}
+}
+
+fn main() {
+
+ let unique = ~StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 };
+ let managed = @StructWithSomePadding { x: 88, y: 888, z: 8888, w: 88888 };
+
+ let unique_dtor = ~StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 };
+ let managed_dtor = @StructWithDestructor { x: 33, y: 333, z: 3333, w: 33333 };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print managed->val.fill
+// check:$1 = 24
+// debugger:print *((uint64_t[3]*)(managed->val.elements))
+// check:$2 = {7, 8, 9}
+
+// debugger:print unique->fill
+// check:$3 = 32
+// debugger:print *((uint64_t[4]*)(unique->elements))
+// check:$4 = {10, 11, 12, 13}
+
+fn main() {
+
+ let managed: @[i64] = @[7, 8, 9];
+ let unique: ~[i64] = ~[10, 11, 12, 13];
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print tuple_interior_padding
+// check:$1 = {0, OneHundred}
+
+// debugger:print tuple_padding_at_end
+// check:$2 = {{1, OneThousand}, 2}
+
+// debugger:print tuple_different_enums
+// check:$3 = {OneThousand, MountainView, OneMillion, Vienna}
+
+// debugger:print padded_struct
+// check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5}
+
+// debugger:print packed_struct
+// check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8}
+
+// debugger:print non_padded_struct
+// check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto}
+
+// debugger:print struct_with_drop
+// check:$7 = {{a = OneHundred, b = Vienna}, 9}
+
+enum AnEnum {
+ OneHundred = 100,
+ OneThousand = 1000,
+ OneMillion = 1000000
+}
+
+enum AnotherEnum {
+ MountainView,
+ Toronto,
+ Vienna
+}
+
+struct PaddedStruct {
+ a: i16,
+ b: AnEnum,
+ c: i16,
+ d: AnotherEnum,
+ e: i16
+}
+
+#[packed]
+struct PackedStruct {
+ a: i16,
+ b: AnEnum,
+ c: i16,
+ d: AnotherEnum,
+ e: i16
+}
+
+struct NonPaddedStruct {
+ a: AnEnum,
+ b: AnotherEnum,
+ c: AnEnum,
+ d: AnotherEnum
+}
+
+struct StructWithDrop {
+ a: AnEnum,
+ b: AnotherEnum
+}
+
+impl Drop for StructWithDrop {
+ fn drop(&self) {()}
+}
+
+fn main() {
+
+ let tuple_interior_padding = (0_i16, OneHundred);
+ // It will depend on the machine architecture if any padding is actually involved here
+ let tuple_padding_at_end = ((1_u64, OneThousand), 2_u64);
+ let tuple_different_enums = (OneThousand, MountainView, OneMillion, Vienna);
+
+ let padded_struct = PaddedStruct {
+ a: 3,
+ b: OneMillion,
+ c: 4,
+ d: Toronto,
+ e: 5
+ };
+
+ let packed_struct = PackedStruct {
+ a: 6,
+ b: OneHundred,
+ c: 7,
+ d: Vienna,
+ e: 8
+ };
+
+ let non_padded_struct = NonPaddedStruct {
+ a: OneMillion,
+ b: MountainView,
+ c: OneThousand,
+ d: Toronto
+ };
+
+ let struct_with_drop = (StructWithDrop { a: OneHundred, b: Vienna }, 9_i64);
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print auto_one
+// check:$1 = One
+
+// debugger:print auto_two
+// check:$2 = Two
+
+// debugger:print auto_three
+// check:$3 = Three
+
+// debugger:print manual_one_hundred
+// check:$4 = OneHundred
+
+// debugger:print manual_one_thousand
+// check:$5 = OneThousand
+
+// debugger:print manual_one_million
+// check:$6 = OneMillion
+
+// debugger:print single_variant
+// check:$7 = TheOnlyVariant
+
+enum AutoDiscriminant {
+ One,
+ Two,
+ Three
+}
+
+enum ManualDiscriminant {
+ OneHundred = 100,
+ OneThousand = 1000,
+ OneMillion = 1000000
+}
+
+enum SingleVariant {
+ TheOnlyVariant
+}
+
+fn main() {
+
+ let auto_one = One;
+ let auto_two = Two;
+ let auto_three = Three;
+
+ let manual_one_hundred = OneHundred;
+ let manual_one_thousand = OneThousand;
+ let manual_one_million = OneMillion;
+
+ let single_variant = TheOnlyVariant;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
// xfail-test
-// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical
-// value.
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// check:$2 = false
fn main() {
- let (a, b) : (int, bool) = (9898, false);
+ let (a, b): (int, bool) = (9898, false);
zzz();
}
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print no_padding1
+// check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}}
+// debugger:print no_padding2
+// check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}}
+
+// debugger:print struct_internal_padding
+// check:$3 = {x = {13, 14}, y = {15, 16}}
+
+// debugger:print single_vec
+// check:$4 = {x = {17, 18, 19, 20, 21}}
+
+// debugger:print struct_padded_at_end
+// check:$5 = {x = {22, 23}, y = {24, 25}}
+
+struct NoPadding1 {
+ x: [u32, ..3],
+ y: i32,
+ z: [f32, ..2]
+}
+
+struct NoPadding2 {
+ x: [u32, ..3],
+ y: [[u32, ..2], ..2]
+}
+
+struct StructInternalPadding {
+ x: [i16, ..2],
+ y: [i64, ..2]
+}
+
+struct SingleVec {
+ x: [i16, ..5]
+}
+
+struct StructPaddedAtEnd {
+ x: [i64, ..2],
+ y: [i16, ..2]
+}
+
+fn main() {
+
+ let no_padding1 = NoPadding1 {
+ x: [0, 1, 2],
+ y: -3,
+ z: [4.5, 5.5]
+ };
+
+ let no_padding2 = NoPadding2 {
+ x: [6, 7, 8],
+ y: [[9, 10], [11, 12]]
+ };
+
+ let struct_internal_padding = StructInternalPadding {
+ x: [13, 14],
+ y: [15, 16]
+ };
+
+ let single_vec = SingleVec {
+ x: [17, 18, 19, 20, 21]
+ };
+
+ let struct_padded_at_end = StructPaddedAtEnd {
+ x: [22, 23],
+ y: [24, 25]
+ };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
// xfail-test
-// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical
-// value.
-
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print the_a->val
+// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}}
+
+// debugger:print the_b->val
+// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
+
+// debugger:print univariant->val
+// check:$3 = {-9747455}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum ABC {
+ TheA { x: i64, y: i64 },
+ TheB (i64, i32, i32),
+}
+
+// This is a special case since it does not have the implicit discriminant field.
+enum Univariant {
+ TheOnlyCase(i64)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let the_a = @TheA { x: 0, y: 8970181431921507452 };
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let the_b = @TheB (0, 286331153, 286331153);
+
+ let univariant = @TheOnlyCase(-9747455);
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print unique->val.elements[0]->val
+// check:$1 = 10
+
+// debugger:print unique->val.elements[1]->val
+// check:$2 = 11
+
+// debugger:print unique->val.elements[2]->val
+// check:$3 = 12
+
+// debugger:print unique->val.elements[3]->val
+// check:$4 = 13
+
+fn main() {
+
+ let unique: ~[@i64] = ~[@10, @11, @12, @13];
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print *ordinary_unique
+// check:$1 = {-1, -2}
+
+// debugger:print managed_within_unique.val->x
+// check:$2 = -3
+
+// debugger:print managed_within_unique.val->y->val
+// check:$3 = -4
+
+struct ContainsManaged
+{
+ x: int,
+ y: @int
+}
+
+fn main() {
+
+ let ordinary_unique = ~(-1, -2);
+
+
+ // This is a special case: Normally values allocated in the exchange heap are not boxed, unless,
+ // however, if they contain managed pointers.
+ // This test case verifies that both cases are handled correctly.
+ let managed_within_unique = ~ContainsManaged { x: -3, y: @-4 };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print first
+// check:$1 = {<No data fields>}
+
+// debugger:print second
+// check:$2 = {<No data fields>}
+
+enum ANilEnum {}
+enum AnotherNilEnum {}
+
+// I (mw) am not sure this test case makes much sense...
+// Also, it relies on some implementation details:
+// 1. That empty enums as well as '()' are represented as empty structs
+// 2. That gdb prints the string "{<No data fields>}" for empty structs (which may change some time)
+fn main() {
+ unsafe {
+ let first: ANilEnum = std::cast::transmute(());
+ let second: AnotherNilEnum = std::cast::transmute(());
+
+ zzz();
+ }
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print some
+// check:$1 = {0x12345678}
+
+// debugger:print none
+// check:$2 = {0x0}
+
+// debugger:print full
+// check:$3 = {454545, 0x87654321, 9988}
+
+// debugger:print empty
+// check:$4 = {0, 0x0, 0}
+
+// debugger:print droid
+// check:$5 = {id = 675675, range = 10000001, internals = 0x43218765}
+
+// debugger:print void_droid
+// check:$6 = {id = 0, range = 0, internals = 0x0}
+
+
+// If a struct has exactly two variants, one of them is empty, and the other one
+// contains a non-nullable pointer, then this value is used as the discriminator.
+// The test cases in this file make sure that something readable is generated for
+// this kind of types.
+
+enum MoreFields<'self> {
+ Full(u32, &'self int, i16),
+ Empty
+}
+
+enum NamedFields<'self> {
+ Droid { id: i32, range: i64, internals: &'self int },
+ Void
+}
+
+fn main() {
+
+ let some: Option<&u32> = Some(unsafe { std::cast::transmute(0x12345678) });
+ let none: Option<&u32> = None;
+
+ let full = Full(454545, unsafe { std::cast::transmute(0x87654321) }, 9988);
+
+ let int_val = 0;
+ let mut empty = Full(0, &int_val, 0);
+ empty = Empty;
+
+ let droid = Droid { id: 675675, range: 10000001, internals: unsafe { std::cast::transmute(0x43218765) } };
+
+ let mut void_droid = Droid { id: 0, range: 0, internals: &int_val };
+ void_droid = Void;
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print packed
+// check:$1 = {x = 123, y = 234, z = 345}
+
+// debugger:print packedInPacked
+// check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}}
+
+// debugger:print packedInUnpacked
+// check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}}
+
+// debugger:print unpackedInPacked
+// check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210}
+
+
+// debugger:print packedInPackedWithDrop
+// check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}}
+
+// debugger:print packedInUnpackedWithDrop
+// check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}}
+
+// debugger:print unpackedInPackedWithDrop
+// check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21}
+
+// debugger:print deeplyNested
+// check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}}
+
+#[packed]
+struct Packed {
+ x: i16,
+ y: i32,
+ z: i64
+}
+
+impl Drop for Packed {
+ fn drop(&self) {}
+}
+
+#[packed]
+struct PackedInPacked {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+struct PackedInUnpacked {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+struct Unpacked {
+ x: i64,
+ y: i32,
+ z: i16
+}
+
+impl Drop for Unpacked {
+ fn drop(&self) {}
+}
+
+#[packed]
+struct UnpackedInPacked {
+ a: i16,
+ b: Unpacked,
+ c: Unpacked,
+ d: i64
+}
+
+#[packed]
+struct PackedInPackedWithDrop {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+impl Drop for PackedInPackedWithDrop {
+ fn drop(&self) {}
+}
+
+struct PackedInUnpackedWithDrop {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+impl Drop for PackedInUnpackedWithDrop {
+ fn drop(&self) {}
+}
+
+#[packed]
+struct UnpackedInPackedWithDrop {
+ a: i16,
+ b: Unpacked,
+ c: Unpacked,
+ d: i64
+}
+
+impl Drop for UnpackedInPackedWithDrop {
+ fn drop(&self) {}
+}
+
+struct DeeplyNested {
+ a: PackedInPacked,
+ b: UnpackedInPackedWithDrop,
+ c: PackedInUnpacked,
+ d: PackedInUnpackedWithDrop,
+ e: UnpackedInPacked,
+ f: PackedInPackedWithDrop
+}
+
+fn main() {
+ let packed = Packed { x: 123, y: 234, z: 345 };
+
+ let packedInPacked = PackedInPacked {
+ a: 1111,
+ b: Packed { x: 2222, y: 3333, z: 4444 },
+ c: 5555,
+ d: Packed { x: 6666, y: 7777, z: 8888 }
+ };
+
+ let packedInUnpacked = PackedInUnpacked {
+ a: -1111,
+ b: Packed { x: -2222, y: -3333, z: -4444 },
+ c: -5555,
+ d: Packed { x: -6666, y: -7777, z: -8888 }
+ };
+
+ let unpackedInPacked = UnpackedInPacked {
+ a: 987,
+ b: Unpacked { x: 876, y: 765, z: 654 },
+ c: Unpacked { x: 543, y: 432, z: 321 },
+ d: 210
+ };
+
+ let packedInPackedWithDrop = PackedInPackedWithDrop {
+ a: 11,
+ b: Packed { x: 22, y: 33, z: 44 },
+ c: 55,
+ d: Packed { x: 66, y: 77, z: 88 }
+ };
+
+ let packedInUnpackedWithDrop = PackedInUnpackedWithDrop {
+ a: -11,
+ b: Packed { x: -22, y: -33, z: -44 },
+ c: -55,
+ d: Packed { x: -66, y: -77, z: -88 }
+ };
+
+ let unpackedInPackedWithDrop = UnpackedInPackedWithDrop {
+ a: 98,
+ b: Unpacked { x: 87, y: 76, z: 65 },
+ c: Unpacked { x: 54, y: 43, z: 32 },
+ d: 21
+ };
+
+ let deeplyNested = DeeplyNested {
+ a: PackedInPacked {
+ a: 1,
+ b: Packed { x: 2, y: 3, z: 4 },
+ c: 5,
+ d: Packed { x: 6, y: 7, z: 8 }
+ },
+ b: UnpackedInPackedWithDrop {
+ a: 9,
+ b: Unpacked { x: 10, y: 11, z: 12 },
+ c: Unpacked { x: 13, y: 14, z: 15 },
+ d: 16
+ },
+ c: PackedInUnpacked {
+ a: 17,
+ b: Packed { x: 18, y: 19, z: 20 },
+ c: 21,
+ d: Packed { x: 22, y: 23, z: 24 }
+ },
+ d: PackedInUnpackedWithDrop {
+ a: 25,
+ b: Packed { x: 26, y: 27, z: 28 },
+ c: 29,
+ d: Packed { x: 30, y: 31, z: 32 }
+ },
+ e: UnpackedInPacked {
+ a: 33,
+ b: Unpacked { x: 34, y: 35, z: 36 },
+ c: Unpacked { x: 37, y: 38, z: 39 },
+ d: 40
+ },
+ f: PackedInPackedWithDrop {
+ a: 41,
+ b: Packed { x: 42, y: 43, z: 44 },
+ c: 45,
+ d: Packed { x: 46, y: 47, z: 48 }
+ }
+ };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print packed
+// check:$1 = {x = 123, y = 234, z = 345}
+
+// debugger:print packedInPacked
+// check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}}
+
+// debugger:print packedInUnpacked
+// check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}}
+
+// debugger:print unpackedInPacked
+// check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98}
+
+// debugger:print sizeof(packed)
+// check:$5 = 14
+
+// debugger:print sizeof(packedInPacked)
+// check:$6 = 40
+
+#[packed]
+struct Packed {
+ x: i16,
+ y: i32,
+ z: i64
+}
+
+#[packed]
+struct PackedInPacked {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+// layout (64 bit): aaaa bbbb bbbb bbbb bb.. .... cccc cccc dddd dddd dddd dd..
+struct PackedInUnpacked {
+ a: i32,
+ b: Packed,
+ c: i64,
+ d: Packed
+}
+
+// layout (64 bit): xx.. yyyy zz.. .... wwww wwww
+struct Unpacked {
+ x: i16,
+ y: i32,
+ z: i16,
+ w: i64
+}
+
+// layout (64 bit): aabb bbbb bbbb bbbb bbbb bbbb bbcc cccc cccc cccc cccc cccc ccdd dddd dd
+#[packed]
+struct UnpackedInPacked {
+ a: i16,
+ b: Unpacked,
+ c: Unpacked,
+ d: i64
+}
+
+fn main() {
+ let packed = Packed { x: 123, y: 234, z: 345 };
+
+ let packedInPacked = PackedInPacked {
+ a: 1111,
+ b: Packed { x: 2222, y: 3333, z: 4444 },
+ c: 5555,
+ d: Packed { x: 6666, y: 7777, z: 8888 }
+ };
+
+ let packedInUnpacked = PackedInUnpacked {
+ a: -1111,
+ b: Packed { x: -2222, y: -3333, z: -4444 },
+ c: -5555,
+ d: Packed { x: -6666, y: -7777, z: -8888 }
+ };
+
+ let unpackedInPacked = UnpackedInPacked {
+ a: 987,
+ b: Unpacked { x: 876, y: 765, z: 654, w: 543 },
+ c: Unpacked { x: 432, y: 321, z: 210, w: 109 },
+ d: -98
+ };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
+++ /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.
-
-// 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
-// about UTF-32 character encoding and will print a rust char as only
-// its numerical value.
-
-// compile-flags:-Z extra-debug-info
-// debugger:break zzz
-// debugger:run
-// debugger:finish
-// debugger:print *bool_ref
-// check:$1 = true
-
-// debugger:print *int_ref
-// check:$2 = -1
-
-// debugger:print *char_ref
-// check:$3 = 97
-
-// debugger:print *i8_ref
-// check:$4 = 68 'D'
-
-// debugger:print *i16_ref
-// check:$5 = -16
-
-// debugger:print *i32_ref
-// check:$6 = -32
-
-// debugger:print *i64_ref
-// check:$7 = -64
-
-// debugger:print *uint_ref
-// check:$8 = 1
-
-// debugger:print *u8_ref
-// check:$9 = 100 'd'
-
-// debugger:print *u16_ref
-// check:$10 = 16
-
-// debugger:print *u32_ref
-// check:$11 = 32
-
-// debugger:print *u64_ref
-// check:$12 = 64
-
-// debugger:print *float_ref
-// check:$13 = 1.5
-
-// debugger:print *f32_ref
-// check:$14 = 2.5
-
-// debugger:print *f64_ref
-// check:$15 = 3.5
-
-fn main() {
- let bool_val: bool = true;
- let bool_ref : &bool = &bool_val;
-
- let int_val: int = -1;
- let int_ref : &int = &int_val;
-
- let char_val: char = 'a';
- let char_ref : &char = &char_val;
-
- let i8_val: i8 = 68;
- let i8_ref : &i8 = &i8_val;
-
- let i16_val: i16 = -16;
- let i16_ref : &i16 = &i16_val;
-
- let i32_val: i32 = -32;
- let i32_ref : &i32 = &i32_val;
-
- let uint_val: i64 = -64;
- let i64_ref : &i64 = &uint_val;
-
- let uint_val: uint = 1;
- let uint_ref : &uint = &uint_val;
-
- let u8_val: u8 = 100;
- let u8_ref : &u8 = &u8_val;
-
- let u16_val: u16 = 16;
- let u16_ref : &u16 = &u16_val;
-
- let u32_val: u32 = 32;
- let u32_ref : &u32 = &u32_val;
-
- let u64_val: u64 = 64;
- let u64_ref : &u64 = &u64_val;
-
- let float_val: float = 1.5;
- let float_ref : &float = &float_val;
-
- let f32_val: f32 = 2.5;
- let f32_ref : &f32 = &f32_val;
-
- let f64_val: f64 = 3.5;
- let f64_ref : &f64 = &f64_val;
- zzz();
-}
-
-fn zzz() {()}
\ No newline at end of file
+++ /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.
-
-// 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.
-
-// compile-flags:-Z extra-debug-info
-// debugger:break zzz
-// debugger:run
-// debugger:finish
-// debugger:print *bool_ref
-// check:$1 = true
-
-// debugger:print *int_ref
-// check:$2 = -1
-
-// debugger:print *char_ref
-// check:$3 = 97
-
-// debugger:print/d *i8_ref
-// check:$4 = 68
-
-// debugger:print *i16_ref
-// check:$5 = -16
-
-// debugger:print *i32_ref
-// check:$6 = -32
-
-// debugger:print *i64_ref
-// check:$7 = -64
-
-// debugger:print *uint_ref
-// check:$8 = 1
-
-// debugger:print/d *u8_ref
-// check:$9 = 100
-
-// debugger:print *u16_ref
-// check:$10 = 16
-
-// debugger:print *u32_ref
-// check:$11 = 32
-
-// debugger:print *u64_ref
-// check:$12 = 64
-
-// debugger:print *float_ref
-// check:$13 = 1.5
-
-// debugger:print *f32_ref
-// check:$14 = 2.5
-
-// debugger:print *f64_ref
-// check:$15 = 3.5
-
-
-fn main() {
- let bool_box: @bool = @true;
- let bool_ref : &bool = bool_box;
-
- let int_box: @int = @-1;
- let int_ref : &int = int_box;
-
- let char_box: @char = @'a';
- let char_ref : &char = char_box;
-
- let i8_box: @i8 = @68;
- let i8_ref : &i8 = i8_box;
-
- let i16_box: @i16 = @-16;
- let i16_ref : &i16 = i16_box;
-
- let i32_box: @i32 = @-32;
- let i32_ref : &i32 = i32_box;
-
- let i64_box: @i64 = @-64;
- let i64_ref : &i64 = i64_box;
-
- let uint_box: @uint = @1;
- let uint_ref : &uint = uint_box;
-
- let u8_box: @u8 = @100;
- let u8_ref : &u8 = u8_box;
-
- let u16_box: @u16 = @16;
- let u16_ref : &u16 = u16_box;
-
- let u32_box: @u32 = @32;
- let u32_ref : &u32 = u32_box;
-
- let u64_box: @u64 = @64;
- let u64_ref : &u64 = u64_box;
-
- let float_box: @float = @1.5;
- let float_ref : &float = float_box;
-
- let f32_box: @f32 = @2.5;
- let f32_ref : &f32 = f32_box;
-
- let f64_box: @f64 = @3.5;
- let f64_ref : &f64 = f64_box;
- zzz();
-}
-
-fn zzz() {()}
\ No newline at end of file
+++ /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.
-
-// 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.
-
-// compile-flags:-Z extra-debug-info
-// debugger:break zzz
-// debugger:run
-// debugger:finish
-
-// debugger:print *stack_val_ref
-// check:$1 = {x = 10, y = 23.5}
-
-// debugger:print *stack_val_interior_ref_1
-// check:$2 = 10
-
-// debugger:print *stack_val_interior_ref_2
-// check:$3 = 23.5
-
-// debugger:print *ref_to_unnamed
-// check:$4 = {x = 11, y = 24.5}
-
-// debugger:print *managed_val_ref
-// check:$5 = {x = 12, y = 25.5}
-
-// debugger:print *managed_val_interior_ref_1
-// check:$6 = 12
-
-// debugger:print *managed_val_interior_ref_2
-// check:$7 = 25.5
-
-// debugger:print *unique_val_ref
-// check:$8 = {x = 13, y = 26.5}
-
-// debugger:print *unique_val_interior_ref_1
-// check:$9 = 13
-
-// debugger:print *unique_val_interior_ref_2
-// check:$10 = 26.5
-
-
-
-struct SomeStruct {
- x: int,
- y: f64
-}
-
-fn main() {
- let stack_val: SomeStruct = SomeStruct { x: 10, y: 23.5 };
- let stack_val_ref : &SomeStruct = &stack_val;
- let stack_val_interior_ref_1 : &int = &stack_val.x;
- let stack_val_interior_ref_2 : &f64 = &stack_val.y;
- let ref_to_unnamed : &SomeStruct = &SomeStruct { x: 11, y: 24.5 };
-
- let managed_val = @SomeStruct { x: 12, y: 25.5 };
- let managed_val_ref : &SomeStruct = managed_val;
- let managed_val_interior_ref_1 : &int = &managed_val.x;
- let managed_val_interior_ref_2 : &f64 = &managed_val.y;
-
- let unique_val = ~SomeStruct { x: 13, y: 26.5 };
- let unique_val_ref : &SomeStruct = unique_val;
- let unique_val_interior_ref_1 : &int = &unique_val.x;
- let unique_val_interior_ref_2 : &f64 = &unique_val.y;
-
- zzz();
-}
-
-fn zzz() {()}
\ No newline at end of file
+++ /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.
-
-// 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.
-
-// compile-flags:-Z extra-debug-info
-// debugger:break zzz
-// debugger:run
-// debugger:finish
-
-// debugger:print *stack_val_ref
-// check:$1 = {-14, -19}
-
-// debugger:print *ref_to_unnamed
-// check:$2 = {-15, -20}
-
-// debugger:print *managed_val_ref
-// check:$3 = {-16, -21}
-
-// debugger:print *unique_val_ref
-// check:$4 = {-17, -22}
-
-fn main() {
- let stack_val: (i16, f32) = (-14, -19f32);
- let stack_val_ref : &(i16, f32) = &stack_val;
- let ref_to_unnamed : &(i16, f32) = &(-15, -20f32);
-
- let managed_val : @(i16, f32) = @(-16, -21f32);
- let managed_val_ref : &(i16, f32) = managed_val;
-
- let unique_val: ~(i16, f32) = ~(-17, -22f32);
- let unique_val_ref : &(i16, f32) = unique_val;
-
- zzz();
-}
-
-fn zzz() {()}
\ No newline at end of file
+++ /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.
-
-// 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.
-
-// compile-flags:-Z extra-debug-info
-// debugger:break zzz
-// debugger:run
-// debugger:finish
-// debugger:print *bool_ref
-// check:$1 = true
-
-// debugger:print *int_ref
-// check:$2 = -1
-
-// debugger:print *char_ref
-// check:$3 = 97
-
-// debugger:print/d *i8_ref
-// check:$4 = 68
-
-// debugger:print *i16_ref
-// check:$5 = -16
-
-// debugger:print *i32_ref
-// check:$6 = -32
-
-// debugger:print *i64_ref
-// check:$7 = -64
-
-// debugger:print *uint_ref
-// check:$8 = 1
-
-// debugger:print/d *u8_ref
-// check:$9 = 100
-
-// debugger:print *u16_ref
-// check:$10 = 16
-
-// debugger:print *u32_ref
-// check:$11 = 32
-
-// debugger:print *u64_ref
-// check:$12 = 64
-
-// debugger:print *float_ref
-// check:$13 = 1.5
-
-// debugger:print *f32_ref
-// check:$14 = 2.5
-
-// debugger:print *f64_ref
-// check:$15 = 3.5
-
-
-fn main() {
- let bool_box: ~bool = ~true;
- let bool_ref : &bool = bool_box;
-
- let int_box: ~int = ~-1;
- let int_ref : &int = int_box;
-
- let char_box: ~char = ~'a';
- let char_ref : &char = char_box;
-
- let i8_box: ~i8 = ~68;
- let i8_ref : &i8 = i8_box;
-
- let i16_box: ~i16 = ~-16;
- let i16_ref : &i16 = i16_box;
-
- let i32_box: ~i32 = ~-32;
- let i32_ref : &i32 = i32_box;
-
- let i64_box: ~i64 = ~-64;
- let i64_ref : &i64 = i64_box;
-
- let uint_box: ~uint = ~1;
- let uint_ref : &uint = uint_box;
-
- let u8_box: ~u8 = ~100;
- let u8_ref : &u8 = u8_box;
-
- let u16_box: ~u16 = ~16;
- let u16_ref : &u16 = u16_box;
-
- let u32_box: ~u32 = ~32;
- let u32_ref : &u32 = u32_box;
-
- let u64_box: ~u64 = ~64;
- let u64_ref : &u64 = u64_box;
-
- let float_box: ~float = ~1.5;
- let float_ref : &float = float_box;
-
- let f32_box: ~f32 = ~2.5;
- let f32_ref : &f32 = f32_box;
-
- let f64_box: ~f64 = ~3.5;
- let f64_ref : &f64 = f64_box;
- zzz();
-}
-
-fn zzz() {()}
\ No newline at end of file
fn main() {
- let noPadding8 : (i8, u8) = (-100, 100);
- let noPadding16 : (i16, i16, u16) = (0, 1, 2);
- let noPadding32 : (i32, f32, u32) = (3, 4.5, 5);
- let noPadding64 : (i64, f64, u64) = (6, 7.5, 8);
+ let noPadding8: (i8, u8) = (-100, 100);
+ let noPadding16: (i16, i16, u16) = (0, 1, 2);
+ let noPadding32: (i32, f32, u32) = (3, 4.5, 5);
+ let noPadding64: (i64, f64, u64) = (6, 7.5, 8);
- let internalPadding1 : (i16, i32) = (9, 10);
- let internalPadding2 : (i16, i32, u32, u64) = (11, 12, 13, 14);
+ let internalPadding1: (i16, i32) = (9, 10);
+ let internalPadding2: (i16, i32, u32, u64) = (11, 12, 13, 14);
- let paddingAtEnd : (i32, i16) = (15, 16);
+ let paddingAtEnd: (i32, i16) = (15, 16);
zzz();
}
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, 0, {x = 2088533116, y = 2088533116, z = 31868}}, {Case1, 0, 8970181431921507452, 31868}}
+
+// debugger:print case2
+// check:$2 = {{Case2, 0, {x = 286331153, y = 286331153, z = 4369}}, {Case2, 0, 1229782938247303441, 4369}}
+
+// debugger:print univariant
+// check:$3 = {{x = 123, y = 456, z = 789}}
+
+struct Struct {
+ x: u32,
+ y: i32,
+ z: i16
+}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular {
+ Case1(u64, Struct),
+ Case2(u64, u64, i16)
+}
+
+enum Univariant {
+ TheOnlyCase(Struct)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1 = Case1(0, Struct { x: 2088533116, y: 2088533116, z: 31868 });
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2 = Case2(0, 1229782938247303441, 4369);
+
+ let univariant = TheOnlyCase(Struct { x: 123, y: 456, z: 789 });
+
+ zzz();
+}
+
+fn zzz() {()}
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {Case1, a = 0, b = 2088533116, c = 2088533116}, {Case1, a = 0, b = 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {Case2, a = 0, b = 286331153, c = 286331153}, {Case2, a = 0, b = 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {a = -1}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular {
+ Case1 { a: u64, b: u16, c: u16, d: u16, e: u16},
+ Case2 { a: u64, b: u32, c: u32},
+ Case3 { a: u64, b: u64 }
+}
+
+enum Univariant {
+ TheOnlyCase { a: i64 }
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2 = Case2 { a: 0, b: 286331153, c: 286331153 };
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3 = Case3 { a: 0, b: 6438275382588823897 };
+
+ let univariant = TheOnlyCase { a: -1 };
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-test
+// 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:print withDestructor
// check:$3 = {a = {x = 10, y = 20}, guard = -1}
+// debugger:print nested
+// check:$4 = {a = {a = {x = 7890, y = 9870}}}
+
struct NoDestructor {
- x : i32,
- y : i64
+ x: i32,
+ y: i64
}
struct WithDestructor {
- x : i32,
- y : i64
+ x: i32,
+ y: i64
}
impl Drop for WithDestructor {
- fn finalize(&self) {}
+ fn drop(&self) {}
}
struct NoDestructorGuarded {
guard: i64
}
+struct NestedInner {
+ a: WithDestructor
+}
+
+impl Drop for NestedInner {
+ fn drop(&self) {}
+}
+
+struct NestedOuter {
+ a: NestedInner
+}
+
// The compiler adds a 'destructed' boolean field to structs implementing Drop. This field is used
// at runtime to prevent drop() to be executed more than once (see middle::trans::adt).
// then the debugger will have an invalid offset for the field 'guard' and thus should not be
// able to read its value correctly (dots are padding bytes, D is the boolean destructor flag):
//
+ // 64 bit
+ //
// NoDestructorGuarded = 0000....00000000FFFFFFFF
// <--------------><------>
// NoDestructor guard
// <----------------------><------> // How it actually is
// WithDestructor guard
//
+ // 32 bit
+ //
+ // NoDestructorGuarded = 000000000000FFFFFFFF
+ // <----------><------>
+ // NoDestructor guard
+ //
+ //
+ // withDestructorGuarded = 000000000000D...FFFFFFFF
+ // <----------><------> // How debug info says it is
+ // WithDestructor guard
+ //
+ // <--------------><------> // How it actually is
+ // WithDestructor guard
+ //
let withDestructor = WithDestructorGuarded {
a: WithDestructor { x: 10, y: 20 },
guard: -1
};
+ // expected layout (64 bit) = xxxx....yyyyyyyyD.......D...
+ // <--WithDestructor------>
+ // <-------NestedInner-------->
+ // <-------NestedOuter-------->
+ let nested = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } };
+
zzz();
}
// check:$7 = {{21, 22}, 23}
fn main() {
- let no_padding1 : ((u32, u32), u32, u32) = ((0, 1), 2, 3);
- let no_padding2 : (u32, (u32, u32), u32) = (4, (5, 6), 7);
- let no_padding3 : (u32, u32, (u32, u32)) = (8, 9, (10, 11));
+ let no_padding1: ((u32, u32), u32, u32) = ((0, 1), 2, 3);
+ let no_padding2: (u32, (u32, u32), u32) = (4, (5, 6), 7);
+ let no_padding3: (u32, u32, (u32, u32)) = (8, 9, (10, 11));
- let internal_padding1 : (i16, (i32, i32)) = (12, (13, 14));
- let internal_padding2 : (i16, (i16, i32)) = (15, (16, 17));
+ let internal_padding1: (i16, (i32, i32)) = (12, (13, 14));
+ let internal_padding2: (i16, (i16, i32)) = (15, (16, 17));
- let padding_at_end1 : (i32, (i32, i16)) = (18, (19, 20));
- let padding_at_end2 : ((i32, i16), i32) = ((21, 22), 23);
+ let padding_at_end1: (i32, (i32, i16)) = (18, (19, 20));
+ let padding_at_end2: ((i32, i16), i32) = ((21, 22), 23);
zzz();
}
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+
+// debugger:print case1
+// check:$1 = {{Case1, 0, 31868, 31868, 31868, 31868}, {Case1, 0, 2088533116, 2088533116}, {Case1, 0, 8970181431921507452}}
+
+// debugger:print case2
+// check:$2 = {{Case2, 0, 4369, 4369, 4369, 4369}, {Case2, 0, 286331153, 286331153}, {Case2, 0, 1229782938247303441}}
+
+// debugger:print case3
+// check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}}
+
+// debugger:print univariant
+// check:$4 = {-1}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum Regular {
+ Case1(u64, u16, u16, u16, u16),
+ Case2(u64, u32, u32),
+ Case3(u64, u64)
+}
+
+enum Univariant {
+ TheOnlyCase(i64)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let case1 = Case1(0, 31868, 31868, 31868, 31868);
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let case2 = Case2(0, 286331153, 286331153);
+
+ // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
+ // 0b01011001010110010101100101011001 = 1499027801
+ // 0b0101100101011001 = 22873
+ // 0b01011001 = 89
+ let case3 = Case3(0, 6438275382588823897);
+
+ let univariant = TheOnlyCase(-1);
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:finish
+
+// debugger:print *the_a
+// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}}
+
+// debugger:print *the_b
+// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}}
+
+// debugger:print *univariant
+// check:$3 = {123234}
+
+// The first element is to ensure proper alignment, irrespective of the machines word size. Since
+// the size of the discriminant value is machine dependent, this has be taken into account when
+// datatype layout should be predictable as in this case.
+enum ABC {
+ TheA { x: i64, y: i64 },
+ TheB (i64, i32, i32),
+}
+
+// This is a special case since it does not have the implicit discriminant field.
+enum Univariant {
+ TheOnlyCase(i64)
+}
+
+fn main() {
+
+ // In order to avoid endianess trouble all of the following test values consist of a single
+ // repeated byte. This way each interpretation of the union should look the same, no matter if
+ // this is a big or little endian machine.
+
+ // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
+ // 0b01111100011111000111110001111100 = 2088533116
+ // 0b0111110001111100 = 31868
+ // 0b01111100 = 124
+ let the_a = ~TheA { x: 0, y: 8970181431921507452 };
+
+ // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
+ // 0b00010001000100010001000100010001 = 286331153
+ // 0b0001000100010001 = 4369
+ // 0b00010001 = 17
+ let the_b = ~TheB (0, 286331153, 286331153);
+
+ let univariant = ~TheOnlyCase(123234);
+
+ zzz();
+}
+
+fn zzz() {()}
\ No newline at end of file
--- /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.
+
+// 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
+// debugger:run
+// debugger:finish
+// debugger:print empty.size_in_bytes
+// check:$1 = 0
+
+// debugger:print singleton.size_in_bytes
+// check:$2 = 8
+// debugger:print *((int64_t[1]*)(singleton.data_ptr))
+// check:$3 = {1}
+
+// debugger:print multiple.size_in_bytes
+// check:$4 = 32
+// debugger:print *((int64_t[4]*)(multiple.data_ptr))
+// check:$5 = {2, 3, 4, 5}
+
+// debugger:print slice_of_slice.size_in_bytes
+// check:$6 = 16
+// debugger:print *((int64_t[2]*)(slice_of_slice.data_ptr))
+// check:$7 = {3, 4}
+
+// debugger:print padded_tuple.size_in_bytes
+// check:$8 = 16
+// debugger:print padded_tuple.data_ptr[0]
+// check:$9 = {6, 7}
+// debugger:print padded_tuple.data_ptr[1]
+// check:$10 = {8, 9}
+
+// debugger:print padded_struct.size_in_bytes
+// check:$11 = 24
+// debugger:print padded_struct.data_ptr[0]
+// check:$12 = {x = 10, y = 11, z = 12}
+// debugger:print padded_struct.data_ptr[1]
+// check:$13 = {x = 13, y = 14, z = 15}
+
+struct AStruct {
+ x: i16,
+ y: i32,
+ z: i16
+}
+
+fn main() {
+ let empty: &[i64] = &[];
+ let singleton: &[i64] = &[1];
+ let multiple: &[i64] = &[2, 3, 4, 5];
+ let slice_of_slice = multiple.slice(1,3);
+
+ let padded_tuple: &[(i32, i16)] = &[(6, 7), (8, 9)];
+
+ let padded_struct: &[AStruct] = &[
+ AStruct { x: 10, y: 11, z: 12 },
+ AStruct { x: 13, y: 14, z: 15 }
+ ];
+
+ zzz();
+}
+
+fn zzz() {()}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// xfail-test
+// 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
+// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print a
// check:$1 = {1, 2, 3}
-// debugger:print b.vec[0]
-// check:$2 = 4
-// debugger:print c->boxed.data[1]
-// check:$3 = 8
-// debugger:print d->boxed.data[2]
-// check:$4 = 12
fn main() {
let a = [1, 2, 3];
- let b = &[4, 5, 6];
- let c = @[7, 8, 9];
- let d = ~[10, 11, 12];
- _zzz();
+
+ zzz();
}
-fn _zzz() {()}
+fn zzz() {()}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
- -> libc::uintptr_t;
+ -> libc::uintptr_t;
}
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_get_argc() -> libc::c_int;
}
}
--- /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.
+
+// error-pattern:nonzero
+// exec-env:RUST_NEWRT=1
+
+use std::os;
+
+fn main() {
+ os::args();
+ fail!("please have a nonzero exit status");
+}
trait fake_ext_ctxt {
fn session() -> fake_session;
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parser::parse_sess;
}
-type fake_options = {cfg: ast::crate_cfg};
+type fake_options = {cfg: ast::Crate_cfg};
type fake_session = {opts: @fake_options,
parse_sess: parser::parse_sess};
impl of fake_ext_ctxt for fake_session {
fn session() -> fake_session {self}
- fn cfg() -> ast::crate_cfg { self.opts.cfg }
+ fn cfg() -> ast::Crate_cfg { self.opts.cfg }
fn parse_sess() -> parser::parse_sess { self.parse_sess }
}
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[allow(non_implicitly_copyable_typarams)];
-
extern mod syntax;
use syntax::ext::base::ExtCtxt;
rec: Option<@mut RecEnum<A>>
}
-fn make_cycle<A>(a: A) {
+fn make_cycle<A:'static>(a: A) {
let g: @mut RecEnum<A> = @mut RecEnum(Rec {val: a, rec: None});
g.rec = Some(g);
}
-fn f<A:Send + Clone,B:Send + Clone>(a: A, b: B) -> @fn() -> (A, B) {
+fn f<A:Send + Clone + 'static,
+ B:Send + Clone + 'static>(
+ a: A,
+ b: B)
+ -> @fn() -> (A, B) {
let result: @fn() -> (A, B) = || (a.clone(), b.clone());
result
}
// xfail-test #6122
-#[forbid(deprecated_pattern)];
-
extern mod extra;
// These tests used to be separate files, but I wanted to refactor all
#[abi = "cdecl"]
#[nolink]
- pub extern {
+ extern {
pub fn rust_get_sched_id() -> libc::intptr_t;
pub fn get_task_id() -> libc::intptr_t;
}
use std::libc;
#[abi = "cdecl"]
- pub extern {
+ extern {
pub fn get_task_id() -> libc::intptr_t;
}
}
mod libc {
#[abi = "cdecl"]
#[nolink]
- pub extern {
+ extern {
pub fn atol(x: *u8) -> int;
pub fn atoll(x: *u8) -> i64;
}
mod rustrt {
#[cfg(bogus)]
#[abi = "cdecl"]
- pub extern {
+ extern {
// This symbol doesn't exist and would be a link error if this
// module was translated
pub fn bogus();
}
#[abi = "cdecl"]
- pub extern {}
+ extern {}
}
#[cfg(bogus)]
mod test_foreign_items {
pub mod rustrt {
#[abi = "cdecl"]
- pub extern {
+ extern {
#[cfg(bogus)]
pub fn rust_get_stdin() -> ~str;
pub fn rust_get_stdin() -> ~str;
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
one: u16, two: u16
}
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s;
}
one: u32, two: u32
}
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
}
one: u64, two: u64
}
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
}
one: u64, two: u64
}
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
}
one: u8, two: u8
}
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s;
}
// Test a function that takes/returns a u8.
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
}
// Test a function that takes/returns a u32.
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
}
// Test a call to a function that takes/returns a u64.
-pub extern {
+extern {
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
}
one: u16, two: u16
}
-pub extern {
+extern {
pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
}
one: u32, two: u32
}
-pub extern {
+extern {
pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
}
one: u64, two: u64
}
-pub extern {
+extern {
pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
}
one: u8, two: u8
}
-pub extern {
+extern {
pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
-> libc::uintptr_t;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-// error on implicit copies to check fixed length vectors
-// are implicitly copyable
-#[deny(implicit_copies)]
pub fn main() {
let arr = [1,2,3];
let arr2 = arr;
#[abi = "cdecl"]
#[link_name = "rustrt"]
- pub extern {
+ extern {
pub fn rust_get_argc() -> libc::c_int;
}
}
#[abi = "cdecl"]
#[link_name = "rustrt"]
- pub extern {
+ extern {
pub fn rust_get_argc() -> libc::c_int;
}
}
mod libc {
#[nolink]
#[abi = "cdecl"]
- pub extern {
+ extern {
#[link_name = "strlen"]
pub fn my_strlen(str: *u8) -> uint;
}
// FIXME: I want to name a mod that would not link successfully
// wouthout providing a -L argument to the compiler, and that
// will also be found successfully at runtime.
- pub extern {
+ extern {
pub fn IDONTKNOW() -> u32;
}
}
mod foo {
#[nolink]
- pub extern {
+ extern {
pub static errno: int;
}
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn get_task_id() -> libc::intptr_t;
}
}
use super::void;
#[nolink]
- pub extern {
+ extern {
pub fn printf(v: void);
}
}
mod bar {
#[abi = "cdecl"]
#[nolink]
- pub extern {}
+ extern {}
}
mod zed {
#[abi = "cdecl"]
#[nolink]
- pub extern {}
+ extern {}
}
mod libc {
#[abi = "cdecl"]
#[nolink]
- pub extern {
+ extern {
pub fn write(fd: int, buf: *u8, count: ::std::libc::size_t)
- -> ::std::libc::ssize_t;
+ -> ::std::libc::ssize_t;
}
}
mod baz {
#[abi = "cdecl"]
#[nolink]
- pub extern {}
+ extern {}
}
pub fn main() { }
-fn box<T>(x: Box<T>) -> @Box<T> { return @x; }
+fn box<T:'static>(x: Box<T>) -> @Box<T> { return @x; }
struct Box<T> {x: T, y: T, z: T}
struct Recbox<T> {x: @T}
-fn reclift<T>(t: T) -> Recbox<T> { return Recbox {x: @t}; }
+fn reclift<T:'static>(t: T) -> Recbox<T> { return Recbox {x: @t}; }
pub fn main() {
let foo: int = 17;
// happen.)
fn eat_tup(_r: ~@(int, @fn(Pair) -> int)) {}
-fn eat_rec(_r: @~Rec) {}
+fn eat_rec(_r: ~Rec) {}
struct Rec<'self> { a: int, b: &'self fn(Pair) -> int }
struct Pair { x: int, y: int }
pub fn main() {
eat_tup(~@(10, |a| a.x ));
- eat_rec(@~Rec{a: 10, b: |a| a.x });
+ eat_rec(~Rec{a: 10, b: |a| a.x });
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn pref_align_of<T>() -> uint;
pub fn min_align_of<T>() -> uint;
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int;
pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int;
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn frame_address(f: &once fn(*u8));
}
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn move_val_init<T>(dst: &mut T, src: T);
pub fn move_val<T>(dst: &mut T, src: T);
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
fn uninit<T>() -> T;
}
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
fn ctpop8(x: i8) -> i8;
fn ctpop16(x: i16) -> i16;
fn ctpop32(x: i32) -> i32;
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
- fn sqrtf32(x: f32) -> f32;
- fn sqrtf64(x: f64) -> f64;
- fn powif32(a: f32, x: i32) -> f32;
- fn powif64(a: f64, x: i32) -> f64;
- fn sinf32(x: f32) -> f32;
- fn sinf64(x: f64) -> f64;
- fn cosf32(x: f32) -> f32;
- fn cosf64(x: f64) -> f64;
- fn powf32(a: f32, x: f32) -> f32;
- fn powf64(a: f64, x: f64) -> f64;
- fn expf32(x: f32) -> f32;
- fn expf64(x: f64) -> f64;
- fn exp2f32(x: f32) -> f32;
- fn exp2f64(x: f64) -> f64;
- fn logf32(x: f32) -> f32;
- fn logf64(x: f64) -> f64;
- fn log10f32(x: f32) -> f32;
- fn log10f64(x: f64) -> f64;
- fn log2f32(x: f32) -> f32;
- fn log2f64(x: f64) -> f64;
- fn fmaf32(a: f32, b: f32, c: f32) -> f32;
- fn fmaf64(a: f64, b: f64, c: f64) -> f64;
- fn fabsf32(x: f32) -> f32;
- fn fabsf64(x: f64) -> f64;
- fn floorf32(x: f32) -> f32;
- fn floorf64(x: f64) -> f64;
- fn ceilf32(x: f32) -> f32;
- fn ceilf64(x: f64) -> f64;
- fn truncf32(x: f32) -> f32;
- fn truncf64(x: f64) -> f64;
+ extern "rust-intrinsic" {
+ pub fn sqrtf32(x: f32) -> f32;
+ pub fn sqrtf64(x: f64) -> f64;
+ pub fn powif32(a: f32, x: i32) -> f32;
+ pub fn powif64(a: f64, x: i32) -> f64;
+ pub fn sinf32(x: f32) -> f32;
+ pub fn sinf64(x: f64) -> f64;
+ pub fn cosf32(x: f32) -> f32;
+ pub fn cosf64(x: f64) -> f64;
+ pub fn powf32(a: f32, x: f32) -> f32;
+ pub fn powf64(a: f64, x: f64) -> f64;
+ pub fn expf32(x: f32) -> f32;
+ pub fn expf64(x: f64) -> f64;
+ pub fn exp2f32(x: f32) -> f32;
+ pub fn exp2f64(x: f64) -> f64;
+ pub fn logf32(x: f32) -> f32;
+ pub fn logf64(x: f64) -> f64;
+ pub fn log10f32(x: f32) -> f32;
+ pub fn log10f64(x: f64) -> f64;
+ pub fn log2f32(x: f32) -> f32;
+ pub fn log2f64(x: f64) -> f64;
+ pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
+ pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
+ pub fn fabsf32(x: f32) -> f32;
+ pub fn fabsf64(x: f64) -> f64;
+ pub fn floorf32(x: f32) -> f32;
+ pub fn floorf64(x: f64) -> f64;
+ pub fn ceilf32(x: f32) -> f32;
+ pub fn ceilf64(x: f64) -> f64;
+ pub fn truncf32(x: f32) -> f32;
+ pub fn truncf64(x: f64) -> f64;
}
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn get_task_id() -> libc::intptr_t;
}
}
pub type rust_task = uint;
pub mod rustrt {
use super::rust_task;
- pub extern {
+ extern {
pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
}
}
pub type rust_task = bool;
pub mod rustrt {
use super::rust_task;
- pub extern {
+ extern {
pub fn rust_task_is_unwinding(rt: *rust_task) -> bool;
}
}
#[link_name = "m"]
#[abi = "cdecl"]
- pub extern {
+ extern {
#[cfg(unix)]
#[link_name="lgamma_r"]
pub fn lgamma(n: c_double, sign: &mut c_int) -> c_double;
fn f<T>(_x: T) {
}
-#[deny(non_implicitly_copyable_typarams)]
pub fn main() {
f(C(1u));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct list<'self, T> {
- element: &'self T,
- next: Option<@mut list<'self, T>>
+static S: &'static str = "str";
+
+struct list<T> {
+ element: T,
+ next: Option<@mut list<T>>
}
-impl<'self, T> list<'self, T>{
- pub fn addEnd(&mut self, element: &'self T) {
+impl<T:'static> list<T> {
+ pub fn addEnd(&mut self, element: T) {
let newList = list {
element: element,
next: None
}
pub fn main() {
- let s = @"str";
let ls = list {
- element: &s,
+ element: S,
next: None
};
- println(*ls.element);
+ println(ls.element);
}
// except according to those terms.
// xfail-fast
+// xfail-test needs networking
extern mod extra;
--- /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.
+
+// Regression test for issue #5275
+
+fn foo(self_: &A) -> int {
+ if true {
+ fail!()
+ } else {
+ *bar(self_.bar)
+ }
+}
+
+fn bar<'r>(_: &'r mut int) -> &'r int {
+ fail!()
+}
+
+struct A {
+ bar: @mut int,
+}
+
+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.
+
+fn swap(f: &fn(~[int]) -> ~[int]) -> ~[int] {
+ let x = ~[1, 2, 3];
+ f(x)
+}
+
+fn main() {
+ let v = swap(|mut x| { x.push(4); x });
+ let w = do swap |mut x| { x.push(4); x };
+ assert_eq!(v, w);
+}
--- /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.
+
+// compile-flags:-Z debug-info
+
+#[allow(default_methods)];
+
+pub trait TraitWithDefaultMethod {
+ pub fn method(self) {
+ ()
+ }
+}
+
+struct MyStruct;
+
+impl TraitWithDefaultMethod for MyStruct { }
+
+fn main() {
+ MyStruct.method();
+}
\ No newline at end of file
pub mod rustrt {
#[attr = "val"]
#[abi = "cdecl"]
- pub extern {}
+ extern {}
}
}
#[attr1 = "val"]
#[attr2 = "val"]
#[abi = "cdecl"]
- pub extern {}
+ extern {}
}
#[attr1 = "val"]
mod rustrt {
#[attr = "val"]
#[abi = "cdecl"]
- pub extern {
+ extern {
}
}
}
#[attr1 = "val"]
#[attr2 = "val"]
#[abi = "cdecl"]
- pub extern {
+ extern {
}
}
*/
use std::libc;
#[abi = "cdecl"]
- pub extern {
+ extern {
#[attr];
#[attr]
trait repeat<A> { fn get(&self) -> A; }
-impl<A:Clone> repeat<A> for @A {
+impl<A:Clone + 'static> repeat<A> for @A {
fn get(&self) -> A {
(**self).clone()
}
}
-fn repeater<A:Clone>(v: @A) -> @repeat:<A> {
+fn repeater<A:Clone + 'static>(v: @A) -> @repeat:<A> {
// Note: owned kind is not necessary as A appears in the trait type
@v as @repeat:<A> // No
}
pub fn main() {
- let x = &3;
+ let x = 3;
let y = repeater(@x);
- assert_eq!(*x, *(y.get()));
+ assert_eq!(x, y.get());
}
struct V<T> { v: ~[option<T>] }
-fn mk<T>() -> @mut Smallintmap<T> {
+fn mk<T:'static>() -> @mut Smallintmap<T> {
let mut v: ~[option<T>] = ~[];
return @mut Smallintmap {v: v};
}
-fn f<T,U>() {
+fn f<T,U:'static>() {
let mut sim = mk::<U>();
error!(sim);
}
--- /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.
+
+// xfail-pretty
+// xfail-fast
+
+mod mod_dir_implicit_aux;
+
+pub fn main() {
+ assert_eq!(mod_dir_implicit_aux::foo(), 10);
+}
--- /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.
+
+pub fn foo() -> int { 10 }
mod rusti {
#[nolink]
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn morestack_addr() -> *();
}
}
mod rustrt {
use std::libc;
- pub extern {
+ extern {
pub fn debug_get_stk_seg() -> *u8;
pub fn rust_get_sched_id() -> libc::intptr_t;
// Issue #901
mod libc {
#[nolink]
- pub extern {
+ extern {
pub fn printf(x: ());
}
}
// Make sure that we can detect when one end of the pipe is closed.
// xfail-win32
+// xfail-test needs sleep
extern mod extra;
use extra::timer::sleep;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern mod extra;
-use extra::timer::sleep;
-use extra::uv;
use std::pipes;
proto! oneshot (
// xfail-pretty
// xfail-win32
+// xfail-test needs sleep
extern mod extra;
use extra::timer::sleep;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test needs sleep
+
extern mod extra;
use extra::timer::sleep;
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn pref_align_of<T>() -> uint;
pub fn min_align_of<T>() -> uint;
}
mod rusti {
#[abi = "rust-intrinsic"]
- pub extern "rust-intrinsic" {
+ extern "rust-intrinsic" {
pub fn pref_align_of<T>() -> uint;
pub fn min_align_of<T>() -> uint;
}
true
}
- fn visit_str(&self) -> bool {
- self.align_to::<~str>();
- if ! self.inner.visit_str() { return false; }
- self.bump_past::<~str>();
- true
- }
-
fn visit_estr_box(&self) -> bool {
self.align_to::<@str>();
if ! self.inner.visit_estr_box() { return false; }
fn visit_f64(&self) -> bool { true }
fn visit_char(&self) -> bool { true }
- fn visit_str(&self) -> bool { true }
fn visit_estr_box(&self) -> bool { true }
fn visit_estr_uniq(&self) -> bool { true }
fn visit_f64(&self) -> bool { true }
fn visit_char(&self) -> bool { true }
- fn visit_str(&self) -> bool { true }
fn visit_estr_box(&self) -> bool { true }
fn visit_estr_uniq(&self) -> bool { true }
+++ /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 Ctxt { v: uint }
-
-trait get_ctxt<'self> {
- fn get_ctxt(&self) -> &'self Ctxt;
-}
-
-struct HasCtxt<'self> { c: &'self Ctxt }
-
-impl<'self> get_ctxt<'self> for HasCtxt<'self> {
- fn get_ctxt(&self) -> &'self Ctxt {
- self.c
- }
-}
-
-fn get_v(gc: @get_ctxt:) -> uint {
- gc.get_ctxt().v
-}
-
-pub fn main() {
- let ctxt = Ctxt { v: 22 };
- let hc = HasCtxt { c: &ctxt };
-
- assert_eq!(get_v(@hc as @get_ctxt:), 22);
-}
use std::libc;
- pub extern {
+ extern {
pub fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id;
pub fn rust_get_sched_id() -> sched_id;
pub fn rust_new_task_in_sched(id: sched_id) -> task_id;
use super::{Floats, Quad};
#[nolink]
- pub extern {
+ extern {
pub fn debug_abi_1(q: Quad) -> Quad;
pub fn debug_abi_2(f: Floats) -> Floats;
}
--- /dev/null
+// xfail-fast
+// aux-build:trait_default_method_xc_aux.rs
+// aux-build:trait_default_method_xc_aux_2.rs
+
+
+extern mod aux(name = "trait_default_method_xc_aux");
+extern mod aux2(name = "trait_default_method_xc_aux_2");
+use aux::A;
+use aux2::{a_struct, welp};
+
+
+fn main () {
+
+ let a = a_struct { x: 0 };
+ let b = a_struct { x: 1 };
+
+ assert_eq!(0i.g(), 10);
+ assert_eq!(a.g(), 10);
+ assert_eq!(a.h(), 11);
+ assert_eq!(b.g(), 10);
+ assert_eq!(b.h(), 11);
+ assert_eq!(A::lurr(&a, &b), 21);
+
+ welp(&0);
+}
mod libc {
#[nolink]
- pub extern {
+ extern {
pub fn malloc(size: int) -> *u8;
}
}
#[cfg(target_os = "win32")]
#[abi = "stdcall"]
- pub extern "stdcall" {
+ extern "stdcall" {
pub fn GetProcessHeap() -> HANDLE;
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T)
-> LPVOID;