/doc/html
/doc/latex
/doc/std
+/doc/arena
/doc/extra
+/doc/flate
+/doc/glob
/doc/green
/doc/native
/doc/rustc
/doc/syntax
+/doc/rustdoc
/doc/rustuv
/doc/rustpkg
/nd/
Vivek Galatage <vivekgalatage@gmail.com>
Volker Mische <volker.mische@gmail.com>
Wade Mealing <wmealing@gmail.com>
-William Ting <william.h.ting@gmail.com>
+William Ting <io@williamting.com>
Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
Young-il Choi <duddlf.choi@samsung.com>
Youngmin Yoo <youngmin.yoo@samsung.com>
ifdef TRACE
CFG_RUSTC_FLAGS += -Z trace
endif
+ifdef CFG_DISABLE_RPATH
+# NOTE: make this CFG_RUSTC_FLAGS after stage0 snapshot
+RUSTFLAGS_STAGE1 += --no-rpath
+RUSTFLAGS_STAGE2 += --no-rpath
+RUSTFLAGS_STAGE3 += --no-rpath
+endif
# The executables crated during this compilation process have no need to include
# static copies of libstd and libextra. We also generate dynamic versions of all
######################################################################
-# Crates
+# Cleaning out old crates
######################################################################
-define DEF_LIBS
-
-CFG_RUNTIME_$(1) :=$(call CFG_STATIC_LIB_NAME_$(1),rustrt)
-CFG_RUSTLLVM_$(1) :=$(call CFG_STATIC_LIB_NAME_$(1),rustllvm)
-CFG_STDLIB_$(1) :=$(call CFG_LIB_NAME_$(1),std)
-CFG_EXTRALIB_$(1) :=$(call CFG_LIB_NAME_$(1),extra)
-CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
-CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
-CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
-CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
-CFG_LIBRUSTUV_$(1) :=$(call CFG_LIB_NAME_$(1),rustuv)
-CFG_LIBGREEN_$(1) :=$(call CFG_LIB_NAME_$(1),green)
-CFG_LIBNATIVE_$(1) :=$(call CFG_LIB_NAME_$(1),native)
-
-EXTRALIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),extra)
-STDLIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),std)
-LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
-LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
-LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
-LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
-LIBRUSTUV_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustuv)
-LIBGREEN_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),green)
-LIBNATIVE_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),native)
-EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
-STDLIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),std)
-LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
-LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
-LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
-LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
-LIBRUSTUV_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustuv)
-LIBGREEN_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),green)
-LIBNATIVE_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),native)
-
-EXTRALIB_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,extra)
-STDLIB_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,std)
-LIBRUSTUV_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,rustuv)
-LIBSYNTAX_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,syntax)
-LIBRUSTC_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,rustc)
-LIBNATIVE_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,native)
-LIBGREEN_RGLOB_$(1) :=$(call CFG_RLIB_GLOB,green)
-
-endef
-
# $(1) is the path for directory to match against
# $(2) is the glob to use in the match
-# $(3) is filename (usually the target being created) to filter out from match
-# (i.e. filename is not out-of-date artifact from prior Rust version/build)
#
# Note that a common bug is to accidentally construct the glob denoted
# by $(2) with a space character prefix, which invalidates the
# construction $(1)$(2).
-define CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT
- $(Q)MATCHES="$(filter-out %$(3),$(wildcard $(1)/$(2)))"; if [ -n "$$MATCHES" ] ; then echo "warning: there are previous" \'$(2)\' "libraries:" $$MATCHES; fi
+define CHECK_FOR_OLD_GLOB_MATCHES
+ $(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then echo "warning: there are previous" \'$(notdir $(2))\' "libraries:" $$MATCHES; fi
endef
# Same interface as above, but deletes rather than just listing the files.
ifdef VERBOSE
-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 $$MATCHES ; fi
+define REMOVE_ALL_OLD_GLOB_MATCHES
+ $(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then echo "warning: removing previous" \'$(notdir $(1))\' "libraries:" $$MATCHES; rm $$MATCHES ; fi
endef
else
-define REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT
- $(Q)MATCHES="$(filter-out %$(3),$(wildcard $(1)/$(2)))"; if [ -n "$$MATCHES" ] ; then rm $$MATCHES ; fi
+define REMOVE_ALL_OLD_GLOB_MATCHES
+ $(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then rm $$MATCHES ; fi
endef
endif
# soon. (This is in contrast to the macros above, which are meant to
# be run at the outset of a command list in a rule.)
ifdef VERBOSE
-define LIST_ALL_OLD_GLOB_MATCHES_EXCEPT
- @echo "info: now are following matches for" '$(2)' "libraries:"
- @( cd $(1) && ( ls $(2) 2>/dev/null || true ) | grep -v $(3) || true )
+define LIST_ALL_OLD_GLOB_MATCHES
+ @echo "info: now are following matches for" '$(notdir $(1))' "libraries:"
+ @( ls $(1) 2>/dev/null || true )
endef
else
-define LIST_ALL_OLD_GLOB_MATCHES_EXCEPT
+define LIST_ALL_OLD_GLOB_MATCHES
endef
endif
-$(foreach target,$(CFG_TARGET),\
- $(eval $(call DEF_LIBS,$(target))))
-
-######################################################################
-# Standard library variables
-######################################################################
-
-STDLIB_CRATE := $(S)src/libstd/lib.rs
-STDLIB_INPUTS := $(wildcard $(addprefix $(S)src/libstd/, \
- *.rs */*.rs */*/*rs */*/*/*rs))
-
-######################################################################
-# Extra library variables
-######################################################################
-
-EXTRALIB_CRATE := $(S)src/libextra/lib.rs
-EXTRALIB_INPUTS := $(wildcard $(addprefix $(S)src/libextra/, \
- *.rs */*.rs))
-
-######################################################################
-# Rust UV library variables
-######################################################################
-
-LIBRUSTUV_CRATE := $(S)src/librustuv/lib.rs
-LIBRUSTUV_INPUTS := $(wildcard $(addprefix $(S)src/librustuv/, \
- *.rs */*.rs))
-
-######################################################################
-# Green threading library variables
-######################################################################
-
-LIBGREEN_CRATE := $(S)src/libgreen/lib.rs
-LIBGREEN_INPUTS := $(wildcard $(addprefix $(S)src/libgreen/, \
- *.rs */*.rs))
-
-######################################################################
-# Native threading library variables
-######################################################################
-
-LIBNATIVE_CRATE := $(S)src/libnative/lib.rs
-LIBNATIVE_INPUTS := $(wildcard $(addprefix $(S)src/libnative/, \
- *.rs */*.rs))
-
-######################################################################
-# rustc crate variables
-######################################################################
-
-COMPILER_CRATE := $(S)src/librustc/lib.rs
-COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \
- *.rs */*.rs */*/*.rs */*/*/*.rs))
-
-LIBSYNTAX_CRATE := $(S)src/libsyntax/lib.rs
-LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
- *.rs */*.rs */*/*.rs */*/*/*.rs))
-
-DRIVER_CRATE := $(S)src/driver/driver.rs
-
######################################################################
# LLVM macros
######################################################################
export CFG_LIBDIR_RELATIVE
export CFG_DISABLE_INJECT_STD_VERSION
-######################################################################
-# Subprograms
-######################################################################
-
######################################################################
# Per-stage targets and runner
######################################################################
+include $(CFG_SRC_DIR)mk/crates.mk
+
define SREQ
# $(1) is the stage number
# $(2) is the target triple
TBIN$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/bin
TLIB$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/lib
-# The name of the standard and extra libraries used by rustc
-HSTDLIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_STDLIB_$(3))
-TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
-
-HEXTRALIB_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_EXTRALIB_$(3))
-TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
-
-HLIBRUSTC_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTC_$(3))
-TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
-
-HLIBRUSTUV_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(3))
-TLIBRUSTUV_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
-
-HLIBGREEN_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBGREEN_$(3))
-TLIBGREEN_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBGREEN_$(2))
-
-HLIBNATIVE_DEFAULT$(1)_H_$(3) = \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBNATIVE_$(3))
-TLIBNATIVE_DEFAULT$(1)_T_$(2)_H_$(3) = \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBNATIVE_$(2))
-
# Preqrequisites for using the stageN compiler
ifeq ($(1),0)
HSREQ$(1)_H_$(3) = $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3))
else
HSREQ$(1)_H_$(3) = \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
- $$(HSTDLIB_DEFAULT$(1)_H_$(3)) \
- $$(HEXTRALIB_DEFAULT$(1)_H_$(3)) \
- $$(HLIBSYNTAX_DEFAULT$(1)_H_$(3)) \
- $$(HLIBRUSTC_DEFAULT$(1)_H_$(3)) \
- $$(HLIBRUSTUV_DEFAULT$(1)_H_$(3)) \
- $$(HLIBGREEN_DEFAULT$(1)_H_$(3)) \
- $$(HLIBNATIVE_DEFAULT$(1)_H_$(3)) \
+ $$(HLIB$(1)_H_$(3))/stamp.rustc \
+ $$(foreach dep,$$(RUST_DEPS_rustc),$$(HLIB$(1)_H_$(3))/stamp.$$(dep)) \
$$(MKFILE_DEPS)
endif
# Prerequisites for using the stageN compiler to build target artifacts
TSREQ$(1)_T_$(2)_H_$(3) = \
$$(HSREQ$(1)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
-# Prerequisites for a working stageN compiler and libraries, for a specific target
+# Prerequisites for a working stageN compiler and libraries, for a specific
+# target
SREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBGREEN_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBNATIVE_$(2))
+ $$(foreach dep,$$(TARGET_CRATES),\
+ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep))
-# Prerequisites for a working stageN compiler and libraries, for a specific target
+# Prerequisites for a working stageN compiler and complete set of target
+# libraries
CSREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
- $$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBGREEN_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBNATIVE_$(2))
+ $$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
+ $$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep))
ifeq ($(1),0)
# Don't run the the stage0 compiler under valgrind - that ship has sailed
endif
endif
+ifdef CFG_DISABLE_RPATH
+ifeq ($$(OSTYPE_$(3)),apple-darwin)
+ RPATH_VAR$(1)_T_$(2)_H_$(3) := \
+ DYLD_LIBRARY_PATH="$$$$DYLD_LIBRARY_PATH:$$(HLIB$(1)_H_$(3))"
+else
+ RPATH_VAR$(1)_T_$(2)_H_$(3) := \
+ LD_LIBRARY_PATH="$$$$LD_LIBRARY_PATH:$$(HLIB$(1)_H_$(3))"
+endif
+else
+ RPATH_VAR$(1)_T_$(2)_H_$(3) :=
+endif
+
STAGE$(1)_T_$(2)_H_$(3) := \
- $$(Q)$$(call CFG_RUN_TARG_$(3),$(1), \
- $$(CFG_VALGRIND_COMPILE$(1)) \
+ $$(Q)$$(RPATH_VAR$(1)_T_$(2)_H_$(3)) \
+ $$(call CFG_RUN_TARG_$(3),$(1), \
+ $$(CFG_VALGRIND_COMPILE$(1)) \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
--cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
$$(RUSTC_FLAGS_$(2))
-PERF_STAGE$(1)_T_$(2)_H_$(3) := \
+PERF_STAGE$(1)_T_$(2)_H_$(3) := \
$$(Q)$$(call CFG_RUN_TARG_$(3),$(1), \
- $$(CFG_PERF_TOOL) \
+ $$(CFG_PERF_TOOL) \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
--cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
# $(2) == stage
rustc-stage$(2)-H-$(1): \
- $$(foreach target,$$(CFG_TARGET), \
- $$(SREQ$(2)_T_$$(target)_H_$(1)))
+ $$(foreach target,$$(CFG_TARGET),$$(SREQ$(2)_T_$$(target)_H_$(1)))
endef
-$(foreach host,$(CFG_HOST), \
- $(eval $(foreach stage,1 2 3, \
+$(foreach host,$(CFG_HOST), \
+ $(eval $(foreach stage,1 2 3, \
$(eval $(call DEF_RUSTC_STAGE_TARGET,$(host),$(stage))))))
rustc-stage1: rustc-stage1-H-$(CFG_BUILD)
CFG_INFO := $(info cfg: *** stage2 and later will not be built ***)
CFG_INFO := $(info cfg:)
-#XXX This is surely busted
+#FIXME This is surely busted
all: $(SREQ1$(CFG_BUILD)) $(GENERATED) docs
else
include $(CFG_SRC_DIR)mk/host.mk
include $(CFG_SRC_DIR)mk/stage0.mk
include $(CFG_SRC_DIR)mk/rustllvm.mk
-include $(CFG_SRC_DIR)mk/tools.mk
include $(CFG_SRC_DIR)mk/docs.mk
include $(CFG_SRC_DIR)mk/llvm.mk
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt pax-flags 0 "apply PaX flags to rustc binaries (required for GRSecurity/PaX-patched kernels)"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
+opt rpath 1 "build rpaths into rustc itself"
valopt prefix "/usr/local" "set installation prefix"
valopt local-rust-root "/usr/local" "set prefix for local rust binary"
valopt llvm-root "" "set LLVM root"
LLVM_OPTS="$LLVM_OPTS --disable-terminfo"
# Try to have LLVM pull in as few dependencies as possible (#9397)
LLVM_OPTS="$LLVM_OPTS --disable-zlib --disable-libffi"
+ # LLVM says it needs a "new" clang/gcc, but we seem to get by ok with
+ # older versions on the bots. Get by for a little longer by asking it to
+ # not do version detection
+ LLVM_OPTS="$LLVM_OPTS --disable-compiler-version-checks"
# Use win32 native thread/lock apis instead of pthread wrapper.
# (llvm's configure tries to find pthread first, so we have to disable it explicitly.)
Use [`File::open`](http://static.rust-lang.org/doc/master/std/io/fs/struct.File.html#method.open) to create a [`File`](http://static.rust-lang.org/doc/master/std/io/fs/struct.File.html) struct, which implements the [`Reader`](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html) trait.
-~~~ {.xfail-test}
+~~~ {.ignore}
use std::path::Path;
use std::io::fs::File;
Attempting to close a closed door is prevented statically:
-~~~ {.xfail-test}
+~~~ {.ignore}
let _ = close(Door::<Closed>(~"front")); // error: mismatched types: expected `main::Door<main::Open>` but found `main::Door<main::Closed>`
~~~
You can use a zero-element `enum` ([phantom type](#how-do-i-express-phantom-types)) to represent the opaque object handle. The FFI would look like this:
-~~~ {.xfail-test}
+~~~ {.ignore}
enum Window {}
extern "C" {
fn createWindow(width: c_int, height: c_int) -> *Window;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
use std::task;
# mod BufferedReader {
fn main() {
// Isolate failure within a subtask.
- let result = do task::try {
+ let result = task::try(proc() {
// The protected logic.
let pairs = read_int_pairs();
println!("{:4.4d}, {:4.4d}", a, b);
}
- };
+ });
if result.is_err() {
println!("parsing failed");
}
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::File;
+use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::MemReader;
~~~~
# #[allow(unused_imports)];
-# extern mod extra;
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# fn main() {}
/// A stream of N zeroes
struct ZeroStream {
- priv remaining: uint
+ remaining: uint
}
impl ZeroStream {
implementing the `FromIterator` trait. For example, the implementation for
vectors is as follows:
-~~~ {.xfail-test}
+~~~ {.ignore}
impl<A> FromIterator<A> for ~[A] {
pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
The `Iterator` trait provides a `size_hint` default method, returning a lower
bound and optionally on upper bound on the length of the iterator:
-~~~ {.xfail-test}
+~~~ {.ignore}
fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
~~~
# fn main() {}
/// A stream of N zeroes
struct ZeroStream {
- priv remaining: uint
+ remaining: uint
}
impl ZeroStream {
The following is a minimal example of calling a foreign function which will
compile if snappy is installed:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
use std::libc::size_t;
#[link(name = "snappy")]
The `extern` block can be extended to cover the entire snappy API:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
use std::libc::{c_int, size_t};
#[link(name = "snappy")]
length is number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
unsafe {
snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
the true length after compression for setting the length.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
pub fn compress(src: &[u8]) -> ~[u8] {
unsafe {
let srclen = src.len() as size_t;
Decompression is similar, because snappy stores the uncompressed size as part of the compression
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
unsafe {
let srclen = src.len() as size_t;
A basic example is:
Rust code:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
extern fn callback(a:i32) {
println!("I'm called from C with value {0}", a);
}
~~~~
C code:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
typedef void (*rust_callback)(int32_t);
rust_callback cb;
## Targetting callbacks to Rust objects
-The former example showed how a global function can be called from C-Code.
+The former example showed how a global function can be called from C code.
However it is often desired that the callback is targetted to a special
Rust object. This could be the object that represents the wrapper for the
respective C object.
This can be achieved by passing an unsafe pointer to the object down to the
C library. The C library can then include the pointer to the Rust object in
-the notification. This will provide a unsafe possibility to access the
-referenced Rust object in callback.
+the notification. This will allow the callback to unsafely access the
+referenced Rust object.
Rust code:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
struct RustObject {
a: i32,
~~~~
C code:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
typedef void (*rust_callback)(int32_t);
void* cb_target;
rust_callback cb;
## Asynchronous callbacks
-In the already given examples the callbacks are invoked as a direct reaction
+In the previously given examples the callbacks are invoked as a direct reaction
to a function call to the external C library.
-The control over the current thread switched from Rust to C to Rust for the
+The control over the current thread is switched from Rust to C to Rust for the
execution of the callback, but in the end the callback is executed on the
same thread (and Rust task) that lead called the function which triggered
the callback.
-Things get more complicated when the external library spawns it's own threads
+Things get more complicated when the external library spawns its own threads
and invokes callbacks from there.
-In these cases access to Rust data structures inside he callbacks is
+In these cases access to Rust data structures inside the callbacks is
especially unsafe and proper synchronization mechanisms must be used.
-Besides classical synchronization mechanisms like mutexes one possibility in
+Besides classical synchronization mechanisms like mutexes, one possibility in
Rust is to use channels (in `std::comm`) to forward data from the C thread
that invoked the callback into a Rust task.
If an asychronous callback targets a special object in the Rust address space
it is also absolutely necessary that no more callbacks are performed by the
-C library after the respective Rust object get's destroyed.
-This can be achieved by unregistering the callback it the object's
+C library after the respective Rust object gets destroyed.
+This can be achieved by unregistering the callback in the object's
destructor and designing the library in a way that guarantees that no
callback will be performed after unregistration.
specifies raw flags which need to get passed to the linker when producing an
artifact. An example usage would be:
-~~~ {.xfail-test}
+~~~ {.ignore}
#[link_args = "-foo -bar -baz"]
extern {}
~~~
global state. In order to access these variables, you declare them in `extern`
blocks with the `static` keyword:
-~~~{.xfail-test}
+~~~{.ignore}
use std::libc;
#[link(name = "readline")]
interface. To do this, statics can be declared with `mut` so rust can mutate
them.
-~~~{.xfail-test}
+~~~{.ignore}
use std::libc;
use std::ptr;
scope_. Therefore, a program like this is illegal (and would be
rejected by the compiler):
-~~~ {.xfail-test}
+~~~ {.ignore}
fn example3() -> int {
let mut x = ~X {f: 3};
let y = &x.f;
and structs, and the compiler will still be able to detect possible
mutations:
-~~~ {.xfail-test}
+~~~ {.ignore}
fn example3() -> int {
struct R { g: int }
struct S { f: ~R }
To emphasize this point, let’s look at a variation on the example, this
time one that does not compile:
-~~~ {.xfail-test}
+~~~ {.ignore}
struct Point {x: f64, y: f64}
fn get_x_sh(p: @Point) -> &f64 {
&p.x // Error reported here
# }
// -+ r
fn select_based_on_unit_circle<'r, T>( // |-+ B
- threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
+ threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
// | |
let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |
select(&shape, threshold, a, b) // | |
So I wrote this code to try it out:
-~~~rust{.xfail-test}
+~~~rust{.ignore}
fn main() {
let number = 5;
let succ_number = succ(number);
fn main() {
let a = Point { x: 10, y: 20 };
- do spawn {
+ spawn(proc() {
println!("{}", a.x);
- }
+ });
}
~~~
fn main() {
let a = ~Point { x: 10, y: 20 };
- do spawn {
+ spawn(proc() {
println!("{}", a.x);
- }
+ });
}
~~~
For example, let's say you're using an owned pointer, and you want to do this:
-~~~rust{.xfail-test}
+~~~rust{.ignore}
struct Point {
x: int,
y: int,
'lifetimes'. Here's the simple explanation: would you expect this code to
compile?
-~~~rust{.xfail-test}
+~~~rust{.ignore}
fn main() {
println!("{}", x);
let x = 5;
is able to determine that that pointer will go out of scope without `x` being
mutated, and therefore, lets us pass. This wouldn't work:
-~~~rust{.xfail-test}
+~~~rust{.ignore}
fn main() {
let mut x = ~5;
if *x < 10 {
The primary concern of an M:N runtime is that a Rust task cannot block itself in
a syscall. If this happens, then the entire OS thread is frozen and unavailable
for running more Rust tasks, making this a (M-1):N runtime (and you can see how
-this can reach 0/deadlock. By using asynchronous I/O under the hood (all I/O
+this can reach 0/deadlock). By using asynchronous I/O under the hood (all I/O
still looks synchronous in terms of code), OS threads are never blocked until
the appropriate time comes.
M:N threading is built upon the concept of a pool of M OS threads (which
libgreen refers to as schedulers), able to run N Rust tasks. This abstraction is
-encompassed in libgreen's [`SchedPool`][schedpool] type. This type allows for
+encompassed in libgreen's [`SchedPool`](green/struct.SchedPool.html) type. This type allows for
fine-grained control over the pool of schedulers which will be used to run Rust
tasks.
#[start]
fn start(argc: int, argv: **u8) -> int {
- do green::start(argc, argv) {
+ green::start(argc, argv, proc() {
main();
- }
+ })
}
fn main() {}
// Print something more profound in a different task using a lambda expression
spawn(proc() println!("I am also running in a different task!") );
-
-// The canonical way to spawn is using `do` notation
-do spawn {
- println!("I too am running in a different task!");
-}
~~~~
In Rust, there is nothing special about creating tasks: a task is not a
// Generate some state locally
let child_task_number = generate_task_number();
-do spawn {
+spawn(proc() {
// Capture it in the remote task
println!("I am child number {}", child_task_number);
-}
+});
~~~
## Communication
let (port, chan): (Port<int>, Chan<int>) = Chan::new();
-do spawn || {
+spawn(proc() {
let result = some_expensive_computation();
chan.send(result);
-}
+});
some_other_expensive_computation();
let result = port.recv();
# use std::task::spawn;
# fn some_expensive_computation() -> int { 42 }
# let (port, chan) = Chan::new();
-do spawn || {
+spawn(proc() {
let result = some_expensive_computation();
chan.send(result);
-}
+});
~~~~
Notice that the creation of the task closure transfers `chan` to the child
`Port`. What if our example needed to compute multiple results across a number
of tasks? The following program is ill-typed:
-~~~ {.xfail-test}
+~~~ {.ignore}
# use std::task::{spawn};
# fn some_expensive_computation() -> int { 42 }
let (port, chan) = Chan::new();
-do spawn {
+spawn(proc() {
chan.send(some_expensive_computation());
-}
+});
// ERROR! The previous spawn statement already owns the channel,
// so the compiler will not allow it to be captured again
-do spawn {
+spawn(proc() {
chan.send(some_expensive_computation());
-}
+});
~~~
Instead we can use a `SharedChan`, a type that allows a single
for init_val in range(0u, 3) {
// Create a new channel handle to distribute to the child task
let child_chan = chan.clone();
- do spawn {
+ spawn(proc() {
child_chan.send(some_expensive_computation(init_val));
- }
+ });
}
let result = port.recv() + port.recv() + port.recv();
// Create a vector of ports, one for each child task
let ports = vec::from_fn(3, |init_val| {
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
chan.send(some_expensive_computation(init_val));
- }
+ });
port
});
}
fn main() {
- let mut futures = vec::from_fn(1000, |ind| do extra::future::Future::spawn { partial_sum(ind) });
+ let mut futures = vec::from_fn(1000, |ind| extra::future::Future::spawn( proc() { partial_sum(ind) }));
let mut final_res = 0f64;
for ft in futures.mut_iter() {
let (port, chan) = Chan::new();
chan.send(numbers_arc.clone());
- do spawn {
+ spawn(proc() {
let local_arc : Arc<~[f64]> = port.recv();
let task_numbers = local_arc.get();
println!("{}-norm = {}", num, pnorm(task_numbers, num));
- }
+ });
}
}
~~~
field (representing a successful result) or an `Err` result (representing
termination with an error).
-~~~{.xfail-test .linked-failure}
+~~~{.ignore .linked-failure}
# use std::task;
# fn some_condition() -> bool { false }
# fn calculate_result() -> int { 0 }
-let result: Result<int, ()> = do task::try {
+let result: Result<int, ()> = task::try(proc() {
if some_condition() {
calculate_result()
} else {
fail!("oops!");
}
-};
+});
assert!(result.is_err());
~~~
the string in response. The child terminates when it receives `0`.
Here is the function that implements the child task:
-~~~{.xfail-test .linked-failure}
+~~~{.ignore .linked-failure}
# use extra::comm::DuplexStream;
# use std::uint;
fn stringifier(channel: &DuplexStream<~str, uint>) {
Here is the code for the parent task:
-~~~{.xfail-test .linked-failure}
+~~~{.ignore .linked-failure}
# use std::task::spawn;
# use std::uint;
# use extra::comm::DuplexStream;
let (from_child, to_child) = DuplexStream::new();
-do spawn {
+spawn(proc() {
stringifier(&to_child);
-};
+});
from_child.send(22);
assert!(from_child.recv() == ~"22");
* [The Rust parser, `libsyntax`](syntax/index.html)
* [The Rust compiler, `librustc`](rustc/index.html)
+* [The `arena` allocation library](arena/index.html)
+* [The `flate` compression library](flate/index.html)
+* [The `glob` file path matching library](glob/index.html)
+
# Tooling
* [The `rustdoc` manual](rustdoc.html)
* [Language FAQ](complement-lang-faq.html)
* [Project FAQ](complement-project-faq.html)
* [Usage FAQ](complement-usage-faq.html)
-* [Code cheatsheet](complement-cheatsheet.html) - "How do I do X?"
+* [Code cheatsheet](complement-cheatsheet.html) - "How do I do X?"
* [How to submit a bug report](complement-bugreport.html)
# External resources
-* The Rust [IRC channel](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust) - `#rust` on irc.mozilla.org
+* The Rust [IRC channel](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust) - `#rust` on irc.mozilla.org
* The Rust community on [Reddit](http://reddit.com/r/rust)
* The Rust [wiki](http://github.com/mozilla/rust/wiki)
#: doc/complement-cheatsheet.md:54
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~ {.xfail-test} use std::path::Path; use std::io::fs::File;"
+msgid "~~~ {.ignore} use std::path::Path; use std::io::fs::File;"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#: doc/guide-ffi.md:16
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~~ {.xfail-test} use std::libc::size_t;"
+msgid "~~~~ {.ignore} use std::libc::size_t;"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#: doc/guide-ffi.md:48
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~~ {.xfail-test} use std::libc::{c_int, size_t};"
+msgid "~~~~ {.ignore} use std::libc::{c_int, size_t};"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#: doc/guide-ffi.md:344
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~{.xfail-test} use std::libc;"
+msgid "~~~{.ignore} use std::libc;"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#: doc/guide-ffi.md:363
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~{.xfail-test} use std::libc; use std::ptr;"
+msgid "~~~{.ignore} use std::libc; use std::ptr;"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#. type: Plain text
#: doc/guide-lifetimes.md:48
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"~~~\n"
"# struct Point {x: f64, y: f64}\n"
"let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-lifetimes.md:82
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"~~~\n"
"# struct Point {x: f64, y: f64}\n"
"compute_distance(managed_box, owned_box);\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:115
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let p0 = Point { x: 5, y: 10};\n"
" println!(\"{:?}\", p1);\n"
"}\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:129
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"~~~rust\n"
"# struct Point {\n"
" Point { x: p.x + 1, y: p.y + 1}\n"
"}\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:145
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn transform(p: Point) -> Point {\n"
" Point { x: p.x + 1, y: p.y + 1}\n"
"}\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:152
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let p0 = Point { x: 5, y: 10};\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:229
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let a = Point { x: 10, y: 20 };\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:246
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let a = ~Point { x: 10, y: 20 };\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:277
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let a = ~Point { x: 10, y: 20 };\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:308
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let a = @Point { x: 10, y: 20 };\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:352
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"fn main() {\n"
" let origin = @Point { x: 0.0, y: 0.0 };\n"
" let p1 = ~Point { x: 5.0, y: 3.0 };\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/guide-pointers.md:378
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
-"~~~rust{.xfail-test}\n"
+"~~~rust{.ignore}\n"
"fn main() {\n"
" println!(\"{}\", x);\n"
" let x = 5;\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/guide-rustpkg.md:22
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" hello::world();\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/guide-rustpkg.md:149
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"pub fn world() {\n"
" println!(\"Hello, world.\");\n"
"}\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#: doc/rust.md:788
#, fuzzy
#| msgid "~~~~ {.ignore} let foo = 10;"
-msgid "~~~~ {.xfail-test} extern mod pcre;"
+msgid "~~~~ {.ignore} extern mod pcre;"
msgstr ""
"~~~~ {.ignore}\n"
"let foo = 10;"
#: doc/rust.md:1395
#, fuzzy
#| msgid ""
-#| "~~~ {.xfail-test} use std::f64::consts::pi; # trait Shape { fn "
+#| "~~~ {.ignore} use std::f64::consts::pi; # trait Shape { fn "
#| "area(&self) -> f64; } # trait Circle : Shape { fn radius(&self) -> f64; } "
#| "# struct Point { x: f64, y: f64 } # struct CircleStruct { center: Point, "
#| "radius: f64 } # impl Circle for CircleStruct { fn radius(&self) -> f64 "
#| "{ (self.area() / pi).sqrt() } } # impl Shape for CircleStruct { fn "
#| "area(&self) -> f64 { pi * square(self.radius) } }"
msgid ""
-"~~~~ {.xfail-test} # trait Shape { fn area(&self) -> f64; } # trait Circle : "
+"~~~~ {.ignore} # trait Shape { fn area(&self) -> f64; } # trait Circle : "
"Shape { fn radius(&self) -> f64; } # impl Shape for int { fn area(&self) -> "
"f64 { 0.0 } } # impl Circle for int { fn radius(&self) -> f64 { 0.0 } } # "
"let mycircle = 0;"
msgstr ""
-"~~~ {.xfail-test}\n"
+"~~~ {.ignore}\n"
"use std::f64::consts::pi;\n"
"# trait Shape { fn area(&self) -> f64; }\n"
"# trait Circle : Shape { fn radius(&self) -> f64; }\n"
#: doc/rust.md:2400
#, fuzzy
#| msgid "~~~~ use std::task::spawn;"
-msgid "~~~~ {.xfail-test} # use std::task; # do task::spawn {"
+msgid "~~~~ {.ignore} # use std::task; # do task::spawn {"
msgstr ""
"~~~~\n"
"use std::task::spawn;"
#. type: Plain text
#: doc/rust.md:3299
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" print(@10 as @Printable);\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:136
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"~~~~\n"
"fn main() {\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:604
msgid ""
-"~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point "
+"~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point "
"{ x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/tutorial.md:1372
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"~~~\n"
"# struct Point { x: f64, y: f64 }\n"
"let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#. type: Plain text
#: doc/tutorial.md:1404
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
+#| msgid "~~~~ {.ignore} # struct Point { x: f64, y: f64 } let mut mypoint = Point { x: 1.0, y: 1.0 }; let origin = Point { x: 0.0, y: 0.0 };"
msgid ""
"~~~\n"
"# struct Point{ x: f64, y: f64 };\n"
"compute_distance(managed_box, owned_box);\n"
"~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"# struct Point { x: f64, y: f64 }\n"
"let mut mypoint = Point { x: 1.0, y: 1.0 };\n"
"let origin = Point { x: 0.0, y: 0.0 };"
#: doc/tutorial.md:2067
#, no-wrap
msgid ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// This does not compile\n"
"fn head_bad<T>(v: &[T]) -> T {\n"
" v[0] // error: copying a non-copyable value\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// このコードはコンパイルできない\n"
"fn head_bad<T>(v: &[T]) -> T {\n"
" v[0] // error: copying a non-copyable value\n"
#. type: Plain text
#: doc/tutorial.md:2148
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"~~~~\n"
"trait Printable {\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:2488
#, fuzzy, no-wrap
-#| msgid "~~~ {.xfail-test} use std::f64::consts::pi; # trait Shape { fn area(&self) -> f64; } # trait Circle : Shape { fn radius(&self) -> f64; } # struct Point { x: f64, y: f64 } # struct CircleStruct { center: Point, radius: f64 } # impl Circle for CircleStruct { fn radius(&self) -> f64 { (self.area() / pi).sqrt() } } # impl Shape for CircleStruct { fn area(&self) -> f64 { pi * square(self.radius) } }"
+#| msgid "~~~ {.ignore} use std::f64::consts::pi; # trait Shape { fn area(&self) -> f64; } # trait Circle : Shape { fn radius(&self) -> f64; } # struct Point { x: f64, y: f64 } # struct CircleStruct { center: Point, radius: f64 } # impl Circle for CircleStruct { fn radius(&self) -> f64 { (self.area() / pi).sqrt() } } # impl Shape for CircleStruct { fn area(&self) -> f64 { pi * square(self.radius) } }"
msgid ""
"~~~~\n"
"use std::f64::consts::PI;\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~ {.xfail-test}\n"
+"~~~ {.ignore}\n"
"use std::f64::consts::pi;\n"
"# trait Shape { fn area(&self) -> f64; }\n"
"# trait Circle : Shape { fn radius(&self) -> f64; }\n"
#: doc/tutorial.md:2517
#, fuzzy
#| msgid ""
-#| "~~~ {.xfail-test} use std::f64::consts::pi; # trait Shape { fn "
+#| "~~~ {.ignore} use std::f64::consts::pi; # trait Shape { fn "
#| "area(&self) -> f64; } # trait Circle : Shape { fn radius(&self) -> f64; } "
#| "# struct Point { x: f64, y: f64 } # struct CircleStruct { center: Point, "
#| "radius: f64 } # impl Circle for CircleStruct { fn radius(&self) -> f64 "
#| "{ (self.area() / pi).sqrt() } } # impl Shape for CircleStruct { fn "
#| "area(&self) -> f64 { pi * square(self.radius) } }"
msgid ""
-"~~~ {.xfail-test} use std::f64::consts::PI; # trait Shape { fn area(&self) -"
+"~~~ {.ignore} use std::f64::consts::PI; # trait Shape { fn area(&self) -"
"> f64; } # trait Circle : Shape { fn radius(&self) -> f64; } # struct Point "
"{ x: f64, y: f64 } # struct CircleStruct { center: Point, radius: f64 } # "
"impl Circle for CircleStruct { fn radius(&self) -> f64 { (self.area() / PI)."
"sqrt() } } # impl Shape for CircleStruct { fn area(&self) -> f64 { PI * "
"square(self.radius) } }"
msgstr ""
-"~~~ {.xfail-test}\n"
+"~~~ {.ignore}\n"
"use std::f64::consts::pi;\n"
"# trait Shape { fn area(&self) -> f64; }\n"
"# trait Circle : Shape { fn radius(&self) -> f64; }\n"
#. type: Plain text
#: doc/tutorial.md:2567
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"~~~~\n"
"// main.rs\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:2600
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" println!(\"Hello farm!\");\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:2620
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" println!(\"Hello chicken!\");\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:2732
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" println!(\"Hello farm!\");\n"
"}\n"
"~~~~\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#. type: Plain text
#: doc/tutorial.md:2929
#, fuzzy, no-wrap
-#| msgid "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
+#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
msgid ""
"fn main() {\n"
" println!(\"Hello farm!\");\n"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
#: doc/tutorial.md:3144
#, fuzzy
#| msgid ""
-#| "~~~~ {.xfail-test} extern mod farm; extern mod my_farm (name = \"farm\", "
+#| "~~~~ {.ignore} extern mod farm; extern mod my_farm (name = \"farm\", "
#| "vers = \"2.5\"); extern mod my_auxiliary_farm (name = \"farm\", author = "
#| "\"mjh\"); ~~~~"
msgid ""
-"~~~~ {.xfail-test} extern mod farm; extern mod farm = \"farm#2.5\"; extern "
+"~~~~ {.ignore} extern mod farm; extern mod farm = \"farm#2.5\"; extern "
"mod my_farm = \"farm\"; ~~~~"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"extern mod farm;\n"
"extern mod my_farm (name = \"farm\", vers = \"2.5\");\n"
"extern mod my_auxiliary_farm (name = \"farm\", author = \"mjh\");\n"
#: doc/tutorial.md:3185
#, fuzzy
#| msgid ""
-#| "~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println(~"
+#| "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~"
#| "\"hello \" + world::explore()); } ~~~~"
msgid ""
-"~~~~ {.xfail-test} // main.rs extern mod world; fn main() { println!(\"hello "
+"~~~~ {.ignore} // main.rs extern mod world; fn main() { println!(\"hello "
"{}\", world::explore()); } ~~~~"
msgstr ""
-"~~~~ {.xfail-test}\n"
+"~~~~ {.ignore}\n"
"// main.rs\n"
"extern mod world;\n"
"fn main() { println(~\"hello \" + world::explore()); }\n"
When a nested submodule is loaded from an external file,
it is loaded from a subdirectory path that mirrors the module hierarchy.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
// Load the `vec` module from `vec.rs`
mod vec;
The directories and files used for loading external file modules can be influenced
with the `path` attribute.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[path = "task_files"]
mod task {
// Load the `local_data` module from `task_files/tls.rs`
Four examples of `extern mod` declarations:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
extern mod pcre;
extern mod extra; // equivalent to: extern mod extra = "extra";
declared, in an angle-bracket-enclosed, comma-separated list following
the function name.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
fn iter<T>(seq: &[T], f: |T|) {
for elt in seq.iter() { f(elt); }
}
Likewise, supertrait methods may also be called on trait objects.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
# trait Shape { fn area(&self) -> f64; }
# trait Circle : Shape { fn radius(&self) -> f64; }
# impl Shape for int { fn area(&self) -> f64 { 0.0 } }
uses the standard C "cdecl" ABI. Other ABIs may be specified using
an `abi` string, as shown here:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
// Interface to the Windows API
extern "stdcall" { }
~~~~
specified the compiler will attempt to link against the native library of the
specified name.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[link(name = "crypto")]
extern { }
~~~~
An example of attributes:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
// General metadata applied to the enclosing module or crate.
#[license = "BSD"];
The lint checks supported by the compiler can be found via `rustc -W help`,
along with their default settings.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
mod m1 {
// Missing documentation is ignored here
#[allow(missing_doc)]
This example shows how one can use `allow` and `warn` to toggle
a particular check on and off.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[warn(missing_doc)]
mod m2{
#[allow(missing_doc)]
This example shows how one can use `forbid` to disallow uses
of `allow` for that lint check.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[forbid(missing_doc)]
mod m3 {
// Attempting to toggle warning signals an error here
The `lang` attribute makes it possible to declare these operations.
For example, the `str` module in the Rust standard library defines the string equality function:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[lang="str_eq"]
pub fn eq_slice(a: &str, b: &str) -> bool {
// details elided
be unstable for the purposes of the lint. One can give an optional
string that will be displayed when the lint flags the use of an item.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[warn(unstable)];
#[deprecated="replaced by `best`"]
For this reason, rust recognizes a special crate-level attribute of the form:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
#[feature(feature1, feature2, feature3)]
~~~~
is bounds-checked at run-time. When the check fails, it will put the
task in a _failing state_.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
# use std::task;
# do task::spawn {
A `loop` expression is only permitted in the body of a loop.
-### Do expressions
-
-~~~~ {.ebnf .gram}
-do_expr : "do" expr [ '|' ident_list '|' ] ? '{' block '}' ;
-~~~~
-
-A _do expression_ provides a more-familiar block syntax
-for invoking a function and passing it a newly-created a procedure.
-
-The optional `ident_list` and `block` provided in a `do` expression are parsed
-as though they constitute a procedure expression;
-if the `ident_list` is missing, an empty `ident_list` is implied.
-
-The procedure expression is then provided as a _trailing argument_
-to the outermost [call](#call-expressions) or
-[method call](#method-call-expressions) expression
-in the `expr` following `do`.
-If the `expr` is a [path expression](#path-expressions), it is parsed as though it is a call expression.
-If the `expr` is a [field expression](#field-expressions), it is parsed as though it is a method call expression.
-
-In this example, both calls to `f` are equivalent:
-
-~~~~
-# fn f(f: proc(int)) { }
-# fn g(i: int) { }
-
-f(proc(j) { g(j) });
-
-do f |j| {
- g(j);
-}
-~~~~
-
-In this example, both calls to the (binary) function `k` are equivalent:
-
-~~~~
-# fn k(x:int, f: proc(int)) { }
-# fn l(i: int) { }
-
-k(3, proc(j) { l(j) });
-
-do k(3) |j| {
- l(j);
-}
-~~~~
-
### For expressions
~~~~ {.ebnf .gram}
A `match` expression branches on a *pattern*. The exact form of matching that
occurs depends on the pattern. Patterns consist of some combination of
-literals, destructured enum constructors, structures, records and tuples, variable binding
-specifications, wildcards (`*`), and placeholders (`_`). A `match` expression has a *head
-expression*, which is the value to compare to the patterns. The type of the
-patterns must equal the type of the head expression.
+literals, destructured vectors or enum constructors, structures, records and
+tuples, variable binding specifications, wildcards (`..`), and placeholders
+(`_`). A `match` expression has a *head expression*, which is the value to
+compare to the patterns. The type of the patterns must equal the type of the
+head expression.
-In a pattern whose head expression has an `enum` type, a placeholder (`_`) stands for a
-*single* data field, whereas a wildcard `..` stands for *all* the fields of a particular
-variant. For example:
+In a pattern whose head expression has an `enum` type, a placeholder (`_`)
+stands for a *single* data field, whereas a wildcard `..` stands for *all* the
+fields of a particular variant. For example:
~~~~
enum List<X> { Nil, Cons(X, ~List<X>) }
}
~~~~
-The first pattern matches lists constructed by applying `Cons` to any head value, and a
-tail value of `~Nil`. The second pattern matches _any_ list constructed with `Cons`,
-ignoring the values of its arguments. The difference between `_` and `*` is that the pattern
-`C(_)` is only type-correct if `C` has exactly one argument, while the pattern `C(..)` is
-type-correct for any enum variant `C`, regardless of how many arguments `C` has.
+The first pattern matches lists constructed by applying `Cons` to any head
+value, and a tail value of `~Nil`. The second pattern matches _any_ list
+constructed with `Cons`, ignoring the values of its arguments. The difference
+between `_` and `..` is that the pattern `C(_)` is only type-correct if `C` has
+exactly one argument, while the pattern `C(..)` is type-correct for any enum
+variant `C`, regardless of how many arguments `C` has.
+
+Used inside a vector pattern, `..` stands for any number of elements. This
+wildcard can be used at most once for a given vector, which implies that it
+cannot be used to specifically match elements that are at an unknown distance
+from both ends of a vector, like `[.., 42, ..]`. If followed by a variable name,
+it will bind the corresponding slice to the variable. Example:
+
+~~~~
+fn is_symmetric(list: &[uint]) -> bool {
+ match list {
+ [] | [_] => true,
+ [x, ..inside, y] if x == y => is_symmetric(inside),
+ _ => false
+ }
+}
+
+fn main() {
+ let sym = &[0, 1, 4, 2, 4, 1, 0];
+ let not_sym = &[0, 1, 7, 2, 4, 1, 0];
+ assert!(is_symmetric(sym));
+ assert!(!is_symmetric(not_sym));
+}
+~~~~
A `match` behaves differently depending on whether or not the head expression
is an [lvalue or an rvalue](#lvalues-rvalues-and-temporaries).
using the `ref` keyword,
or to a mutable reference using `ref mut`.
+Subpatterns can also be bound to variables by the use of the syntax
+`variable @ pattern`.
+For example:
+
+~~~~
+enum List { Nil, Cons(uint, ~List) }
+
+fn is_sorted(list: &List) -> bool {
+ match *list {
+ Nil | Cons(_, ~Nil) => true,
+ Cons(x, ref r @ ~Cons(y, _)) => (x <= y) && is_sorted(*r)
+ }
+}
+
+fn main() {
+ let a = Cons(6, ~Cons(7, ~Cons(42, ~Nil)));
+ assert!(is_sorted(&a));
+}
+
+~~~~
+
Patterns can also dereference pointers by using the `&`,
`~` or `@` symbols, as appropriate. For example, these two matches
on `x: &int` are equivalent:
assert_eq!(y, z);
~~~~
-A pattern that's just an identifier, like `Nil` in the previous answer,
+A pattern that's just an identifier, like `Nil` in the previous example,
could either refer to an enum variant that's in scope, or bind a new variable.
The compiler resolves this ambiguity by forbidding variable bindings that occur
in `match` patterns from shadowing names of variants that are in scope.
y)` matches any tuple whose first element is zero, and binds `y` to
the second element. `(x, y)` matches any two-element tuple, and binds both
elements to variables.
+A subpattern can also be bound to a variable, using `variable @ pattern`. For
+example:
+
+~~~~
+# let age = 23;
+match age {
+ a @ 0..20 => println!("{} years old", a),
+ _ => println!("older than 21")
+}
+~~~~
Any `match` arm can have a guard clause (written `if EXPR`), called a
*pattern guard*, which is an expression of type `bool` that
`mypoint.y += 1.0`. But in an immutable location, such an assignment to a
struct without inherited mutability would result in a type error.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
# struct Point { x: f64, y: f64 }
let mut mypoint = Point { x: 1.0, y: 1.0 };
let origin = Point { x: 0.0, y: 0.0 };
a `List` type as being *either* the end of the list (`Nil`) or another node
(`Cons`). The full definition of the `Cons` variant will require some thought.
-~~~ {.xfail-test}
+~~~ {.ignore}
enum List {
Cons(...), // an incomplete definition of the next element in a List
Nil // the end of a List
The obvious approach is to define `Cons` as containing an element in the list
along with the next `List` node. However, this will generate a compiler error.
-~~~ {.xfail-test}
+~~~ {.ignore}
// error: illegal recursive enum type; wrap the inner value in a box to make it representable
enum List {
Cons(u32, List), // an element (`u32`) and the next node in the list
The `clone` method is provided by the `Clone` trait, and can be derived for
our `List` type. Traits will be explained in detail later.
-~~~{.xfail-test}
+~~~{.ignore}
#[deriving(Clone)]
enum List {
Cons(u32, ~List),
let z = x;
-// and now, it can no longer be used since it has been moved from
+// and now, it can no longer be used since it has been moved
~~~
The mutability of a value may be changed by moving it to a new owner:
The obvious signature for a `List` equality comparison is the following:
-~~~{.xfail-test}
+~~~{.ignore}
fn eq(xs: List, ys: List) -> bool { ... }
~~~
isn't required to compare the lists, so the function should take *references*
(&T) instead.
-~~~{.xfail-test}
+~~~{.ignore}
fn eq(xs: &List, ys: &List) -> bool { ... }
~~~
});
~~~~
-This is such a useful pattern that Rust has a special form of function
-call for these functions.
-
-~~~~
-# fn call_it(op: proc(v: int)) { }
-do call_it() |n| {
- println!("{}", n);
-}
-~~~~
-
-The call is prefixed with the keyword `do` and, instead of writing the
-final procedure inside the argument list, it appears outside of the
-parentheses, where it looks more like a typical block of
-code.
-
-`do` is a convenient way to create tasks with the `task::spawn`
-function. `spawn` has the signature `spawn(fn: proc())`. In other
-words, it is a function that takes an owned closure that takes no
-arguments.
+A practical example of this pattern is found when using the `spawn` function,
+which starts a new task.
~~~~
use std::task::spawn;
-
-do spawn() || {
- debug!("I'm a task, whatever");
-}
-~~~~
-
-Look at all those bars and parentheses -- that's two empty argument
-lists back to back. Since that is so unsightly, empty argument lists
-may be omitted from `do` expressions.
-
-~~~~
-use std::task::spawn;
-
-do spawn {
- debug!("Kablam!");
-}
+spawn(proc() {
+ debug!("I'm a new task")
+});
~~~~
-If you want to see the output of `debug!` statements, you will need to turn on `debug!` logging.
-To enable `debug!` logging, set the RUST_LOG environment variable to the name of your crate, which, for a file named `foo.rs`, will be `foo` (e.g., with bash, `export RUST_LOG=foo`).
+If you want to see the output of `debug!` statements, you will need to turn on
+`debug!` logging. To enable `debug!` logging, set the RUST_LOG environment
+variable to the name of your crate, which, for a file named `foo.rs`, will be
+`foo` (e.g., with bash, `export RUST_LOG=foo`).
# Methods
methods. The absence of a `self` parameter distinguishes such methods.
These methods are the preferred way to define constructor functions.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
impl Circle {
fn area(&self) -> f64 { ... }
fn new(area: f64) -> Circle { ... }
In Rust, we can't,
and if we try to run the following code the compiler will complain.
-~~~~ {.xfail-test}
+~~~~ {.ignore}
// This does not compile
fn head_bad<T>(v: &[T]) -> T {
v[0] // error: copying a non-copyable value
Likewise, supertrait methods may also be called on trait objects.
-~~~ {.xfail-test}
+~~~ {.ignore}
use std::f64::consts::PI;
# trait Shape { fn area(&self) -> f64; }
# trait Circle : Shape { fn radius(&self) -> f64; }
We've now defined a nice module hierarchy. But how do we access the items in it from our `main` function?
One way to do it is to simply fully qualifying it:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
mod farm {
fn chicken() { println!("cluck cluck"); }
// ...
scope with corresponding `use` statements.
~~~ {.ignore}
-# // XXX: Allow unused import in doc test
+# // FIXME: Allow unused import in doc test
use farm::cow;
// ...
# mod farm { pub fn cow() { println!("Hidden ninja cow is hidden.") } }
example, these `extern mod` statements would both accept and select the
crate define above:
-~~~~ {.xfail-test}
+~~~~ {.ignore}
extern mod farm;
extern mod farm = "farm#2.5";
extern mod my_farm = "farm";
# fn main() {}
~~~~
-~~~~ {.xfail-test}
+~~~~ {.ignore}
// main.rs
extern mod world;
fn main() { println!("hello {}", world::explore()); }
-name '*.[odasS]' -o \
-name '*.so' -o \
-name '*.dylib' -o \
+ -name 'stamp.*' -o \
-name '*.lib' -o \
-name '*.dll' -o \
-name '*.def' -o \
define CLEAN_HOST_STAGE_N
-clean$(1)_H_$(2):
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustc$(X_$(2))
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
- $(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUNTIME_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_STDLIB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTUV_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBNATIVE_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBGREEN_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_RGLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_RGLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTUV_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTUV_RGLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBNATIVE_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBNATIVE_RGLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBGREEN_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBGREEN_RGLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
- $(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM_$(2))
+clean$(1)_H_$(2): \
+ $$(foreach crate,$$(CRATES),clean$(1)_H_$(2)-lib-$$(crate)) \
+ $$(foreach tool,$$(TOOLS),clean$(1)_H_$(2)-tool-$$(tool))
+
+clean$(1)_H_$(2)-tool-%:
+ $$(Q)rm -f $$(HBIN$(1)_H_$(2))/$$*$$(X_$(2))
+
+clean$(1)_H_$(2)-lib-%:
+ $$(Q)rm -f $$(HLIB$(1)_H_$(2))/$$(call CFG_LIB_GLOB_$(2),$$*)
+ $$(Q)rm -f $$(HLIB$(1)_H_$(2))/$$(call CFG_RLIB_GLOB,$$*)
endef
define CLEAN_TARGET_STAGE_N
-clean$(1)_T_$(2)_H_$(3):
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$(X_$(2))
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
- $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBGREEN_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBNATIVE_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTUV_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTUV_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBNATIVE_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBNATIVE_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBGREEN_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBGREEN_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_RGLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(2))
- $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
+clean$(1)_T_$(2)_H_$(3): \
+ $$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
+ $$(foreach tool,$$(TOOLS),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
+ $$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
+
+clean$(1)_T_$(2)_H_$(3)-tool-%:
+ $$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/$$*$$(X_$(2))
+
+clean$(1)_T_$(2)_H_$(3)-lib-%:
+ $$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$$(call CFG_LIB_GLOB_$(2),$$*)
+ $$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$$(call CFG_RLIB_GLOB,$$*)
endef
$(foreach host, $(CFG_HOST), \
--- /dev/null
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <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's standard distribution of crates and tools
+#
+# The crates outlined below are the standard distribution of libraries provided
+# in a rust installation. These rules are meant to abstract over the
+# dependencies (both native and rust) of crates and basically generate all the
+# necessary makefile rules necessary to build everything.
+#
+# Here's an explanation of the variables below
+#
+# TARGET_CRATES
+# This list of crates will be built for all targets, including
+# cross-compiled targets
+#
+# HOST_CRATES
+# This list of crates will be compiled for only host targets. Note that
+# this set is explicitly *not* a subset of TARGET_CRATES, but rather it is
+# a disjoint set. Nothing in the TARGET_CRATES set can depend on crates in
+# the HOST_CRATES set, but the HOST_CRATES set can depend on target
+# crates.
+#
+# TOOLS
+# A list of all tools which will be built as part of the compilation
+# process. It is currently assumed that most tools are built through
+# src/driver/driver.rs with a particular configuration (there's a
+# corresponding library providing the implementation)
+#
+# DEPS_<crate>
+# These lists are the dependencies of the <crate> that is to be built.
+# Rust dependencies are listed bare (i.e. std, extra, green) and native
+# dependencies have a "native:" prefix (i.e. native:sundown). All deps
+# will be built before the crate itself is built.
+#
+# TOOL_DEPS_<tool>/TOOL_SOURCE_<tool>
+# Similar to the DEPS variable, this is the library crate dependencies
+# list for tool as well as the source file for the specified tool
+#
+# You shouldn't need to modify much other than these variables. Crates are
+# automatically generated for all stage/host/target combinations.
+################################################################################
+
+TARGET_CRATES := std extra green rustuv native flate arena glob
+HOST_CRATES := syntax rustc rustdoc rustpkg
+CRATES := $(TARGET_CRATES) $(HOST_CRATES)
+TOOLS := compiletest rustpkg rustdoc rustc
+
+DEPS_std := native:rustrt
+DEPS_extra := std
+DEPS_green := std
+DEPS_rustuv := std native:uv native:uv_support
+DEPS_native := std
+DEPS_syntax := std extra
+DEPS_rustc := syntax native:rustllvm flate arena
+DEPS_rustdoc := rustc native:sundown
+DEPS_rustpkg := rustc
+DEPS_flate := std native:miniz
+DEPS_arena := std extra
+DEPS_glob := std
+
+TOOL_DEPS_compiletest := extra green rustuv
+TOOL_DEPS_rustpkg := rustpkg green rustuv
+TOOL_DEPS_rustdoc := rustdoc green rustuv
+TOOL_DEPS_rustc := rustc green rustuv
+TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
+TOOL_SOURCE_rustpkg := $(S)src/driver/driver.rs
+TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
+TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
+
+################################################################################
+# You should not need to edit below this line
+################################################################################
+
+DOC_CRATES := $(filter-out rustc, $(filter-out syntax, $(CRATES)))
+
+# This macro creates some simple definitions for each crate being built, just
+# some munging of all of the parameters above.
+#
+# $(1) is the crate to generate variables for
+define RUST_CRATE
+CRATEFILE_$(1) := $$(S)src/lib$(1)/lib.rs
+RSINPUTS_$(1) := $$(wildcard $$(addprefix $(S)src/lib$(1), \
+ *.rs */*.rs */*/*.rs */*/*/*.rs))
+RUST_DEPS_$(1) := $$(filter-out native:%,$$(DEPS_$(1)))
+NATIVE_DEPS_$(1) := $$(patsubst native:%,%,$$(filter native:%,$$(DEPS_$(1))))
+endef
+
+$(foreach crate,$(CRATES),$(eval $(call RUST_CRATE,$(crate))))
+
+# Similar to the macro above for crates, this macro is for tools
+#
+# $(1) is the crate to generate variables for
+define RUST_TOOL
+TOOL_INPUTS_$(1) := $$(wildcard $$(addprefix $(S)$$(dir $$(TOOL_SOURCE_$(1))), \
+ *.rs */*.rs */*/*.rs */*/*/*.rs))
+endef
+
+$(foreach crate,$(TOOLS),$(eval $(call RUST_TOOL,$(crate))))
RUSTDOC = $(HBIN2_H_$(CFG_BUILD))/rustdoc$(X_$(CFG_BUILD))
# The library documenting macro
+#
# $(1) - The crate name (std/extra)
-# $(2) - The crate file
-# $(3) - The relevant host build triple (to depend on libstd)
#
# Passes --cfg stage2 to rustdoc because it uses the stage2 librustc.
define libdoc
-doc/$(1)/index.html: $$(RUSTDOC) $$(TLIB2_T_$(3)_H_$(3))/$(CFG_STDLIB_$(3)) \
- $(foreach name,$(4),$$(TLIB2_T_$(3)_H_$(3))/$$(CFG_$(name)_$(3)))
- @$$(call E, rustdoc: $$@)
- $(Q)$(RUSTDOC) --cfg stage2 $(2)
-
-DOCS += doc/$(1)/index.html
-endef
-
-define compiledoc
-doc/$(1)/index.html: $$(RUSTDOC) $$(TLIB2_T_$(3)_H_$(3))/$(CFG_STDLIB_$(3))
+doc/$(1)/index.html: \
+ $$(CRATEFILE_$(1)) \
+ $$(RSINPUTS_$(1)) \
+ $$(RUSTDOC) \
+ $$(foreach dep,$$(RUST_DEPS_$(1)), \
+ $$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep))
@$$(call E, rustdoc: $$@)
- $(Q)$(RUSTDOC) --cfg stage2 $(2)
-
-CDOCS += doc/$(1)/index.html
+ $$(Q)$$(RUSTDOC) --cfg stage2 $$<
endef
-$(eval $(call libdoc,std,$(STDLIB_CRATE),$(CFG_BUILD)))
-$(eval $(call libdoc,extra,$(EXTRALIB_CRATE),$(CFG_BUILD)))
-$(eval $(call libdoc,native,$(LIBNATIVE_CRATE),$(CFG_BUILD)))
-$(eval $(call libdoc,green,$(LIBGREEN_CRATE),$(CFG_BUILD)))
-$(eval $(call libdoc,rustuv,$(LIBRUSTUV_CRATE),$(CFG_BUILD)))
-$(eval $(call libdoc,rustpkg,$(RUSTPKG_LIB),$(CFG_BUILD),EXTRALIB LIBRUSTC))
+$(foreach crate,$(CRATES),$(eval $(call libdoc,$(crate))))
-$(eval $(call compiledoc,rustc,$(COMPILER_CRATE),$(CFG_BUILD)))
-$(eval $(call compiledoc,syntax,$(LIBSYNTAX_CRATE),$(CFG_BUILD)))
+DOCS += $(DOC_CRATES:%=doc/%/index.html)
+CDOCS += doc/rustc/index.html
+CDOCS += doc/syntax/index.html
ifdef CFG_DISABLE_DOCS
$(info cfg: disabling doc build (CFG_DISABLE_DOCS))
# option. This file may not be copied, modified, or distributed
# except according to those terms.
-# CP_HOST_STAGE_N template: arg 1 is the N we're promoting *from*, arg
-# 2 is N+1. Must be invoked to promote target artifacts to host
-# artifacts for stage 1-3 (stage0 host artifacts come from the
-# snapshot). Arg 3 is the triple we're copying FROM and arg 4 is the
-# triple we're copying TO.
+# Generic rule for copying any target crate to a host crate. This rule will also
+# promote any dependent rust crates up to their host locations as well
#
-# The easiest way to read this template is to assume we're promoting
-# stage1 to stage2 and mentally gloss $(1) as 1, $(2) as 2.
-
-define CP_HOST_STAGE_N
-
-# Host libraries and executables (stage$(2)/bin/rustc and its runtime needs)
-
-# Note: $(3) and $(4) are both the same!
-
-$$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rustc$$(X_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
- | $$(HBIN$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)) \
+# $(1) - the stage to copy from
+# $(2) - the stage to copy to
+# $(3) - the host triple
+# $(4) - the target triple (same as $(3))
+# $(5) - the name of the crate being processed
+define CP_HOST_STAGE_N_CRATE
+
+$$(HLIB$(2)_H_$(4))/stamp.$(5): \
+ $$(TLIB$(1)_T_$(3)_H_$(4))/stamp.$(5) \
+ $$(RUST_DEPS_$(5):%=$$(HLIB$(2)_H_$(4))/stamp.%) \
| $$(HLIB$(2)_H_$(4))/
-
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@))
+ @$$(call E, cp: $$(@D)/lib$(5))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_LIB_GLOB_$(3),$(5)))
$$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_DSYM_GLOB_$(4))) \
+ $$(Q)cp -R $$(TLIB$(1)_T_$(3)_H_$(4))/$$(call CFG_LIB_GLOB_$(3),$(5)) \
$$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(4)),$$(notdir $$@))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_LIB_GLOB_$(3),$(5)))
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBSYNTAX_$(4)) \
- $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
- $$(HEXTRALIB_DEFAULT$(2)_H_$(4)) \
- $$(HLIBRUSTUV_DEFAULT$(2)_H_$(4)) \
- $$(HLIBGREEN_DEFAULT$(2)_H_$(4)) \
- $$(HLIBNATIVE_DEFAULT$(2)_H_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(4)),$$(notdir $$@))
+endef
-$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
+# Same as the above macro, but for tools instead of crates
+define CP_HOST_STAGE_N_TOOL
-$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
-# Subtle: We do not let the shell expand $$(STDLIB_DSYM_GLOB) directly rather
-# we use Make's $$(wildcard) facility. The reason is that, on mac, when using
-# USE_SNAPSHOT_STDLIB, we copy the std.dylib file out of the snapshot.
-# In that case, there is no .dSYM file. Annoyingly, bash then refuses to expand
-# glob, and cp reports an error because libstd-*.dylib.dsym does not exist.
-# Make instead expands the glob to nothing, which gives us the correct behavior.
-# (Copy .dsym file if it exists, but do nothing otherwise)
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_RGLOB_$(4))) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(4)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(4)),$$(notdir $$@))
-
-$$(HLIB$(2)_H_$(4))/$(CFG_EXTRALIB_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_EXTRALIB_$(4)) \
- $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
+$$(HBIN$(2)_H_$(4))/$(5)$$(X_$(3)): \
+ $$(TBIN$(1)_T_$(3)_H_$(4))/$(5)$$(X_$(3)) \
+ $$(TOOL_DEPS_$(5):%=$$(HLIB$(2)_H_$(4))/stamp.%) \
+ | $$(HBIN$(2)_H_$(4))/
@$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_RGLOB_$(4))) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(EXTRALIB_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(4)),$$(notdir $$@))
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTUV_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTUV_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_RGLOB_$(4))) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTUV_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(4)),$$(notdir $$@))
+endef
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBGREEN_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBGREEN_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_GLOB_$(4)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_RGLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBGREEN_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBGREEN_RGLOB_$(4))) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBGREEN_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_GLOB_$(4)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_RGLOB_$(4)),$$(notdir $$@))
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBNATIVE_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBNATIVE_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_GLOB_$(4)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_RGLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBNATIVE_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBNATIVE_RGLOB_$(4))) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBNATIVE_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_GLOB_$(4)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_RGLOB_$(4)),$$(notdir $$@))
+# Miscellaneous rules for just making a few directories.
+#
+# $(1) - the stage to copy from
+# $(2) - the stage to copy to
+# $(3) - the target triple
+# $(4) - the host triple (same as $(3))
+define CP_HOST_STAGE_N
$$(HBIN$(2)_H_$(4))/:
- mkdir -p $$@
+ @mkdir -p $$@
ifneq ($(CFG_LIBDIR_RELATIVE),bin)
$$(HLIB$(2)_H_$(4))/:
- mkdir -p $$@
+ @mkdir -p $$@
endif
endef
-$(foreach t,$(CFG_HOST), \
- $(eval $(call CP_HOST_STAGE_N,0,1,$(t),$(t))) \
- $(eval $(call CP_HOST_STAGE_N,1,2,$(t),$(t))) \
+$(foreach t,$(CFG_HOST), \
+ $(eval $(call CP_HOST_STAGE_N,0,1,$(t),$(t))) \
+ $(eval $(call CP_HOST_STAGE_N,1,2,$(t),$(t))) \
$(eval $(call CP_HOST_STAGE_N,2,3,$(t),$(t))))
+
+$(foreach crate,$(CRATES), \
+ $(foreach t,$(CFG_HOST), \
+ $(eval $(call CP_HOST_STAGE_N_CRATE,0,1,$(t),$(t),$(crate))) \
+ $(eval $(call CP_HOST_STAGE_N_CRATE,1,2,$(t),$(t),$(crate))) \
+ $(eval $(call CP_HOST_STAGE_N_CRATE,2,3,$(t),$(t),$(crate)))))
+
+$(foreach tool,$(TOOLS), \
+ $(foreach t,$(CFG_HOST), \
+ $(eval $(call CP_HOST_STAGE_N_TOOL,0,1,$(t),$(t),$(tool))) \
+ $(eval $(call CP_HOST_STAGE_N_TOOL,1,2,$(t),$(t),$(tool))) \
+ $(eval $(call CP_HOST_STAGE_N_TOOL,2,3,$(t),$(t),$(tool)))))
PREFIX_BIN = $(PREFIX_ROOT)/bin
PREFIX_LIB = $(CFG_LIBDIR)
+INSTALL_TOOLS := $(filter-out compiletest, $(TOOLS))
+
define INSTALL_PREPARE_N
# $(1) is the target triple
# $(2) is the host triple
define INSTALL_TARGET_N
install-target-$(1)-host-$(2): LIB_SOURCE_DIR=$$(TL$(1)$(2))
install-target-$(1)-host-$(2): LIB_DESTIN_DIR=$$(PTL$(1)$(2))
-install-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
+install-target-$(1)-host-$(2): \
+ $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) \
+ $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(Q)$$(call MK_INSTALL_DIR,$$(PTL$(1)$(2)))
- $$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(STDLIB_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBGREEN_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBGREEN_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBNATIVE_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBNATIVE_RGLOB_$(1)))
+ $$(Q)$$(foreach crate,$$(TARGET_CRATES),\
+ $$(call INSTALL_LIB,$$(call CFG_LIB_GLOB_$(1),$$(crate)));\
+ $$(call INSTALL_LIB,$$(call CFG_RLIB_GLOB,$$(crate)));)
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
endef
define INSTALL_HOST_N
+
install-target-$(1)-host-$(2): LIB_SOURCE_DIR=$$(TL$(1)$(2))
install-target-$(1)-host-$(2): LIB_DESTIN_DIR=$$(PTL$(1)$(2))
install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(Q)$$(call MK_INSTALL_DIR,$$(PTL$(1)$(2)))
- $$(Q)$$(call INSTALL_LIB,$$(STDLIB_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(STDLIB_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(EXTRALIB_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTUV_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBGREEN_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBGREEN_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBNATIVE_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBNATIVE_RGLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTC_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBSYNTAX_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTPKG_GLOB_$(1)))
- $$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOC_GLOB_$(1)))
+ $$(Q)$$(foreach crate,$$(CRATES),\
+ $$(call INSTALL_LIB,$$(call CFG_LIB_GLOB_$(1),$$(crate)));)
+ $$(Q)$$(foreach crate,$$(TARGET_CRATES),\
+ $$(call INSTALL_LIB,$$(call CFG_RLIB_GLOB,$$(crate)));)
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
-
endef
$(foreach target,$(CFG_TARGET), \
# Shorthand for the prefix bin directory
PHL = $(PREFIX_LIB)
-install-host: LIB_SOURCE_DIR=$(HL)
-install-host: LIB_DESTIN_DIR=$(PHL)
-install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_)_H_$(CFG_BUILD_))
+install-host%: LIB_SOURCE_DIR=$(HL)
+install-host%: LIB_DESTIN_DIR=$(PHL)
+install-host: \
+ install-host-prep \
+ $(foreach tool,$(INSTALL_TOOLS),install-host-tool-$(tool))
+
+install-host-prep: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD)_H_$(CFG_BUILD))
$(Q)$(call MK_INSTALL_DIR,$(PREFIX_BIN))
$(Q)$(call MK_INSTALL_DIR,$(PREFIX_LIB))
$(Q)$(call MK_INSTALL_DIR,$(CFG_MANDIR)/man1)
- $(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X_$(CFG_BUILD)))
- $(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD)))
- $(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(EXTRALIB_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBRUSTUV_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBGREEN_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL_LIB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD)))
- $(Q)$(call INSTALL,$(S)/man,$(CFG_MANDIR)/man1,rustc.1)
- $(Q)$(call INSTALL,$(S)/man,$(CFG_MANDIR)/man1,rustdoc.1)
- $(Q)$(call INSTALL,$(S)/man,$(CFG_MANDIR)/man1,rustpkg.1)
+
+define INSTALL_HOST_TOOL
+install-host-tool-$(1): \
+ $$(foreach dep,$$(TOOL_DEPS_$(1)),install-host-lib-$$(dep)) \
+ $$(CSREQ$$(ISTAGE)_T_$$(CFG_BUILD)_H_$$(CFG_BUILD))
+ $$(Q)$$(call INSTALL,$$(HB2),$$(PHB),$(1)$$(X_$$(CFG_BUILD)))
+ $$(Q)$$(call INSTALL,$$(S)/man,$$(CFG_MANDIR)/man1,$(1).1)
+endef
+
+$(foreach tool,$(INSTALL_TOOLS),$(eval $(call INSTALL_HOST_TOOL,$(tool))))
+
+define INSTALL_HOST_LIB
+install-host-lib-$(1): \
+ $$(foreach dep,$$(RUST_DEPS_$(1)),install-host-lib-$$(dep)) \
+ $$(CSREQ$$(ISTAGE)_T_$$(CFG_BUILD)_H_$$(CFG_BUILD))
+ $$(Q)$$(call INSTALL_LIB,$$(call CFG_LIB_GLOB_$$(CFG_BUILD),$(1)))
+endef
+
+$(foreach lib,$(CRATES),$(eval $(call INSTALL_HOST_LIB,$(lib))))
install-targets: $(INSTALL_TARGET_RULES)
HOST_LIB_FROM_HL_GLOB = \
$(patsubst $(HL)/%,$(PHL)/%,$(wildcard $(HL)/$(1)))
-uninstall:
- $(Q)rm -f $(PHB)/rustc$(X_$(CFG_BUILD))
- $(Q)rm -f $(PHB)/rustpkg$(X_$(CFG_BUILD))
- $(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD))
- $(Q)for i in \
- $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_RGLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(EXTRALIB_RGLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTUV_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTUV_RGLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBGREEN_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBGREEN_RGLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBNATIVE_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBNATIVE_RGLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD))) \
- $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD))) \
- ; \
- do rm -f $$i ; \
- done
+uninstall: $(foreach tool,$(INSTALL_TOOLS),uninstall-tool-$(tool))
$(Q)rm -Rf $(PHL)/$(CFG_RUSTLIBDIR)
- $(Q)rm -f $(CFG_MANDIR)/man1/rustc.1
- $(Q)rm -f $(CFG_MANDIR)/man1/rustdoc.1
- $(Q)rm -f $(CFG_MANDIR)/man1/rusti.1
- $(Q)rm -f $(CFG_MANDIR)/man1/rustpkg.1
+
+define UNINSTALL_TOOL
+uninstall-tool-$(1): $$(foreach dep,$$(TOOL_DEPS_$(1)),uninstall-lib-$$(dep))
+ $$(Q)rm -f $$(PHB)/$(1)$$(X_$$(CFG_BUILD))
+ $$(Q)rm -f $$(CFG_MANDIR)/man1/$(1).1
+endef
+
+$(foreach tool,$(INSTALL_TOOLS),$(eval $(call UNINSTALL_TOOL,$(tool))))
+
+define UNINSTALL_LIB
+uninstall-lib-$(1): $$(foreach dep,$$(RUST_DEPS_$(1)),uninstall-lib-$$(dep))
+ $$(Q)rm -f $$(call HOST_LIB_FROM_HL_GLOB,$$(call CFG_LIB_GLOB_$$(CFG_BUILD),$(1)))
+endef
+
+$(foreach lib,$(CRATES),$(eval $(call UNINSTALL_LIB,$(lib))))
# target platform specific variables
# for arm-linux-androidabi
define INSTALL_RUNTIME_TARGET_N
install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2))
- $(Q)$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR))
- $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
- $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(EXTRALIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
- $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(LIBRUSTUV_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
- $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(LIBGREEN_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR))
+ $$(Q)$$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR))
+ $$(Q)$$(foreach crate,$$(TARGET_CRATES),\
+ $$(call ADB_PUSH,$$(TL$(1)$(2))/$$(call CFG_LIB_GLOB_$(1),$$(crate)),\
+ $$(CFG_RUNTIME_PUSH_DIR));)
endef
define INSTALL_RUNTIME_TARGET_CLEANUP_N
install-runtime-target-$(1)-cleanup:
- $(Q)$(call ADB,remount)
- $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1)))
- $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(EXTRALIB_GLOB_$(1)))
- $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(LIBRUSTUV_GLOB_$(1)))
- $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(LIBGREEN_GLOB_$(1)))
+ $$(Q)$$(call ADB,remount)
+ $$(Q)$$(foreach crate,$$(TARGET_CRATES),\
+ $$(call ADB_SHELL,rm,$$(CFG_RUNTIME_PUSH_DIR)/$$(call CFG_LIB_GLOB_$(1),$$(crate)));)
endef
$(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD)))
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_OSTYPE_VAR,$(t))))
$(foreach t,$(CFG_TARGET),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
-# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
-# has a frame pointer and the stack walker can understand it. Turning off
-# frame pointers everywhere is overkill
-CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer
-
# On Darwin, we need to run dsymutil so the debugging information ends
# up in the right place. On other platforms, it automatically gets
# embedded into the executable, so use a no-op command.
CFG_LLC_FLAGS_x86_64-unknown-linux-gnu :=
CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
CFG_LIBUV_LINK_FLAGS_x86_64-unknown-linux-gnu =
-CFG_LLVM_BUILD_ENV_x86_64-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
CFG_UNIXY_x86_64-unknown-linux-gnu := 1
CFG_LLC_FLAGS_i686-unknown-linux-gnu :=
CFG_INSTALL_NAME_i686-unknown-linux-gnu =
CFG_LIBUV_LINK_FLAGS_i686-unknown-linux-gnu =
-CFG_LLVM_BUILD_ENV_i686-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
CFG_WINDOWSY_i686-unknown-linux-gnu :=
CFG_UNIXY_i686-unknown-linux-gnu := 1
else
# For the ARM and MIPS crosses, use the toolchain assembler
- # XXX: We should be able to use the LLVM assembler
+ # FIXME: We should be able to use the LLVM assembler
CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
$$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
-# This is a procedure to define the targets for building
-# the runtime.
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
#
-# Argument 1 is the target triple.
+# 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.
+
+################################################################################
+# Native libraries built as part of the rust build process
#
-# This is not really the right place to explain this, but
-# for those of you who are not Makefile gurus, let me briefly
-# cover the $ expansion system in use here, because it
-# confused me for a while! The variable DEF_RUNTIME_TARGETS
-# will be defined once and then expanded with different
-# values substituted for $(1) each time it is called.
-# That resulting text is then eval'd.
+# This portion of the rust build system is meant to keep track of native
+# dependencies and how to build them. It is currently required that all native
+# dependencies are built as static libraries, as slinging around dynamic
+# libraries isn't exactly the most fun thing to do.
#
-# For most variables, you could use a single $ sign. The result
-# is that the substitution would occur when the CALL occurs,
-# I believe. The problem is that the automatic variables $< and $@
-# need to be expanded-per-rule. Therefore, for those variables at
-# least, you need $$< and $$@ in the variable text. This way, after
-# the CALL substitution occurs, you will have $< and $@. This text
-# will then be evaluated, and all will work as you like.
+# This section should need minimal modification to add new libraries. The
+# relevant variables are:
#
-# Reader beware, this explanantion could be wrong, but it seems to
-# fit the experimental data (i.e., I was able to get the system
-# working under these assumptions).
+# NATIVE_LIBS
+# This is a list of all native libraries which are built as part of the
+# build process. It will build all libraries into RT_OUTPUT_DIR with the
+# appropriate name of static library as dictated by the target platform
+#
+# NATIVE_DEPS_<lib>
+# This is a list of files relative to the src/rt directory which are
+# needed to build the native library. Each file will be compiled to an
+# object file, and then all the object files will be assembled into an
+# archive (static library). The list contains files of any extension
+#
+# If adding a new library, you should update the NATIVE_LIBS list, and then list
+# the required files below it. The list of required files is a list of files
+# that's per-target so you're allowed to conditionally add files based on the
+# target.
+################################################################################
+NATIVE_LIBS := rustrt sundown uv_support morestack miniz
+
+# $(1) is the target triple
+define NATIVE_LIBRARIES
+
+NATIVE_DEPS_sundown_$(1) := sundown/src/autolink.c \
+ sundown/src/buffer.c \
+ sundown/src/stack.c \
+ sundown/src/markdown.c \
+ sundown/html/houdini_href_e.c \
+ sundown/html/houdini_html_e.c \
+ sundown/html/html_smartypants.c \
+ sundown/html/html.c
+NATIVE_DEPS_uv_support_$(1) := rust_uv.c
+NATIVE_DEPS_miniz_$(1) = miniz.c
+NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \
+ rust_android_dummy.c \
+ rust_test_helpers.c \
+ rust_try.ll \
+ arch/$$(HOST_$(1))/_context.S \
+ arch/$$(HOST_$(1))/record_sp.S
+NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
+
+################################################################################
+# You shouldn't find it that necessary to edit anything below this line.
+################################################################################
+
+# While we're defining the native libraries for each target, we define some
+# common rules used to build files for various targets.
-# when we're doing a snapshot build, we intentionally degrade as many
-# features in libuv and the runtime as possible, to ease portability.
+RT_OUTPUT_DIR_$(1) := $(1)/rt
+
+$$(RT_OUTPUT_DIR_$(1))/%.o: rt/%.ll $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD))
+ @mkdir -p $$(@D)
+ @$$(call E, compile: $$@)
+ $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
+ -filetype=obj -mtriple=$(1) -relocation-model=pic -o $$@ $$<
+
+$$(RT_OUTPUT_DIR_$(1))/%.o: rt/%.c $$(MKFILE_DEPS)
+ @mkdir -p $$(@D)
+ @$$(call E, compile: $$@)
+ $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
+ -I $$(S)src/rt/sundown/src -I $$(S)src/rt/sundown/html \
+ -I $$(S)src/libuv/include -I $$(S)src/rt \
+ $$(RUNTIME_CFLAGS_$(1))) $$<
+
+$$(RT_OUTPUT_DIR_$(1))/%.o: rt/%.S $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD))
+ @mkdir -p $$(@D)
+ @$$(call E, compile: $$@)
+ $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
+endef
+
+$(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target))))
+
+# A macro for devining how to build third party libraries listed above (based
+# on their dependencies).
+#
+# $(1) is the target
+# $(2) is the lib name
+define THIRD_PARTY_LIB
+
+OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
+OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
+OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
+OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
+OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
+NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
+$$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
+ @$$(call E, link: $$@)
+ $$(Q)$$(AR_$(1)) rcs $$@ $$^
+
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(eval $(call RUNTIME_RULES,$(target))))
+$(foreach lib,$(NATIVE_LIBS), \
+ $(foreach target,$(CFG_TARGET), \
+ $(eval $(call THIRD_PARTY_LIB,$(target),$(lib)))))
-SNAP_DEFINES:=
-ifneq ($(strip $(findstring snap,$(MAKECMDGOALS))),)
- SNAP_DEFINES=-DRUST_SNAPSHOT
-endif
+
+################################################################################
+# Building third-party targets with external build systems
+#
+# The only current member of this section is libuv, but long ago this used to
+# also be occupied by jemalloc. This location is meant for dependencies which
+# have external build systems. It is still assumed that the output of each of
+# these steps is a static library in the correct location.
+################################################################################
define DEF_LIBUV_ARCH_VAR
LIBUV_ARCH_$(1) = $$(subst i386,ia32,$$(subst x86_64,x64,$$(HOST_$(1))))
export PYTHONPATH := $(PYTHONPATH):$(S)src/gyp/pylib
-define DEF_RUNTIME_TARGETS
-
-######################################################################
-# Runtime (C++) library variables
-######################################################################
-
-# $(1) is the target triple
-# $(2) is the stage number
-
-RUNTIME_CFLAGS_$(1)_$(2) = -D_RUST_STAGE$(2)
-RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE$(2)
-
-# XXX: Like with --cfg stage0, pass the defines for stage1 to the stage0
-# build of non-build-triple host compilers
-ifeq ($(2),0)
-ifneq ($(strip $(CFG_BUILD)),$(strip $(1)))
-RUNTIME_CFLAGS_$(1)_$(2) = -D_RUST_STAGE1
-RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE1
-endif
-endif
-
-RUNTIME_CS_$(1)_$(2) := \
- rt/rust_builtin.c \
- rt/miniz.c \
- rt/rust_android_dummy.c \
- rt/rust_test_helpers.c
-
-RUNTIME_LL_$(1)_$(2) := \
- rt/rust_try.ll
-
-# stage0 remove this after the next snapshot
-%.cpp:
- @touch tmp/foo.o
-
-RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
- rt/arch/$$(HOST_$(1))/record_sp.S
-
-RT_BUILD_DIR_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/stage$(2)
-
-RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1))
-RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
- -I $$(S)src/rt/arch/$$(HOST_$(1))
-RUNTIME_OBJS_$(1)_$(2) := \
- $$(RUNTIME_CS_$(1)_$(2):rt/%.c=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
- $$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
- $$(RUNTIME_LL_$(1)_$(2):rt/%.ll=$$(RT_BUILD_DIR_$(1)_$(2))/%.o)
-
-ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
-
-MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o
-ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
-
-$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.c $$(MKFILE_DEPS)
- @$$(call E, compile: $$@)
- $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
- $$(SNAP_DEFINES) $$(RUNTIME_CFLAGS_$(1)_$(2))) $$<
-
-$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.S $$(MKFILE_DEPS) \
- $$(LLVM_CONFIG_$$(CFG_BUILD))
- @$$(call E, compile: $$@)
- $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
-
-$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.ll $$(MKFILE_DEPS) \
- $$(LLVM_CONFIG_$$(CFG_BUILD))
- @$$(call E, compile: $$@)
- $$(Q)$(LLC_$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) -filetype=obj -mtriple=$(1) -relocation-model=pic -o $$@ $$<
-
-$$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJS_$(1)_$(2))
- @$$(call E, link: $$@)
- $$(Q)$(AR_$(1)) rcs $$@ $$^
-
-$$(RT_BUILD_DIR_$(1)_$(2))/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS)
- @$$(call E, link: $$@)
- $$(Q)$(AR_$(1)) rcs $$@ $$(RUNTIME_OBJS_$(1)_$(2))
-
-# These could go in rt.mk or rustllvm.mk, they're needed for both.
-
-# This regexp has a single $$ escaped twice
-$(1)/%.bsd.def: %.def.in $$(MKFILE_DEPS)
- @$$(call E, def: $$@)
- $$(Q)echo "{" > $$@
- $$(Q)sed 's/.$$$$/&;/' $$< >> $$@
- $$(Q)echo "};" >> $$@
-
-$(1)/%.linux.def: %.def.in $$(MKFILE_DEPS)
- @$$(call E, def: $$@)
- $$(Q)echo "{" > $$@
- $$(Q)sed 's/.$$$$/&;/' $$< >> $$@
- $$(Q)echo "};" >> $$@
-
-$(1)/%.darwin.def: %.def.in $$(MKFILE_DEPS)
- @$$(call E, def: $$@)
- $$(Q)sed 's/^./_&/' $$< > $$@
-
-$(1)/%.android.def: %.def.in $$(MKFILE_DEPS)
- @$$(call E, def: $$@)
- $$(Q)echo "{" > $$@
- $$(Q)sed 's/.$$$$/&;/' $$< >> $$@
- $$(Q)echo "};" >> $$@
-
-$(1)/%.mingw32.def: %.def.in $$(MKFILE_DEPS)
- @$$(call E, def: $$@)
- $$(Q)echo LIBRARY $$* > $$@
- $$(Q)echo EXPORTS >> $$@
- $$(Q)sed 's/^./ &/' $$< >> $$@
-
-endef
-
-
-######################################################################
-# Runtime third party targets (libuv, jemalloc, etc.)
-#
-# These targets do not need to be built once per stage, so these
-# rules just build them once and then we're done with them.
-######################################################################
-
define DEF_THIRD_PARTY_TARGETS
# $(1) is the target triple
-RT_OUTPUT_DIR_$(1) := $(1)/rt
-
ifeq ($$(CFG_WINDOWSY_$(1)), 1)
LIBUV_OSTYPE_$(1) := win
else ifeq ($(OSTYPE_$(1)), apple-darwin)
LIBUV_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),uv)
LIBUV_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/libuv
-LIBUV_LIB_$(1) := $$(LIBUV_DIR_$(1))/$$(LIBUV_NAME_$(1))
+LIBUV_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(LIBUV_NAME_$(1))
LIBUV_MAKEFILE_$(1) := $$(CFG_BUILD_DIR)$$(RT_OUTPUT_DIR_$(1))/libuv/Makefile
$$(Q)cp $$(S)src/libuv/libuv.a $$@
else
$$(LIBUV_LIB_$(1)): $$(LIBUV_DIR_$(1))/Release/libuv.a $$(MKFILE_DEPS)
- $$(Q)ln -f $$< $$@
+ $$(Q)cp $$< $$@
$$(LIBUV_DIR_$(1))/Release/libuv.a: $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)) \
$$(MKFILE_DEPS)
$$(Q)$$(MAKE) -C $$(LIBUV_DIR_$(1)) \
BUILDTYPE=Release \
NO_LOAD="$$(LIBUV_NO_LOAD)" \
V=$$(VERBOSE)
-endif
-
-# libuv support functionality (extra C/C++ that we need to use libuv)
-UV_SUPPORT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),uv_support)
-UV_SUPPORT_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/uv_support
-UV_SUPPORT_LIB_$(1) := $$(UV_SUPPORT_DIR_$(1))/$$(UV_SUPPORT_NAME_$(1))
-UV_SUPPORT_CS_$(1) := rt/rust_uv.c
-UV_SUPPORT_OBJS_$(1) := $$(UV_SUPPORT_CS_$(1):rt/%.c=$$(UV_SUPPORT_DIR_$(1))/%.o)
-
-$$(UV_SUPPORT_DIR_$(1))/%.o: rt/%.c
- @$$(call E, compile: $$@)
- @mkdir -p $$(@D)
- $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
- -I $$(S)src/libuv/include \
- $$(RUNTIME_CFLAGS_$(1))) $$<
-
-$$(UV_SUPPORT_LIB_$(1)): $$(UV_SUPPORT_OBJS_$(1))
- @$$(call E, link: $$@)
- $$(Q)$$(AR_$(1)) rcs $$@ $$^
-
-# sundown markdown library (used by librustdoc)
-
-SUNDOWN_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),sundown)
-SUNDOWN_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/sundown
-SUNDOWN_LIB_$(1) := $$(SUNDOWN_DIR_$(1))/$$(SUNDOWN_NAME_$(1))
-
-SUNDOWN_CS_$(1) := rt/sundown/src/autolink.c \
- rt/sundown/src/buffer.c \
- rt/sundown/src/stack.c \
- rt/sundown/src/markdown.c \
- rt/sundown/html/houdini_href_e.c \
- rt/sundown/html/houdini_html_e.c \
- rt/sundown/html/html_smartypants.c \
- rt/sundown/html/html.c
-
-SUNDOWN_OBJS_$(1) := $$(SUNDOWN_CS_$(1):rt/%.c=$$(SUNDOWN_DIR_$(1))/%.o)
-
-$$(SUNDOWN_DIR_$(1))/%.o: rt/%.c
- @$$(call E, compile: $$@)
- @mkdir -p $$(@D)
- $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
- -I $$(S)src/rt/sundown/src -I $$(S)src/rt/sundown/html \
- $$(RUNTIME_CFLAGS_$(1))) $$<
-
-$$(SUNDOWN_LIB_$(1)): $$(SUNDOWN_OBJS_$(1))
- @$$(call E, link: $$@)
- $$(Q)$$(AR_$(1)) rcs $$@ $$^
+endif
endef
# Instantiate template for all stages/targets
$(foreach target,$(CFG_TARGET), \
$(eval $(call DEF_THIRD_PARTY_TARGETS,$(target))))
-$(foreach stage,$(STAGES), \
- $(foreach target,$(CFG_TARGET), \
- $(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
RUSTLLVM_OBJS_OBJS_$(1) := $$(RUSTLLVM_OBJS_CS_$(1):rustllvm/%.cpp=$(1)/rustllvm/%.o)
ALL_OBJ_FILES += $$(RUSTLLVM_OBJS_OBJS_$(1))
-$(1)/rustllvm/$(CFG_RUSTLLVM_$(1)): $$(RUSTLLVM_OBJS_OBJS_$(1))
+$$(RT_OUTPUT_DIR_$(1))/$$(call CFG_STATIC_LIB_NAME_$(1),rustllvm): \
+ $$(RUSTLLVM_OBJS_OBJS_$(1))
@$$(call E, link: $$@)
$$(Q)$$(AR_$(1)) rcs $$@ $$(RUSTLLVM_OBJS_OBJS_$(1))
WFLAGS_ST1 = -D warnings
WFLAGS_ST2 = -D warnings
-# TARGET_STAGE_N template: This defines how target artifacts are built
-# for all stage/target architecture combinations. The arguments:
+# Macro that generates the full list of dependencies for a crate at a particular
+# stage/target/host tuple.
+#
+# $(1) - stage
+# $(2) - target
+# $(3) - host
+# $(4) crate
+define RUST_CRATE_FULLDEPS
+CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4) := \
+ $$(CRATEFILE_$(4)) \
+ $$(RSINPUTS_$(4)) \
+ $$(foreach dep,$$(RUST_DEPS_$(4)), \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
+ $$(foreach dep,$$(NATIVE_DEPS_$(4)), \
+ $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep)))
+endef
+
+$(foreach host,$(CFG_HOST), \
+ $(foreach target,$(CFG_TARGET), \
+ $(foreach stage,$(STAGES), \
+ $(foreach crate,$(CRATES), \
+ $(eval $(call RUST_CRATE_FULLDEPS,$(stage),$(target),$(host),$(crate)))))))
+
+# RUST_TARGET_STAGE_N template: This defines how target artifacts are built
+# for all stage/target architecture combinations. This is one giant rule which
+# works as follows:
+#
+# 1. The immediate dependencies are the rust source files
+# 2. Each rust crate dependency is listed (based on their stamp files),
+# as well as all native dependencies (listed in RT_OUTPUT_DIR)
+# 3. The stage (n-1) compiler is required through the TSREQ dependency, along
+# with the morestack library
+# 4. When actually executing the rule, the first thing we do is to clean out
+# old libs and rlibs via the REMOVE_ALL_OLD_GLOB_MATCHES macro
+# 5. Finally, we get around to building the actual crate. It's just one
+# "small" invocation of the previous stage rustc. We use -L to
+# RT_OUTPUT_DIR so all the native dependencies are picked up.
+# Additionally, we pass in the llvm dir so rustc can link against it.
+# 6. Some cleanup is done (listing what was just built) if verbose is turned
+# on.
+#
# $(1) is the stage
# $(2) is the target triple
# $(3) is the host triple
+# $(4) is the crate name
+define RUST_TARGET_STAGE_N
+
+$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): CFG_COMPILER = $(2)
+$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
+ $$(CRATEFILE_$(4)) \
+ $$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
+ $$(TSREQ$(1)_T_$(2)_H_$(3)) \
+ | $$(TLIB$(1)_T_$(2)_H_$(3))/
+ @$$(call E, compile_and_link: $$(@D)/lib$(4))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
+ $$(call REMOVE_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_RLIB_GLOB,$(4)))
+ $$(STAGE$(1)_T_$(2)_H_$(3)) \
+ $$(WFLAGS_ST$(1)) \
+ -L "$$(RT_OUTPUT_DIR_$(2))" \
+ -L "$$(LLVM_LIBDIR_$(2))" \
+ --out-dir $$(@D) $$<
+ @touch $$@
+ $$(call LIST_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
+ $$(call LIST_ALL_OLD_GLOB_MATCHES,\
+ $$(dir $$@)$$(call CFG_RLIB_GLOB,$(4)))
+
+endef
+
+# Macro for building any tool as part of the rust compilation process. Each
+# tool is defined in crates.mk with a list of library dependencies as well as
+# the source file for the tool. Building each tool will also be passed '--cfg
+# <tool>' for usage in driver.rs
+#
+# This build rule is similar to the one found above, just tweaked for
+# locations and things.
+#
+# $(1) - stage
+# $(2) - target triple
+# $(3) - host triple
+# $(4) - name of the tool being built
+define TARGET_TOOL
+
+$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
+ $$(TOOL_SOURCE_$(4)) \
+ $$(TOOL_INPUTS_$(4)) \
+ $$(foreach dep,$$(TOOL_DEPS_$(4)), \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
+ $$(TSREQ$(1)_T_$(2)_H_$(3)) \
+ | $$(TBIN$(1)_T_$(4)_H_$(3))/
+ @$$(call E, compile_and_link: $$@)
+ $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --cfg $(4)
+
+endef
-# Every recipe in TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3),
+# Every recipe in RUST_TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3),
# a directory that can be cleaned out during the middle of a run of
# the get-snapshot.py script. Therefore, every recipe needs to have
# an order-only dependency either on $(SNAPSHOT_RUSTC_POST_CLEANUP) or
# put into the target area until after the get-snapshot.py script has
# had its chance to clean it out; otherwise the other products will be
# inadvertantly included in the clean out.
-
SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))
-define TARGET_STAGE_N
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
- $(2)/rt/stage$(1)/arch/$$(HOST_$(2))/libmorestack.a \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/ \
- $(SNAPSHOT_RUSTC_POST_CLEANUP)
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
+define TARGET_HOST_RULES
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \
- $(2)/rt/stage$(1)/$(CFG_RUNTIME_$(2)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/ \
- $(SNAPSHOT_RUSTC_POST_CLEANUP)
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
- $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(STDLIB_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)): \
- $$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTUV_$(2)): \
- $$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- $$(LIBUV_LIB_$(2)) \
- $$(UV_SUPPORT_LIB_$(2)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- -L $$(UV_SUPPORT_DIR_$(2)) \
- -L $$(dir $$(LIBUV_LIB_$(2))) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBGREEN_$(2)): \
- $$(LIBGREEN_CRATE) $$(LIBGREEN_INPUTS) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBGREEN_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBNATIVE_$(2)): \
- $$(LIBNATIVE_CRATE) $$(LIBNATIVE_INPUTS) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBNATIVE_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
- $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- $$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
- $$(TEXTRALIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) $(BORROWCK) \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBSYNTAX_RGLOB_$(2)),$$(notdir $$@))
-
-# Only build the compiler for host triples
-ifneq ($$(findstring $(2),$$(CFG_HOST)),)
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \
- $(2)/rustllvm/$(CFG_RUSTLLVM_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/ \
- $(SNAPSHOT_RUSTC_POST_CLEANUP)
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): CFG_COMPILER = $(2)
-$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \
- $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
- $(S)src/librustc/lib/llvmdeps.rs \
- $$(TSREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_RGLOB_$(2)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(2)_H_$(3)) $$(WFLAGS_ST$(1)) \
- -L "$$(LLVM_LIBDIR_$(2))" \
- --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_GLOB_$(2)),$$(notdir $$@))
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTC_RGLOB_$(2)),$$(notdir $$@))
-
-$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
- $$(DRIVER_CRATE) \
- $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \
- | $$(TBIN$(1)_T_$(2)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$<
-ifdef CFG_ENABLE_PAX_FLAGS
- @$$(call E, apply PaX flags: $$@)
- @"$(CFG_PAXCTL)" -cm "$$@"
-endif
-
-endif
+$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc: $(S)src/librustc/lib/llvmdeps.rs
$$(TBIN$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
+$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
+ $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),morestack) \
+ | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
endef
-# In principle, each host can build each target:
-$(foreach source,$(CFG_HOST), \
- $(foreach target,$(CFG_TARGET), \
- $(eval $(call TARGET_STAGE_N,0,$(target),$(source))) \
- $(eval $(call TARGET_STAGE_N,1,$(target),$(source))) \
- $(eval $(call TARGET_STAGE_N,2,$(target),$(source))) \
- $(eval $(call TARGET_STAGE_N,3,$(target),$(source)))))
+$(foreach source,$(CFG_HOST), \
+ $(foreach target,$(CFG_TARGET), \
+ $(eval $(call TARGET_HOST_RULES,0,$(target),$(source))) \
+ $(eval $(call TARGET_HOST_RULES,1,$(target),$(source))) \
+ $(eval $(call TARGET_HOST_RULES,2,$(target),$(source))) \
+ $(eval $(call TARGET_HOST_RULES,3,$(target),$(source)))))
+
+# In principle, each host can build each target for both libs and tools
+$(foreach crate,$(CRATES), \
+ $(foreach source,$(CFG_HOST), \
+ $(foreach target,$(CFG_TARGET), \
+ $(eval $(call RUST_TARGET_STAGE_N,0,$(target),$(source),$(crate))) \
+ $(eval $(call RUST_TARGET_STAGE_N,1,$(target),$(source),$(crate))) \
+ $(eval $(call RUST_TARGET_STAGE_N,2,$(target),$(source),$(crate))) \
+ $(eval $(call RUST_TARGET_STAGE_N,3,$(target),$(source),$(crate))))))
+
+$(foreach host,$(CFG_HOST), \
+ $(foreach target,$(CFG_TARGET), \
+ $(foreach stage,$(STAGES), \
+ $(foreach tool,$(TOOLS), \
+ $(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))
######################################################################
# The names of crates that must be tested
-TEST_TARGET_CRATES = std extra rustuv green native
-TEST_DOC_CRATES = std extra
-TEST_HOST_CRATES = rustpkg rustc rustdoc syntax
+TEST_TARGET_CRATES = $(TARGET_CRATES)
+TEST_DOC_CRATES = $(DOC_CRATES)
+TEST_HOST_CRATES = $(HOST_CRATES)
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
$(shell $(CFG_ADB) shell mkdir $(CFG_ADB_TEST_DIR)) \
$(shell $(CFG_ADB) shell mkdir $(CFG_ADB_TEST_DIR)/tmp) \
$(shell $(CFG_ADB) push $(S)src/etc/adb_run_wrapper.sh $(CFG_ADB_TEST_DIR) 1>/dev/null) \
- $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(CFG_RUNTIME_arm-linux-androideabi) \
- $(CFG_ADB_TEST_DIR)) \
- $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(STDLIB_GLOB_arm-linux-androideabi) \
- $(CFG_ADB_TEST_DIR)) \
- $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(EXTRALIB_GLOB_arm-linux-androideabi) \
- $(CFG_ADB_TEST_DIR)) \
- $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(LIBRUSTUV_GLOB_arm-linux-androideabi) \
- $(CFG_ADB_TEST_DIR)) \
- $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(LIBGREEN_GLOB_arm-linux-androideabi) \
- $(CFG_ADB_TEST_DIR)) \
+ $(foreach crate,$(TARGET_CRATES),\
+ $(shell $(CFG_ADB) push $(TLIB2_T_arm-linux-androideabi_H_$(CFG_BUILD))/$(call CFG_LIB_GLOB_arm-linux-androideabi,$(crate)) \
+ $(CFG_ADB_TEST_DIR)))\
)
else
CFG_ADB_TEST_DIR=
# If NO_REBUILD is set then break the dependencies on extra so we can
# test crates without rebuilding std and extra first
ifeq ($(NO_REBUILD),)
-STDTESTDEP_$(1)_$(2)_$(3) = $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_EXTRALIB_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTUV_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBGREEN_$(2))
+STDTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(SREQ$(1)_T_$(2)_H_$(3)) \
+ $$(foreach crate,$$(TARGET_CRATES),\
+ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate))
else
-STDTESTDEP_$(1)_$(2)_$(3) =
+STDTESTDEP_$(1)_$(2)_$(3)_$(4) =
endif
-$(3)/stage$(1)/test/stdtest-$(2)$$(X_$(2)): \
- $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
+$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): CFG_COMPILER = $(2)
+$(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \
+ $$(CRATEFILE_$(4)) \
+ $$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
+ $$(STDTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/extratest-$(2)$$(X_$(2)): \
- $$(EXTRALIB_CRATE) $$(EXTRALIB_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/rustuvtest-$(2)$$(X_$(2)): \
- $$(LIBRUSTUV_CRATE) $$(LIBRUSTUV_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test \
- -L $$(UV_SUPPORT_DIR_$(2)) \
- -L $$(dir $$(LIBUV_LIB_$(2)))
-
-$(3)/stage$(1)/test/nativetest-$(2)$$(X_$(2)): \
- $$(LIBNATIVE_CRATE) $$(LIBNATIVE_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/greentest-$(2)$$(X_$(2)): \
- $$(LIBGREEN_CRATE) $$(LIBGREEN_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/syntaxtest-$(2)$$(X_$(2)): \
- $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
- $$(STDTESTDEP_$(1)_$(2)_$(3))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): CFG_COMPILER = $(2)
-$(3)/stage$(1)/test/rustctest-$(2)$$(X_$(2)): \
- $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
- $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_RUSTLLVM_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test \
- -L "$$(LLVM_LIBDIR_$(2))"
-
-$(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
- $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
- $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
- $$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(2)) \
- $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \
- $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
-
-$(3)/stage$(1)/test/rustdoctest-$(2)$$(X_$(2)): \
- $$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
- $$(SREQ$(1)_T_$(2)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
- $$(SUNDOWN_LIB_$(2))
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test \
- -L $$(SUNDOWN_DIR_$(2))
+ $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test \
+ -L "$$(RT_OUTPUT_DIR_$(2))" \
+ -L "$$(LLVM_LIBDIR_$(2))"
endef
$(foreach host,$(CFG_HOST), \
$(eval $(foreach target,$(CFG_TARGET), \
$(eval $(foreach stage,$(STAGES), \
- $(eval $(call TEST_RUNNER,$(stage),$(target),$(host))))))))
+ $(eval $(foreach crate,$(TEST_CRATES), \
+ $(eval $(call TEST_RUNNER,$(stage),$(target),$(host),$(crate))))))))))
define DEF_TEST_CRATE_RULES
check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
--host $(3) \
--adb-path=$(CFG_ADB) \
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
- --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CTEST_RUSTC_FLAGS)" \
+ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CTEST_RUSTC_FLAGS) -L $$(RT_OUTPUT_DIR_$(2))" \
$$(CTEST_TESTARGS)
CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS)
$(foreach docname,$(DOC_TEST_NAMES), \
$(eval $(call DEF_RUN_DOC_TEST,$(stage),$(target),$(host),$(docname)))))))
-CRATE_DOC_LIB-std = $(STDLIB_CRATE)
-CRATE_DOC_LIB-extra = $(EXTRALIB_CRATE)
-
define DEF_CRATE_DOC_TEST
check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4))
ifeq ($(2),$$(CFG_BUILD))
-$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \
- $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
+$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \
+ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
+ $$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3))
@$$(call E, run doc-$(4) [$(2)])
$$(Q)$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) --test \
- $$(CRATE_DOC_LIB-$(4)) --test-args "$$(TESTARGS)" && touch $$@
+ $$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
touch $$@
tmp/$$(FT).rc \
$$(SREQ2_T_$(2)_H_$(3))
@$$(call E, compile_and_link: $$@)
- $$(STAGE2_T_$(2)_H_$(3)) --lib -o $$@ $$<
+ $$(STAGE2_T_$(2)_H_$(3)) --lib -o $$@ $$< \
+ -L "$$(RT_OUTPUT_DIR_$(2))"
$(3)/test/$$(FT_DRIVER)-$(2)$$(X_$(2)): \
tmp/$$(FT_DRIVER).rs \
$$(TLIB2_T_$(2)_H_$(3))/$$(FT_LIB) \
$$(SREQ2_T_$(2)_H_$(3))
@$$(call E, compile_and_link: $$@ $$<)
- $$(STAGE2_T_$(2)_H_$(3)) -o $$@ $$<
+ $$(STAGE2_T_$(2)_H_$(3)) -o $$@ $$< \
+ -L "$$(RT_OUTPUT_DIR_$(2))"
$(3)/test/$$(FT_DRIVER)-$(2).out: \
$(3)/test/$$(FT_DRIVER)-$(2)$$(X_$(2)) \
+++ /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.
-
-# Rules for non-core tools built with the compiler, both for target
-# and host architectures
-
-# The test runner that runs the cfail/rfail/rpass and bxench tests
-COMPILETEST_CRATE := $(S)src/compiletest/compiletest.rs
-COMPILETEST_INPUTS := $(wildcard $(S)src/compiletest/*.rs)
-
-# Rustpkg, the package manager and build system
-RUSTPKG_LIB := $(S)src/librustpkg/lib.rs
-RUSTPKG_INPUTS := $(wildcard $(S)src/librustpkg/*.rs)
-
-# Rustdoc, the documentation tool
-RUSTDOC_LIB := $(S)src/librustdoc/lib.rs
-RUSTDOC_INPUTS := $(wildcard $(addprefix $(S)src/librustdoc/, \
- *.rs */*.rs */*/*.rs))
-
-# FIXME: These are only built for the host arch. Eventually we'll
-# have tools that need to built for other targets.
-define TOOLS_STAGE_N_TARGET
-
-$$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)): \
- $$(COMPILETEST_CRATE) $$(COMPILETEST_INPUTS) \
- $$(SREQ$(1)_T_$(4)_H_$(3)) \
- | $$(TBIN$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$<
-
-$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)): \
- $$(RUSTPKG_LIB) $$(RUSTPKG_INPUTS) \
- $$(SREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
- | $$(TLIB$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
-
-$$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)): \
- $$(DRIVER_CRATE) \
- $$(TSREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \
- | $$(TBIN$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustpkg -o $$@ $$<
-
-$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)): \
- $$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
- $$(SREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
- $$(SUNDOWN_LIB_$(4)) \
- | $$(TLIB$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) \
- -L $$(SUNDOWN_DIR_$(4)) --out-dir $$(@D) $$< && touch $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
-
-$$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
- $$(DRIVER_CRATE) \
- $$(TSREQ$(1)_T_$(4)_H_$(3)) \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \
- | $$(TBIN$(1)_T_$(4)_H_$(3))/
- @$$(call E, compile_and_link: $$@)
- $$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc -o $$@ $$<
-
-endef
-
-define TOOLS_STAGE_N_HOST
-
-$$(HBIN$(2)_H_$(4))/compiletest$$(X_$(4)): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/compiletest$$(X_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HBIN$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTPKG_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTPKG_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTPKG_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTPKG_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTPKG_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
-
-$$(HBIN$(2)_H_$(4))/rustpkg$$(X_$(4)): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rustpkg$$(X_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTPKG_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HBIN$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOC_$(4)): \
- $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTDOC_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HLIB$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp $$< $$@
- $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTDOC_GLOB_$(4)),$$(notdir $$@))
- $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOC_GLOB_$(4)) \
- $$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOC_DSYM_GLOB_$(4))) \
- $$(HLIB$(2)_H_$(4))
-
-$$(HBIN$(2)_H_$(4))/rustdoc$$(X_$(4)): \
- $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)) \
- $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOC_$(4)) \
- $$(HSREQ$(2)_H_$(4)) \
- | $$(HBIN$(2)_H_$(4))/
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-endef
-
-$(foreach host,$(CFG_HOST), \
-$(foreach target,$(CFG_TARGET), \
- $(eval $(call TOOLS_STAGE_N_TARGET,0,1,$(host),$(target))) \
- $(eval $(call TOOLS_STAGE_N_TARGET,1,2,$(host),$(target))) \
- $(eval $(call TOOLS_STAGE_N_TARGET,2,3,$(host),$(target))) \
- $(eval $(call TOOLS_STAGE_N_TARGET,3,bogus,$(host),$(target)))))
-
-$(foreach host,$(CFG_HOST), \
- $(eval $(call TOOLS_STAGE_N_HOST,0,1,$(host),$(host))) \
- $(eval $(call TOOLS_STAGE_N_HOST,1,2,$(host),$(host))) \
- $(eval $(call TOOLS_STAGE_N_HOST,2,3,$(host),$(host))))
loop {
//waiting 1 second for gdbserver start
timer::sleep(1000);
- let result = do task::try {
+ let result = task::try(proc() {
tcp::TcpStream::connect(
SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 5039 });
- };
+ });
if result.is_err() {
continue;
}
let abs_ab = config.aux_base.join(rel_ab.as_slice());
let aux_props = load_props(&abs_ab);
let aux_args =
- make_compile_args(config, &aux_props, ~[~"--lib"] + extra_link_args,
+ make_compile_args(config, &aux_props, ~[~"--dylib"] + extra_link_args,
|a,b| make_lib_name(a, b, testfile), &abs_ab);
let auxres = compose_and_run(config, &abs_ab, aux_args, ~[],
config.compile_lib_path, None);
#!/usr/bin/env python
# xfail-license
+import glob
import sys
if __name__ == '__main__':
def count(t):
return sum(map(lambda (f, s): len(s.get(t, [])), summaries))
logfiles = sys.argv[1:]
- map(summarise, logfiles)
+ for files in map(glob.glob, logfiles):
+ map(summarise, files)
ok = count('ok')
failed = count('failed')
ignored = count('ignored')
# xfail-license
+# -*- coding: utf-8 -*-
+"""
+Script for extracting compilable fragments from markdown documentation. See
+prep.js for a description of the format recognized by this tool. Expects
+a directory fragments/ to exist under the current directory, and writes the
+fragments in there as individual .rs files.
+"""
+from __future__ import print_function
+from codecs import open
+from collections import deque
+from itertools import imap
+import os
+import re
+import sys
-# Script for extracting compilable fragments from markdown
-# documentation. See prep.js for a description of the format
-# recognized by this tool. Expects a directory fragments/ to exist
-# under the current directory, and writes the fragments in there as
-# individual .rs files.
-
-import sys, re
-
-if len(sys.argv) < 3:
- print("Please provide an input filename")
- sys.exit(1)
-
-filename = sys.argv[1]
-dest = sys.argv[2]
-f = open(filename)
-lines = f.readlines()
-f.close()
-
-cur = 0
-line = ""
-chapter = ""
-chapter_n = 0
-
-while cur < len(lines):
- line = lines[cur]
- cur += 1
- chap = re.match("# (.*)", line)
- if chap:
- chapter = re.sub(r"\W", "_", chap.group(1)).lower()
- chapter_n = 1
- elif re.match("~~~", line):
- # Parse the tags that open a code block in the pandoc format:
- # ~~~ {.tag1 .tag2}
- tags = re.findall("\.([\w-]*)", line)
- block = ""
- ignore = "notrust" in tags or "ignore" in tags
- # Some tags used by the language ref that indicate not rust
- ignore |= "ebnf" in tags
- ignore |= "abnf" in tags
- ignore |= "keyword" in tags
- ignore |= "field" in tags
- ignore |= "precedence" in tags
- xfail = "xfail-test" in tags
- while cur < len(lines):
- line = lines[cur]
- cur += 1
- if re.match("~~~", line):
- break
- else:
- # Lines beginning with '# ' are turned into valid code
- line = re.sub("^# ", "", line)
- # Allow ellipses in code snippets
- line = re.sub("\.\.\.", "", line)
- block += line
- if not ignore:
- if not re.search(r"\bfn main\b", block):
- block = "fn main() {\n" + block + "\n}\n"
- if not re.search(r"\bextern mod extra\b", block):
- block = "extern mod extra;\n" + block
- block = """#[ deny(warnings) ];
-#[ allow(unused_variable) ];\n
-#[ allow(dead_assignment) ];\n
-#[ allow(unused_mut) ];\n
-#[ allow(attribute_usage) ];\n
-#[ allow(dead_code) ];\n
-#[ feature(macro_rules, globs, struct_variant, managed_boxes) ];\n
-""" + block
- if xfail:
- block = "// xfail-test\n" + block
- filename = (dest + "/" + str(chapter)
- + "_" + str(chapter_n) + ".rs")
- chapter_n += 1
- f = open(filename, 'w')
- f.write(block)
- f.close()
+# regexes
+CHAPTER_NAME_REGEX = re.compile(r'# (.*)')
+CODE_BLOCK_DELIM_REGEX = re.compile(r'~~~')
+COMMENT_REGEX = re.compile(r'^# ')
+COMPILER_DIRECTIVE_REGEX = re.compile(r'\#\[(.*)\];')
+ELLIPSES_REGEX = re.compile(r'\.\.\.')
+EXTERN_MOD_REGEX = re.compile(r'\bextern mod extra\b')
+MAIN_FUNCTION_REGEX = re.compile(r'\bfn main\b')
+TAGS_REGEX = re.compile(r'\.([\w-]*)')
+
+# tags to ignore
+IGNORE_TAGS = \
+ frozenset(["abnf", "ebnf", "field", "keyword", "notrust", "precedence"])
+
+# header for code snippet files
+OUTPUT_BLOCK_HEADER = '\n'.join((
+ "#[ deny(warnings) ];",
+ "#[ allow(unused_variable) ];",
+ "#[ allow(dead_assignment) ];",
+ "#[ allow(unused_mut) ];",
+ "#[ allow(attribute_usage) ];",
+ "#[ allow(dead_code) ];",
+ "#[ feature(macro_rules, globs, struct_variant, managed_boxes) ];\n",))
+
+
+def add_extern_mod(block):
+ if not has_extern_mod(block):
+ # add `extern mod extra;` after compiler directives
+ directives = []
+ while len(block) and is_compiler_directive(block[0]):
+ directives.append(block.popleft())
+
+ block.appendleft("\nextern mod extra;\n\n")
+ block.extendleft(reversed(directives))
+
+ return block
+
+
+def add_main_function(block):
+ if not has_main_function(block):
+ prepend_spaces = lambda x: ' ' + x
+ block = deque(imap(prepend_spaces, block))
+ block.appendleft("\nfn main() {\n")
+ block.append("\n}\n")
+ return block
+
+
+def extract_code_fragments(dest_dir, lines):
+ """
+ Extracts all the code fragments from a file that do not have ignored tags
+ writing them to the following file:
+
+ [dest dir]/[chapter name]_[chapter_index].rs
+ """
+ chapter_name = None
+ chapter_index = 0
+
+ for line in lines:
+ if is_chapter_title(line):
+ chapter_name = get_chapter_name(line)
+ chapter_index = 1
+ continue
+
+ if not is_code_block_delim(line):
+ continue
+
+ assert chapter_name, "Chapter name missing for code block."
+ tags = get_tags(line)
+ block = get_code_block(lines)
+
+ if tags & IGNORE_TAGS:
+ continue
+
+ block = add_extern_mod(add_main_function(block))
+ block.appendleft(OUTPUT_BLOCK_HEADER)
+
+ if "ignore" in tags:
+ block.appendleft("//xfail-test\n")
+ elif "should_fail" in tags:
+ block.appendleft("//should-fail\n")
+
+ output_filename = os.path.join(
+ dest_dir,
+ chapter_name + '_' + str(chapter_index) + '.rs')
+
+ write_file(output_filename, block)
+ chapter_index += 1
+
+
+def has_extern_mod(block):
+ """Checks if a code block has the line `extern mod extra`."""
+ find_extern_mod = lambda x: re.search(EXTERN_MOD_REGEX, x)
+ return any(imap(find_extern_mod, block))
+
+
+def has_main_function(block):
+ """Checks if a code block has a main function."""
+ find_main_fn = lambda x: re.search(MAIN_FUNCTION_REGEX, x)
+ return any(imap(find_main_fn, block))
+
+
+def is_chapter_title(line):
+ return re.match(CHAPTER_NAME_REGEX, line)
+
+
+def is_code_block_delim(line):
+ return re.match(CODE_BLOCK_DELIM_REGEX, line)
+
+
+def is_compiler_directive(line):
+ return re.match(COMPILER_DIRECTIVE_REGEX, line)
+
+
+def get_chapter_name(line):
+ """Get the chapter name from a `# Containers` line."""
+ return re.sub(
+ r'\W',
+ '_',
+ re.match(CHAPTER_NAME_REGEX, line).group(1)).lower()
+
+
+def get_code_block(lines):
+ """
+ Get a code block surrounded by ~~~, for example:
+
+ 1: ~~~ { .tag }
+ 2: let u: ~[u32] = ~[0, 1, 2];
+ 3: let v: &[u32] = &[0, 1, 2, 3];
+ 4: let w: [u32, .. 5] = [0, 1, 2, 3, 4];
+ 5:
+ 6: println!("u: {}, v: {}, w: {}", u.len(), v.len(), w.len());
+ 7: ~~~
+
+ Returns lines 2-6. Assumes line 1 has been consumed by the caller.
+ """
+ strip_comments = lambda x: re.sub(COMMENT_REGEX, '', x)
+ strip_ellipses = lambda x: re.sub(ELLIPSES_REGEX, '', x)
+
+ result = deque()
+
+ for line in lines:
+ if is_code_block_delim(line):
+ break
+ result.append(strip_comments(strip_ellipses(line)))
+ return result
+
+
+def get_lines(filename):
+ with open(filename) as f:
+ for line in f:
+ yield line
+
+
+def get_tags(line):
+ """
+ Retrieves all tags from the line format:
+ ~~~ { .tag1 .tag2 .tag3 }
+ """
+ return set(re.findall(TAGS_REGEX, line))
+
+
+def write_file(filename, lines):
+ with open(filename, 'w', encoding='utf-8') as f:
+ for line in lines:
+ f.write(unicode(line, encoding='utf-8', errors='replace'))
+
+
+def main(argv=None):
+ if not argv:
+ argv = sys.argv
+
+ if len(sys.argv) < 2:
+ sys.stderr.write("Please provide an input filename.")
+ sys.exit(1)
+ elif len(sys.argv) < 3:
+ sys.stderr.write("Please provide a destination directory.")
+ sys.exit(1)
+
+ input_file = sys.argv[1]
+ dest_dir = sys.argv[2]
+
+ if not os.path.exists(input_file):
+ sys.stderr.write("Input file does not exist.")
+ sys.exit(1)
+
+ if not os.path.exists(dest_dir):
+ os.mkdir(dest_dir)
+
+ extract_code_fragments(dest_dir, get_lines(input_file))
+
+
+if __name__ == "__main__":
+ sys.exit(main())
<keyword>f64</keyword>
<keyword>char</keyword>
<keyword>str</keyword>
- <keyword>Either</keyword>
<keyword>Option</keyword>
<keyword>Result</keyword>
</context>
<keyword>false</keyword>
<keyword>Some</keyword>
<keyword>None</keyword>
- <keyword>Left</keyword>
- <keyword>Right</keyword>
<keyword>Ok</keyword>
<keyword>Err</keyword>
<keyword>Success</keyword>
--- /dev/null
+#!/usr/bin/env python
+# xfail-license
+# Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+"""
+This script creates a pile of compile-fail tests check that all the
+derivings have spans that point to the fields, rather than the
+#[deriving(...)] line.
+
+sample usage: src/etc/generate-deriving-span-tests.py
+"""
+
+import sys, os, datetime, stat
+
+TEST_DIR = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), '../test/compile-fail'))
+
+YEAR = datetime.datetime.now().year
+
+TEMPLATE = """// Copyright {year} The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+{error_deriving}
+struct Error;
+{code}
+fn main() {{}}
+"""
+
+ENUM_STRING = """
+#[deriving({traits})]
+enum Enum {{
+ A(
+ Error {errors}
+ )
+}}
+"""
+ENUM_STRUCT_VARIANT_STRING = """
+#[deriving({traits})]
+enum Enum {{
+ A {{
+ x: Error {errors}
+ }}
+}}
+"""
+STRUCT_STRING = """
+#[deriving({traits})]
+struct Struct {{
+ x: Error {errors}
+}}
+"""
+STRUCT_TUPLE_STRING = """
+#[deriving({traits})]
+struct Struct(
+ Error {errors}
+);
+"""
+
+ENUM_TUPLE, ENUM_STRUCT, STRUCT_FIELDS, STRUCT_TUPLE = range(4)
+
+def create_test_case(type, trait, super_traits, number_of_errors):
+ string = [ENUM_STRING, ENUM_STRUCT_VARIANT_STRING, STRUCT_STRING, STRUCT_TUPLE_STRING][type]
+ all_traits = ','.join([trait] + super_traits)
+ super_traits = ','.join(super_traits)
+ error_deriving = '#[deriving(%s)]' % super_traits if super_traits else ''
+
+ errors = '\n'.join('//~%s ERROR' % ('^' * n) for n in range(error_count))
+ code = string.format(traits = all_traits, errors = errors)
+ return TEMPLATE.format(year = YEAR, error_deriving=error_deriving, code = code)
+
+def write_file(name, string):
+ test_file = os.path.join(TEST_DIR, 'deriving-span-%s.rs' % name)
+
+ # set write permission if file exists, so it can be changed
+ if os.path.exists(test_file):
+ os.chmod(test_file, stat.S_IWUSR)
+
+ with open(test_file, 'wt') as f:
+ f.write(string)
+
+ # mark file read-only
+ os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
+
+
+
+ENUM = 1
+STRUCT = 2
+ALL = STRUCT | ENUM
+
+traits = {
+ 'Zero': (STRUCT, [], 1),
+ 'Default': (STRUCT, [], 1),
+ 'FromPrimitive': (0, [], 0), # only works for C-like enums
+
+ 'Decodable': (0, [], 0), # FIXME: quoting gives horrible spans
+ 'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans
+}
+
+for (trait, supers, errs) in [('Rand', [], 1),
+ ('Clone', [], 1), ('DeepClone', ['Clone'], 1),
+ ('Eq', [], 2), ('Ord', [], 8),
+ ('TotalEq', [], 1), ('TotalOrd', ['TotalEq'], 1)]:
+ traits[trait] = (ALL, supers, errs)
+
+for (trait, (types, super_traits, error_count)) in traits.items():
+ mk = lambda ty: create_test_case(ty, trait, super_traits, error_count)
+ if types & ENUM:
+ write_file(trait + '-enum', mk(ENUM_TUPLE))
+ write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT))
+ if types & STRUCT:
+ write_file(trait + '-struct', mk(STRUCT_FIELDS))
+ write_file(trait + '-tuple-struct', mk(STRUCT_TUPLE))
<item> float </item>
<item> char </item>
<item> str </item>
- <item> Either </item>
<item> Option </item>
<item> Result </item>
<item> Self </item>
<item> false </item>
<item> Some </item>
<item> None </item>
- <item> Left </item>
- <item> Right </item>
<item> Ok </item>
<item> Err </item>
<item> Success </item>
openhook=fileinput.hook_encoded("utf-8")):
if fileinput.filename().find("tidy.py") == -1:
- if line.find("FIXME") != -1:
- if re.search("FIXME.*#\d+", line) == None:
- report_err("FIXME without issue number")
+ if line.find("// XXX") != -1:
+ report_err("XXX is no longer necessary, use FIXME")
if line.find("TODO") != -1:
report_err("TODO is deprecated; use FIXME")
match = re.match(r'^.*//\s*(NOTE.*)$', line)
" to make it easy to update.
" Core operators {{{3
-syn keyword rustEnum Either
-syn keyword rustEnumVariant Left Right
syn keyword rustTrait Sized
syn keyword rustTrait Freeze Send
syn keyword rustTrait Add Sub Mul Div Rem Neg Not
syn keyword rustTrait FromIterator Extendable
syn keyword rustTrait Iterator DoubleEndedIterator RandomAccessIterator CloneableIterator
syn keyword rustTrait OrdIterator MutableDoubleEndedIterator ExactSize
-syn keyword rustTrait Times
syn keyword rustTrait Algebraic Trigonometric Exponential Hyperbolic
syn keyword rustTrait Bitwise Bounded Integer Fractional Real RealExt
syn keyword rustTrait Str StrVector StrSlice OwnedStr
syn keyword rustTrait IterBytes
syn keyword rustTrait ToStr IntoStr
-syn keyword rustTrait CopyableTuple ImmutableTuple
+syn keyword rustTrait CloneableTuple ImmutableTuple
syn keyword rustTrait Tuple1 Tuple2 Tuple3 Tuple4
syn keyword rustTrait Tuple5 Tuple6 Tuple7 Tuple8
syn keyword rustTrait Tuple9 Tuple10 Tuple11 Tuple12
syn keyword rustTrait ImmutableTuple1 ImmutableTuple2 ImmutableTuple3 ImmutableTuple4
syn keyword rustTrait ImmutableTuple5 ImmutableTuple6 ImmutableTuple7 ImmutableTuple8
syn keyword rustTrait ImmutableTuple9 ImmutableTuple10 ImmutableTuple11 ImmutableTuple12
-syn keyword rustTrait ImmutableEqVector ImmutableTotalOrdVector ImmutableCopyableVector
-syn keyword rustTrait OwnedVector OwnedCopyableVector OwnedEqVector MutableVector
-syn keyword rustTrait Vector VectorVector CopyableVector ImmutableVector
+syn keyword rustTrait ImmutableEqVector ImmutableTotalOrdVector ImmutableCloneableVector
+syn keyword rustTrait OwnedVector OwnedCloneableVector OwnedEqVector MutableVector
+syn keyword rustTrait Vector VectorVector CloneableVector ImmutableVector
"syn keyword rustFunction stream
syn keyword rustTrait Port Chan GenericChan GenericSmartChan GenericPort Peekable
syn keyword rustBoolean true false
syn keyword rustConstant Some None " option
-syn keyword rustConstant Left Right " either
syn keyword rustConstant Ok Err " result
syn keyword rustConstant Less Equal Greater " Ordering
--- /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.
+//
+//! The arena, a fast but limited type of allocator.
+//!
+//! Arenas are a type of allocator that destroy the objects within, all at
+//! once, once the arena itself is destroyed. They do not support deallocation
+//! of individual objects while the arena itself is still alive. The benefit
+//! of an arena is very fast allocation; just a pointer bump.
+
+#[crate_id = "arena#0.10-pre"];
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
+#[license = "MIT/ASL2"];
+#[allow(missing_doc)];
+#[feature(managed_boxes)];
+
+extern mod extra;
+
+use extra::list::{List, Cons, Nil};
+use extra::list;
+
+use std::at_vec;
+use std::cast::{transmute, transmute_mut, transmute_mut_region};
+use std::cast;
+use std::cell::{Cell, RefCell};
+use std::num;
+use std::ptr;
+use std::mem;
+use std::rt::global_heap;
+use std::uint;
+use std::unstable::intrinsics::{TyDesc, get_tydesc};
+use std::unstable::intrinsics;
+use std::util;
+
+// The way arena uses arrays is really deeply awful. The arrays are
+// allocated, and have capacities reserved, but the fill for the array
+// will always stay at 0.
+#[deriving(Clone)]
+struct Chunk {
+ data: RefCell<@[u8]>,
+ fill: Cell<uint>,
+ is_pod: Cell<bool>,
+}
+
+// Arenas are used to quickly allocate objects that share a
+// lifetime. The arena uses ~[u8] vectors as a backing store to
+// allocate objects from. For each allocated object, the arena stores
+// a pointer to the type descriptor followed by the
+// object. (Potentially with alignment padding after each of them.)
+// When the arena is destroyed, it iterates through all of its chunks,
+// and uses the tydesc information to trace through the objects,
+// calling the destructors on them.
+// One subtle point that needs to be addressed is how to handle
+// failures while running the user provided initializer function. It
+// is important to not run the destructor on uninitialized objects, but
+// how to detect them is somewhat subtle. Since alloc() can be invoked
+// recursively, it is not sufficient to simply exclude the most recent
+// object. To solve this without requiring extra space, we use the low
+// order bit of the tydesc pointer to encode whether the object it
+// describes has been fully initialized.
+
+// As an optimization, objects with destructors are stored in
+// different chunks than objects without destructors. This reduces
+// overhead when initializing plain-old-data and means we don't need
+// to waste time running the destructors of POD.
+#[no_freeze]
+pub struct Arena {
+ // The head is separated out from the list as a unbenchmarked
+ // microoptimization, to avoid needing to case on the list to
+ // access the head.
+ priv head: Chunk,
+ priv pod_head: Chunk,
+ priv chunks: RefCell<@List<Chunk>>,
+}
+
+impl Arena {
+ pub fn new() -> Arena {
+ Arena::new_with_size(32u)
+ }
+
+ pub fn new_with_size(initial_size: uint) -> Arena {
+ Arena {
+ head: chunk(initial_size, false),
+ pod_head: chunk(initial_size, true),
+ chunks: RefCell::new(@Nil),
+ }
+ }
+}
+
+fn chunk(size: uint, is_pod: bool) -> Chunk {
+ let mut v: @[u8] = @[];
+ unsafe { at_vec::raw::reserve(&mut v, size); }
+ Chunk {
+ data: RefCell::new(unsafe { cast::transmute(v) }),
+ fill: Cell::new(0u),
+ is_pod: Cell::new(is_pod),
+ }
+}
+
+#[unsafe_destructor]
+impl Drop for Arena {
+ fn drop(&mut self) {
+ unsafe {
+ destroy_chunk(&self.head);
+
+ list::each(self.chunks.get(), |chunk| {
+ if !chunk.is_pod.get() {
+ destroy_chunk(chunk);
+ }
+ true
+ });
+ }
+ }
+}
+
+#[inline]
+fn round_up(base: uint, align: uint) -> uint {
+ (base.checked_add(&(align - 1))).unwrap() & !(&(align - 1))
+}
+
+// Walk down a chunk, running the destructors for any objects stored
+// in it.
+unsafe fn destroy_chunk(chunk: &Chunk) {
+ let mut idx = 0;
+ let buf = {
+ let data = chunk.data.borrow();
+ data.get().as_ptr()
+ };
+ let fill = chunk.fill.get();
+
+ while idx < fill {
+ let tydesc_data: *uint = transmute(ptr::offset(buf, idx as int));
+ let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
+ let (size, align) = ((*tydesc).size, (*tydesc).align);
+
+ let after_tydesc = idx + mem::size_of::<*TyDesc>();
+
+ let start = round_up(after_tydesc, align);
+
+ //debug!("freeing object: idx = {}, size = {}, align = {}, done = {}",
+ // start, size, align, is_done);
+ if is_done {
+ ((*tydesc).drop_glue)(ptr::offset(buf, start as int) as *i8);
+ }
+
+ // Find where the next tydesc lives
+ idx = round_up(start + size, mem::pref_align_of::<*TyDesc>());
+ }
+}
+
+// We encode whether the object a tydesc describes has been
+// initialized in the arena in the low bit of the tydesc pointer. This
+// is necessary in order to properly do cleanup if a failure occurs
+// during an initializer.
+#[inline]
+unsafe fn bitpack_tydesc_ptr(p: *TyDesc, is_done: bool) -> uint {
+ let p_bits: uint = transmute(p);
+ p_bits | (is_done as uint)
+}
+#[inline]
+unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TyDesc, bool) {
+ (transmute(p & !1), p & 1 == 1)
+}
+
+impl Arena {
+ // Functions for the POD part of the arena
+ fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 {
+ // Allocate a new chunk.
+ let chunk_size = at_vec::capacity(self.pod_head.data.get());
+ let new_min_chunk_size = num::max(n_bytes, chunk_size);
+ self.chunks.set(@Cons(self.pod_head.clone(), self.chunks.get()));
+ self.pod_head =
+ chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);
+
+ return self.alloc_pod_inner(n_bytes, align);
+ }
+
+ #[inline]
+ fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 {
+ unsafe {
+ let this = transmute_mut_region(self);
+ let start = round_up(this.pod_head.fill.get(), align);
+ let end = start + n_bytes;
+ if end > at_vec::capacity(this.pod_head.data.get()) {
+ return this.alloc_pod_grow(n_bytes, align);
+ }
+ this.pod_head.fill.set(end);
+
+ //debug!("idx = {}, size = {}, align = {}, fill = {}",
+ // start, n_bytes, align, head.fill.get());
+
+ ptr::offset(this.pod_head.data.get().as_ptr(), start as int)
+ }
+ }
+
+ #[inline]
+ fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
+ unsafe {
+ let tydesc = get_tydesc::<T>();
+ let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
+ let ptr: *mut T = transmute(ptr);
+ intrinsics::move_val_init(&mut (*ptr), op());
+ return transmute(ptr);
+ }
+ }
+
+ // Functions for the non-POD part of the arena
+ fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint)
+ -> (*u8, *u8) {
+ // Allocate a new chunk.
+ let chunk_size = at_vec::capacity(self.head.data.get());
+ let new_min_chunk_size = num::max(n_bytes, chunk_size);
+ self.chunks.set(@Cons(self.head.clone(), self.chunks.get()));
+ self.head =
+ chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);
+
+ return self.alloc_nonpod_inner(n_bytes, align);
+ }
+
+ #[inline]
+ fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint)
+ -> (*u8, *u8) {
+ unsafe {
+ let start;
+ let end;
+ let tydesc_start;
+ let after_tydesc;
+
+ {
+ let head = transmute_mut_region(&mut self.head);
+
+ tydesc_start = head.fill.get();
+ after_tydesc = head.fill.get() + mem::size_of::<*TyDesc>();
+ start = round_up(after_tydesc, align);
+ end = start + n_bytes;
+ }
+
+ if end > at_vec::capacity(self.head.data.get()) {
+ return self.alloc_nonpod_grow(n_bytes, align);
+ }
+
+ let head = transmute_mut_region(&mut self.head);
+ head.fill.set(round_up(end, mem::pref_align_of::<*TyDesc>()));
+
+ //debug!("idx = {}, size = {}, align = {}, fill = {}",
+ // start, n_bytes, align, head.fill);
+
+ let buf = self.head.data.get().as_ptr();
+ return (ptr::offset(buf, tydesc_start as int), ptr::offset(buf, start as int));
+ }
+ }
+
+ #[inline]
+ fn alloc_nonpod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
+ unsafe {
+ let tydesc = get_tydesc::<T>();
+ let (ty_ptr, ptr) =
+ self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
+ let ty_ptr: *mut uint = transmute(ty_ptr);
+ let ptr: *mut T = transmute(ptr);
+ // Write in our tydesc along with a bit indicating that it
+ // has *not* been initialized yet.
+ *ty_ptr = transmute(tydesc);
+ // Actually initialize it
+ intrinsics::move_val_init(&mut(*ptr), op());
+ // Now that we are done, update the tydesc to indicate that
+ // the object is there.
+ *ty_ptr = bitpack_tydesc_ptr(tydesc, true);
+
+ return transmute(ptr);
+ }
+ }
+
+ // The external interface
+ #[inline]
+ pub fn alloc<'a, T>(&'a self, op: || -> T) -> &'a T {
+ unsafe {
+ // FIXME: Borrow check
+ let this = transmute_mut(self);
+ if intrinsics::needs_drop::<T>() {
+ this.alloc_nonpod(op)
+ } else {
+ this.alloc_pod(op)
+ }
+ }
+ }
+}
+
+#[test]
+fn test_arena_destructors() {
+ let arena = Arena::new();
+ for i in range(0u, 10) {
+ // Arena allocate something with drop glue to make sure it
+ // doesn't leak.
+ arena.alloc(|| @i);
+ // Allocate something with funny size and alignment, to keep
+ // things interesting.
+ arena.alloc(|| [0u8, 1u8, 2u8]);
+ }
+}
+
+#[test]
+#[should_fail]
+fn test_arena_destructors_fail() {
+ let arena = Arena::new();
+ // Put some stuff in the arena.
+ for i in range(0u, 10) {
+ // Arena allocate something with drop glue to make sure it
+ // doesn't leak.
+ arena.alloc(|| { @i });
+ // Allocate something with funny size and alignment, to keep
+ // things interesting.
+ arena.alloc(|| { [0u8, 1u8, 2u8] });
+ }
+ // Now, fail while allocating
+ arena.alloc::<@int>(|| {
+ // Now fail.
+ fail!();
+ });
+}
+
+/// An arena that can hold objects of only one type.
+///
+/// Safety note: Modifying objects in the arena that have already had their
+/// `drop` destructors run can cause leaks, because the destructor will not
+/// run again for these objects.
+pub struct TypedArena<T> {
+ /// A pointer to the next object to be allocated.
+ priv ptr: *T,
+
+ /// A pointer to the end of the allocated area. When this pointer is
+ /// reached, a new chunk is allocated.
+ priv end: *T,
+
+ /// The type descriptor of the objects in the arena. This should not be
+ /// necessary, but is until generic destructors are supported.
+ priv tydesc: *TyDesc,
+
+ /// A pointer to the first arena segment.
+ priv first: Option<~TypedArenaChunk>,
+}
+
+struct TypedArenaChunk {
+ /// Pointer to the next arena segment.
+ next: Option<~TypedArenaChunk>,
+
+ /// The number of elements that this chunk can hold.
+ capacity: uint,
+
+ // Objects follow here, suitably aligned.
+}
+
+impl TypedArenaChunk {
+ #[inline]
+ fn new<T>(next: Option<~TypedArenaChunk>, capacity: uint)
+ -> ~TypedArenaChunk {
+ let mut size = mem::size_of::<TypedArenaChunk>();
+ size = round_up(size, mem::min_align_of::<T>());
+ let elem_size = mem::size_of::<T>();
+ let elems_size = elem_size.checked_mul(&capacity).unwrap();
+ size = size.checked_add(&elems_size).unwrap();
+
+ let mut chunk = unsafe {
+ let chunk = global_heap::exchange_malloc(size);
+ let mut chunk: ~TypedArenaChunk = cast::transmute(chunk);
+ intrinsics::move_val_init(&mut chunk.next, next);
+ chunk
+ };
+
+ chunk.capacity = capacity;
+ chunk
+ }
+
+ /// Destroys this arena chunk. If the type descriptor is supplied, the
+ /// drop glue is called; otherwise, drop glue is not called.
+ #[inline]
+ unsafe fn destroy(&mut self, len: uint, opt_tydesc: Option<*TyDesc>) {
+ // Destroy all the allocated objects.
+ match opt_tydesc {
+ None => {}
+ Some(tydesc) => {
+ let mut start = self.start(tydesc);
+ for _ in range(0, len) {
+ ((*tydesc).drop_glue)(start as *i8);
+ start = start.offset((*tydesc).size as int)
+ }
+ }
+ }
+
+ // Destroy the next chunk.
+ let next_opt = util::replace(&mut self.next, None);
+ match next_opt {
+ None => {}
+ Some(mut next) => {
+ // We assume that the next chunk is completely filled.
+ next.destroy(next.capacity, opt_tydesc)
+ }
+ }
+ }
+
+ // Returns a pointer to the first allocated object.
+ #[inline]
+ fn start(&self, tydesc: *TyDesc) -> *u8 {
+ let this: *TypedArenaChunk = self;
+ unsafe {
+ cast::transmute(round_up(this.offset(1) as uint, (*tydesc).align))
+ }
+ }
+
+ // Returns a pointer to the end of the allocated space.
+ #[inline]
+ fn end(&self, tydesc: *TyDesc) -> *u8 {
+ unsafe {
+ let size = (*tydesc).size.checked_mul(&self.capacity).unwrap();
+ self.start(tydesc).offset(size as int)
+ }
+ }
+}
+
+impl<T> TypedArena<T> {
+ /// Creates a new arena with preallocated space for 8 objects.
+ #[inline]
+ pub fn new() -> TypedArena<T> {
+ TypedArena::with_capacity(8)
+ }
+
+ /// Creates a new arena with preallocated space for the given number of
+ /// objects.
+ #[inline]
+ pub fn with_capacity(capacity: uint) -> TypedArena<T> {
+ let chunk = TypedArenaChunk::new::<T>(None, capacity);
+ let tydesc = unsafe {
+ intrinsics::get_tydesc::<T>()
+ };
+ TypedArena {
+ ptr: chunk.start(tydesc) as *T,
+ end: chunk.end(tydesc) as *T,
+ tydesc: tydesc,
+ first: Some(chunk),
+ }
+ }
+
+ /// Allocates an object into this arena.
+ #[inline]
+ pub fn alloc<'a>(&'a self, object: T) -> &'a T {
+ unsafe {
+ let this = cast::transmute_mut(self);
+ if this.ptr == this.end {
+ this.grow()
+ }
+
+ let ptr: &'a mut T = cast::transmute(this.ptr);
+ intrinsics::move_val_init(ptr, object);
+ this.ptr = this.ptr.offset(1);
+ let ptr: &'a T = ptr;
+ ptr
+ }
+ }
+
+ /// Grows the arena.
+ #[inline(never)]
+ fn grow(&mut self) {
+ let chunk = self.first.take_unwrap();
+ let new_capacity = chunk.capacity.checked_mul(&2).unwrap();
+ let chunk = TypedArenaChunk::new::<T>(Some(chunk), new_capacity);
+ self.ptr = chunk.start(self.tydesc) as *T;
+ self.end = chunk.end(self.tydesc) as *T;
+ self.first = Some(chunk)
+ }
+}
+
+#[unsafe_destructor]
+impl<T> Drop for TypedArena<T> {
+ fn drop(&mut self) {
+ // Determine how much was filled.
+ let start = self.first.get_ref().start(self.tydesc) as uint;
+ let end = self.ptr as uint;
+ let diff = (end - start) / mem::size_of::<T>();
+
+ // Pass that to the `destroy` method.
+ unsafe {
+ let opt_tydesc = if intrinsics::needs_drop::<T>() {
+ Some(self.tydesc)
+ } else {
+ None
+ };
+ self.first.get_mut_ref().destroy(diff, opt_tydesc)
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::{Arena, TypedArena};
+ use extra::test::BenchHarness;
+
+ struct Point {
+ x: int,
+ y: int,
+ z: int,
+ }
+
+ #[test]
+ pub fn test_pod() {
+ let arena = TypedArena::new();
+ for _ in range(0, 100000) {
+ arena.alloc(Point {
+ x: 1,
+ y: 2,
+ z: 3,
+ });
+ }
+ }
+
+ #[bench]
+ pub fn bench_pod(bh: &mut BenchHarness) {
+ let arena = TypedArena::new();
+ bh.iter(|| {
+ arena.alloc(Point {
+ x: 1,
+ y: 2,
+ z: 3,
+ });
+ })
+ }
+
+ #[bench]
+ pub fn bench_pod_nonarena(bh: &mut BenchHarness) {
+ bh.iter(|| {
+ let _ = ~Point {
+ x: 1,
+ y: 2,
+ z: 3,
+ };
+ })
+ }
+
+ #[bench]
+ pub fn bench_pod_old_arena(bh: &mut BenchHarness) {
+ let arena = Arena::new();
+ bh.iter(|| {
+ arena.alloc(|| {
+ Point {
+ x: 1,
+ y: 2,
+ z: 3,
+ }
+ });
+ })
+ }
+
+ struct Nonpod {
+ string: ~str,
+ array: ~[int],
+ }
+
+ #[test]
+ pub fn test_nonpod() {
+ let arena = TypedArena::new();
+ for _ in range(0, 100000) {
+ arena.alloc(Nonpod {
+ string: ~"hello world",
+ array: ~[ 1, 2, 3, 4, 5 ],
+ });
+ }
+ }
+
+ #[bench]
+ pub fn bench_nonpod(bh: &mut BenchHarness) {
+ let arena = TypedArena::new();
+ bh.iter(|| {
+ arena.alloc(Nonpod {
+ string: ~"hello world",
+ array: ~[ 1, 2, 3, 4, 5 ],
+ });
+ })
+ }
+
+ #[bench]
+ pub fn bench_nonpod_nonarena(bh: &mut BenchHarness) {
+ bh.iter(|| {
+ let _ = ~Nonpod {
+ string: ~"hello world",
+ array: ~[ 1, 2, 3, 4, 5 ],
+ };
+ })
+ }
+
+ #[bench]
+ pub fn bench_nonpod_old_arena(bh: &mut BenchHarness) {
+ let arena = Arena::new();
+ bh.iter(|| {
+ let _ = arena.alloc(|| Nonpod {
+ string: ~"hello world",
+ array: ~[ 1, 2, 3, 4, 5 ],
+ });
+ })
+ }
+}
+
+
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
* let (port, chan) = Chan::new();
* chan.send(shared_numbers.clone());
*
- * do spawn {
+ * spawn(proc() {
* let shared_numbers = port.recv();
* let local_numbers = shared_numbers.get();
*
* // Work with the local numbers
- * }
+ * });
* }
* ```
*/
use std::cast;
use std::sync::arc::UnsafeArc;
use std::task;
-use std::borrow;
/// As sync::condvar, a mechanism for unlock-and-descheduling and signaling.
pub struct Condvar<'a> {
****************************************************************************/
#[doc(hidden)]
-struct MutexArcInner<T> { priv lock: Mutex, priv failed: bool, priv data: T }
+struct MutexArcInner<T> { lock: Mutex, failed: bool, data: T }
/// An Arc with mutable data protected by a blocking mutex.
#[no_freeze]
****************************************************************************/
#[doc(hidden)]
-struct RWArcInner<T> { priv lock: RWLock, priv failed: bool, priv data: T }
+struct RWArcInner<T> { lock: RWLock, failed: bool, 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.
// of this cast is removing the mutability.)
let new_data = data;
// Downgrade ensured the token belonged to us. Just a sanity check.
- assert!(borrow::ref_eq(&(*state).data, new_data));
+ assert!((&(*state).data as *T as uint) == (new_data as *mut T as uint));
// Produce new token
RWReadMode {
data: new_data,
let (p, c) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
let arc_v: Arc<~[int]> = p.recv();
let v = arc_v.get().clone();
assert_eq!(v[3], 4);
- };
+ });
c.send(arc_v.clone());
let arc = ~MutexArc::new(false);
let arc2 = ~arc.clone();
let (p,c) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
// wait until parent gets in
p.recv();
arc2.access_cond(|state, cond| {
*state = true;
cond.signal();
})
- }
+ });
arc.access_cond(|state, cond| {
c.send(());
let arc2 = ~arc.clone();
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
let _ = p.recv();
arc2.access_cond(|one, cond| {
cond.signal();
// Parent should fail when it wakes up.
assert_eq!(*one, 0);
})
- }
+ });
arc.access_cond(|one, cond| {
c.send(());
fn test_mutex_arc_poison() {
let arc = ~MutexArc::new(1);
let arc2 = ~arc.clone();
- do task::try || {
+ task::try(proc() {
arc2.access(|one| {
assert_eq!(*one, 2);
})
- };
+ });
arc.access(|one| {
assert_eq!(*one, 1);
})
// to underlaying data.
let arc = ~MutexArc::new(1);
let arc2 = ~MutexArc::new(*arc);
- do task::spawn || {
+ task::spawn(proc() {
(*arc2).unsafe_access(|mutex| {
(*mutex).access(|one| {
assert!(*one == 1);
})
})
- };
+ });
}
}
fn test_rw_arc_poison_wr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.write(|one| {
assert_eq!(*one, 2);
})
- };
+ });
arc.read(|one| {
assert_eq!(*one, 1);
})
fn test_rw_arc_poison_ww() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.write(|one| {
assert_eq!(*one, 2);
})
- };
+ });
arc.write(|one| {
assert_eq!(*one, 1);
})
fn test_rw_arc_poison_dw() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.write_downgrade(|mut write_mode| {
write_mode.write(|one| {
assert_eq!(*one, 2);
})
})
- };
+ });
arc.write(|one| {
assert_eq!(*one, 1);
})
fn test_rw_arc_no_poison_rr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.read(|one| {
assert_eq!(*one, 2);
})
- };
+ });
arc.read(|one| {
assert_eq!(*one, 1);
})
fn test_rw_arc_no_poison_rw() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.read(|one| {
assert_eq!(*one, 2);
})
- };
+ });
arc.write(|one| {
assert_eq!(*one, 1);
})
fn test_rw_arc_no_poison_dr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
- do task::try {
+ task::try(proc() {
arc2.write_downgrade(|write_mode| {
let read_mode = arc2.downgrade(write_mode);
read_mode.read(|one| {
assert_eq!(*one, 2);
})
})
- };
+ });
arc.write(|one| {
assert_eq!(*one, 1);
})
let arc2 = arc.clone();
let (p, c) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
arc2.write(|num| {
- 10.times(|| {
+ for _ in range(0, 10) {
let tmp = *num;
*num = -1;
task::deschedule();
*num = tmp + 1;
- });
+ }
c.send(());
})
- }
+ });
// Readers try to catch the writer in the act
let mut children = ~[];
- 5.times(|| {
+ for _ in range(0, 5) {
let arc3 = arc.clone();
let mut builder = task::task();
children.push(builder.future_result());
- do builder.spawn {
+ builder.spawn(proc() {
arc3.read(|num| {
assert!(*num >= 0);
})
- }
- });
+ });
+ }
// Wait for children to pass their asserts
for r in children.mut_iter() {
// Reader tasks
let mut reader_convos = ~[];
- 10.times(|| {
+ for _ in range(0, 10) {
let ((rp1, rc1), (rp2, rc2)) = (Chan::new(), Chan::new());
reader_convos.push((rc1, rp2));
let arcn = arc.clone();
- do task::spawn {
+ task::spawn(proc() {
rp1.recv(); // wait for downgrader to give go-ahead
arcn.read(|state| {
assert_eq!(*state, 31337);
rc2.send(());
})
- }
- });
+ });
+ }
// Writer task
let arc2 = arc.clone();
let ((wp1, wc1), (wp2, wc2)) = (Chan::new(), Chan::new());
- do task::spawn || {
+ task::spawn(proc() {
wp1.recv();
arc2.write_cond(|state, cond| {
assert_eq!(*state, 0);
*state = 42;
});
wc2.send(());
- }
+ });
// Downgrader (us)
arc.write_downgrade(|mut write_mode| {
// writer task
let xw = x.clone();
- do task::spawn {
+ task::spawn(proc() {
xw.write_cond(|state, c| {
wc.send(()); // tell downgrader it's ok to go
c.wait();
// trying to receive the "reader cloud lock hand-off".
*state = false;
})
- }
+ });
wp.recv(); // wait for writer to get in
// make a reader task to trigger the "reader cloud lock" handoff
let xr = x.clone();
let (rp, rc) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
rc.send(());
xr.read(|_state| { })
- }
+ });
rp.recv(); // wait for reader task to exist
let read_mode = x.downgrade(write_mode);
read_mode.read(|state| {
// if writer mistakenly got in, make sure it mutates state
// before we assert on it
- 5.times(|| task::deschedule());
+ for _ in range(0, 5) { task::deschedule(); }
// make sure writer didn't get in.
assert!(*state);
})
// helped to expose the race nearly 100% of the time... but adding
// deschedules in the intuitively-right locations made it even less likely,
// and I wasn't sure why :( . This is a mediocre "next best" option.
- 8.times(|| test_rw_write_cond_downgrade_read_race_helper());
+ for _ in range(0, 8) { test_rw_write_cond_downgrade_read_race_helper(); }
}
}
+++ /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.
-//
-//! The arena, a fast but limited type of allocator.
-//!
-//! Arenas are a type of allocator that destroy the objects within, all at
-//! once, once the arena itself is destroyed. They do not support deallocation
-//! of individual objects while the arena itself is still alive. The benefit
-//! of an arena is very fast allocation; just a pointer bump.
-
-#[allow(missing_doc)];
-
-use list::{List, Cons, Nil};
-use list;
-
-use std::at_vec;
-use std::cast::{transmute, transmute_mut, transmute_mut_region};
-use std::cast;
-use std::cell::{Cell, RefCell};
-use std::num;
-use std::ptr;
-use std::mem;
-use std::rt::global_heap;
-use std::uint;
-use std::unstable::intrinsics::{TyDesc, get_tydesc};
-use std::unstable::intrinsics;
-use std::util;
-
-// The way arena uses arrays is really deeply awful. The arrays are
-// allocated, and have capacities reserved, but the fill for the array
-// will always stay at 0.
-#[deriving(Clone)]
-struct Chunk {
- data: RefCell<@[u8]>,
- fill: Cell<uint>,
- is_pod: Cell<bool>,
-}
-
-// Arenas are used to quickly allocate objects that share a
-// lifetime. The arena uses ~[u8] vectors as a backing store to
-// allocate objects from. For each allocated object, the arena stores
-// a pointer to the type descriptor followed by the
-// object. (Potentially with alignment padding after each of them.)
-// When the arena is destroyed, it iterates through all of its chunks,
-// and uses the tydesc information to trace through the objects,
-// calling the destructors on them.
-// One subtle point that needs to be addressed is how to handle
-// failures while running the user provided initializer function. It
-// is important to not run the destructor on uninitialized objects, but
-// how to detect them is somewhat subtle. Since alloc() can be invoked
-// recursively, it is not sufficient to simply exclude the most recent
-// object. To solve this without requiring extra space, we use the low
-// order bit of the tydesc pointer to encode whether the object it
-// describes has been fully initialized.
-
-// As an optimization, objects with destructors are stored in
-// different chunks than objects without destructors. This reduces
-// overhead when initializing plain-old-data and means we don't need
-// to waste time running the destructors of POD.
-#[no_freeze]
-pub struct Arena {
- // The head is separated out from the list as a unbenchmarked
- // microoptimization, to avoid needing to case on the list to
- // access the head.
- priv head: Chunk,
- priv pod_head: Chunk,
- priv chunks: RefCell<@List<Chunk>>,
-}
-
-impl Arena {
- pub fn new() -> Arena {
- Arena::new_with_size(32u)
- }
-
- pub fn new_with_size(initial_size: uint) -> Arena {
- Arena {
- head: chunk(initial_size, false),
- pod_head: chunk(initial_size, true),
- chunks: RefCell::new(@Nil),
- }
- }
-}
-
-fn chunk(size: uint, is_pod: bool) -> Chunk {
- let mut v: @[u8] = @[];
- unsafe { at_vec::raw::reserve(&mut v, size); }
- Chunk {
- data: RefCell::new(unsafe { cast::transmute(v) }),
- fill: Cell::new(0u),
- is_pod: Cell::new(is_pod),
- }
-}
-
-#[unsafe_destructor]
-impl Drop for Arena {
- fn drop(&mut self) {
- unsafe {
- destroy_chunk(&self.head);
-
- list::each(self.chunks.get(), |chunk| {
- if !chunk.is_pod.get() {
- destroy_chunk(chunk);
- }
- true
- });
- }
- }
-}
-
-#[inline]
-fn round_up(base: uint, align: uint) -> uint {
- (base.checked_add(&(align - 1))).unwrap() & !(&(align - 1))
-}
-
-// Walk down a chunk, running the destructors for any objects stored
-// in it.
-unsafe fn destroy_chunk(chunk: &Chunk) {
- let mut idx = 0;
- let buf = {
- let data = chunk.data.borrow();
- data.get().as_ptr()
- };
- let fill = chunk.fill.get();
-
- while idx < fill {
- let tydesc_data: *uint = transmute(ptr::offset(buf, idx as int));
- let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
- let (size, align) = ((*tydesc).size, (*tydesc).align);
-
- let after_tydesc = idx + mem::size_of::<*TyDesc>();
-
- let start = round_up(after_tydesc, align);
-
- //debug!("freeing object: idx = {}, size = {}, align = {}, done = {}",
- // start, size, align, is_done);
- if is_done {
- ((*tydesc).drop_glue)(ptr::offset(buf, start as int) as *i8);
- }
-
- // Find where the next tydesc lives
- idx = round_up(start + size, mem::pref_align_of::<*TyDesc>());
- }
-}
-
-// We encode whether the object a tydesc describes has been
-// initialized in the arena in the low bit of the tydesc pointer. This
-// is necessary in order to properly do cleanup if a failure occurs
-// during an initializer.
-#[inline]
-unsafe fn bitpack_tydesc_ptr(p: *TyDesc, is_done: bool) -> uint {
- let p_bits: uint = transmute(p);
- p_bits | (is_done as uint)
-}
-#[inline]
-unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TyDesc, bool) {
- (transmute(p & !1), p & 1 == 1)
-}
-
-impl Arena {
- // Functions for the POD part of the arena
- fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 {
- // Allocate a new chunk.
- let chunk_size = at_vec::capacity(self.pod_head.data.get());
- let new_min_chunk_size = num::max(n_bytes, chunk_size);
- self.chunks.set(@Cons(self.pod_head.clone(), self.chunks.get()));
- self.pod_head =
- chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);
-
- return self.alloc_pod_inner(n_bytes, align);
- }
-
- #[inline]
- fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 {
- unsafe {
- let this = transmute_mut_region(self);
- let start = round_up(this.pod_head.fill.get(), align);
- let end = start + n_bytes;
- if end > at_vec::capacity(this.pod_head.data.get()) {
- return this.alloc_pod_grow(n_bytes, align);
- }
- this.pod_head.fill.set(end);
-
- //debug!("idx = {}, size = {}, align = {}, fill = {}",
- // start, n_bytes, align, head.fill.get());
-
- ptr::offset(this.pod_head.data.get().as_ptr(), start as int)
- }
- }
-
- #[inline]
- fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
- unsafe {
- let tydesc = get_tydesc::<T>();
- let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
- let ptr: *mut T = transmute(ptr);
- intrinsics::move_val_init(&mut (*ptr), op());
- return transmute(ptr);
- }
- }
-
- // Functions for the non-POD part of the arena
- fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint)
- -> (*u8, *u8) {
- // Allocate a new chunk.
- let chunk_size = at_vec::capacity(self.head.data.get());
- let new_min_chunk_size = num::max(n_bytes, chunk_size);
- self.chunks.set(@Cons(self.head.clone(), self.chunks.get()));
- self.head =
- chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);
-
- return self.alloc_nonpod_inner(n_bytes, align);
- }
-
- #[inline]
- fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint)
- -> (*u8, *u8) {
- unsafe {
- let start;
- let end;
- let tydesc_start;
- let after_tydesc;
-
- {
- let head = transmute_mut_region(&mut self.head);
-
- tydesc_start = head.fill.get();
- after_tydesc = head.fill.get() + mem::size_of::<*TyDesc>();
- start = round_up(after_tydesc, align);
- end = start + n_bytes;
- }
-
- if end > at_vec::capacity(self.head.data.get()) {
- return self.alloc_nonpod_grow(n_bytes, align);
- }
-
- let head = transmute_mut_region(&mut self.head);
- head.fill.set(round_up(end, mem::pref_align_of::<*TyDesc>()));
-
- //debug!("idx = {}, size = {}, align = {}, fill = {}",
- // start, n_bytes, align, head.fill);
-
- let buf = self.head.data.get().as_ptr();
- return (ptr::offset(buf, tydesc_start as int), ptr::offset(buf, start as int));
- }
- }
-
- #[inline]
- fn alloc_nonpod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
- unsafe {
- let tydesc = get_tydesc::<T>();
- let (ty_ptr, ptr) =
- self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
- let ty_ptr: *mut uint = transmute(ty_ptr);
- let ptr: *mut T = transmute(ptr);
- // Write in our tydesc along with a bit indicating that it
- // has *not* been initialized yet.
- *ty_ptr = transmute(tydesc);
- // Actually initialize it
- intrinsics::move_val_init(&mut(*ptr), op());
- // Now that we are done, update the tydesc to indicate that
- // the object is there.
- *ty_ptr = bitpack_tydesc_ptr(tydesc, true);
-
- return transmute(ptr);
- }
- }
-
- // The external interface
- #[inline]
- pub fn alloc<'a, T>(&'a self, op: || -> T) -> &'a T {
- unsafe {
- // XXX: Borrow check
- let this = transmute_mut(self);
- if intrinsics::needs_drop::<T>() {
- this.alloc_nonpod(op)
- } else {
- this.alloc_pod(op)
- }
- }
- }
-}
-
-#[test]
-fn test_arena_destructors() {
- let arena = Arena::new();
- for i in range(0u, 10) {
- // Arena allocate something with drop glue to make sure it
- // doesn't leak.
- arena.alloc(|| @i);
- // Allocate something with funny size and alignment, to keep
- // things interesting.
- arena.alloc(|| [0u8, 1u8, 2u8]);
- }
-}
-
-#[test]
-#[should_fail]
-fn test_arena_destructors_fail() {
- let arena = Arena::new();
- // Put some stuff in the arena.
- for i in range(0u, 10) {
- // Arena allocate something with drop glue to make sure it
- // doesn't leak.
- arena.alloc(|| { @i });
- // Allocate something with funny size and alignment, to keep
- // things interesting.
- arena.alloc(|| { [0u8, 1u8, 2u8] });
- }
- // Now, fail while allocating
- arena.alloc::<@int>(|| {
- // Now fail.
- fail!();
- });
-}
-
-/// An arena that can hold objects of only one type.
-///
-/// Safety note: Modifying objects in the arena that have already had their
-/// `drop` destructors run can cause leaks, because the destructor will not
-/// run again for these objects.
-pub struct TypedArena<T> {
- /// A pointer to the next object to be allocated.
- priv ptr: *T,
-
- /// A pointer to the end of the allocated area. When this pointer is
- /// reached, a new chunk is allocated.
- priv end: *T,
-
- /// The type descriptor of the objects in the arena. This should not be
- /// necessary, but is until generic destructors are supported.
- priv tydesc: *TyDesc,
-
- /// A pointer to the first arena segment.
- priv first: Option<~TypedArenaChunk>,
-}
-
-struct TypedArenaChunk {
- /// Pointer to the next arena segment.
- next: Option<~TypedArenaChunk>,
-
- /// The number of elements that this chunk can hold.
- capacity: uint,
-
- // Objects follow here, suitably aligned.
-}
-
-impl TypedArenaChunk {
- #[inline]
- fn new<T>(next: Option<~TypedArenaChunk>, capacity: uint)
- -> ~TypedArenaChunk {
- let mut size = mem::size_of::<TypedArenaChunk>();
- size = round_up(size, mem::min_align_of::<T>());
- let elem_size = mem::size_of::<T>();
- let elems_size = elem_size.checked_mul(&capacity).unwrap();
- size = size.checked_add(&elems_size).unwrap();
-
- let mut chunk = unsafe {
- let chunk = global_heap::exchange_malloc(size);
- let mut chunk: ~TypedArenaChunk = cast::transmute(chunk);
- intrinsics::move_val_init(&mut chunk.next, next);
- chunk
- };
-
- chunk.capacity = capacity;
- chunk
- }
-
- /// Destroys this arena chunk. If the type descriptor is supplied, the
- /// drop glue is called; otherwise, drop glue is not called.
- #[inline]
- unsafe fn destroy(&mut self, len: uint, opt_tydesc: Option<*TyDesc>) {
- // Destroy all the allocated objects.
- match opt_tydesc {
- None => {}
- Some(tydesc) => {
- let mut start = self.start(tydesc);
- for _ in range(0, len) {
- ((*tydesc).drop_glue)(start as *i8);
- start = start.offset((*tydesc).size as int)
- }
- }
- }
-
- // Destroy the next chunk.
- let next_opt = util::replace(&mut self.next, None);
- match next_opt {
- None => {}
- Some(mut next) => {
- // We assume that the next chunk is completely filled.
- next.destroy(next.capacity, opt_tydesc)
- }
- }
- }
-
- // Returns a pointer to the first allocated object.
- #[inline]
- fn start(&self, tydesc: *TyDesc) -> *u8 {
- let this: *TypedArenaChunk = self;
- unsafe {
- cast::transmute(round_up(this.offset(1) as uint, (*tydesc).align))
- }
- }
-
- // Returns a pointer to the end of the allocated space.
- #[inline]
- fn end(&self, tydesc: *TyDesc) -> *u8 {
- unsafe {
- let size = (*tydesc).size.checked_mul(&self.capacity).unwrap();
- self.start(tydesc).offset(size as int)
- }
- }
-}
-
-impl<T> TypedArena<T> {
- /// Creates a new arena with preallocated space for 8 objects.
- #[inline]
- pub fn new() -> TypedArena<T> {
- TypedArena::with_capacity(8)
- }
-
- /// Creates a new arena with preallocated space for the given number of
- /// objects.
- #[inline]
- pub fn with_capacity(capacity: uint) -> TypedArena<T> {
- let chunk = TypedArenaChunk::new::<T>(None, capacity);
- let tydesc = unsafe {
- intrinsics::get_tydesc::<T>()
- };
- TypedArena {
- ptr: chunk.start(tydesc) as *T,
- end: chunk.end(tydesc) as *T,
- tydesc: tydesc,
- first: Some(chunk),
- }
- }
-
- /// Allocates an object into this arena.
- #[inline]
- pub fn alloc<'a>(&'a self, object: T) -> &'a T {
- unsafe {
- let this = cast::transmute_mut(self);
- if this.ptr == this.end {
- this.grow()
- }
-
- let ptr: &'a mut T = cast::transmute(this.ptr);
- intrinsics::move_val_init(ptr, object);
- this.ptr = this.ptr.offset(1);
- let ptr: &'a T = ptr;
- ptr
- }
- }
-
- /// Grows the arena.
- #[inline(never)]
- fn grow(&mut self) {
- let chunk = self.first.take_unwrap();
- let new_capacity = chunk.capacity.checked_mul(&2).unwrap();
- let chunk = TypedArenaChunk::new::<T>(Some(chunk), new_capacity);
- self.ptr = chunk.start(self.tydesc) as *T;
- self.end = chunk.end(self.tydesc) as *T;
- self.first = Some(chunk)
- }
-}
-
-#[unsafe_destructor]
-impl<T> Drop for TypedArena<T> {
- fn drop(&mut self) {
- // Determine how much was filled.
- let start = self.first.get_ref().start(self.tydesc) as uint;
- let end = self.ptr as uint;
- let diff = (end - start) / mem::size_of::<T>();
-
- // Pass that to the `destroy` method.
- unsafe {
- let opt_tydesc = if intrinsics::needs_drop::<T>() {
- Some(self.tydesc)
- } else {
- None
- };
- self.first.get_mut_ref().destroy(diff, opt_tydesc)
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::{Arena, TypedArena};
- use test::BenchHarness;
-
- struct Point {
- x: int,
- y: int,
- z: int,
- }
-
- #[test]
- pub fn test_pod() {
- let arena = TypedArena::new();
- for _ in range(0, 1000000) {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- });
- }
- }
-
- #[bench]
- pub fn bench_pod(bh: &mut BenchHarness) {
- let arena = TypedArena::new();
- bh.iter(|| {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- });
- })
- }
-
- #[bench]
- pub fn bench_pod_nonarena(bh: &mut BenchHarness) {
- bh.iter(|| {
- let _ = ~Point {
- x: 1,
- y: 2,
- z: 3,
- };
- })
- }
-
- #[bench]
- pub fn bench_pod_old_arena(bh: &mut BenchHarness) {
- let arena = Arena::new();
- bh.iter(|| {
- arena.alloc(|| {
- Point {
- x: 1,
- y: 2,
- z: 3,
- }
- });
- })
- }
-
- struct Nonpod {
- string: ~str,
- array: ~[int],
- }
-
- #[test]
- pub fn test_nonpod() {
- let arena = TypedArena::new();
- for _ in range(0, 1000000) {
- arena.alloc(Nonpod {
- string: ~"hello world",
- array: ~[ 1, 2, 3, 4, 5 ],
- });
- }
- }
-
- #[bench]
- pub fn bench_nonpod(bh: &mut BenchHarness) {
- let arena = TypedArena::new();
- bh.iter(|| {
- arena.alloc(Nonpod {
- string: ~"hello world",
- array: ~[ 1, 2, 3, 4, 5 ],
- });
- })
- }
-
- #[bench]
- pub fn bench_nonpod_nonarena(bh: &mut BenchHarness) {
- bh.iter(|| {
- let _ = ~Nonpod {
- string: ~"hello world",
- array: ~[ 1, 2, 3, 4, 5 ],
- };
- })
- }
-
- #[bench]
- pub fn bench_nonpod_old_arena(bh: &mut BenchHarness) {
- let arena = Arena::new();
- bh.iter(|| {
- let _ = arena.alloc(|| Nonpod {
- string: ~"hello world",
- array: ~[ 1, 2, 3, 4, 5 ],
- });
- })
- }
-}
-
-
use std::rand::{task_rng, random, Rng};
use std::vec;
- 1000.times(|| {
+ for _ in range(0, 1000) {
let times = task_rng().gen_range(1u, 100);
let v = vec::from_fn(times, |_| random::<u8>());
assert_eq!(v.to_base64(STANDARD).from_base64().unwrap(), v);
- })
+ }
}
#[bench]
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
*/
#[inline]
fn big_mask(nbits: uint, elem: uint) -> uint {
- let rmd = nbits % uint::bits;
- let nelems = nbits/uint::bits + if rmd == 0 {0} else {1};
+ let rmd = nbits % uint::BITS;
+ let nelems = nbits/uint::BITS + if rmd == 0 {0} else {1};
if elem < nelems - 1 || rmd == 0 {
!0
#[inline]
pub fn get(&self, i: uint) -> bool {
- let w = i / uint::bits;
- let b = i % uint::bits;
+ let w = i / uint::BITS;
+ let b = i % uint::BITS;
let x = 1 & self.storage[w] >> b;
x == 1
}
#[inline]
pub fn set(&mut self, i: uint, x: bool) {
- let w = i / uint::bits;
- let b = i % uint::bits;
+ let w = i / uint::BITS;
+ let b = i % uint::BITS;
let flag = 1 << b;
self.storage[w] = if x { self.storage[w] | flag }
else { self.storage[w] & !flag };
impl Bitv {
pub fn new(nbits: uint, init: bool) -> Bitv {
- let rep = if nbits < uint::bits {
+ let rep = if nbits < uint::BITS {
Small(SmallBitv::new(if init {(1<<nbits)-1} else {0}))
- } else if nbits == uint::bits {
+ } else if nbits == uint::BITS {
Small(SmallBitv::new(if init {!0} else {0}))
} else {
- let exact = nbits % uint::bits == 0;
- let nelems = nbits/uint::bits + if exact {0} else {1};
+ let exact = nbits % uint::BITS == 0;
+ let nelems = nbits/uint::BITS + if exact {0} else {1};
let s =
if init {
if exact {
vec::from_elem(nelems, !0u)
} else {
let mut v = vec::from_elem(nelems-1, !0u);
- v.push((1<<nbits % uint::bits)-1);
+ v.push((1<<nbits % uint::BITS)-1);
v
}
} else { vec::from_elem(nelems, 0u)};
if bits == 0 {
return true;
}
- for i in range(0u, uint::bits) {
+ for i in range(0u, uint::BITS) {
if bits & (1 << i) != 0 {
if !f(base + i) {
return false;
/// Returns the capacity in bits for this bit vector. Inserting any
/// element less than this amount will not trigger a resizing.
- pub fn capacity(&self) -> uint { self.bitv.storage.len() * uint::bits }
+ pub fn capacity(&self) -> uint { self.bitv.storage.len() * uint::BITS }
/// Consumes this set to return the underlying bit vector
pub fn unwrap(self) -> Bitv {
fn other_op(&mut self, other: &BitvSet, f: |uint, uint| -> uint) {
fn nbits(mut w: uint) -> uint {
let mut bits = 0;
- for _ in range(0u, uint::bits) {
+ for _ in range(0u, uint::BITS) {
if w == 0 {
break;
}
return bits;
}
if self.capacity() < other.capacity() {
- self.bitv.storage.grow(other.capacity() / uint::bits, &0);
+ self.bitv.storage.grow(other.capacity() / uint::BITS, &0);
}
for (i, &w) in other.bitv.storage.iter().enumerate() {
let old = self.bitv.storage[i];
impl Set<uint> for BitvSet {
fn contains(&self, value: &uint) -> bool {
- *value < self.bitv.storage.len() * uint::bits && self.bitv.get(*value)
+ *value < self.bitv.storage.len() * uint::BITS && self.bitv.get(*value)
}
fn is_disjoint(&self, other: &BitvSet) -> bool {
}
let nbits = self.capacity();
if value >= nbits {
- let newsize = num::max(value, nbits * 2) / uint::bits + 1;
+ let newsize = num::max(value, nbits * 2) / uint::BITS + 1;
assert!(newsize > self.bitv.storage.len());
self.bitv.storage.grow(newsize, &0);
}
let min = num::min(self.bitv.storage.len(), other.bitv.storage.len());
self.bitv.storage.slice(0, min).iter().enumerate()
.zip(Repeat::new(&other.bitv.storage))
- .map(|((i, &w), o_store)| (i * uint::bits, w, o_store[i]))
+ .map(|((i, &w), o_store)| (i * uint::BITS, w, o_store[i]))
}
/// Visits each word in `self` or `other` that extends beyond the other. This
if olen < slen {
self.bitv.storage.slice_from(olen).iter().enumerate()
.zip(Repeat::new(olen))
- .map(|((i, &w), min)| (true, (i + min) * uint::bits, w))
+ .map(|((i, &w), min)| (true, (i + min) * uint::BITS, w))
} else {
other.bitv.storage.slice_from(slen).iter().enumerate()
.zip(Repeat::new(slen))
- .map(|((i, &w), min)| (false, (i + min) * uint::bits, w))
+ .map(|((i, &w), min)| (false, (i + min) * uint::BITS, w))
}
}
}
assert!(a.insert(1000));
assert!(a.remove(&1000));
- assert_eq!(a.capacity(), uint::bits);
+ assert_eq!(a.capacity(), uint::BITS);
}
#[test]
let mut r = rng();
let mut bitv = 0 as uint;
b.iter(|| {
- bitv |= (1 << ((r.next_u32() as uint) % uint::bits));
+ bitv |= (1 << ((r.next_u32() as uint) % uint::BITS));
})
}
#[bench]
fn bench_small_bitv_small(b: &mut BenchHarness) {
let mut r = rng();
- let mut bitv = SmallBitv::new(uint::bits);
+ let mut bitv = SmallBitv::new(uint::BITS);
b.iter(|| {
- bitv.set((r.next_u32() as uint) % uint::bits, true);
+ bitv.set((r.next_u32() as uint) % uint::BITS, true);
})
}
let mut r = rng();
let mut bitv = BigBitv::new(~[0]);
b.iter(|| {
- bitv.set((r.next_u32() as uint) % uint::bits, true);
+ bitv.set((r.next_u32() as uint) % uint::BITS, true);
})
}
fn bench_big_bitv_big(b: &mut BenchHarness) {
let mut r = rng();
let mut storage = ~[];
- storage.grow(BENCH_BITS / uint::bits, &0u);
+ storage.grow(BENCH_BITS / uint::BITS, &0u);
let mut bitv = BigBitv::new(storage);
b.iter(|| {
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
#[bench]
fn bench_bitv_small(b: &mut BenchHarness) {
let mut r = rng();
- let mut bitv = Bitv::new(uint::bits, false);
+ let mut bitv = Bitv::new(uint::BITS, false);
b.iter(|| {
- bitv.set((r.next_u32() as uint) % uint::bits, true);
+ bitv.set((r.next_u32() as uint) % uint::BITS, true);
})
}
let mut r = rng();
let mut bitv = BitvSet::new();
b.iter(|| {
- bitv.insert((r.next_u32() as uint) % uint::bits);
+ bitv.insert((r.next_u32() as uint) % uint::BITS);
})
}
#[bench]
fn bench_btv_small_iter(b: &mut BenchHarness) {
- let bitv = Bitv::new(uint::bits, false);
+ let bitv = Bitv::new(uint::BITS, false);
b.iter(|| {
let mut _sum = 0;
for pres in bitv.iter() {
///number of elements that a given node can contain.
#[allow(missing_doc)]
pub struct BTree<K, V> {
- root: Node<K, V>,
- len: uint,
- lower_bound: uint,
- upper_bound: uint
+ priv root: Node<K, V>,
+ priv len: uint,
+ priv lower_bound: uint,
+ priv upper_bound: uint
}
//We would probably want to remove the dependence on the Clone trait in the future.
///Helper function for clone: returns new BTree with supplied root node,
///length, and lower bound. For use when the length is known already.
- pub fn new_with_node_len(n: Node<K, V>,
- length: uint,
- lb: uint) -> BTree<K, V> {
+ fn new_with_node_len(n: Node<K, V>,
+ length: uint,
+ lb: uint) -> BTree<K, V> {
BTree {
root: n,
len: length,
}
}
-
pub fn basic_rendezvous_test() {
let (port, chan) = rendezvous();
- do spawn {
+ spawn(proc() {
chan.send("abc");
- }
+ });
assert!(port.recv() == "abc");
}
fn recv_a_lot() {
// Rendezvous streams should be able to handle any number of messages being sent
let (port, chan) = rendezvous();
- do spawn {
- 10000.times(|| { chan.send(()) })
- }
- 10000.times(|| { port.recv() })
+ spawn(proc() {
+ for _ in range(0, 10000) { chan.send(()); }
+ });
+ for _ in range(0, 10000) { port.recv(); }
}
#[test]
fn send_and_fail_and_try_recv() {
let (port, chan) = rendezvous();
- do spawn {
+ spawn(proc() {
chan.duplex_stream.send(()); // Can't access this field outside this module
fail!()
- }
+ });
port.recv()
}
#[test]
fn try_send_and_recv_then_fail_before_ack() {
let (port, chan) = rendezvous();
- do spawn {
+ spawn(proc() {
port.duplex_stream.recv();
fail!()
- }
+ });
chan.try_send(());
}
#[should_fail]
fn send_and_recv_then_fail_before_ack() {
let (port, chan) = rendezvous();
- do spawn {
+ spawn(proc() {
port.duplex_stream.recv();
fail!()
- }
+ });
chan.send(());
}
}
}
type Link<T> = Option<~Node<T>>;
-struct Rawlink<T> { priv p: *mut T }
+struct Rawlink<T> { p: *mut T }
struct Node<T> {
- priv next: Link<T>,
- priv prev: Rawlink<Node<T>>,
- priv value: T,
+ next: Link<T>,
+ prev: Rawlink<Node<T>>,
+ value: T,
}
/// Double-ended DList iterator
-#[deriving(Clone)]
pub struct Items<'a, T> {
priv head: &'a Link<T>,
priv tail: Rawlink<Node<T>>,
priv nelem: uint,
}
+// FIXME #11820: the &'a Option<> of the Link stops clone working.
+impl<'a, T> Clone for Items<'a, T> {
+ fn clone(&self) -> Items<'a, T> { *self }
+}
+
/// Double-ended mutable DList iterator
pub struct MutItems<'a, T> {
priv list: &'a mut DList<T>,
#[test]
fn test_send() {
let n = list_from([1,2,3]);
- do spawn {
+ spawn(proc() {
check_links(&n);
assert_eq!(~[&1,&2,&3], n.iter().collect::<~[&int]>());
- }
+ });
}
#[test]
#[test]
fn test_fuzz() {
- 25.times(|| {
+ for _ in range(0, 25) {
fuzz_test(3);
fuzz_test(16);
fuzz_test(189);
- })
+ }
}
#[cfg(test)]
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) }
fn read_uint(&mut self) -> uint {
let v = doc_as_u64(self.next_doc(EsUint));
- if v > (::std::uint::max_value as u64) {
+ if v > (::std::uint::MAX as u64) {
fail!("uint {} too large for this architecture", v);
}
v as uint
}
fn read_int(&mut self) -> int {
let v = doc_as_u64(self.next_doc(EsInt)) as i64;
- if v > (int::max_value as i64) || v < (int::min_value as i64) {
+ if v > (int::MAX as i64) || v < (int::MIN as i64) {
debug!("FIXME \\#6122: Removing this makes this function miscompile");
fail!("int {} out of range for this architecture", v);
}
// FIXME (#2741): Provide a function to write the standard ebml header.
impl<'a> Encoder<'a> {
- /// XXX(pcwalton): Workaround for badness in trans. DO NOT USE ME.
+ /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME.
pub unsafe fn unsafe_clone(&self) -> Encoder<'a> {
Encoder {
writer: cast::transmute_copy(&self.writer),
+++ /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.
-
-/*!
-
-Simple compression
-
-*/
-
-#[allow(missing_doc)];
-
-use std::libc::{c_void, size_t, c_int};
-use std::libc;
-use std::vec;
-
-pub mod rustrt {
- use std::libc::{c_int, c_void, size_t};
-
- #[link(name = "rustrt", kind = "static")]
- extern {
- pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
- src_buf_len: size_t,
- pout_len: *mut size_t,
- flags: c_int)
- -> *c_void;
-
- pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
- src_buf_len: size_t,
- pout_len: *mut size_t,
- flags: c_int)
- -> *c_void;
- }
-}
-
-static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal"
-static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
-static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
-
-fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
- unsafe {
- let mut outsz : size_t = 0;
- let res = rustrt::tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void,
- bytes.len() as size_t,
- &mut outsz,
- flags);
- assert!(res as int != 0);
- let out = vec::raw::from_buf_raw(res as *u8,
- outsz as uint);
- libc::free(res as *mut c_void);
- out
- }
-}
-
-pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
- deflate_bytes_internal(bytes, LZ_NORM)
-}
-
-pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
- deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
-}
-
-fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
- unsafe {
- let mut outsz : size_t = 0;
- let res = rustrt::tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void,
- bytes.len() as size_t,
- &mut outsz,
- flags);
- assert!(res as int != 0);
- let out = vec::raw::from_buf_raw(res as *u8,
- outsz as uint);
- libc::free(res as *mut c_void);
- out
- }
-}
-
-pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
- inflate_bytes_internal(bytes, 0)
-}
-
-pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
- inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::rand;
- use std::rand::Rng;
-
- #[test]
- fn test_flate_round_trip() {
- let mut r = rand::rng();
- let mut words = ~[];
- 20.times(|| {
- let range = r.gen_range(1u, 10);
- words.push(r.gen_vec::<u8>(range));
- });
- 20.times(|| {
- let mut input = ~[];
- 2000.times(|| {
- input.push_all(r.choose(words));
- });
- debug!("de/inflate of {} bytes of random word-sequences",
- input.len());
- let cmp = deflate_bytes(input);
- let out = inflate_bytes(cmp);
- debug!("{} bytes deflated to {} ({:.1f}% size)",
- input.len(), cmp.len(),
- 100.0 * ((cmp.len() as f64) / (input.len() as f64)));
- assert_eq!(input, out);
- });
- }
-
- #[test]
- fn test_zlib_flate() {
- let bytes = ~[1, 2, 3, 4, 5];
- let deflated = deflate_bytes(bytes);
- let inflated = inflate_bytes(deflated);
- assert_eq!(inflated, bytes);
- }
-}
* use extra::future::Future;
* # fn fib(n: uint) -> uint {42};
* # fn make_a_sandwich() {};
- * let mut delayed_fib = do Future::spawn { fib(5000) };
+ * let mut delayed_fib = Future::spawn(proc() { fib(5000) });
* make_a_sandwich();
* println!("fib(5000) = {}", delayed_fib.get())
* ```
* waiting for the result to be received on the port.
*/
- do Future::from_fn {
+ Future::from_fn(proc() {
port.recv()
- }
+ })
}
pub fn spawn(blk: proc() -> A) -> Future<A> {
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
chan.send(blk());
- }
+ });
Future::from_port(port)
}
#[test]
fn test_sendable_future() {
let expected = "schlorf";
- let f = do Future::spawn { expected };
- do task::spawn {
+ let f = Future::spawn(proc() { expected });
+ task::spawn(proc() {
let mut f = f;
let actual = f.get();
assert_eq!(actual, expected);
- }
+ });
}
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// here we just need to indent the start of the description
let rowlen = row.char_len();
if rowlen < 24 {
- (24 - rowlen).times(|| {
- row.push_char(' ')
- })
+ for _ in range(0, 24 - rowlen) {
+ row.push_char(' ');
+ }
} else {
row.push_str(desc_sep)
}
t("hello", 15, [~"hello"]);
t("\nMary had a little lamb\nLittle lamb\n", 15,
[~"Mary had a", ~"little lamb", ~"Little lamb"]);
- t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::max_value,
+ t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::MAX,
[~"Mary had a little lamb\nLittle lamb"]);
}
} // end groups module
+++ /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.
-
-/*!
- * Support for matching file paths against Unix shell style patterns.
- *
- * The `glob` and `glob_with` functions, in concert with the `Paths`
- * type, allow querying the filesystem for all files that match a particular
- * pattern - just like the libc `glob` function (for an example see the `glob`
- * documentation). The methods on the `Pattern` type provide functionality
- * for checking if individual paths match a particular pattern - in a similar
- * manner to the libc `fnmatch` function
- *
- * For consistency across platforms, and for Windows support, this module
- * is implemented entirely in Rust rather than deferring to the libc
- * `glob`/`fnmatch` functions.
- */
-
-use std::{os, path};
-use std::io;
-use std::io::fs;
-use std::path::is_sep;
-
-/**
- * An iterator that yields Paths from the filesystem that match a particular
- * pattern - see the `glob` function for more details.
- */
-pub struct Paths {
- priv root: Path,
- priv dir_patterns: ~[Pattern],
- priv options: MatchOptions,
- priv todo: ~[(Path,uint)]
-}
-
-///
-/// Return an iterator that produces all the Paths that match the given pattern,
-/// which may be absolute or relative to the current working directory.
-///
-/// is method uses the default match options and is equivalent to calling
-/// `glob_with(pattern, MatchOptions::new())`. Use `glob_with` directly if you
-/// want to use non-default match options.
-///
-/// # Example
-///
-/// Consider a directory `/media/pictures` containing only the files `kittens.jpg`,
-/// `puppies.jpg` and `hamsters.gif`:
-///
-/// ```rust
-/// use extra::glob::glob;
-///
-/// for path in glob("/media/pictures/*.jpg") {
-/// println!("{}", path.display());
-/// }
-/// ```
-///
-/// The above code will print:
-///
-/// ```
-/// /media/pictures/kittens.jpg
-/// /media/pictures/puppies.jpg
-/// ```
-///
-pub fn glob(pattern: &str) -> Paths {
- glob_with(pattern, MatchOptions::new())
-}
-
-/**
- * Return an iterator that produces all the Paths that match the given pattern,
- * which may be absolute or relative to the current working directory.
- *
- * This function accepts Unix shell style patterns as described by `Pattern::new(..)`.
- * The options given are passed through unchanged to `Pattern::matches_with(..)` with
- * the exception that `require_literal_separator` is always set to `true` regardless of the
- * value passed to this function.
- *
- * Paths are yielded in alphabetical order, as absolute paths.
- */
-pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
- #[cfg(windows)]
- fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
- #[cfg(not(windows))]
- fn check_windows_verbatim(_: &Path) -> bool { false }
-
- // calculate root this way to handle volume-relative Windows paths correctly
- let mut root = os::getcwd();
- let pat_root = Path::new(pattern).root_path();
- if pat_root.is_some() {
- if check_windows_verbatim(pat_root.get_ref()) {
- // XXX: How do we want to handle verbatim paths? I'm inclined to return nothing,
- // since we can't very well find all UNC shares with a 1-letter server name.
- return Paths { root: root, dir_patterns: ~[], options: options, todo: ~[] };
- }
- root.push(pat_root.get_ref());
- }
-
- let root_len = pat_root.map_or(0u, |p| p.as_vec().len());
- let dir_patterns = pattern.slice_from(root_len.min(&pattern.len()))
- .split_terminator(is_sep).map(|s| Pattern::new(s)).to_owned_vec();
-
- let todo = list_dir_sorted(&root).move_iter().map(|x|(x,0u)).to_owned_vec();
-
- Paths {
- root: root,
- dir_patterns: dir_patterns,
- options: options,
- todo: todo,
- }
-}
-
-impl Iterator<Path> for Paths {
-
- fn next(&mut self) -> Option<Path> {
- loop {
- if self.dir_patterns.is_empty() || self.todo.is_empty() {
- return None;
- }
-
- let (path,idx) = self.todo.pop().unwrap();
- let ref pattern = self.dir_patterns[idx];
-
- if pattern.matches_with(match path.filename_str() {
- // this ugly match needs to go here to avoid a borrowck error
- None => {
- // FIXME (#9639): How do we handle non-utf8 filenames? Ignore them for now
- // Ideally we'd still match them against a *
- continue;
- }
- Some(x) => x
- }, self.options) {
- if idx == self.dir_patterns.len() - 1 {
- // it is not possible for a pattern to match a directory *AND* its children
- // so we don't need to check the children
- return Some(path);
- } else {
- self.todo.extend(&mut list_dir_sorted(&path).move_iter().map(|x|(x,idx+1)));
- }
- }
- }
- }
-
-}
-
-fn list_dir_sorted(path: &Path) -> ~[Path] {
- match io::result(|| fs::readdir(path)) {
- Ok(mut children) => {
- children.sort_by(|p1, p2| p2.filename().cmp(&p1.filename()));
- children
- }
- Err(..) => ~[]
- }
-}
-
-/**
- * A compiled Unix shell style pattern.
- */
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
-pub struct Pattern {
- priv tokens: ~[PatternToken]
-}
-
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-enum PatternToken {
- Char(char),
- AnyChar,
- AnySequence,
- AnyWithin(~[CharSpecifier]),
- AnyExcept(~[CharSpecifier])
-}
-
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-enum CharSpecifier {
- SingleChar(char),
- CharRange(char, char)
-}
-
-#[deriving(Eq)]
-enum MatchResult {
- Match,
- SubPatternDoesntMatch,
- EntirePatternDoesntMatch
-}
-
-impl Pattern {
-
- /**
- * This function compiles Unix shell style patterns: `?` matches any single
- * character, `*` matches any (possibly empty) sequence of characters and
- * `[...]` matches any character inside the brackets, unless the first
- * character is `!` in which case it matches any character except those
- * between the `!` and the `]`. Character sequences can also specify ranges
- * of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any
- * character between 0 and 9 inclusive.
- *
- * The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets
- * (e.g. `[?]`). When a `]` occurs immediately following `[` or `[!` then
- * it is interpreted as being part of, rather then ending, the character
- * set, so `]` and NOT `]` can be matched by `[]]` and `[!]]` respectively.
- * The `-` character can be specified inside a character sequence pattern by
- * placing it at the start or the end, e.g. `[abc-]`.
- *
- * When a `[` does not have a closing `]` before the end of the string then
- * the `[` will be treated literally.
- */
- pub fn new(pattern: &str) -> Pattern {
-
- let chars = pattern.chars().to_owned_vec();
- let mut tokens = ~[];
- let mut i = 0;
-
- while i < chars.len() {
- match chars[i] {
- '?' => {
- tokens.push(AnyChar);
- i += 1;
- }
- '*' => {
- // *, **, ***, ****, ... are all equivalent
- while i < chars.len() && chars[i] == '*' {
- i += 1;
- }
- tokens.push(AnySequence);
- }
- '[' => {
-
- if i <= chars.len() - 4 && chars[i + 1] == '!' {
- match chars.slice_from(i + 3).position_elem(&']') {
- None => (),
- Some(j) => {
- let chars = chars.slice(i + 2, i + 3 + j);
- let cs = parse_char_specifiers(chars);
- tokens.push(AnyExcept(cs));
- i += j + 4;
- continue;
- }
- }
- }
- else if i <= chars.len() - 3 && chars[i + 1] != '!' {
- match chars.slice_from(i + 2).position_elem(&']') {
- None => (),
- Some(j) => {
- let cs = parse_char_specifiers(chars.slice(i + 1, i + 2 + j));
- tokens.push(AnyWithin(cs));
- i += j + 3;
- continue;
- }
- }
- }
-
- // if we get here then this is not a valid range pattern
- tokens.push(Char('['));
- i += 1;
- }
- c => {
- tokens.push(Char(c));
- i += 1;
- }
- }
- }
-
- Pattern { tokens: tokens }
- }
-
- /**
- * Escape metacharacters within the given string by surrounding them in
- * brackets. The resulting string will, when compiled into a `Pattern`,
- * match the input string and nothing else.
- */
- pub fn escape(s: &str) -> ~str {
- let mut escaped = ~"";
- for c in s.chars() {
- match c {
- // note that ! does not need escaping because it is only special inside brackets
- '?' | '*' | '[' | ']' => {
- escaped.push_char('[');
- escaped.push_char(c);
- escaped.push_char(']');
- }
- c => {
- escaped.push_char(c);
- }
- }
- }
- escaped
- }
-
- /**
- * Return if the given `str` matches this `Pattern` using the default
- * match options (i.e. `MatchOptions::new()`).
- *
- * # Example
- *
- * ```rust
- * use extra::glob::Pattern;
- *
- * assert!(Pattern::new("c?t").matches("cat"));
- * assert!(Pattern::new("k[!e]tteh").matches("kitteh"));
- * assert!(Pattern::new("d*g").matches("doog"));
- * ```
- */
- pub fn matches(&self, str: &str) -> bool {
- self.matches_with(str, MatchOptions::new())
- }
-
- /**
- * Return if the given `Path`, when converted to a `str`, matches this `Pattern`
- * using the default match options (i.e. `MatchOptions::new()`).
- */
- pub fn matches_path(&self, path: &Path) -> bool {
- // FIXME (#9639): This needs to handle non-utf8 paths
- path.as_str().map_or(false, |s| {
- self.matches(s)
- })
- }
-
- /**
- * Return if the given `str` matches this `Pattern` using the specified match options.
- */
- pub fn matches_with(&self, str: &str, options: MatchOptions) -> bool {
- self.matches_from(None, str, 0, options) == Match
- }
-
- /**
- * Return if the given `Path`, when converted to a `str`, matches this `Pattern`
- * using the specified match options.
- */
- pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool {
- // FIXME (#9639): This needs to handle non-utf8 paths
- path.as_str().map_or(false, |s| {
- self.matches_with(s, options)
- })
- }
-
- fn matches_from(&self,
- mut prev_char: Option<char>,
- mut file: &str,
- i: uint,
- options: MatchOptions) -> MatchResult {
-
- let require_literal = |c| {
- (options.require_literal_separator && is_sep(c)) ||
- (options.require_literal_leading_dot && c == '.'
- && is_sep(prev_char.unwrap_or('/')))
- };
-
- for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
- match *token {
- AnySequence => {
- loop {
- match self.matches_from(prev_char, file, i + ti + 1, options) {
- SubPatternDoesntMatch => (), // keep trying
- m => return m,
- }
-
- if file.is_empty() {
- return EntirePatternDoesntMatch;
- }
-
- let (c, next) = file.slice_shift_char();
- if require_literal(c) {
- return SubPatternDoesntMatch;
- }
- prev_char = Some(c);
- file = next;
- }
- }
- _ => {
- if file.is_empty() {
- return EntirePatternDoesntMatch;
- }
-
- let (c, next) = file.slice_shift_char();
- let matches = match *token {
- AnyChar => {
- !require_literal(c)
- }
- AnyWithin(ref specifiers) => {
- !require_literal(c) && in_char_specifiers(*specifiers, c, options)
- }
- AnyExcept(ref specifiers) => {
- !require_literal(c) && !in_char_specifiers(*specifiers, c, options)
- }
- Char(c2) => {
- chars_eq(c, c2, options.case_sensitive)
- }
- AnySequence => {
- unreachable!()
- }
- };
- if !matches {
- return SubPatternDoesntMatch;
- }
- prev_char = Some(c);
- file = next;
- }
- }
- }
-
- if file.is_empty() {
- Match
- } else {
- SubPatternDoesntMatch
- }
- }
-
-}
-
-fn parse_char_specifiers(s: &[char]) -> ~[CharSpecifier] {
- let mut cs = ~[];
- let mut i = 0;
- while i < s.len() {
- if i + 3 <= s.len() && s[i + 1] == '-' {
- cs.push(CharRange(s[i], s[i + 2]));
- i += 3;
- } else {
- cs.push(SingleChar(s[i]));
- i += 1;
- }
- }
- cs
-}
-
-fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool {
-
- for &specifier in specifiers.iter() {
- match specifier {
- SingleChar(sc) => {
- if chars_eq(c, sc, options.case_sensitive) {
- return true;
- }
- }
- CharRange(start, end) => {
-
- // FIXME: work with non-ascii chars properly (issue #1347)
- if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {
-
- let start = start.to_ascii().to_lower();
- let end = end.to_ascii().to_lower();
-
- let start_up = start.to_upper();
- let end_up = end.to_upper();
-
- // only allow case insensitive matching when
- // both start and end are within a-z or A-Z
- if start != start_up && end != end_up {
- let start = start.to_char();
- let end = end.to_char();
- let c = c.to_ascii().to_lower().to_char();
- if c >= start && c <= end {
- return true;
- }
- }
- }
-
- if c >= start && c <= end {
- return true;
- }
- }
- }
- }
-
- false
-}
-
-/// A helper function to determine if two chars are (possibly case-insensitively) equal.
-fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
- if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
- true
- } else if !case_sensitive && a.is_ascii() && b.is_ascii() {
- // FIXME: work with non-ascii chars properly (issue #1347)
- a.to_ascii().eq_ignore_case(b.to_ascii())
- } else {
- a == b
- }
-}
-
-/**
- * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
- */
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
-pub struct MatchOptions {
-
- /**
- * Whether or not patterns should be matched in a case-sensitive manner. This
- * currently only considers upper/lower case relationships between ASCII characters,
- * but in future this might be extended to work with Unicode.
- */
- priv case_sensitive: bool,
-
- /**
- * If this is true then path-component separator characters (e.g. `/` on Posix)
- * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
- */
- priv require_literal_separator: bool,
-
- /**
- * If this is true then paths that contain components that start with a `.` will
- * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
- * will not match. This is useful because such files are conventionally considered
- * hidden on Unix systems and it might be desirable to skip them when listing files.
- */
- priv require_literal_leading_dot: bool
-}
-
-impl MatchOptions {
-
- /**
- * Constructs a new `MatchOptions` with default field values. This is used
- * when calling functions that do not take an explicit `MatchOptions` parameter.
- *
- * This function always returns this value:
- *
- * ```rust,ignore
- * MatchOptions {
- * case_sensitive: true,
- * require_literal_separator: false.
- * require_literal_leading_dot: false
- * }
- * ```
- */
- pub fn new() -> MatchOptions {
- MatchOptions {
- case_sensitive: true,
- require_literal_separator: false,
- require_literal_leading_dot: false
- }
- }
-
-}
-
-#[cfg(test)]
-mod test {
- use std::os;
- use super::*;
-
- #[test]
- fn test_absolute_pattern() {
- // assume that the filesystem is not empty!
- assert!(glob("/*").next().is_some());
- assert!(glob("//").next().is_none());
-
- // check windows absolute paths with host/device components
- let root_with_device = os::getcwd().root_path().unwrap().join("*");
- // FIXME (#9639): This needs to handle non-utf8 paths
- assert!(glob(root_with_device.as_str().unwrap()).next().is_some());
- }
-
- #[test]
- fn test_wildcard_optimizations() {
- assert!(Pattern::new("a*b").matches("a___b"));
- assert!(Pattern::new("a**b").matches("a___b"));
- assert!(Pattern::new("a***b").matches("a___b"));
- assert!(Pattern::new("a*b*c").matches("abc"));
- assert!(!Pattern::new("a*b*c").matches("abcd"));
- assert!(Pattern::new("a*b*c").matches("a_b_c"));
- assert!(Pattern::new("a*b*c").matches("a___b___c"));
- assert!(Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabc"));
- assert!(!Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabca"));
- assert!(Pattern::new("a*a*a*a*a*a*a*a*a").matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
- assert!(Pattern::new("a*b[xyz]c*d").matches("abxcdbxcddd"));
- }
-
- #[test]
- fn test_lots_of_files() {
- // this is a good test because it touches lots of differently named files
- glob("/*/*/*/*").skip(10000).next();
- }
-
- #[test]
- fn test_range_pattern() {
-
- let pat = Pattern::new("a[0-9]b");
- for i in range(0, 10) {
- assert!(pat.matches(format!("a{}b", i)));
- }
- assert!(!pat.matches("a_b"));
-
- let pat = Pattern::new("a[!0-9]b");
- for i in range(0, 10) {
- assert!(!pat.matches(format!("a{}b", i)));
- }
- assert!(pat.matches("a_b"));
-
- let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"];
- for &p in pats.iter() {
- let pat = Pattern::new(p);
- for c in "abcdefghijklmnopqrstuvwxyz".chars() {
- assert!(pat.matches(c.to_str()));
- }
- for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() {
- let options = MatchOptions {case_sensitive: false, .. MatchOptions::new()};
- assert!(pat.matches_with(c.to_str(), options));
- }
- assert!(pat.matches("1"));
- assert!(pat.matches("2"));
- assert!(pat.matches("3"));
- }
-
- let pats = ["[abc-]", "[-abc]", "[a-c-]"];
- for &p in pats.iter() {
- let pat = Pattern::new(p);
- assert!(pat.matches("a"));
- assert!(pat.matches("b"));
- assert!(pat.matches("c"));
- assert!(pat.matches("-"));
- assert!(!pat.matches("d"));
- }
-
- let pat = Pattern::new("[2-1]");
- assert!(!pat.matches("1"));
- assert!(!pat.matches("2"));
-
- assert!(Pattern::new("[-]").matches("-"));
- assert!(!Pattern::new("[!-]").matches("-"));
- }
-
- #[test]
- fn test_unclosed_bracket() {
- // unclosed `[` should be treated literally
- assert!(Pattern::new("abc[def").matches("abc[def"));
- assert!(Pattern::new("abc[!def").matches("abc[!def"));
- assert!(Pattern::new("abc[").matches("abc["));
- assert!(Pattern::new("abc[!").matches("abc[!"));
- assert!(Pattern::new("abc[d").matches("abc[d"));
- assert!(Pattern::new("abc[!d").matches("abc[!d"));
- assert!(Pattern::new("abc[]").matches("abc[]"));
- assert!(Pattern::new("abc[!]").matches("abc[!]"));
- }
-
- #[test]
- fn test_pattern_matches() {
- let txt_pat = Pattern::new("*hello.txt");
- assert!(txt_pat.matches("hello.txt"));
- assert!(txt_pat.matches("gareth_says_hello.txt"));
- assert!(txt_pat.matches("some/path/to/hello.txt"));
- assert!(txt_pat.matches("some\\path\\to\\hello.txt"));
- assert!(txt_pat.matches("/an/absolute/path/to/hello.txt"));
- assert!(!txt_pat.matches("hello.txt-and-then-some"));
- assert!(!txt_pat.matches("goodbye.txt"));
-
- let dir_pat = Pattern::new("*some/path/to/hello.txt");
- assert!(dir_pat.matches("some/path/to/hello.txt"));
- assert!(dir_pat.matches("a/bigger/some/path/to/hello.txt"));
- assert!(!dir_pat.matches("some/path/to/hello.txt-and-then-some"));
- assert!(!dir_pat.matches("some/other/path/to/hello.txt"));
- }
-
- #[test]
- fn test_pattern_escape() {
- let s = "_[_]_?_*_!_";
- assert_eq!(Pattern::escape(s), ~"_[[]_[]]_[?]_[*]_!_");
- assert!(Pattern::new(Pattern::escape(s)).matches(s));
- }
-
- #[test]
- fn test_pattern_matches_case_insensitive() {
-
- let pat = Pattern::new("aBcDeFg");
- let options = MatchOptions {
- case_sensitive: false,
- require_literal_separator: false,
- require_literal_leading_dot: false
- };
-
- assert!(pat.matches_with("aBcDeFg", options));
- assert!(pat.matches_with("abcdefg", options));
- assert!(pat.matches_with("ABCDEFG", options));
- assert!(pat.matches_with("AbCdEfG", options));
- }
-
- #[test]
- fn test_pattern_matches_case_insensitive_range() {
-
- let pat_within = Pattern::new("[a]");
- let pat_except = Pattern::new("[!a]");
-
- let options_case_insensitive = MatchOptions {
- case_sensitive: false,
- require_literal_separator: false,
- require_literal_leading_dot: false
- };
- let options_case_sensitive = MatchOptions {
- case_sensitive: true,
- require_literal_separator: false,
- require_literal_leading_dot: false
- };
-
- assert!(pat_within.matches_with("a", options_case_insensitive));
- assert!(pat_within.matches_with("A", options_case_insensitive));
- assert!(!pat_within.matches_with("A", options_case_sensitive));
-
- assert!(!pat_except.matches_with("a", options_case_insensitive));
- assert!(!pat_except.matches_with("A", options_case_insensitive));
- assert!(pat_except.matches_with("A", options_case_sensitive));
- }
-
- #[test]
- fn test_pattern_matches_require_literal_separator() {
-
- let options_require_literal = MatchOptions {
- case_sensitive: true,
- require_literal_separator: true,
- require_literal_leading_dot: false
- };
- let options_not_require_literal = MatchOptions {
- case_sensitive: true,
- require_literal_separator: false,
- require_literal_leading_dot: false
- };
-
- assert!(Pattern::new("abc/def").matches_with("abc/def", options_require_literal));
- assert!(!Pattern::new("abc?def").matches_with("abc/def", options_require_literal));
- assert!(!Pattern::new("abc*def").matches_with("abc/def", options_require_literal));
- assert!(!Pattern::new("abc[/]def").matches_with("abc/def", options_require_literal));
-
- assert!(Pattern::new("abc/def").matches_with("abc/def", options_not_require_literal));
- assert!(Pattern::new("abc?def").matches_with("abc/def", options_not_require_literal));
- assert!(Pattern::new("abc*def").matches_with("abc/def", options_not_require_literal));
- assert!(Pattern::new("abc[/]def").matches_with("abc/def", options_not_require_literal));
- }
-
- #[test]
- fn test_pattern_matches_require_literal_leading_dot() {
-
- let options_require_literal_leading_dot = MatchOptions {
- case_sensitive: true,
- require_literal_separator: false,
- require_literal_leading_dot: true
- };
- let options_not_require_literal_leading_dot = MatchOptions {
- case_sensitive: true,
- require_literal_separator: false,
- require_literal_leading_dot: false
- };
-
- let f = |options| Pattern::new("*.txt").matches_with(".hello.txt", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(!f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new(".*.*").matches_with(".hello.txt", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/.ccc", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(!f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/c.c.c.", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new("aaa/bbb/.*").matches_with("aaa/bbb/.ccc", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new("aaa/?bbb").matches_with("aaa/.bbb", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(!f(options_require_literal_leading_dot));
-
- let f = |options| Pattern::new("aaa/[.]bbb").matches_with("aaa/.bbb", options);
- assert!(f(options_not_require_literal_leading_dot));
- assert!(!f(options_require_literal_leading_dot));
- }
-
- #[test]
- fn test_matches_path() {
- // on windows, (Path::new("a/b").as_str().unwrap() == "a\\b"), so this
- // tests that / and \ are considered equivalent on windows
- assert!(Pattern::new("a/b").matches_path(&Path::new("a/b")));
- }
-}
fn spaces(n: uint) -> ~str {
let mut ss = ~"";
- n.times(|| ss.push_str(" "));
+ for _ in range(0, n) { ss.push_str(" "); }
return ss;
}
}
fn check_err<T: Decodable<Decoder>>(to_parse: &'static str, expected_error: &str) {
use std::task;
- let res = do task::try {
+ let res = task::try(proc() {
// either fails in `decode` (which is what we want), or
// returns Some(error_message)/None if the string was
// invalid or valid JSON.
None
}
}
- };
+ });
match res {
Ok(Some(parse_error)) => fail!("`{}` is not valid json: {}",
to_parse, parse_error),
pub mod getopts;
pub mod json;
pub mod tempfile;
-pub mod glob;
pub mod term;
pub mod time;
-pub mod arena;
pub mod base64;
pub mod workcache;
pub mod enum_set;
pub mod complex;
pub mod stats;
pub mod semver;
-pub mod flate;
pub mod hex;
pub mod uuid;
use std::ptr;
use std::cast;
-struct KeyRef<K> { priv k: *K }
+struct KeyRef<K> { k: *K }
struct LruEntry<K, V> {
- priv key: Option<K>,
- priv value: Option<V>,
- priv next: *mut LruEntry<K, V>,
- priv prev: *mut LruEntry<K, V>,
+ key: Option<K>,
+ value: Option<V>,
+ next: *mut LruEntry<K, V>,
+ prev: *mut LruEntry<K, V>,
}
/// An LRU Cache.
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
if n < m {
Some(-(n as i64))
} else if n == m {
- Some(i64::min_value)
+ Some(i64::MIN)
} else {
None
}
Some(BigInt::from_biguint(Plus, n))
})
} else if n < 0 {
- FromPrimitive::from_u64(u64::max_value - (n as u64) + 1).and_then(
+ FromPrimitive::from_u64(u64::MAX - (n as u64) + 1).and_then(
|n| {
Some(BigInt::from_biguint(Minus, n))
})
check(Zero::zero(), 0);
check(One::one(), 1);
- check(i64::max_value.to_biguint().unwrap(), i64::max_value);
+ check(i64::MAX.to_biguint().unwrap(), i64::MAX);
check(BigUint::new(~[ ]), 0);
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits)));
check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1);
check(BigUint::new(~[ 0, 0, 0, 1 ]), (1 << (3*BigDigit::bits)));
- check(BigUint::new(~[-1, -1, -1, -1 >> 1]), i64::max_value);
+ check(BigUint::new(~[-1, -1, -1, -1 >> 1]), i64::MAX);
- assert_eq!(i64::min_value.to_biguint(), None);
+ assert_eq!(i64::MIN.to_biguint(), None);
assert_eq!(BigUint::new(~[-1, -1, -1, -1 ]).to_i64(), None);
assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_i64(), None);
assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_i64(), None);
check(Zero::zero(), 0);
check(One::one(), 1);
- check(i64::max_value.to_biguint().unwrap(), i64::max_value);
+ check(i64::MAX.to_biguint().unwrap(), i64::MAX);
check(BigUint::new(~[ ]), 0);
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits)));
- check(BigUint::new(~[-1, -1 >> 1]), i64::max_value);
+ check(BigUint::new(~[-1, -1 >> 1]), i64::MAX);
- assert_eq!(i64::min_value.to_biguint(), None);
+ assert_eq!(i64::MIN.to_biguint(), None);
assert_eq!(BigUint::new(~[-1, -1 ]).to_i64(), None);
assert_eq!(BigUint::new(~[ 0, 0, 1]).to_i64(), None);
assert_eq!(BigUint::new(~[-1, -1, -1]).to_i64(), None);
check(Zero::zero(), 0);
check(One::one(), 1);
- check(u64::min_value.to_biguint().unwrap(), u64::min_value);
- check(u64::max_value.to_biguint().unwrap(), u64::max_value);
+ check(u64::MIN.to_biguint().unwrap(), u64::MIN);
+ check(u64::MAX.to_biguint().unwrap(), u64::MAX);
check(BigUint::new(~[ ]), 0);
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits)));
check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1);
check(BigUint::new(~[ 0, 0, 0, 1]), (1 << (3*BigDigit::bits)));
- check(BigUint::new(~[-1, -1, -1, -1]), u64::max_value);
+ check(BigUint::new(~[-1, -1, -1, -1]), u64::MAX);
assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_u64(), None);
assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_u64(), None);
check(Zero::zero(), 0);
check(One::one(), 1);
- check(u64::min_value.to_biguint().unwrap(), u64::min_value);
- check(u64::max_value.to_biguint().unwrap(), u64::max_value);
+ check(u64::MIN.to_biguint().unwrap(), u64::MIN);
+ check(u64::MAX.to_biguint().unwrap(), u64::MAX);
check(BigUint::new(~[ ]), 0);
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
check(BigUint::new(~[ 0, 1]), (1 << (1*BigDigit::bits)));
- check(BigUint::new(~[-1, -1]), u64::max_value);
+ check(BigUint::new(~[-1, -1]), u64::MAX);
assert_eq!(BigUint::new(~[ 0, 0, 1]).to_u64(), None);
assert_eq!(BigUint::new(~[-1, -1, -1]).to_u64(), None);
fn test_rand_range() {
let mut rng = task_rng();
- 10.times(|| {
+ for _ in range(0, 10) {
assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_uint(236).unwrap(),
&FromPrimitive::from_uint(237).unwrap()),
FromPrimitive::from_uint(236).unwrap());
- });
+ }
let l = FromPrimitive::from_uint(403469000 + 2352).unwrap();
let u = FromPrimitive::from_uint(403469000 + 3513).unwrap();
- 1000.times(|| {
+ for _ in range(0, 1000) {
let n: BigUint = rng.gen_biguint_below(&u);
assert!(n < u);
let n: BigUint = rng.gen_biguint_range(&l, &u);
assert!(n >= l);
assert!(n < u);
- })
+ }
}
#[test]
check(Zero::zero(), 0);
check(One::one(), 1);
- check(i64::min_value.to_bigint().unwrap(), i64::min_value);
- check(i64::max_value.to_bigint().unwrap(), i64::max_value);
+ check(i64::MIN.to_bigint().unwrap(), i64::MIN);
+ check(i64::MAX.to_bigint().unwrap(), i64::MAX);
assert_eq!(
- (i64::max_value as u64 + 1).to_bigint().unwrap().to_i64(),
+ (i64::MAX as u64 + 1).to_bigint().unwrap().to_i64(),
None);
assert_eq!(
check(Zero::zero(), 0);
check(One::one(), 1);
- check(u64::min_value.to_bigint().unwrap(), u64::min_value);
- check(u64::max_value.to_bigint().unwrap(), u64::max_value);
+ check(u64::MIN.to_bigint().unwrap(), u64::MIN);
+ check(u64::MAX.to_bigint().unwrap(), u64::MAX);
assert_eq!(
BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(),
None);
- let max_value: BigUint = FromPrimitive::from_u64(u64::max_value).unwrap();
+ let max_value: BigUint = FromPrimitive::from_u64(u64::MAX).unwrap();
assert_eq!(BigInt::from_biguint(Minus, max_value).to_u64(), None);
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(), None);
}
fn test_rand_range() {
let mut rng = task_rng();
- 10.times(|| {
+ for _ in range(0, 10) {
assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_uint(236).unwrap(),
&FromPrimitive::from_uint(237).unwrap()),
FromPrimitive::from_uint(236).unwrap());
- });
+ }
fn check(l: BigInt, u: BigInt) {
let mut rng = task_rng();
- 1000.times(|| {
+ for _ in range(0, 1000) {
let n: BigInt = rng.gen_bigint_range(&l, &u);
assert!(n >= l);
assert!(n < u);
- });
+ }
}
let l: BigInt = FromPrimitive::from_uint(403469000 + 2352).unwrap();
let u: BigInt = FromPrimitive::from_uint(403469000 + 3513).unwrap();
fn bench_grow(b: &mut test::BenchHarness) {
let mut deq = RingBuf::new();
b.iter(|| {
- 65.times(|| {
+ for _ in range(0, 65) {
deq.push_front(1);
- })
+ }
})
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
*/
-use std::borrow;
use std::comm;
use std::unstable::sync::Exclusive;
use std::sync::arc::UnsafeArc;
use std::util;
use std::util::NonCopyable;
+use arc::MutexArc;
+
/****************************************************************************
* Internals
****************************************************************************/
}
});
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
- /* 1000.times(|| task::deschedule()); */
+ /* for _ in range(0, 1000) { task::deschedule(); } */
// Need to wait outside the exclusive.
if waiter_nobe.is_some() {
let _ = waiter_nobe.unwrap().recv();
fn new_and_signal(count: int, num_condvars: uint)
-> Sem<~[WaitQueue]> {
let mut queues = ~[];
- num_condvars.times(|| queues.push(WaitQueue::new()));
+ for _ in range(0, num_condvars) { queues.push(WaitQueue::new()); }
Sem::new(count, queues)
}
}
/// To be called inside of the write_downgrade block.
pub fn downgrade<'a>(&self, token: RWLockWriteMode<'a>)
-> RWLockReadMode<'a> {
- if !borrow::ref_eq(self, token.lock) {
+ if !((self as *RWLock) == (token.lock as *RWLock)) {
fail!("Can't downgrade() with a different rwlock's write_mode!");
}
unsafe {
pub fn read<U>(&self, blk: || -> U) -> U { blk() }
}
+/// A barrier enables multiple tasks to synchronize the beginning
+/// of some computation.
+///
+/// ```rust
+/// use extra::sync::Barrier;
+///
+/// let barrier = Barrier::new(10);
+/// for _ in range(0, 10) {
+/// let c = barrier.clone();
+/// // The same messages will be printed together.
+/// // You will NOT see any interleaving.
+/// spawn(proc() {
+/// println!("before wait");
+/// c.wait();
+/// println!("after wait");
+/// });
+/// }
+/// ```
+#[deriving(Clone)]
+pub struct Barrier {
+ priv arc: MutexArc<BarrierState>,
+ priv num_tasks: uint,
+}
+
+// The inner state of a double barrier
+struct BarrierState {
+ count: uint,
+ generation_id: uint,
+}
+
+impl Barrier {
+ /// Create a new barrier that can block a given number of tasks.
+ pub fn new(num_tasks: uint) -> Barrier {
+ Barrier {
+ arc: MutexArc::new(BarrierState {
+ count: 0,
+ generation_id: 0,
+ }),
+ num_tasks: num_tasks,
+ }
+ }
+
+ /// Block the current task until a certain number of tasks is waiting.
+ pub fn wait(&self) {
+ self.arc.access_cond(|state, cond| {
+ let local_gen = state.generation_id;
+ state.count += 1;
+ if state.count < self.num_tasks {
+ // We need a while loop to guard against spurious wakeups.
+ // http://en.wikipedia.org/wiki/Spurious_wakeup
+ while local_gen == state.generation_id && state.count < self.num_tasks {
+ cond.wait();
+ }
+ } else {
+ state.count = 0;
+ state.generation_id += 1;
+ cond.broadcast();
+ }
+ });
+ }
+}
+
/****************************************************************************
* Tests
****************************************************************************/
use std::cast;
use std::result;
use std::task;
+ use std::comm::{SharedChan, Empty};
/************************************************************************
* Semaphore tests
fn test_sem_as_mutex() {
let s = Semaphore::new(1);
let s2 = s.clone();
- do task::spawn {
+ task::spawn(proc() {
s2.access(|| {
- 5.times(|| { task::deschedule(); })
+ for _ in range(0, 5) { task::deschedule(); }
})
- }
+ });
s.access(|| {
- 5.times(|| { task::deschedule(); })
+ for _ in range(0, 5) { task::deschedule(); }
})
}
#[test]
let (p, c) = Chan::new();
let s = Semaphore::new(0);
let s2 = s.clone();
- do task::spawn {
+ task::spawn(proc() {
s2.acquire();
c.send(());
- }
- 5.times(|| { task::deschedule(); });
+ });
+ for _ in range(0, 5) { task::deschedule(); }
s.release();
let _ = p.recv();
let (p, c) = Chan::new();
let s = Semaphore::new(0);
let s2 = s.clone();
- do task::spawn {
- 5.times(|| { task::deschedule(); });
+ task::spawn(proc() {
+ for _ in range(0, 5) { task::deschedule(); }
s2.release();
let _ = p.recv();
- }
+ });
s.acquire();
c.send(());
}
let s2 = s.clone();
let (p1,c1) = Chan::new();
let (p2,c2) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
s2.access(|| {
let _ = p2.recv();
c1.send(());
})
- }
+ });
s.access(|| {
c2.send(());
let _ = p1.recv();
let mut child_data = Some((s2, c));
s.access(|| {
let (s2, c) = child_data.take_unwrap();
- do task::spawn {
+ task::spawn(proc() {
c.send(());
s2.access(|| { });
c.send(());
- }
+ });
let _ = p.recv(); // wait for child to come alive
- 5.times(|| { task::deschedule(); }); // let the child contend
+ for _ in range(0, 5) { task::deschedule(); } // let the child contend
});
let _ = p.recv(); // wait for child to be done
}
let mut sharedstate = ~0;
{
let ptr: *int = &*sharedstate;
- do task::spawn {
+ task::spawn(proc() {
let sharedstate: &mut int =
unsafe { cast::transmute(ptr) };
access_shared(sharedstate, &m2, 10);
c.send(());
-
- }
+ });
}
{
access_shared(sharedstate, &m, 10);
}
fn access_shared(sharedstate: &mut int, m: &Mutex, n: uint) {
- n.times(|| {
+ for _ in range(0, n) {
m.lock(|| {
let oldval = *sharedstate;
task::deschedule();
*sharedstate = oldval + 1;
})
- })
+ }
}
}
#[test]
// Child wakes up parent
m.lock_cond(|cond| {
let m2 = m.clone();
- do task::spawn {
+ task::spawn(proc() {
m2.lock_cond(|cond| {
let woken = cond.signal();
assert!(woken);
})
- }
+ });
cond.wait();
});
// Parent wakes up child
let (port,chan) = Chan::new();
let m3 = m.clone();
- do task::spawn {
+ task::spawn(proc() {
m3.lock_cond(|cond| {
chan.send(());
cond.wait();
chan.send(());
})
- }
+ });
let _ = port.recv(); // Wait until child gets in the mutex
m.lock_cond(|cond| {
let woken = cond.signal();
let m = Mutex::new();
let mut ports = ~[];
- num_waiters.times(|| {
+ for _ in range(0, num_waiters) {
let mi = m.clone();
let (port, chan) = Chan::new();
ports.push(port);
- do task::spawn {
+ task::spawn(proc() {
mi.lock_cond(|cond| {
chan.send(());
cond.wait();
chan.send(());
})
- }
- });
+ });
+ }
// wait until all children get in the mutex
for port in ports.mut_iter() { let _ = port.recv(); }
fn test_mutex_cond_no_waiter() {
let m = Mutex::new();
let m2 = m.clone();
- do task::try {
+ task::try(proc() {
m.lock_cond(|_x| { })
- };
+ });
m2.lock_cond(|cond| {
assert!(!cond.signal());
})
let m = Mutex::new();
let m2 = m.clone();
- let result: result::Result<(), ~Any> = do task::try {
+ let result: result::Result<(), ~Any> = task::try(proc() {
m2.lock(|| {
fail!();
})
- };
+ });
assert!(result.is_err());
// child task must have finished by the time try returns
m.lock(|| { })
let m = Mutex::new();
let m2 = m.clone();
- let result: result::Result<(), ~Any> = do task::try {
+ let result: result::Result<(), ~Any> = task::try(proc() {
let (p, c) = Chan::new();
- do task::spawn { // linked
+ task::spawn(proc() { // linked
let _ = p.recv(); // wait for sibling to get in the mutex
task::deschedule();
fail!();
- }
+ });
m2.lock_cond(|cond| {
c.send(()); // tell sibling go ahead
cond.wait(); // block forever
})
- };
+ });
assert!(result.is_err());
// child task must have finished by the time try returns
m.lock_cond(|cond| {
let m2 = m.clone();
let (p, c) = Chan::new();
- let result: result::Result<(), ~Any> = do task::try {
+ let result: result::Result<(), ~Any> = task::try(proc() {
let mut sibling_convos = ~[];
- 2.times(|| {
+ for _ in range(0, 2) {
let (p, c) = Chan::new();
sibling_convos.push(p);
let mi = m2.clone();
// spawn sibling task
- do task::spawn { // linked
+ task::spawn(proc() { // linked
mi.lock_cond(|cond| {
c.send(()); // tell sibling to go ahead
(|| {
error!("task unwinding and done sending");
})
})
- }
- });
+ });
+ }
for p in sibling_convos.mut_iter() {
let _ = p.recv(); // wait for sibling to get in the mutex
}
m2.lock(|| { });
c.send(sibling_convos); // let parent wait on all children
fail!();
- };
+ });
assert!(result.is_err());
// child task must have finished by the time try returns
let mut r = p.recv();
let m = Mutex::new();
m.lock_cond(|cond| {
let m2 = m.clone();
- do task::spawn {
+ task::spawn(proc() {
m2.lock_cond(|cond| {
cond.signal_on(0);
})
- }
+ });
cond.wait();
})
}
#[test]
#[ignore(reason = "linked failure?")]
fn test_mutex_different_conds() {
- let result = do task::try {
+ let result = task::try(proc() {
let m = Mutex::new_with_condvars(2);
let m2 = m.clone();
let (p, c) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
m2.lock_cond(|cond| {
c.send(());
cond.wait_on(1);
})
- }
+ });
let _ = p.recv();
m.lock_cond(|cond| {
if !cond.signal_on(0) {
fail!(); // success; punt sibling awake.
}
})
- };
+ });
assert!(result.is_err());
}
#[test]
fn test_mutex_no_condvars() {
- let result = do task::try {
+ let result = task::try(proc() {
let m = Mutex::new_with_condvars(0);
m.lock_cond(|cond| { cond.wait(); })
- };
+ });
assert!(result.is_err());
- let result = do task::try {
+ let result = task::try(proc() {
let m = Mutex::new_with_condvars(0);
m.lock_cond(|cond| { cond.signal(); })
- };
+ });
assert!(result.is_err());
- let result = do task::try {
+ let result = task::try(proc() {
let m = Mutex::new_with_condvars(0);
m.lock_cond(|cond| { cond.broadcast(); })
- };
+ });
assert!(result.is_err());
}
/************************************************************************
let mut sharedstate = ~0;
{
let ptr: *int = &*sharedstate;
- do task::spawn {
+ task::spawn(proc() {
let sharedstate: &mut int =
unsafe { cast::transmute(ptr) };
access_shared(sharedstate, &x2, mode1, 10);
c.send(());
- }
+ });
}
{
access_shared(sharedstate, x, mode2, 10);
fn access_shared(sharedstate: &mut int, x: &RWLock, mode: RWLockMode,
n: uint) {
- n.times(|| {
+ for _ in range(0, n) {
lock_rwlock_in_mode(x, mode, || {
let oldval = *sharedstate;
task::deschedule();
*sharedstate = oldval + 1;
})
- })
+ }
}
}
#[test]
let x2 = x.clone();
let (p1, c1) = Chan::new();
let (p2, c2) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
if !make_mode2_go_first {
let _ = p2.recv(); // parent sends to us once it locks, or ...
}
let _ = p2.recv();
c1.send(());
})
- }
+ });
if make_mode2_go_first {
let _ = p1.recv(); // child sends to us once it locks, or ...
}
// Child wakes up parent
x.write_cond(|cond| {
let x2 = x.clone();
- do task::spawn {
+ task::spawn(proc() {
x2.write_cond(|cond| {
let woken = cond.signal();
assert!(woken);
})
- }
+ });
cond.wait();
});
// Parent wakes up child
let (port, chan) = Chan::new();
let x3 = x.clone();
- do task::spawn {
+ task::spawn(proc() {
x3.write_cond(|cond| {
chan.send(());
cond.wait();
chan.send(());
})
- }
+ });
let _ = port.recv(); // Wait until child gets in the rwlock
x.read(|| { }); // Must be able to get in as a reader in the meantime
x.write_cond(|cond| { // Or as another writer
let x = RWLock::new();
let mut ports = ~[];
- num_waiters.times(|| {
+ for _ in range(0, num_waiters) {
let xi = x.clone();
let (port, chan) = Chan::new();
ports.push(port);
- do task::spawn {
+ task::spawn(proc() {
lock_cond(&xi, dg1, |cond| {
chan.send(());
cond.wait();
chan.send(());
})
- }
- });
+ });
+ }
// wait until all children get in the mutex
for port in ports.mut_iter() { let _ = port.recv(); }
let x = RWLock::new();
let x2 = x.clone();
- let result: result::Result<(), ~Any> = do task::try || {
+ let result: result::Result<(), ~Any> = task::try(proc() {
lock_rwlock_in_mode(&x2, mode1, || {
fail!();
})
- };
+ });
assert!(result.is_err());
// child task must have finished by the time try returns
lock_rwlock_in_mode(&x, mode2, || { })
})
})
}
+
+ /************************************************************************
+ * Barrier tests
+ ************************************************************************/
+ #[test]
+ fn test_barrier() {
+ let barrier = Barrier::new(10);
+ let (port, chan) = SharedChan::new();
+
+ for _ in range(0, 9) {
+ let c = barrier.clone();
+ let chan = chan.clone();
+ spawn(proc() {
+ c.wait();
+ chan.send(true);
+ });
+ }
+
+ // At this point, all spawned tasks should be blocked,
+ // so we shouldn't get anything from the port
+ assert!(match port.try_recv() {
+ Empty => true,
+ _ => false,
+ });
+
+ barrier.wait();
+ // Now, the barrier is cleared and we should get data.
+ for _ in range(0, 9) {
+ port.recv();
+ }
+ }
}
g
};
let mut pool = TaskPool::new(4, f);
- 8.times(|| {
+ for _ in range(0, 8) {
pool.execute(proc(i) println!("Hello from thread {}!", *i));
- })
+ }
}
logfile: Option<Path>
}
-type OptRes = Result<TestOpts, ~str>;
+/// Result of parsing the options.
+pub type OptRes = Result<TestOpts, ~str>;
fn optgroups() -> ~[getopts::groups::OptGroup] {
~[groups::optflag("", "ignored", "Run ignored tests"),
TeResult(TestDesc, TestResult),
}
-type MonitorMsg = (TestDesc, TestResult);
+/// The message sent to the test monitor from the individual runners.
+pub type MonitorMsg = (TestDesc, TestResult);
fn run_tests(opts: &TestOpts,
tests: ~[TestDescAndFn],
fn run_test_inner(desc: TestDesc,
monitor_ch: SharedChan<MonitorMsg>,
testfn: proc()) {
- do spawn {
+ spawn(proc() {
let mut task = task::task();
task.name(match desc.name {
DynTestName(ref name) => SendStrOwned(name.clone()),
let task_result = result_future.recv();
let test_result = calc_result(&desc, task_result.is_ok());
monitor_ch.send((desc.clone(), test_result));
- }
+ });
}
match testfn {
return;
}
StaticBenchFn(benchfn) => {
- let bs = ::test::bench::benchmark(benchfn);
+ let bs = ::test::bench::benchmark(|harness| benchfn(harness));
monitor_ch.send((desc, TrBench(bs)));
return;
}
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(&[42]);
- 3.times(|| {
- 90.times(|| {
+ for _ in range(0, 3) {
+ for _ in range(0, 90) {
let k = rng.gen();
let v = rng.gen();
if !ctrl.iter().any(|x| x == &(k, v)) {
check_structure(&map);
check_equal(ctrl, &map);
}
- });
+ }
- 30.times(|| {
+ for _ in range(0, 30) {
let r = rng.gen_range(0, ctrl.len());
let (key, _) = ctrl.remove(r).unwrap();
assert!(map.remove(&key));
check_structure(&map);
check_equal(ctrl, &map);
- });
- })
+ }
+ }
}
#[test]
let mut bytes = [0, 0];
match rdr.read(bytes) {
Some(2) => {}
- _ => fail!() // XXX: malformed url?
+ _ => fail!() // FIXME: malformed url?
}
let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char;
let mut bytes = [0, 0];
match rdr.read(bytes) {
Some(2) => {}
- _ => fail!() // XXX: malformed?
+ _ => fail!() // FIXME: malformed?
}
uint::parse_bytes(bytes, 16u).unwrap() as u8 as char
}
let (port, chan) = Chan::new();
let blk = bo.take_unwrap();
- // XXX: What happens if the task fails?
- do spawn {
+ // FIXME: What happens if the task fails?
+ spawn(proc() {
let mut exe = Exec {
discovered_inputs: WorkMap::new(),
discovered_outputs: WorkMap::new(),
};
let v = blk(&mut exe);
chan.send((exe, v));
- }
+ });
Work::from_task(self, port)
}
}
// FIXME (#9639): This needs to handle non-utf8 paths
prep.declare_input("file", pth.as_str().unwrap(), file_content);
- do prep.exec |_exe| {
+ prep.exec(proc(_exe) {
let out = make_path(~"foo.o");
// FIXME (#9639): This needs to handle non-utf8 paths
run::process_status("gcc", [pth.as_str().unwrap().to_owned(),
// FIXME (#9639): This needs to handle non-utf8 paths
out.as_str().unwrap().to_owned()
- }
+ })
});
println!("{}", s);
--- /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.
+
+/*!
+
+Simple compression
+
+*/
+
+#[crate_id = "flate#0.10-pre"];
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
+#[license = "MIT/ASL2"];
+#[allow(missing_doc)];
+
+use std::libc::{c_void, size_t, c_int};
+use std::libc;
+use std::vec;
+
+pub mod rustrt {
+ use std::libc::{c_int, c_void, size_t};
+
+ #[link(name = "miniz", kind = "static")]
+ extern {
+ pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
+ src_buf_len: size_t,
+ pout_len: *mut size_t,
+ flags: c_int)
+ -> *c_void;
+
+ pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
+ src_buf_len: size_t,
+ pout_len: *mut size_t,
+ flags: c_int)
+ -> *c_void;
+ }
+}
+
+static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal"
+static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
+static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
+
+fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ unsafe {
+ let mut outsz : size_t = 0;
+ let res = rustrt::tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void,
+ bytes.len() as size_t,
+ &mut outsz,
+ flags);
+ assert!(res as int != 0);
+ let out = vec::raw::from_buf_raw(res as *u8,
+ outsz as uint);
+ libc::free(res as *mut c_void);
+ out
+ }
+}
+
+pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
+ deflate_bytes_internal(bytes, LZ_NORM)
+}
+
+pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
+ deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
+}
+
+fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ unsafe {
+ let mut outsz : size_t = 0;
+ let res = rustrt::tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void,
+ bytes.len() as size_t,
+ &mut outsz,
+ flags);
+ assert!(res as int != 0);
+ let out = vec::raw::from_buf_raw(res as *u8,
+ outsz as uint);
+ libc::free(res as *mut c_void);
+ out
+ }
+}
+
+pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
+ inflate_bytes_internal(bytes, 0)
+}
+
+pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
+ inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{inflate_bytes, deflate_bytes};
+ use std::rand;
+ use std::rand::Rng;
+
+ #[test]
+ fn test_flate_round_trip() {
+ let mut r = rand::rng();
+ let mut words = ~[];
+ for _ in range(0, 20) {
+ let range = r.gen_range(1u, 10);
+ words.push(r.gen_vec::<u8>(range));
+ }
+ for _ in range(0, 20) {
+ let mut input = ~[];
+ for _ in range(0, 2000) {
+ input.push_all(r.choose(words));
+ }
+ debug!("de/inflate of {} bytes of random word-sequences",
+ input.len());
+ let cmp = deflate_bytes(input);
+ let out = inflate_bytes(cmp);
+ debug!("{} bytes deflated to {} ({:.1f}% size)",
+ input.len(), cmp.len(),
+ 100.0 * ((cmp.len() as f64) / (input.len() as f64)));
+ assert_eq!(input, out);
+ }
+ }
+
+ #[test]
+ fn test_zlib_flate() {
+ let bytes = ~[1, 2, 3, 4, 5];
+ let deflated = deflate_bytes(bytes);
+ let inflated = inflate_bytes(deflated);
+ assert_eq!(inflated, bytes);
+ }
+}
--- /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.
+
+/*!
+ * Support for matching file paths against Unix shell style patterns.
+ *
+ * The `glob` and `glob_with` functions, in concert with the `Paths`
+ * type, allow querying the filesystem for all files that match a particular
+ * pattern - just like the libc `glob` function (for an example see the `glob`
+ * documentation). The methods on the `Pattern` type provide functionality
+ * for checking if individual paths match a particular pattern - in a similar
+ * manner to the libc `fnmatch` function
+ *
+ * For consistency across platforms, and for Windows support, this module
+ * is implemented entirely in Rust rather than deferring to the libc
+ * `glob`/`fnmatch` functions.
+ */
+
+#[crate_id = "glob#0.10-pre"];
+#[crate_type = "rlib"];
+#[crate_type = "dylib"];
+#[license = "MIT/ASL2"];
+
+use std::{os, path};
+use std::io;
+use std::io::fs;
+use std::path::is_sep;
+
+/**
+ * An iterator that yields Paths from the filesystem that match a particular
+ * pattern - see the `glob` function for more details.
+ */
+pub struct Paths {
+ priv root: Path,
+ priv dir_patterns: ~[Pattern],
+ priv options: MatchOptions,
+ priv todo: ~[(Path,uint)]
+}
+
+///
+/// Return an iterator that produces all the Paths that match the given pattern,
+/// which may be absolute or relative to the current working directory.
+///
+/// is method uses the default match options and is equivalent to calling
+/// `glob_with(pattern, MatchOptions::new())`. Use `glob_with` directly if you
+/// want to use non-default match options.
+///
+/// # Example
+///
+/// Consider a directory `/media/pictures` containing only the files `kittens.jpg`,
+/// `puppies.jpg` and `hamsters.gif`:
+///
+/// ```rust
+/// use glob::glob;
+///
+/// for path in glob("/media/pictures/*.jpg") {
+/// println!("{}", path.display());
+/// }
+/// ```
+///
+/// The above code will print:
+///
+/// ```
+/// /media/pictures/kittens.jpg
+/// /media/pictures/puppies.jpg
+/// ```
+///
+pub fn glob(pattern: &str) -> Paths {
+ glob_with(pattern, MatchOptions::new())
+}
+
+/**
+ * Return an iterator that produces all the Paths that match the given pattern,
+ * which may be absolute or relative to the current working directory.
+ *
+ * This function accepts Unix shell style patterns as described by `Pattern::new(..)`.
+ * The options given are passed through unchanged to `Pattern::matches_with(..)` with
+ * the exception that `require_literal_separator` is always set to `true` regardless of the
+ * value passed to this function.
+ *
+ * Paths are yielded in alphabetical order, as absolute paths.
+ */
+pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
+ #[cfg(windows)]
+ fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
+ #[cfg(not(windows))]
+ fn check_windows_verbatim(_: &Path) -> bool { false }
+
+ // calculate root this way to handle volume-relative Windows paths correctly
+ let mut root = os::getcwd();
+ let pat_root = Path::new(pattern).root_path();
+ if pat_root.is_some() {
+ if check_windows_verbatim(pat_root.get_ref()) {
+ // FIXME: How do we want to handle verbatim paths? I'm inclined to return nothing,
+ // since we can't very well find all UNC shares with a 1-letter server name.
+ return Paths { root: root, dir_patterns: ~[], options: options, todo: ~[] };
+ }
+ root.push(pat_root.get_ref());
+ }
+
+ let root_len = pat_root.map_or(0u, |p| p.as_vec().len());
+ let dir_patterns = pattern.slice_from(root_len.min(&pattern.len()))
+ .split_terminator(is_sep).map(|s| Pattern::new(s)).to_owned_vec();
+
+ let todo = list_dir_sorted(&root).move_iter().map(|x|(x,0u)).to_owned_vec();
+
+ Paths {
+ root: root,
+ dir_patterns: dir_patterns,
+ options: options,
+ todo: todo,
+ }
+}
+
+impl Iterator<Path> for Paths {
+
+ fn next(&mut self) -> Option<Path> {
+ loop {
+ if self.dir_patterns.is_empty() || self.todo.is_empty() {
+ return None;
+ }
+
+ let (path,idx) = self.todo.pop().unwrap();
+ let ref pattern = self.dir_patterns[idx];
+
+ if pattern.matches_with(match path.filename_str() {
+ // this ugly match needs to go here to avoid a borrowck error
+ None => {
+ // FIXME (#9639): How do we handle non-utf8 filenames? Ignore them for now
+ // Ideally we'd still match them against a *
+ continue;
+ }
+ Some(x) => x
+ }, self.options) {
+ if idx == self.dir_patterns.len() - 1 {
+ // it is not possible for a pattern to match a directory *AND* its children
+ // so we don't need to check the children
+ return Some(path);
+ } else {
+ self.todo.extend(&mut list_dir_sorted(&path).move_iter().map(|x|(x,idx+1)));
+ }
+ }
+ }
+ }
+
+}
+
+fn list_dir_sorted(path: &Path) -> ~[Path] {
+ match io::result(|| fs::readdir(path)) {
+ Ok(mut children) => {
+ children.sort_by(|p1, p2| p2.filename().cmp(&p1.filename()));
+ children
+ }
+ Err(..) => ~[]
+ }
+}
+
+/**
+ * A compiled Unix shell style pattern.
+ */
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
+pub struct Pattern {
+ priv tokens: ~[PatternToken]
+}
+
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+enum PatternToken {
+ Char(char),
+ AnyChar,
+ AnySequence,
+ AnyWithin(~[CharSpecifier]),
+ AnyExcept(~[CharSpecifier])
+}
+
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+enum CharSpecifier {
+ SingleChar(char),
+ CharRange(char, char)
+}
+
+#[deriving(Eq)]
+enum MatchResult {
+ Match,
+ SubPatternDoesntMatch,
+ EntirePatternDoesntMatch
+}
+
+impl Pattern {
+
+ /**
+ * This function compiles Unix shell style patterns: `?` matches any single
+ * character, `*` matches any (possibly empty) sequence of characters and
+ * `[...]` matches any character inside the brackets, unless the first
+ * character is `!` in which case it matches any character except those
+ * between the `!` and the `]`. Character sequences can also specify ranges
+ * of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any
+ * character between 0 and 9 inclusive.
+ *
+ * The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets
+ * (e.g. `[?]`). When a `]` occurs immediately following `[` or `[!` then
+ * it is interpreted as being part of, rather then ending, the character
+ * set, so `]` and NOT `]` can be matched by `[]]` and `[!]]` respectively.
+ * The `-` character can be specified inside a character sequence pattern by
+ * placing it at the start or the end, e.g. `[abc-]`.
+ *
+ * When a `[` does not have a closing `]` before the end of the string then
+ * the `[` will be treated literally.
+ */
+ pub fn new(pattern: &str) -> Pattern {
+
+ let chars = pattern.chars().to_owned_vec();
+ let mut tokens = ~[];
+ let mut i = 0;
+
+ while i < chars.len() {
+ match chars[i] {
+ '?' => {
+ tokens.push(AnyChar);
+ i += 1;
+ }
+ '*' => {
+ // *, **, ***, ****, ... are all equivalent
+ while i < chars.len() && chars[i] == '*' {
+ i += 1;
+ }
+ tokens.push(AnySequence);
+ }
+ '[' => {
+
+ if i <= chars.len() - 4 && chars[i + 1] == '!' {
+ match chars.slice_from(i + 3).position_elem(&']') {
+ None => (),
+ Some(j) => {
+ let chars = chars.slice(i + 2, i + 3 + j);
+ let cs = parse_char_specifiers(chars);
+ tokens.push(AnyExcept(cs));
+ i += j + 4;
+ continue;
+ }
+ }
+ }
+ else if i <= chars.len() - 3 && chars[i + 1] != '!' {
+ match chars.slice_from(i + 2).position_elem(&']') {
+ None => (),
+ Some(j) => {
+ let cs = parse_char_specifiers(chars.slice(i + 1, i + 2 + j));
+ tokens.push(AnyWithin(cs));
+ i += j + 3;
+ continue;
+ }
+ }
+ }
+
+ // if we get here then this is not a valid range pattern
+ tokens.push(Char('['));
+ i += 1;
+ }
+ c => {
+ tokens.push(Char(c));
+ i += 1;
+ }
+ }
+ }
+
+ Pattern { tokens: tokens }
+ }
+
+ /**
+ * Escape metacharacters within the given string by surrounding them in
+ * brackets. The resulting string will, when compiled into a `Pattern`,
+ * match the input string and nothing else.
+ */
+ pub fn escape(s: &str) -> ~str {
+ let mut escaped = ~"";
+ for c in s.chars() {
+ match c {
+ // note that ! does not need escaping because it is only special inside brackets
+ '?' | '*' | '[' | ']' => {
+ escaped.push_char('[');
+ escaped.push_char(c);
+ escaped.push_char(']');
+ }
+ c => {
+ escaped.push_char(c);
+ }
+ }
+ }
+ escaped
+ }
+
+ /**
+ * Return if the given `str` matches this `Pattern` using the default
+ * match options (i.e. `MatchOptions::new()`).
+ *
+ * # Example
+ *
+ * ```rust
+ * use glob::Pattern;
+ *
+ * assert!(Pattern::new("c?t").matches("cat"));
+ * assert!(Pattern::new("k[!e]tteh").matches("kitteh"));
+ * assert!(Pattern::new("d*g").matches("doog"));
+ * ```
+ */
+ pub fn matches(&self, str: &str) -> bool {
+ self.matches_with(str, MatchOptions::new())
+ }
+
+ /**
+ * Return if the given `Path`, when converted to a `str`, matches this `Pattern`
+ * using the default match options (i.e. `MatchOptions::new()`).
+ */
+ pub fn matches_path(&self, path: &Path) -> bool {
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ path.as_str().map_or(false, |s| {
+ self.matches(s)
+ })
+ }
+
+ /**
+ * Return if the given `str` matches this `Pattern` using the specified match options.
+ */
+ pub fn matches_with(&self, str: &str, options: MatchOptions) -> bool {
+ self.matches_from(None, str, 0, options) == Match
+ }
+
+ /**
+ * Return if the given `Path`, when converted to a `str`, matches this `Pattern`
+ * using the specified match options.
+ */
+ pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool {
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ path.as_str().map_or(false, |s| {
+ self.matches_with(s, options)
+ })
+ }
+
+ fn matches_from(&self,
+ mut prev_char: Option<char>,
+ mut file: &str,
+ i: uint,
+ options: MatchOptions) -> MatchResult {
+
+ let require_literal = |c| {
+ (options.require_literal_separator && is_sep(c)) ||
+ (options.require_literal_leading_dot && c == '.'
+ && is_sep(prev_char.unwrap_or('/')))
+ };
+
+ for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
+ match *token {
+ AnySequence => {
+ loop {
+ match self.matches_from(prev_char, file, i + ti + 1, options) {
+ SubPatternDoesntMatch => (), // keep trying
+ m => return m,
+ }
+
+ if file.is_empty() {
+ return EntirePatternDoesntMatch;
+ }
+
+ let (c, next) = file.slice_shift_char();
+ if require_literal(c) {
+ return SubPatternDoesntMatch;
+ }
+ prev_char = Some(c);
+ file = next;
+ }
+ }
+ _ => {
+ if file.is_empty() {
+ return EntirePatternDoesntMatch;
+ }
+
+ let (c, next) = file.slice_shift_char();
+ let matches = match *token {
+ AnyChar => {
+ !require_literal(c)
+ }
+ AnyWithin(ref specifiers) => {
+ !require_literal(c) && in_char_specifiers(*specifiers, c, options)
+ }
+ AnyExcept(ref specifiers) => {
+ !require_literal(c) && !in_char_specifiers(*specifiers, c, options)
+ }
+ Char(c2) => {
+ chars_eq(c, c2, options.case_sensitive)
+ }
+ AnySequence => {
+ unreachable!()
+ }
+ };
+ if !matches {
+ return SubPatternDoesntMatch;
+ }
+ prev_char = Some(c);
+ file = next;
+ }
+ }
+ }
+
+ if file.is_empty() {
+ Match
+ } else {
+ SubPatternDoesntMatch
+ }
+ }
+
+}
+
+fn parse_char_specifiers(s: &[char]) -> ~[CharSpecifier] {
+ let mut cs = ~[];
+ let mut i = 0;
+ while i < s.len() {
+ if i + 3 <= s.len() && s[i + 1] == '-' {
+ cs.push(CharRange(s[i], s[i + 2]));
+ i += 3;
+ } else {
+ cs.push(SingleChar(s[i]));
+ i += 1;
+ }
+ }
+ cs
+}
+
+fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool {
+
+ for &specifier in specifiers.iter() {
+ match specifier {
+ SingleChar(sc) => {
+ if chars_eq(c, sc, options.case_sensitive) {
+ return true;
+ }
+ }
+ CharRange(start, end) => {
+
+ // FIXME: work with non-ascii chars properly (issue #1347)
+ if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {
+
+ let start = start.to_ascii().to_lower();
+ let end = end.to_ascii().to_lower();
+
+ let start_up = start.to_upper();
+ let end_up = end.to_upper();
+
+ // only allow case insensitive matching when
+ // both start and end are within a-z or A-Z
+ if start != start_up && end != end_up {
+ let start = start.to_char();
+ let end = end.to_char();
+ let c = c.to_ascii().to_lower().to_char();
+ if c >= start && c <= end {
+ return true;
+ }
+ }
+ }
+
+ if c >= start && c <= end {
+ return true;
+ }
+ }
+ }
+ }
+
+ false
+}
+
+/// A helper function to determine if two chars are (possibly case-insensitively) equal.
+fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
+ if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
+ true
+ } else if !case_sensitive && a.is_ascii() && b.is_ascii() {
+ // FIXME: work with non-ascii chars properly (issue #1347)
+ a.to_ascii().eq_ignore_case(b.to_ascii())
+ } else {
+ a == b
+ }
+}
+
+/**
+ * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
+ */
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
+pub struct MatchOptions {
+
+ /**
+ * Whether or not patterns should be matched in a case-sensitive manner. This
+ * currently only considers upper/lower case relationships between ASCII characters,
+ * but in future this might be extended to work with Unicode.
+ */
+ priv case_sensitive: bool,
+
+ /**
+ * If this is true then path-component separator characters (e.g. `/` on Posix)
+ * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
+ */
+ priv require_literal_separator: bool,
+
+ /**
+ * If this is true then paths that contain components that start with a `.` will
+ * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
+ * will not match. This is useful because such files are conventionally considered
+ * hidden on Unix systems and it might be desirable to skip them when listing files.
+ */
+ priv require_literal_leading_dot: bool
+}
+
+impl MatchOptions {
+
+ /**
+ * Constructs a new `MatchOptions` with default field values. This is used
+ * when calling functions that do not take an explicit `MatchOptions` parameter.
+ *
+ * This function always returns this value:
+ *
+ * ```rust,ignore
+ * MatchOptions {
+ * case_sensitive: true,
+ * require_literal_separator: false.
+ * require_literal_leading_dot: false
+ * }
+ * ```
+ */
+ pub fn new() -> MatchOptions {
+ MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ }
+ }
+
+}
+
+#[cfg(test)]
+mod test {
+ use std::os;
+ use super::{glob, Pattern, MatchOptions};
+
+ #[test]
+ fn test_absolute_pattern() {
+ // assume that the filesystem is not empty!
+ assert!(glob("/*").next().is_some());
+ assert!(glob("//").next().is_none());
+
+ // check windows absolute paths with host/device components
+ let root_with_device = os::getcwd().root_path().unwrap().join("*");
+ // FIXME (#9639): This needs to handle non-utf8 paths
+ assert!(glob(root_with_device.as_str().unwrap()).next().is_some());
+ }
+
+ #[test]
+ fn test_wildcard_optimizations() {
+ assert!(Pattern::new("a*b").matches("a___b"));
+ assert!(Pattern::new("a**b").matches("a___b"));
+ assert!(Pattern::new("a***b").matches("a___b"));
+ assert!(Pattern::new("a*b*c").matches("abc"));
+ assert!(!Pattern::new("a*b*c").matches("abcd"));
+ assert!(Pattern::new("a*b*c").matches("a_b_c"));
+ assert!(Pattern::new("a*b*c").matches("a___b___c"));
+ assert!(Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabc"));
+ assert!(!Pattern::new("abc*abc*abc").matches("abcabcabcabcabcabcabca"));
+ assert!(Pattern::new("a*a*a*a*a*a*a*a*a").matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ assert!(Pattern::new("a*b[xyz]c*d").matches("abxcdbxcddd"));
+ }
+
+ #[test]
+ fn test_lots_of_files() {
+ // this is a good test because it touches lots of differently named files
+ glob("/*/*/*/*").skip(10000).next();
+ }
+
+ #[test]
+ fn test_range_pattern() {
+
+ let pat = Pattern::new("a[0-9]b");
+ for i in range(0, 10) {
+ assert!(pat.matches(format!("a{}b", i)));
+ }
+ assert!(!pat.matches("a_b"));
+
+ let pat = Pattern::new("a[!0-9]b");
+ for i in range(0, 10) {
+ assert!(!pat.matches(format!("a{}b", i)));
+ }
+ assert!(pat.matches("a_b"));
+
+ let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"];
+ for &p in pats.iter() {
+ let pat = Pattern::new(p);
+ for c in "abcdefghijklmnopqrstuvwxyz".chars() {
+ assert!(pat.matches(c.to_str()));
+ }
+ for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() {
+ let options = MatchOptions {case_sensitive: false, .. MatchOptions::new()};
+ assert!(pat.matches_with(c.to_str(), options));
+ }
+ assert!(pat.matches("1"));
+ assert!(pat.matches("2"));
+ assert!(pat.matches("3"));
+ }
+
+ let pats = ["[abc-]", "[-abc]", "[a-c-]"];
+ for &p in pats.iter() {
+ let pat = Pattern::new(p);
+ assert!(pat.matches("a"));
+ assert!(pat.matches("b"));
+ assert!(pat.matches("c"));
+ assert!(pat.matches("-"));
+ assert!(!pat.matches("d"));
+ }
+
+ let pat = Pattern::new("[2-1]");
+ assert!(!pat.matches("1"));
+ assert!(!pat.matches("2"));
+
+ assert!(Pattern::new("[-]").matches("-"));
+ assert!(!Pattern::new("[!-]").matches("-"));
+ }
+
+ #[test]
+ fn test_unclosed_bracket() {
+ // unclosed `[` should be treated literally
+ assert!(Pattern::new("abc[def").matches("abc[def"));
+ assert!(Pattern::new("abc[!def").matches("abc[!def"));
+ assert!(Pattern::new("abc[").matches("abc["));
+ assert!(Pattern::new("abc[!").matches("abc[!"));
+ assert!(Pattern::new("abc[d").matches("abc[d"));
+ assert!(Pattern::new("abc[!d").matches("abc[!d"));
+ assert!(Pattern::new("abc[]").matches("abc[]"));
+ assert!(Pattern::new("abc[!]").matches("abc[!]"));
+ }
+
+ #[test]
+ fn test_pattern_matches() {
+ let txt_pat = Pattern::new("*hello.txt");
+ assert!(txt_pat.matches("hello.txt"));
+ assert!(txt_pat.matches("gareth_says_hello.txt"));
+ assert!(txt_pat.matches("some/path/to/hello.txt"));
+ assert!(txt_pat.matches("some\\path\\to\\hello.txt"));
+ assert!(txt_pat.matches("/an/absolute/path/to/hello.txt"));
+ assert!(!txt_pat.matches("hello.txt-and-then-some"));
+ assert!(!txt_pat.matches("goodbye.txt"));
+
+ let dir_pat = Pattern::new("*some/path/to/hello.txt");
+ assert!(dir_pat.matches("some/path/to/hello.txt"));
+ assert!(dir_pat.matches("a/bigger/some/path/to/hello.txt"));
+ assert!(!dir_pat.matches("some/path/to/hello.txt-and-then-some"));
+ assert!(!dir_pat.matches("some/other/path/to/hello.txt"));
+ }
+
+ #[test]
+ fn test_pattern_escape() {
+ let s = "_[_]_?_*_!_";
+ assert_eq!(Pattern::escape(s), ~"_[[]_[]]_[?]_[*]_!_");
+ assert!(Pattern::new(Pattern::escape(s)).matches(s));
+ }
+
+ #[test]
+ fn test_pattern_matches_case_insensitive() {
+
+ let pat = Pattern::new("aBcDeFg");
+ let options = MatchOptions {
+ case_sensitive: false,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ };
+
+ assert!(pat.matches_with("aBcDeFg", options));
+ assert!(pat.matches_with("abcdefg", options));
+ assert!(pat.matches_with("ABCDEFG", options));
+ assert!(pat.matches_with("AbCdEfG", options));
+ }
+
+ #[test]
+ fn test_pattern_matches_case_insensitive_range() {
+
+ let pat_within = Pattern::new("[a]");
+ let pat_except = Pattern::new("[!a]");
+
+ let options_case_insensitive = MatchOptions {
+ case_sensitive: false,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ };
+ let options_case_sensitive = MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ };
+
+ assert!(pat_within.matches_with("a", options_case_insensitive));
+ assert!(pat_within.matches_with("A", options_case_insensitive));
+ assert!(!pat_within.matches_with("A", options_case_sensitive));
+
+ assert!(!pat_except.matches_with("a", options_case_insensitive));
+ assert!(!pat_except.matches_with("A", options_case_insensitive));
+ assert!(pat_except.matches_with("A", options_case_sensitive));
+ }
+
+ #[test]
+ fn test_pattern_matches_require_literal_separator() {
+
+ let options_require_literal = MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: true,
+ require_literal_leading_dot: false
+ };
+ let options_not_require_literal = MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ };
+
+ assert!(Pattern::new("abc/def").matches_with("abc/def", options_require_literal));
+ assert!(!Pattern::new("abc?def").matches_with("abc/def", options_require_literal));
+ assert!(!Pattern::new("abc*def").matches_with("abc/def", options_require_literal));
+ assert!(!Pattern::new("abc[/]def").matches_with("abc/def", options_require_literal));
+
+ assert!(Pattern::new("abc/def").matches_with("abc/def", options_not_require_literal));
+ assert!(Pattern::new("abc?def").matches_with("abc/def", options_not_require_literal));
+ assert!(Pattern::new("abc*def").matches_with("abc/def", options_not_require_literal));
+ assert!(Pattern::new("abc[/]def").matches_with("abc/def", options_not_require_literal));
+ }
+
+ #[test]
+ fn test_pattern_matches_require_literal_leading_dot() {
+
+ let options_require_literal_leading_dot = MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: false,
+ require_literal_leading_dot: true
+ };
+ let options_not_require_literal_leading_dot = MatchOptions {
+ case_sensitive: true,
+ require_literal_separator: false,
+ require_literal_leading_dot: false
+ };
+
+ let f = |options| Pattern::new("*.txt").matches_with(".hello.txt", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(!f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new(".*.*").matches_with(".hello.txt", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/.ccc", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(!f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new("aaa/bbb/*").matches_with("aaa/bbb/c.c.c.", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new("aaa/bbb/.*").matches_with("aaa/bbb/.ccc", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new("aaa/?bbb").matches_with("aaa/.bbb", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(!f(options_require_literal_leading_dot));
+
+ let f = |options| Pattern::new("aaa/[.]bbb").matches_with("aaa/.bbb", options);
+ assert!(f(options_not_require_literal_leading_dot));
+ assert!(!f(options_require_literal_leading_dot));
+ }
+
+ #[test]
+ fn test_matches_path() {
+ // on windows, (Path::new("a/b").as_str().unwrap() == "a\\b"), so this
+ // tests that / and \ are considered equivalent on windows
+ assert!(Pattern::new("a/b").matches_path(&Path::new("a/b")));
+ }
+}
self.work.push(f);
}
- // XXX: Seems like a really weird requirement to have an event loop provide.
+ // FIXME: Seems like a really weird requirement to have an event loop provide.
fn pausable_idle_callback(&mut self, cb: ~Callback) -> ~PausableIdleCallback {
let callback = ~BasicPausable::new(self, cb);
rtassert!(self.idle.is_none());
#[test]
fn smoke() {
- do run {}
+ run(proc() {});
}
#[test]
fn some_channels() {
- do run {
+ run(proc() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
c.send(());
- }
+ });
p.recv();
- }
+ });
}
#[test]
});
for _ in range(0, 20) {
- do pool.spawn(TaskOpts::new()) {
+ pool.spawn(TaskOpts::new(), proc() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
c.send(());
- }
+ });
p.recv();
- }
+ });
}
pool.shutdown();
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use std::uint;
use std::cast::{transmute, transmute_mut_unsafe,
transmute_region, transmute_mut_region};
+use stack::Stack;
use std::unstable::stack;
-use stack::StackSegment;
-
// FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
// SSE regs. It would be marginally better not to do this. In C++ we
// use an attribute on a struct.
}
/// Create a new context that will resume execution by running proc()
- pub fn new(start: proc(), stack: &mut StackSegment) -> Context {
+ pub fn new(start: proc(), stack: &mut Stack) -> Context {
// The C-ABI function that is the task entry point
//
// Note that this function is a little sketchy. We're taking a
// be passed to the spawn function. Another unfortunate
// allocation
let start = ~start;
+
initialize_call_frame(&mut *regs,
task_start_wrapper as *c_void,
unsafe { transmute(&*start) },
// If we're going back to one of the original contexts or
// something that's possibly not a "normal task", then reset
// the stack limit to 0 to make morestack never fail
- None => stack::record_stack_bounds(0, uint::max_value),
+ None => stack::record_stack_bounds(0, uint::MAX),
}
rust_swap_registers(out_regs, in_regs)
}
use std::rt::env;
use context::Context;
-use stack::{StackPool, StackSegment};
+use stack::{StackPool, Stack};
/// A coroutine is nothing more than a (register context, stack) pair.
pub struct Coroutine {
///
/// Servo needs this to be public in order to tell SpiderMonkey
/// about the stack bounds.
- current_stack_segment: StackSegment,
+ current_stack_segment: Stack,
/// Always valid if the task is alive and not running.
saved_context: Context
Some(size) => size,
None => env::min_stack()
};
- let mut stack = stack_pool.take_segment(stack_size);
+ let mut stack = stack_pool.take_stack(stack_size);
let initial_context = Context::new(start, &mut stack);
Coroutine {
current_stack_segment: stack,
pub fn empty() -> Coroutine {
Coroutine {
- current_stack_segment: StackSegment::new(0),
+ current_stack_segment: unsafe { Stack::dummy_stack() },
saved_context: Context::empty()
}
}
/// Destroy coroutine and try to reuse std::stack segment.
pub fn recycle(self, stack_pool: &mut StackPool) {
let Coroutine { current_stack_segment, .. } = self;
- stack_pool.give_segment(current_stack_segment);
+ stack_pool.give_stack(current_stack_segment);
}
}
#[cfg(not(test))]
pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
use std::cast;
- do start(argc, argv) {
+ start(argc, argv, proc() {
let main: extern "Rust" fn() = unsafe { cast::transmute(main) };
main();
- }
+ })
}
/// Set up a default runtime configuration, given compiler-supplied arguments.
pool.task_state.clone());
pool.handles.push(sched.make_handle());
let sched = sched;
- pool.threads.push(do Thread::start { sched.bootstrap(); });
+ pool.threads.push(Thread::start(proc() { sched.bootstrap(); }));
}
return pool;
let ret = sched.make_handle();
self.handles.push(sched.make_handle());
let sched = sched;
- self.threads.push(do Thread::start { sched.bootstrap() });
+ self.threads.push(Thread::start(proc() { sched.bootstrap() }));
return ret;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// XXX: this file probably shouldn't exist
+// FIXME: this file probably shouldn't exist
#[macro_escape];
use std::fmt;
// Indicates whether we should perform expensive sanity checks, including rtassert!
-// XXX: Once the runtime matures remove the `true` below to turn off rtassert, etc.
+// FIXME: Once the runtime matures remove the `true` below to turn off rtassert, etc.
pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert);
macro_rules! rterrln (
/// struct. The scheduler struct acts like a baton, all scheduling
/// actions are transfers of the baton.
///
-/// XXX: This creates too many callbacks to run_sched_once, resulting
+/// FIXME: This creates too many callbacks to run_sched_once, resulting
/// in too much allocation and too many events.
pub struct Scheduler {
/// ID number of the pool that this scheduler is a member of. When
return sched;
}
- // XXX: This may eventually need to be refactored so that
+ // FIXME: This may eventually need to be refactored so that
// the scheduler itself doesn't have to call event_loop.run.
// That will be important for embedding the runtime into external
// event loops.
}
}
-// XXX: Some hacks to put a || closure in Scheduler without borrowck
+// FIXME: Some hacks to put a || closure in Scheduler without borrowck
// complaining
type UnsafeTaskReceiver = raw::Closure;
trait ClosureConverter {
fn trivial_run_in_newsched_task_test() {
let mut task_ran = false;
let task_ran_ptr: *mut bool = &mut task_ran;
- do run {
+ run(proc() {
unsafe { *task_ran_ptr = true };
rtdebug!("executed from the new scheduler")
- }
+ });
assert!(task_ran);
}
let task_run_count_ptr: *mut uint = &mut task_run_count;
// with only one thread this is safe to run in without worries of
// contention.
- do run {
+ run(proc() {
for _ in range(0u, total) {
- do spawn || {
+ spawn(proc() {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1};
- }
+ });
}
- }
+ });
assert!(task_run_count == total);
}
fn multiple_task_nested_test() {
let mut task_run_count = 0;
let task_run_count_ptr: *mut uint = &mut task_run_count;
- do run {
- do spawn {
+ run(proc() {
+ spawn(proc() {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
- do spawn {
+ spawn(proc() {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
- do spawn {
+ spawn(proc() {
unsafe { *task_run_count_ptr = *task_run_count_ptr + 1 };
- }
- }
- }
- }
+ })
+ })
+ })
+ });
assert!(task_run_count == 3);
}
let mut handle1 = pool.spawn_sched();
let mut handle2 = pool.spawn_sched();
- handle1.send(TaskFromFriend(do pool.task(TaskOpts::new()) {
+ handle1.send(TaskFromFriend(pool.task(TaskOpts::new(), proc() {
chan.send(sched_id());
- }));
+ })));
let sched1_id = port.recv();
- let mut task = do pool.task(TaskOpts::new()) {
+ let mut task = pool.task(TaskOpts::new(), proc() {
assert_eq!(sched_id(), sched1_id);
dchan.send(());
- };
+ });
task.give_home(HomeSched(handle1));
handle2.send(TaskFromFriend(task));
}
use std::rt::thread::Thread;
use std::sync::deque::BufferPool;
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let sleepers = SleeperList::new();
let mut pool = BufferPool::new();
let (normal_worker, normal_stealer) = pool.deque();
ret
}
- let task1 = do GreenTask::new_homed(&mut special_sched.stack_pool,
- None, HomeSched(t1_handle)) {
+ let task1 = GreenTask::new_homed(&mut special_sched.stack_pool,
+ None, HomeSched(t1_handle), proc() {
rtassert!(on_appropriate_sched());
- };
+ });
- let task2 = do GreenTask::new(&mut normal_sched.stack_pool, None) {
+ let task2 = GreenTask::new(&mut normal_sched.stack_pool, None, proc() {
rtassert!(on_appropriate_sched());
- };
+ });
- let task3 = do GreenTask::new(&mut normal_sched.stack_pool, None) {
+ let task3 = GreenTask::new(&mut normal_sched.stack_pool, None, proc() {
rtassert!(on_appropriate_sched());
- };
+ });
- let task4 = do GreenTask::new_homed(&mut special_sched.stack_pool,
- None, HomeSched(t4_handle)) {
+ let task4 = GreenTask::new_homed(&mut special_sched.stack_pool,
+ None, HomeSched(t4_handle), proc() {
rtassert!(on_appropriate_sched());
- };
+ });
// Signal from the special task that we are done.
let (port, chan) = Chan::<()>::new();
sched.run_task(task, next)
}
- let normal_task = do GreenTask::new(&mut normal_sched.stack_pool,
- None) {
+ let normal_task = GreenTask::new(&mut normal_sched.stack_pool, None, proc() {
run(task2);
run(task4);
port.recv();
nh.send(Shutdown);
let mut sh = special_handle;
sh.send(Shutdown);
- };
+ });
normal_sched.enqueue_task(normal_task);
- let special_task = do GreenTask::new(&mut special_sched.stack_pool,
- None) {
+ let special_task = GreenTask::new(&mut special_sched.stack_pool, None, proc() {
run(task1);
run(task3);
chan.send(());
- };
+ });
special_sched.enqueue_task(special_task);
let normal_sched = normal_sched;
- let normal_thread = do Thread::start { normal_sched.bootstrap() };
+ let normal_thread = Thread::start(proc() { normal_sched.bootstrap() });
let special_sched = special_sched;
- let special_thread = do Thread::start { special_sched.bootstrap() };
+ let special_thread = Thread::start(proc() { special_sched.bootstrap() });
normal_thread.join();
special_thread.join();
- }
+ });
}
//#[test]
// the work queue, but we are performing I/O, that once we do put
// something in the work queue again the scheduler picks it up and
// doesn't exit before emptying the work queue
- do pool.spawn(TaskOpts::new()) {
- do spawn {
+ pool.spawn(TaskOpts::new(), proc() {
+ spawn(proc() {
timer::sleep(10);
- }
- }
+ });
+ });
pool.shutdown();
}
let mut pool1 = pool();
let mut pool2 = pool();
- do pool1.spawn(TaskOpts::new()) {
+ pool1.spawn(TaskOpts::new(), proc() {
let id = sched_id();
chan1.send(());
port2.recv();
assert_eq!(id, sched_id());
- }
+ });
- do pool2.spawn(TaskOpts::new()) {
+ pool2.spawn(TaskOpts::new(), proc() {
let id = sched_id();
port1.recv();
assert_eq!(id, sched_id());
chan2.send(());
- }
+ });
pool1.shutdown();
pool2.shutdown();
#[test]
fn multithreading() {
- do run {
+ run(proc() {
let mut ports = ~[];
- 10.times(|| {
+ for _ in range(0, 10) {
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
chan.send(());
- }
+ });
ports.push(port);
- });
+ }
loop {
match ports.pop() {
None => break,
}
}
- }
+ });
}
#[test]
fn thread_ring() {
- do run {
+ run(proc() {
let (end_port, end_chan) = Chan::new();
let n_tasks = 10;
let (next_p, ch) = Chan::new();
let imm_i = i;
let imm_p = p;
- do spawn {
+ spawn(proc() {
roundtrip(imm_i, n_tasks, &imm_p, &ch);
- };
+ });
p = next_p;
i += 1;
}
let p = p;
- do spawn {
+ spawn(proc() {
roundtrip(1, n_tasks, &p, &ch1);
- }
+ });
end_port.recv();
- }
+ });
fn roundtrip(id: int, n_tasks: int,
p: &Port<(int, Chan<()>)>,
fn start_closure_dtor() {
// Regression test that the `start` task entrypoint can
// contain dtors that use task resources
- do run {
+ run(proc() {
struct S { field: () }
impl Drop for S {
let s = S { field: () };
- do spawn {
+ spawn(proc() {
let _ss = &s;
- }
- }
+ });
+ });
}
// FIXME: #9407: xfail-test
threads: 2, // this must be > 1
event_loop_factory: Some(basic::event_loop),
});
- do pool.spawn(TaskOpts::new()) {
+ pool.spawn(TaskOpts::new(), proc() {
let (port, chan) = Chan::new();
// This task should not be able to starve the sender;
// The sender should get stolen to another thread.
- do spawn {
+ spawn(proc() {
while port.try_recv() != comm::Data(()) { }
- }
+ });
chan.send(());
- }
+ });
pool.shutdown();
}
#[test]
fn dont_starve_2() {
- do run {
+ run(proc() {
let (port, chan) = Chan::new();
let (_port2, chan2) = Chan::new();
// This task should not be able to starve the other task.
// The sends should eventually yield.
- do spawn {
+ spawn(proc() {
while port.try_recv() != comm::Data(()) {
chan2.send(());
}
- }
+ });
chan.send(());
- }
+ });
}
// Regression test for a logic bug that would cause single-threaded
#[test]
fn single_threaded_yield() {
use std::task::deschedule;
- do run {
- 5.times(deschedule);
- }
+ run(proc() {
+ for _ in range(0, 5) { deschedule(); }
+ });
}
#[test]
let (setup_po, setup_ch) = Chan::new();
let (parent_po, parent_ch) = Chan::new();
- do spawn {
+ spawn(proc() {
let (child_po, child_ch) = Chan::new();
setup_ch.send(child_ch);
pingpong(&child_po, &parent_ch);
- };
+ });
let child_ch = setup_po.recv();
child_ch.send(20);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::vec;
-use std::libc::{c_uint, uintptr_t};
+use std::rt::env::max_cached_stacks;
+use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
+ MapNonStandardFlags, MapVirtual};
+use std::libc;
-pub struct StackSegment {
- priv buf: ~[u8],
- priv valgrind_id: c_uint
+/// A task's stack. The name "Stack" is a vestige of segmented stacks.
+pub struct Stack {
+ priv buf: MemoryMap,
+ priv min_size: uint,
+ priv valgrind_id: libc::c_uint,
}
-impl StackSegment {
- pub fn new(size: uint) -> StackSegment {
- unsafe {
- // Crate a block of uninitialized values
- let mut stack = vec::with_capacity(size);
- stack.set_len(size);
-
- let mut stk = StackSegment {
- buf: stack,
- valgrind_id: 0
- };
-
- // XXX: Using the FFI to call a C macro. Slow
- stk.valgrind_id = rust_valgrind_stack_register(stk.start(), stk.end());
- return stk;
+// Try to use MAP_STACK on platforms that support it (it's what we're doing
+// anyway), but some platforms don't support it at all. For example, it appears
+// that there's a bug in freebsd that MAP_STACK implies MAP_FIXED (so it always
+// fails): http://lists.freebsd.org/pipermail/freebsd-bugs/2011-July/044840.html
+#[cfg(not(windows), not(target_os = "freebsd"))]
+static STACK_FLAGS: libc::c_int = libc::MAP_STACK | libc::MAP_PRIVATE |
+ libc::MAP_ANON;
+#[cfg(target_os = "freebsd")]
+static STACK_FLAGS: libc::c_int = libc::MAP_PRIVATE | libc::MAP_ANON;
+#[cfg(windows)]
+static STACK_FLAGS: libc::c_int = 0;
+
+impl Stack {
+ /// Allocate a new stack of `size`. If size = 0, this will fail. Use
+ /// `dummy_stack` if you want a zero-sized stack.
+ pub fn new(size: uint) -> Stack {
+ // Map in a stack. Eventually we might be able to handle stack
+ // allocation failure, which would fail to spawn the task. But there's
+ // not many sensible things to do on OOM. Failure seems fine (and is
+ // what the old stack allocation did).
+ let stack = match MemoryMap::new(size, [MapReadable, MapWritable,
+ MapNonStandardFlags(STACK_FLAGS)]) {
+ Ok(map) => map,
+ Err(e) => fail!("mmap for stack of size {} failed: {}", size, e)
+ };
+
+ // Change the last page to be inaccessible. This is to provide safety;
+ // when an FFI function overflows it will (hopefully) hit this guard
+ // page. It isn't guaranteed, but that's why FFI is unsafe. buf.data is
+ // guaranteed to be aligned properly.
+ if !protect_last_page(&stack) {
+ fail!("Could not memory-protect guard page. stack={:?}, errno={}",
+ stack, errno());
+ }
+
+ let mut stk = Stack {
+ buf: stack,
+ min_size: size,
+ valgrind_id: 0
+ };
+
+ // FIXME: Using the FFI to call a C macro. Slow
+ stk.valgrind_id = unsafe {
+ rust_valgrind_stack_register(stk.start(), stk.end())
+ };
+ return stk;
+ }
+
+ /// Create a 0-length stack which starts (and ends) at 0.
+ pub unsafe fn dummy_stack() -> Stack {
+ Stack {
+ buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
+ min_size: 0,
+ valgrind_id: 0
}
}
/// Point to the low end of the allocated stack
pub fn start(&self) -> *uint {
- self.buf.as_ptr() as *uint
+ self.buf.data as *uint
}
- /// Point one word beyond the high end of the allocated stack
+ /// Point one uint beyond the high end of the allocated stack
pub fn end(&self) -> *uint {
unsafe {
- self.buf.as_ptr().offset(self.buf.len() as int) as *uint
+ self.buf.data.offset(self.buf.len as int) as *uint
}
}
}
-impl Drop for StackSegment {
+#[cfg(unix)]
+fn protect_last_page(stack: &MemoryMap) -> bool {
+ unsafe {
+ // This may seem backwards: the start of the segment is the last page?
+ // Yes! The stack grows from higher addresses (the end of the allocated
+ // block) to lower addresses (the start of the allocated block).
+ let last_page = stack.data as *libc::c_void;
+ libc::mprotect(last_page, page_size() as libc::size_t,
+ libc::PROT_NONE) != -1
+ }
+}
+
+#[cfg(windows)]
+fn protect_last_page(stack: &MemoryMap) -> bool {
+ unsafe {
+ // see above
+ let last_page = stack.data as *mut libc::c_void;
+ let mut old_prot: libc::DWORD = 0;
+ libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
+ libc::PAGE_NOACCESS,
+ &mut old_prot as libc::LPDWORD) != 0
+ }
+}
+
+impl Drop for Stack {
fn drop(&mut self) {
unsafe {
- // XXX: Using the FFI to call a C macro. Slow
+ // FIXME: Using the FFI to call a C macro. Slow
rust_valgrind_stack_deregister(self.valgrind_id);
}
}
}
-pub struct StackPool(());
+pub struct StackPool {
+ // Ideally this would be some datastructure that preserved ordering on
+ // Stack.min_size.
+ priv stacks: ~[Stack],
+}
impl StackPool {
- pub fn new() -> StackPool { StackPool(()) }
+ pub fn new() -> StackPool {
+ StackPool {
+ stacks: ~[],
+ }
+ }
- pub fn take_segment(&self, min_size: uint) -> StackSegment {
- StackSegment::new(min_size)
+ pub fn take_stack(&mut self, min_size: uint) -> Stack {
+ // Ideally this would be a binary search
+ match self.stacks.iter().position(|s| s.min_size < min_size) {
+ Some(idx) => self.stacks.swap_remove(idx),
+ None => Stack::new(min_size)
+ }
}
- pub fn give_segment(&self, _stack: StackSegment) {
+ pub fn give_stack(&mut self, stack: Stack) {
+ if self.stacks.len() <= max_cached_stacks() {
+ self.stacks.push(stack)
+ }
}
}
extern {
- fn rust_valgrind_stack_register(start: *uintptr_t, end: *uintptr_t) -> c_uint;
- fn rust_valgrind_stack_deregister(id: c_uint);
+ fn rust_valgrind_stack_register(start: *libc::uintptr_t,
+ end: *libc::uintptr_t) -> libc::c_uint;
+ fn rust_valgrind_stack_deregister(id: libc::c_uint);
}
#[test]
fn smoke() {
let (p, c) = Chan::new();
- do spawn_opts(TaskOpts::new()) {
+ spawn_opts(TaskOpts::new(), proc() {
c.send(());
- }
+ });
p.recv();
}
#[test]
fn smoke_fail() {
let (p, c) = Chan::<()>::new();
- do spawn_opts(TaskOpts::new()) {
+ spawn_opts(TaskOpts::new(), proc() {
let _c = c;
fail!()
- }
+ });
assert_eq!(p.recv_opt(), None);
}
#[test]
fn yield_test() {
let (p, c) = Chan::new();
- do spawn_opts(TaskOpts::new()) {
- 10.times(task::deschedule);
+ spawn_opts(TaskOpts::new(), proc() {
+ for _ in range(0, 10) { task::deschedule(); }
c.send(());
- }
+ });
p.recv();
}
#[test]
fn spawn_children() {
let (p, c) = Chan::new();
- do spawn_opts(TaskOpts::new()) {
+ spawn_opts(TaskOpts::new(), proc() {
let (p, c2) = Chan::new();
- do spawn {
+ spawn(proc() {
let (p, c3) = Chan::new();
- do spawn {
+ spawn(proc() {
c3.send(());
- }
+ });
p.recv();
c2.send(());
- }
+ });
p.recv();
c.send(());
- }
+ });
p.recv();
}
#[test]
fn spawn_inherits() {
let (p, c) = Chan::new();
- do spawn_opts(TaskOpts::new()) {
+ spawn_opts(TaskOpts::new(), proc() {
let c = c;
- do spawn {
+ spawn(proc() {
let mut task: ~Task = Local::take();
match task.maybe_take_runtime::<GreenTask>() {
Some(ops) => {
}
Local::put(task);
c.send(());
- }
- }
+ });
+ });
p.recv();
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 ai = std::io::net::addrinfo;
+use std::c_str::CString;
+use std::cast;
+use std::io::IoError;
+use std::libc;
+use std::libc::{c_char, c_int};
+use std::ptr::null;
+
+use super::net::sockaddr_to_addr;
+
+pub struct GetAddrInfoRequest;
+
+impl GetAddrInfoRequest {
+ pub fn run(host: Option<&str>, servname: Option<&str>,
+ hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
+ assert!(host.is_some() || servname.is_some());
+
+ let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
+ let c_serv = servname.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
+
+ let hint = hint.map(|hint| {
+ libc::addrinfo {
+ ai_flags: hint.flags as c_int,
+ ai_family: hint.family as c_int,
+ ai_socktype: 0,
+ ai_protocol: 0,
+ ai_addrlen: 0,
+ ai_canonname: null(),
+ ai_addr: null(),
+ ai_next: null()
+ }
+ });
+
+ let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
+ let res = null();
+
+ // Make the call
+ let s = unsafe {
+ let ch = if c_host.is_null() { null() } else { c_host.with_ref(|x| x) };
+ let cs = if c_serv.is_null() { null() } else { c_serv.with_ref(|x| x) };
+ getaddrinfo(ch, cs, hint_ptr, &res)
+ };
+
+ // Error?
+ if s != 0 {
+ return Err(get_error(s));
+ }
+
+ // Collect all the results we found
+ let mut addrs = ~[];
+ let mut rp = res;
+ while rp.is_not_null() {
+ unsafe {
+ let addr = match sockaddr_to_addr(cast::transmute((*rp).ai_addr),
+ (*rp).ai_addrlen as uint) {
+ Ok(a) => a,
+ Err(e) => return Err(e)
+ };
+ addrs.push(ai::Info {
+ address: addr,
+ family: (*rp).ai_family as uint,
+ socktype: None,
+ protocol: None,
+ flags: (*rp).ai_flags as uint
+ });
+
+ rp = (*rp).ai_next;
+ }
+ }
+
+ unsafe { freeaddrinfo(res); }
+
+ Ok(addrs)
+ }
+}
+
+extern "system" {
+ fn getaddrinfo(node: *c_char, service: *c_char,
+ hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int;
+ fn freeaddrinfo(res: *libc::addrinfo);
+ #[cfg(not(windows))]
+ fn gai_strerror(errcode: c_int) -> *c_char;
+ #[cfg(windows)]
+ fn WSAGetLastError() -> c_int;
+}
+
+#[cfg(windows)]
+fn get_error(_: c_int) -> IoError {
+ use super::translate_error;
+
+ unsafe {
+ translate_error(WSAGetLastError() as i32, true)
+ }
+}
+
+#[cfg(not(windows))]
+fn get_error(s: c_int) -> IoError {
+ use std::io;
+ use std::str::raw::from_c_str;
+
+ let err_str = unsafe { from_c_str(gai_strerror(s)) };
+ IoError {
+ kind: io::OtherIoError,
+ desc: "unable to resolve host",
+ detail: Some(err_str),
+ }
+}
impl io::Writer for FileDesc {
fn write(&mut self, buf: &[u8]) {
- self.inner_write(buf);
+ match self.inner_write(buf) {
+ Ok(()) => {}
+ Err(e) => { io::io_error::cond.raise(e); }
+ }
}
}
_ => Ok(())
}
};
- self.seek(orig_pos as i64, io::SeekSet);
+ let _ = self.seek(orig_pos as i64, io::SeekSet);
return ret;
}
#[cfg(unix)]
}
fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
- self.flush();
- self.fd.pread(buf, offset)
+ self.flush().and_then(|()| self.fd.pread(buf, offset))
}
fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> {
- self.flush();
- self.fd.pwrite(buf, offset)
+ self.flush().and_then(|()| self.fd.pwrite(buf, offset))
}
fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
let whence = match style {
}
}
fn fsync(&mut self) -> Result<(), IoError> {
- self.flush();
- self.fd.fsync()
+ self.flush().and_then(|()| self.fd.fsync())
}
fn datasync(&mut self) -> Result<(), IoError> {
- self.flush();
- self.fd.fsync()
+ self.flush().and_then(|()| self.fd.fsync())
}
fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
- self.flush();
- self.fd.truncate(offset)
+ self.flush().and_then(|()| self.fd.truncate(offset))
}
}
pub fn readlink(p: &CString) -> IoResult<Path> {
return os_readlink(p);
- // XXX: I have a feeling that this reads intermediate symlinks as well.
+ // FIXME: I have a feeling that this reads intermediate symlinks as well.
#[cfg(windows)]
fn os_readlink(p: &CString) -> IoResult<Path> {
let handle = unsafe {
let p = p.with_ref(|p| p);
let mut len = unsafe { libc::pathconf(p, libc::_PC_NAME_MAX) };
if len == -1 {
- len = 1024; // XXX: read PATH_MAX from C ffi?
+ len = 1024; // FIXME: read PATH_MAX from C ffi?
}
let mut buf = vec::with_capacity::<u8>(len as uint);
match retry(|| unsafe {
pub fn lstat(p: &CString) -> IoResult<io::FileStat> {
return os_lstat(p);
- // XXX: windows implementation is missing
+ // FIXME: windows implementation is missing
#[cfg(windows)]
fn os_lstat(_p: &CString) -> IoResult<io::FileStat> {
Err(super::unimpl())
use std::c_str::CString;
use std::comm::SharedChan;
+use std::io;
+use std::io::IoError;
+use std::io::net::ip::SocketAddr;
+use std::io::process::ProcessConfig;
+use std::io::signal::Signum;
use std::libc::c_int;
use std::libc;
use std::os;
use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket,
RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess,
RtioSignal, RtioTTY, CloseBehavior, RtioTimer};
-use std::io;
-use std::io::IoError;
-use std::io::net::ip::SocketAddr;
-use std::io::process::ProcessConfig;
-use std::io::signal::Signum;
use ai = std::io::net::addrinfo;
// Local re-exports
pub use self::process::Process;
// Native I/O implementations
+pub mod addrinfo;
pub mod file;
-pub mod process;
pub mod net;
+pub mod process;
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
+#[cfg(target_os = "android")]
#[path = "timer_other.rs"]
pub mod timer;
#[cfg(target_os = "linux")]
-#[cfg(target_os = "android")]
#[path = "timer_timerfd.rs"]
pub mod timer;
mod timer_helper;
-type IoResult<T> = Result<T, IoError>;
+pub type IoResult<T> = Result<T, IoError>;
fn unimpl() -> IoError {
IoError {
#[cfg(not(windows))]
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
- // XXX: this should probably be a bit more descriptive...
+ // FIXME: this should probably be a bit more descriptive...
match errno {
libc::EOF => (io::EndOfFile, "end of file"),
libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
Err(unimpl())
}
- fn get_host_addresses(&mut self, _host: Option<&str>, _servname: Option<&str>,
- _hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
- Err(unimpl())
+ fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
+ hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
+ addrinfo::GetAddrInfoRequest::run(host, servname, hint)
}
// filesystem operations
return sockaddr_to_addr(&storage, len as uint);
}
-fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
- len: uint) -> IoResult<ip::SocketAddr> {
+pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
+ len: uint) -> IoResult<ip::SocketAddr> {
match storage.ss_family as libc::c_int {
libc::AF_INET => {
assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
let (addr, len) = addr_to_sockaddr(addr);
let addrp = &addr as *libc::sockaddr_storage;
let ret = TcpListener { fd: fd };
+ // On platforms with Berkeley-derived sockets, this allows
+ // to quickly rebind a socket, without needing to wait for
+ // the OS to clean up the previous one.
+ if cfg!(unix) {
+ match setsockopt(fd, libc::SOL_SOCKET,
+ libc::SO_REUSEADDR,
+ 1 as libc::c_int) {
+ Err(n) => { return Err(n); },
+ Ok(..) => { }
+ }
+ }
match libc::bind(fd, addrp as *libc::sockaddr,
len as libc::socklen_t) {
-1 => Err(super::last_error()),
(errno << 8) as u8,
(errno << 0) as u8,
];
- output.inner_write(bytes);
+ assert!(output.inner_write(bytes).is_ok());
intrinsics::abort();
})
}
let (receive, send) = imp::new();
HELPER_SIGNAL = send;
- do task::spawn {
+ task::spawn(proc() {
bookkeeping::decrement();
helper(receive, msgp);
- }
+ });
rt::at_exit(proc() { shutdown() });
})
}
pub fn signal(fd: libc::c_int) {
- FileDesc::new(fd, false).inner_write([0]);
+ FileDesc::new(fd, false).inner_write([0]).unwrap();
}
pub fn close(fd: libc::c_int) {
// drain the file descriptor
let mut buf = [0];
- fd.inner_read(buf);
+ fd.inner_read(buf).unwrap();
}
-1 if os::errno() == libc::EINTR as int => {}
}
}
+#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
mod imp {
use std::libc;
if fd == input {
let mut buf = [0, ..1];
// drain the input file descriptor of its input
- FileDesc::new(fd, false).inner_read(buf);
+ FileDesc::new(fd, false).inner_read(buf).unwrap();
incoming = true;
} else {
let mut bits = [0, ..8];
// drain the timerfd of how many times its fired
//
- // XXX: should this perform a send() this number of
+ // FIXME: should this perform a send() this number of
// times?
- FileDesc::new(fd, false).inner_read(bits);
+ FileDesc::new(fd, false).inner_read(bits).unwrap();
let remove = {
match map.find(&fd).expect("fd unregistered") {
&(ref c, oneshot) => !c.try_send(()) || oneshot
#[test]
fn smoke() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
c.send(());
- }
+ });
p.recv();
}
#[test]
fn smoke_fail() {
let (p, c) = Chan::<()>::new();
- do spawn {
+ spawn(proc() {
let _c = c;
fail!()
- }
+ });
assert_eq!(p.recv_opt(), None);
}
#[test]
fn yield_test() {
let (p, c) = Chan::new();
- do spawn {
- 10.times(task::deschedule);
+ spawn(proc() {
+ for _ in range(0, 10) { task::deschedule(); }
c.send(());
- }
+ });
p.recv();
}
#[test]
fn spawn_children() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
let (p, c2) = Chan::new();
- do spawn {
+ spawn(proc() {
let (p, c3) = Chan::new();
- do spawn {
+ spawn(proc() {
c3.send(());
- }
+ });
p.recv();
c2.send(());
- }
+ });
p.recv();
c.send(());
- }
+ });
p.recv();
}
#[test]
fn spawn_inherits() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
let c = c;
- do spawn {
+ spawn(proc() {
let mut task: ~Task = Local::take();
match task.maybe_take_runtime::<Ops>() {
Some(ops) => {
}
Local::put(task);
c.send(());
- }
- }
+ });
+ });
p.recv();
}
}
pub static tydesc_field_size: uint = 0u;
pub static tydesc_field_align: uint = 1u;
-pub static tydesc_field_take_glue: uint = 2u;
-pub static tydesc_field_drop_glue: uint = 3u;
-pub static tydesc_field_visit_glue: uint = 4u;
-pub static tydesc_field_name_offset: uint = 5u;
-pub static n_tydesc_fields: uint = 6u;
+pub static tydesc_field_drop_glue: uint = 2u;
+pub static tydesc_field_visit_glue: uint = 3u;
+pub static tydesc_field_name_offset: uint = 4u;
+pub static n_tydesc_fields: uint = 5u;
// The two halves of a closure: code and environment.
pub static fn_field_code: uint = 0u;
};
let use_softfp = sess.opts.debugging_opts & session::USE_SOFTFP != 0;
+ // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
+ let no_fp_elim = sess.opts.debuginfo;
+
let tm = sess.targ_cfg.target_strs.target_triple.with_c_str(|T| {
sess.opts.target_cpu.with_c_str(|CPU| {
sess.opts.target_feature.with_c_str(|Features| {
lib::llvm::RelocPIC,
OptLevel,
true,
- use_softfp
+ use_softfp,
+ no_fp_elim
)
})
})
args.push(~"-dynamiclib");
args.push(~"-Wl,-dylib");
// FIXME (#9639): This needs to handle non-utf8 paths
- args.push(~"-Wl,-install_name,@rpath/" +
- out_filename.filename_str().unwrap());
+ if !sess.opts.no_rpath {
+ args.push(~"-Wl,-install_name,@rpath/" +
+ out_filename.filename_str().unwrap());
+ }
} else {
args.push(~"-shared")
}
// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
// addl_lib_search_paths
- args.push_all(rpath::get_rpath_flags(sess, out_filename));
+ if !sess.opts.no_rpath {
+ args.push_all(rpath::get_rpath_flags(sess, out_filename));
+ }
// Finally add all the linker arguments provided on the command line along
// with any #[link_args] attributes found inside the crate
time(time_passes, "gated feature checking", (), |_|
front::feature_gate::check_crate(sess, &crate));
+ crate = time(time_passes, "crate injection", crate, |crate|
+ front::std_inject::maybe_inject_crates_ref(sess, crate));
+
// strip before expansion to allow macros to depend on
// configuration variables e.g/ in
//
// mod bar { macro_rules! baz!(() => {{}}) }
//
// baz! should not use this definition unless foo is enabled.
- crate = time(time_passes, "std macros injection", crate, |crate|
- syntax::ext::expand::inject_std_macros(sess.parse_sess,
- cfg.clone(),
- crate));
crate = time(time_passes, "configuration 1", crate, |crate|
front::config::strip_unconfigured_items(crate));
crate = time(time_passes, "maybe building test harness", crate, |crate|
front::test::modify_for_testing(sess, crate));
- crate = time(time_passes, "std injection", crate, |crate|
- front::std_inject::maybe_inject_libstd_ref(sess, crate));
+ crate = time(time_passes, "prelude injection", crate, |crate|
+ front::std_inject::maybe_inject_prelude(sess, crate));
time(time_passes, "assinging node ids and indexing ast", crate, |crate|
front::assign_node_ids_and_map::assign_node_ids_and_map(sess, crate))
demitter: @diagnostic::Emitter)
-> @session::Options {
let mut outputs = ~[];
+ if matches.opt_present("lib") {
+ outputs.push(session::default_lib_output());
+ }
if matches.opt_present("rlib") {
outputs.push(session::OutputRlib)
}
if matches.opt_present("staticlib") {
outputs.push(session::OutputStaticlib)
}
- // dynamic libraries are the "compiler blesssed" default library
- if matches.opt_present("dylib") || matches.opt_present("lib") {
+ if matches.opt_present("dylib") {
outputs.push(session::OutputDylib)
}
if matches.opt_present("bin") {
let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");
+ let no_rpath = matches.opt_present("no-rpath");
let lint_levels = [lint::allow, lint::warn,
lint::deny, lint::forbid];
parse_only: parse_only,
no_trans: no_trans,
no_analysis: no_analysis,
+ no_rpath: no_rpath,
debugging_opts: debugging_opts,
android_cross_path: android_cross_path,
write_dependency_info: write_dependency_info,
return sopts;
}
-pub fn build_session(sopts: @session::Options, demitter: @diagnostic::Emitter)
+pub fn build_session(sopts: @session::Options,
+ local_crate_source_file: Option<Path>,
+ demitter: @diagnostic::Emitter)
-> Session {
let codemap = @codemap::CodeMap::new();
let diagnostic_handler =
diagnostic::mk_handler(Some(demitter));
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
- build_session_(sopts, codemap, demitter, span_diagnostic_handler)
+
+ build_session_(sopts, local_crate_source_file, codemap, demitter, span_diagnostic_handler)
}
pub fn build_session_(sopts: @session::Options,
- cm: @codemap::CodeMap,
+ local_crate_source_file: Option<Path>,
+ codemap: @codemap::CodeMap,
demitter: @diagnostic::Emitter,
span_diagnostic_handler: @diagnostic::SpanHandler)
-> Session {
let target_cfg = build_target_config(sopts, demitter);
- let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
- cm);
+ let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler, codemap);
let cstore = @CStore::new(token::get_ident_interner());
let filesearch = @filesearch::FileSearch::new(
&sopts.maybe_sysroot,
sopts.target_triple,
sopts.addl_lib_search_paths);
+
+ // Make the path absolute, if necessary
+ let local_crate_source_file = local_crate_source_file.map(|path|
+ if path.is_absolute() {
+ path.clone()
+ } else {
+ os::getcwd().join(path.clone())
+ }
+ );
+
@Session_ {
targ_cfg: target_cfg,
opts: sopts,
cstore: cstore,
parse_sess: p_s,
- codemap: cm,
+ codemap: codemap,
// For a library crate, this is always none
entry_fn: RefCell::new(None),
entry_type: Cell::new(None),
span_diagnostic: span_diagnostic_handler,
filesearch: filesearch,
building_library: Cell::new(false),
+ local_crate_source_file: local_crate_source_file,
working_dir: os::getcwd(),
lints: RefCell::new(HashMap::new()),
node_id: Cell::new(1),
\"list\" will list all of the available passes", "NAMES"),
optopt("", "llvm-args", "A list of arguments to pass to llvm, comma \
separated", "ARGS"),
+ optflag("", "no-rpath", "Disables setting the rpath in libs/exes"),
optopt( "", "out-dir",
"Write output to compiler-chosen filename
in <dir>", "DIR"),
Ok(m) => m,
Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
};
- let sessopts = build_session_options(
- ~"rustc",
- matches,
- @diagnostic::DefaultEmitter as @diagnostic::Emitter);
- let sess = build_session(sessopts,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter);
+ let sessopts = build_session_options(~"rustc", matches, @diagnostic::DefaultEmitter);
+ let sess = build_session(sessopts, None, @diagnostic::DefaultEmitter);
let cfg = build_configuration(sess);
assert!((attr::contains_name(cfg, "test")));
}
f.to_err_msg());
}
};
- let sessopts = build_session_options(
- ~"rustc",
- matches,
- @diagnostic::DefaultEmitter as @diagnostic::Emitter);
- let sess = build_session(sessopts,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter);
+ let sessopts = build_session_options(~"rustc", matches, @diagnostic::DefaultEmitter);
+ let sess = build_session(sessopts, None, @diagnostic::DefaultEmitter);
let cfg = build_configuration(sess);
let mut test_items = cfg.iter().filter(|m| "test" == m.name());
assert!(test_items.next().is_some());
parse_only: bool,
no_trans: bool,
no_analysis: bool,
+ no_rpath: bool,
debugging_opts: u64,
android_cross_path: Option<~str>,
/// Whether to write dependency files. It's (enabled, optional filename).
macro_registrar_fn: RefCell<Option<ast::DefId>>,
filesearch: @filesearch::FileSearch,
building_library: Cell<bool>,
+ // The name of the root source file of the crate, in the local file system. The path is always
+ // expected to be absolute. `None` means that there is no source file.
+ local_crate_source_file: Option<Path>,
working_dir: Path,
lints: RefCell<HashMap<ast::NodeId,
~[(lint::Lint, codemap::Span, ~str)]>>,
parse_only: false,
no_trans: false,
no_analysis: false,
+ no_rpath: false,
debugging_opts: 0,
android_cross_path: None,
write_dependency_info: (false, None),
}
}
+pub fn default_lib_output() -> OutputStyle {
+ OutputRlib
+}
+
pub fn collect_outputs(session: &Session,
attrs: &[ast::Attribute]) -> ~[OutputStyle] {
// If we're generating a test executable, then ignore all other output
match a.value_str() {
Some(n) if "rlib" == n => Some(OutputRlib),
Some(n) if "dylib" == n => Some(OutputDylib),
- Some(n) if "lib" == n => Some(OutputDylib),
+ Some(n) if "lib" == n => Some(default_lib_output()),
Some(n) if "staticlib" == n => Some(OutputStaticlib),
Some(n) if "bin" == n => Some(OutputExecutable),
Some(_) => {
("phase", Active),
("macro_registrar", Active),
("log_syntax", Active),
+ ("trace_macros", Active),
+ ("simd", Active),
+ ("default_type_params", Active),
// These are used to test this portion of the compiler, they don't actually
// mean anything
}
}
+ ast::ItemStruct(..) => {
+ if attr::contains_name(i.attrs, "simd") {
+ self.gate_feature("simd", i.span,
+ "SIMD types are experimental and possibly buggy");
+ }
+ }
+
_ => {}
}
self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \
stable enough for use and is subject to change");
}
+ else if path.segments.last().unwrap().identifier == self.sess.ident_of("trace_macros") {
+ self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
+ stable enough for use and is subject to change");
+ }
}
fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
}
visit::walk_expr(self, e, ());
}
+
+ fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
+ for type_parameter in generics.ty_params.iter() {
+ match type_parameter.default {
+ Some(ty) => {
+ self.gate_feature("default_type_params", ty.span,
+ "default type parameters are \
+ experimental and possibly buggy");
+ }
+ None => {}
+ }
+ }
+ visit::walk_generics(self, generics, ());
+ }
}
pub fn check_crate(sess: Session, crate: &ast::Crate) {
pub static VERSION: &'static str = "0.10-pre";
-pub fn maybe_inject_libstd_ref(sess: Session, crate: ast::Crate)
+pub fn maybe_inject_crates_ref(sess: Session, crate: ast::Crate)
-> ast::Crate {
if use_std(&crate) {
- inject_libstd_ref(sess, crate)
+ inject_crates_ref(sess, crate)
+ } else {
+ crate
+ }
+}
+
+pub fn maybe_inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate {
+ if use_std(&crate) {
+ inject_prelude(sess, crate)
} else {
crate
}
attr::contains_name(attrs, "no_implicit_prelude")
}
-fn spanned<T>(x: T) -> codemap::Spanned<T> {
- codemap::Spanned {
- node: x,
- span: DUMMY_SP,
- }
-}
-
struct StandardLibraryInjector {
sess: Session,
}
node: ast::ViewItemExternMod(self.sess.ident_of("std"),
with_version("std"),
ast::DUMMY_NODE_ID),
- attrs: ~[],
+ attrs: ~[
+ attr::mk_attr(attr::mk_list_item(@"phase",
+ ~[attr::mk_word_item(@"syntax"),
+ attr::mk_word_item(@"link")]))
+ ],
vis: ast::Inherited,
span: DUMMY_SP
}];
}
vis.push_all(crate.module.view_items);
- let mut new_module = ast::Mod {
+ let new_module = ast::Mod {
view_items: vis,
..crate.module.clone()
};
- if !no_prelude(crate.attrs) {
- // only add `use std::prelude::*;` if there wasn't a
- // `#[no_implicit_prelude];` at the crate level.
- new_module = self.fold_mod(&new_module);
- }
-
ast::Crate {
module: new_module,
..crate
}
}
+}
+
+fn inject_crates_ref(sess: Session, crate: ast::Crate) -> ast::Crate {
+ let mut fold = StandardLibraryInjector {
+ sess: sess,
+ };
+ fold.fold_crate(crate)
+}
+
+struct PreludeInjector {
+ sess: Session,
+}
+
+
+impl fold::Folder for PreludeInjector {
+ fn fold_crate(&mut self, crate: ast::Crate) -> ast::Crate {
+ if !no_prelude(crate.attrs) {
+ // only add `use std::prelude::*;` if there wasn't a
+ // `#[no_implicit_prelude];` at the crate level.
+ ast::Crate {
+ module: self.fold_mod(&crate.module),
+ ..crate
+ }
+ } else {
+ crate
+ }
+ }
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
if !no_prelude(item.attrs) {
],
};
- let vp = @spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID));
+ let vp = @codemap::dummy_spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID));
let vi2 = ast::ViewItem {
node: ast::ViewItemUse(~[vp]),
attrs: ~[],
}
}
-fn inject_libstd_ref(sess: Session, crate: ast::Crate) -> ast::Crate {
- let mut fold = StandardLibraryInjector {
+fn inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate {
+ let mut fold = PreludeInjector {
sess: sess,
};
fold.fold_crate(crate)
#[feature(macro_rules, globs, struct_variant, managed_boxes)];
extern mod extra;
+extern mod flate;
+extern mod arena;
extern mod syntax;
use back::link;
version(binary);
return;
}
- let input = match matches.free.len() {
+ let (input, input_file_path) = match matches.free.len() {
0u => d::early_error(demitter, "no input filename given"),
1u => {
let ifile = matches.free[0].as_slice();
if "-" == ifile {
let src = str::from_utf8_owned(io::stdin().read_to_end()).unwrap();
- d::StrInput(src.to_managed())
+ (d::StrInput(src.to_managed()), None)
} else {
- d::FileInput(Path::new(ifile))
+ (d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
}
}
_ => d::early_error(demitter, "multiple input filenames provided")
};
let sopts = d::build_session_options(binary, matches, demitter);
- let sess = d::build_session(sopts, demitter);
+ let sess = d::build_session(sopts, input_file_path, demitter);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
let ofile = matches.opt_str("o").map(|o| Path::new(o));
let cfg = d::build_configuration(sess);
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor(f: proc(@diagnostic::Emitter)) {
- // XXX: This is a hack for newsched since it doesn't support split stacks.
+ // FIXME: This is a hack for newsched since it doesn't support split stacks.
// rustc needs a lot of stack! When optimizations are disabled, it needs
// even *more* stack than usual as well.
#[cfg(rtopt)]
let mut task_builder = task::task();
task_builder.name("rustc");
- // XXX: Hacks on hacks. If the env is trying to override the stack size
+ // FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
if os::getenv("RUST_MIN_STACK").is_none() {
task_builder.opts.stack_size = Some(STACK_SIZE);
Dialect: c_uint)
-> ValueRef;
+ pub static LLVMRustDebugMetadataVersion: u32;
+
+ pub fn LLVMRustAddModuleFlag(M: ModuleRef,
+ name: *c_char,
+ value: u32);
pub fn LLVMDIBuilderCreate(M: ModuleRef) -> DIBuilderRef;
Reloc: RelocMode,
Level: CodeGenOptLevel,
EnableSegstk: bool,
- UseSoftFP: bool) -> TargetMachineRef;
+ UseSoftFP: bool,
+ NoFramePointerElim: bool) -> TargetMachineRef;
pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef,
PM: PassManagerRef,
pub fn LLVMRustArchiveReadSection(AR: ArchiveRef, name: *c_char,
out_len: *mut size_t) -> *c_char;
pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
+
+ pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
}
}
pub static tag_item_method_tps: uint = 0x7b;
pub static tag_item_method_fty: uint = 0x7c;
-pub static tag_item_method_transformed_self_ty: uint = 0x7d;
-pub static tag_mod_child: uint = 0x7e;
-pub static tag_misc_info: uint = 0x7f;
-pub static tag_misc_info_crate_items: uint = 0x80;
+pub static tag_mod_child: uint = 0x7d;
+pub static tag_misc_info: uint = 0x7e;
+pub static tag_misc_info_crate_items: uint = 0x7f;
-pub static tag_item_method_provided_source: uint = 0x81;
-pub static tag_item_impl_vtables: uint = 0x82;
+pub static tag_item_method_provided_source: uint = 0x80;
+pub static tag_item_impl_vtables: uint = 0x81;
-pub static tag_impls: uint = 0x83;
-pub static tag_impls_impl: uint = 0x84;
+pub static tag_impls: uint = 0x82;
+pub static tag_impls_impl: uint = 0x83;
-pub static tag_items_data_item_inherent_impl: uint = 0x85;
-pub static tag_items_data_item_extension_impl: uint = 0x86;
+pub static tag_items_data_item_inherent_impl: uint = 0x84;
+pub static tag_items_data_item_extension_impl: uint = 0x85;
-pub static tag_path_elem_pretty_name: uint = 0x87;
-pub static tag_path_elem_pretty_name_ident: uint = 0x88;
-pub static tag_path_elem_pretty_name_extra: uint = 0x89;
+pub static tag_path_elem_pretty_name: uint = 0x86;
+pub static tag_path_elem_pretty_name_ident: uint = 0x87;
+pub static tag_path_elem_pretty_name_extra: uint = 0x88;
pub static tag_region_param_def: uint = 0x100;
pub static tag_region_param_def_ident: uint = 0x101;
|_, did| translate_def_id(cdata, did))
}
-fn doc_transformed_self_ty(doc: ebml::Doc,
- tcx: ty::ctxt,
- cdata: Cmd) -> Option<ty::t>
-{
- reader::maybe_get_doc(doc, tag_item_method_transformed_self_ty).map(|tp| {
- parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
- |_, did| translate_def_id(cdata, did))
- })
-}
-
pub fn item_type(_item_id: ast::DefId, item: ebml::Doc,
tcx: ty::ctxt, cdata: Cmd) -> ty::t {
doc_type(item, tcx, cdata)
let explicit_self_kind = string[0];
match explicit_self_kind as char {
's' => ast::SelfStatic,
- 'v' => ast::SelfValue(get_mutability(string[1])),
+ 'v' => ast::SelfValue,
'@' => ast::SelfBox,
- '~' => ast::SelfUniq(get_mutability(string[1])),
+ '~' => ast::SelfUniq,
// FIXME(#4846) expl. region
'&' => ast::SelfRegion(None, get_mutability(string[1])),
_ => fail!("unknown self type code: `{}`", explicit_self_kind as char)
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, tcx, cdata);
- let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
type_param_defs: type_param_defs,
region_param_defs: rp_defs,
},
- transformed_self_ty,
fty,
explicit_self,
vis,
ebml_w.end_tag();
}
-fn encode_transformed_self_ty(ecx: &EncodeContext,
- ebml_w: &mut writer::Encoder,
- opt_typ: Option<ty::t>) {
- for &typ in opt_typ.iter() {
- ebml_w.start_tag(tag_item_method_transformed_self_ty);
- write_type(ecx, ebml_w, typ);
- ebml_w.end_tag();
- }
-}
-
fn encode_method_fty(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
typ: &ty::BareFnTy) {
// Encode the base self type.
match explicit_self {
- SelfStatic => {
- ebml_w.writer.write(&[ 's' as u8 ]);
- }
- SelfValue(m) => {
- ebml_w.writer.write(&[ 'v' as u8 ]);
- encode_mutability(ebml_w, m);
- }
+ SelfStatic => ebml_w.writer.write(&[ 's' as u8 ]),
+ SelfValue => ebml_w.writer.write(&[ 'v' as u8 ]),
+ SelfBox => ebml_w.writer.write(&[ '@' as u8 ]),
+ SelfUniq => ebml_w.writer.write(&[ '~' as u8 ]),
SelfRegion(_, m) => {
// FIXME(#4846) encode custom lifetime
- ebml_w.writer.write(&[ '&' as u8 ]);
- encode_mutability(ebml_w, m);
- }
- SelfBox => {
- ebml_w.writer.write(&[ '@' as u8 ]);
- }
- SelfUniq(m) => {
- ebml_w.writer.write(&[ '~' as u8 ]);
+ ebml_w.writer.write(&['&' as u8]);
encode_mutability(ebml_w, m);
}
}
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(ctor_id));
encode_family(ebml_w, 'f');
+ encode_bounds_and_type(ebml_w, ecx,
+ &lookup_item_type(ecx.tcx, local_def(ctor_id)));
encode_name(ecx, ebml_w, name);
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id));
encode_path(ecx, ebml_w, path, ast_map::PathName(name));
encode_ty_type_param_defs(ebml_w, ecx,
method_ty.generics.type_param_defs,
tag_item_method_tps);
- encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty);
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);
// If this is a static method, we've already encoded
// this.
if method_ty.explicit_self != SelfStatic {
- // XXX: I feel like there is something funny going on.
+ // FIXME: 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);
}
}
pub fn get_or_default_sysroot() -> Path {
- match os::self_exe_path() {
- option::Some(p) => { let mut p = p; p.pop(); p }
+ // Follow symlinks. If the resolved path is relative, make it absolute.
+ fn canonicalize(path: Option<Path>) -> Option<Path> {
+ path.and_then(|mut path|
+ match io::io_error::cond.trap(|_| ()).inside(|| fs::readlink(&path)) {
+ Some(canon) => {
+ if canon.is_absolute() {
+ Some(canon)
+ } else {
+ path.pop();
+ Some(path.join(canon))
+ }
+ },
+ None => Some(path),
+ })
+ }
+
+ match canonicalize(os::self_exe_name()) {
+ option::Some(p) => { let mut p = p; p.pop(); p.pop(); p }
option::None => fail!("can't determine value for sysroot")
}
}
use std::ptr;
use std::str;
use std::vec;
-use extra::flate;
+use flate;
pub enum Os {
OsMacos,
for lib in libs.mut_iter() {
match lib.dylib {
Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
- assert!(lib.rlib.is_none()); // XXX: legit compiler error
+ assert!(lib.rlib.is_none()); // FIXME: legit compiler error
lib.rlib = Some(path.clone());
return true;
}
for lib in libs.mut_iter() {
match lib.rlib {
Some(ref p) if p.filename_str() == Some(file.as_slice()) => {
- assert!(lib.dylib.is_none()); // XXX: legit compiler error
+ assert!(lib.dylib.is_none()); // FIXME: legit compiler error
lib.dylib = Some(path.clone());
return true;
}
return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, |x,y| conv(x,y)));
}
'Y' => return ty::mk_type(st.tcx),
- 'C' => {
- let sigil = parse_sigil(st);
- return ty::mk_opaque_closure_ptr(st.tcx, sigil);
- }
'#' => {
let pos = parse_hex(st);
assert_eq!(next(st), ':');
}
fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef {
- ty::TypeParameterDef {ident: parse_ident(st, ':'),
- def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
- bounds: @parse_bounds(st, |x,y| conv(x,y))}
+ ty::TypeParameterDef {
+ ident: parse_ident(st, ':'),
+ def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
+ bounds: @parse_bounds(st, |x,y| conv(x,y)),
+ default: parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)))
+ }
}
fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
mywrite!(w, "s{}|", (cx.ds)(did));
}
ty::ty_type => mywrite!(w, "Y"),
- ty::ty_opaque_closure_ptr(p) => {
- mywrite!(w, "C&");
- enc_sigil(w, p);
- }
ty::ty_struct(def, ref substs) => {
mywrite!(w, "a[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
pub fn enc_type_param_def(w: &mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) {
mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id));
enc_bounds(w, cx, v.bounds);
+ enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
}
ast::DefMethod(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
}
ast::DefSelfTy(nid) => { ast::DefSelfTy(xcx.tr_id(nid)) }
- ast::DefSelf(nid, m) => { ast::DefSelf(xcx.tr_id(nid), m) }
ast::DefMod(did) => { ast::DefMod(did.tr(xcx)) }
ast::DefForeignMod(did) => { ast::DefForeignMod(did.tr(xcx)) }
ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }
-> method_map_entry;
}
-fn encode_method_map_entry(ecx: &e::EncodeContext,
- ebml_w: &mut writer::Encoder,
- mme: method_map_entry) {
+fn encode_method_map_entry(ebml_w: &mut writer::Encoder, mme: method_map_entry) {
ebml_w.emit_struct("method_map_entry", 3, |ebml_w| {
- ebml_w.emit_struct_field("self_ty", 0u, |ebml_w| {
- ebml_w.emit_ty(ecx, mme.self_ty);
- });
- ebml_w.emit_struct_field("explicit_self", 2u, |ebml_w| {
- mme.explicit_self.encode(ebml_w);
- });
ebml_w.emit_struct_field("origin", 1u, |ebml_w| {
mme.origin.encode(ebml_w);
});
-> method_map_entry {
self.read_struct("method_map_entry", 3, |this| {
method_map_entry {
- self_ty: this.read_struct_field("self_ty", 0u, |this| {
- this.read_ty(xcx)
- }),
- explicit_self: this.read_struct_field("explicit_self",
- 2,
- |this| {
- let explicit_self: ast::ExplicitSelf_ = Decodable::decode(this);
- explicit_self
- }),
origin: this.read_struct_field("origin", 1, |this| {
let method_origin: method_origin =
Decodable::decode(this);
// it is mutable. But I believe it's harmless since we generate
// balanced EBML.
//
- // XXX(pcwalton): Don't copy this way.
+ // FIXME(pcwalton): Don't copy this way.
let mut new_ebml_w = unsafe {
self.new_ebml_w.unsafe_clone()
};
ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
- encode_method_map_entry(ecx, ebml_w, *mme)
+ encode_method_map_entry(ebml_w, *mme)
})
})
}
debug!("mark_writes_through_upvars_as_used_mut(cmt={})",
cmt.repr(this.tcx()));
match cmt.cat {
- mc::cat_local(id) |
- mc::cat_arg(id) |
- mc::cat_self(id) => {
+ mc::cat_local(id) | mc::cat_arg(id) => {
let mut used_mut_nodes = this.tcx()
.used_mut_nodes
.borrow_mut();
mc::cat_rvalue(..) |
mc::cat_local(..) |
mc::cat_arg(_) |
- mc::cat_self(..) |
mc::cat_deref(_, _, mc::unsafe_ptr(..)) |
mc::cat_static_item(..) |
mc::cat_deref(_, _, mc::gc_ptr) |
let method_map = this.bccx.method_map.borrow();
match expr.node {
- ast::ExprSelf |
ast::ExprPath(..) => {
if !this.move_data.is_assignee(expr.id) {
let cmt = this.bccx.cat_expr_unadjusted(expr);
ast::ExprCall(f, ref args, _) => {
this.check_call(expr, Some(f), f.id, f.span, *args);
}
- ast::ExprMethodCall(callee_id, _, _, _, ref args, _) => {
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
this.check_call(expr, None, callee_id, expr.span, *args);
}
ast::ExprIndex(callee_id, _, rval) |
ast::ExprBinary(callee_id, _, _, rval)
if method_map.get().contains_key(&expr.id) => {
- this.check_call(expr,
- None,
- callee_id,
- expr.span,
- [rval]);
+ this.check_call(expr, None, callee_id, expr.span, [rval]);
}
ast::ExprUnary(callee_id, _, _) | ast::ExprIndex(callee_id, _, _)
if method_map.get().contains_key(&expr.id) => {
- this.check_call(expr,
- None,
- callee_id,
- expr.span,
- []);
+ this.check_call(expr, None, callee_id, expr.span, []);
}
ast::ExprInlineAsm(ref ia) => {
for &(_, out) in ia.outputs.iter() {
this.check_assignment(out);
}
}
- _ => { }
+ _ => {}
}
}
mc::cat_rvalue(..) |
mc::cat_local(..) |
- mc::cat_arg(..) |
- mc::cat_self(..) => {
+ mc::cat_arg(..) => {
true
}
mc::cat_copied_upvar(..) | // L-Local
mc::cat_local(..) | // L-Local
mc::cat_arg(..) | // L-Local
- mc::cat_self(..) | // L-Local
mc::cat_deref(_, _, mc::region_ptr(..)) | // L-Deref-Borrowed
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
let scope = self.scope(cmt);
match cmt.guarantor().cat {
mc::cat_local(id) |
- mc::cat_self(id) |
mc::cat_arg(id) => {
let moved_variables_set = self.bccx
.moved_variables_set
ty::ReStatic
}
mc::cat_local(local_id) |
- mc::cat_arg(local_id) |
- mc::cat_self(local_id) => {
+ mc::cat_arg(local_id) => {
ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
}
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
}
ty::AutoObject(..) => {
- // XXX: Handle @Trait to &Trait casts here?
+ // FIXME: Handle @Trait to &Trait casts here?
}
}
}
}
mc::cat_local(local_id) |
- mc::cat_arg(local_id) |
- mc::cat_self(local_id) => {
+ mc::cat_arg(local_id) => {
// R-Variable
let lp = @LpVar(local_id);
SafeIf(lp, ~[Restriction {loan_path: lp,
use std::result::{Result};
use syntax::ast;
use syntax::ast_map;
+use syntax::ast_util;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit;
pub struct LoanDataFlowOperator;
-/// XXX(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
+/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
impl Clone for LoanDataFlowOperator {
fn clone(&self) -> LoanDataFlowOperator {
None
}
- mc::cat_local(id) |
- mc::cat_arg(id) |
- mc::cat_self(id) => {
+ mc::cat_local(id) | mc::cat_arg(id) => {
Some(@LpVar(id))
}
match *loan_path {
LpVar(id) => {
match self.tcx.items.find(id) {
- Some(ast_map::NodeLocal(ref ident, _)) => {
- out.push_str(token::ident_to_str(ident));
+ Some(ast_map::NodeLocal(pat)) => {
+ match pat.node {
+ ast::PatIdent(_, ref path, _) => {
+ let ident = ast_util::path_to_ident(path);
+ out.push_str(token::ident_to_str(&ident));
+ }
+ _ => {
+ self.tcx.sess.bug(
+ format!("Loan path LpVar({:?}) maps to {:?}, not local",
+ id, pat));
+ }
+ }
}
r => {
self.tcx.sess.bug(
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
}
static InvalidMovePathIndex: MovePathIndex =
- MovePathIndex(uint::max_value);
+ MovePathIndex(uint::MAX);
/// Index into `MoveData.moves`, used like a pointer
#[deriving(Eq)]
}
static InvalidMoveIndex: MoveIndex =
- MoveIndex(uint::max_value);
+ MoveIndex(uint::MAX);
pub struct MovePath {
/// Loan path corresponding to this move path
pub struct MoveDataFlowOperator;
-/// XXX(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
+/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
impl Clone for MoveDataFlowOperator {
fn clone(&self) -> MoveDataFlowOperator {
pub struct AssignDataFlowOperator;
-/// XXX(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
+/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
impl Clone for AssignDataFlowOperator {
fn clone(&self) -> AssignDataFlowOperator {
self.call(expr, pred, func, *args)
}
- ast::ExprMethodCall(_, rcvr, _, _, ref args, _) => {
- self.call(expr, pred, rcvr, *args)
+ ast::ExprMethodCall(_, _, _, ref args, _) => {
+ self.call(expr, pred, args[0], args.slice_from(1))
}
ast::ExprIndex(_, l, r) |
}
ast::ExprAddrOf(_, e) |
- ast::ExprDoBody(e) |
ast::ExprCast(e, _) |
ast::ExprUnary(_, _, e) |
ast::ExprParen(e) |
ast::ExprLogLevel |
ast::ExprMac(..) |
ast::ExprInlineAsm(..) |
- ast::ExprSelf |
ast::ExprFnBlock(..) |
ast::ExprProc(..) |
ast::ExprLit(..) |
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
priv bits_per_id: uint,
/// number of words we will use to store bits_per_id.
- /// equal to bits_per_id/uint::bits rounded up.
+ /// equal to bits_per_id/uint::BITS rounded up.
priv words_per_id: uint,
// mapping from node to bitset index.
oper: O,
id_range: IdRange,
bits_per_id: uint) -> DataFlowContext<O> {
- let words_per_id = (bits_per_id + uint::bits - 1) / uint::bits;
+ let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS;
debug!("DataFlowContext::new(id_range={:?}, bits_per_id={:?}, words_per_id={:?})",
id_range, bits_per_id, words_per_id);
len
});
if expanded {
- let entry = if self.oper.initial_value() { uint::max_value } else {0};
- self.words_per_id.times(|| {
+ let entry = if self.oper.initial_value() { uint::MAX } else {0};
+ for _ in range(0, self.words_per_id) {
self.gens.push(0);
self.kills.push(0);
self.on_entry.push(entry);
- })
+ }
}
let start = *n * self.words_per_id;
let end = start + self.words_per_id;
for (word_index, &word) in words.iter().enumerate() {
if word != 0 {
- let base_index = word_index * uint::bits;
- for offset in range(0u, uint::bits) {
+ let base_index = word_index * uint::BITS;
+ for offset in range(0u, uint::BITS) {
let bit = 1 << offset;
if (word & bit) != 0 {
// NB: we round up the total number of bits
// that we store in any given bit set so that
- // it is an even multiple of uint::bits. This
+ // it is an even multiple of uint::BITS. This
// means that there may be some stray bits at
// the end that do not correspond to any
// actual value. So before we callback, check
}
ast::ExprCall(f, ref args, _) => {
- self.walk_call(f.id, expr.id,
- f, *args, in_out, loop_scopes);
+ self.walk_expr(f, in_out, loop_scopes);
+ self.walk_call(f.id, expr.id, *args, in_out, loop_scopes);
}
- ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
- self.walk_call(callee_id, expr.id,
- rcvr, *args, in_out, loop_scopes);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ self.walk_call(callee_id, expr.id, *args, in_out, loop_scopes);
}
ast::ExprIndex(callee_id, l, r) |
ast::ExprBinary(callee_id, _, l, r) if self.is_method_call(expr) => {
- self.walk_call(callee_id, expr.id,
- l, [r], in_out, loop_scopes);
+ self.walk_call(callee_id, expr.id, [l, r], in_out, loop_scopes);
}
ast::ExprUnary(callee_id, _, e) if self.is_method_call(expr) => {
- self.walk_call(callee_id, expr.id,
- e, [], in_out, loop_scopes);
+ self.walk_call(callee_id, expr.id, [e], in_out, loop_scopes);
}
ast::ExprTup(ref exprs) => {
ast::ExprLogLevel |
ast::ExprLit(..) |
- ast::ExprPath(..) |
- ast::ExprSelf => {
- }
+ ast::ExprPath(..) => {}
ast::ExprAddrOf(_, e) |
- ast::ExprDoBody(e) |
ast::ExprCast(e, _) |
ast::ExprUnary(_, _, e) |
ast::ExprParen(e) |
fn walk_call(&mut self,
_callee_id: ast::NodeId,
call_id: ast::NodeId,
- arg0: &ast::Expr,
args: &[@ast::Expr],
in_out: &mut [uint],
loop_scopes: &mut ~[LoopScope]) {
- self.walk_expr(arg0, in_out, loop_scopes);
self.walk_exprs(args, in_out, loop_scopes);
// FIXME(#6268) nested method calls
}
fn reset(&mut self, bits: &mut [uint]) {
- let e = if self.dfcx.oper.initial_value() {uint::max_value} else {0};
+ let e = if self.dfcx.oper.initial_value() {uint::MAX} else {0};
for b in bits.mut_iter() { *b = e; }
}
for &word in words.iter() {
let mut v = word;
- for _ in range(0u, uint::bytes) {
+ for _ in range(0u, uint::BYTES) {
result.push_char(sep);
result.push_str(format!("{:02x}", v & 0xFF));
v >>= 8;
fn set_bit(words: &mut [uint], bit: uint) -> bool {
debug!("set_bit: words={} bit={}",
mut_bits_to_str(words), bit_str(bit));
- let word = bit / uint::bits;
- let bit_in_word = bit % uint::bits;
+ let word = bit / uint::BITS;
+ let bit_in_word = bit % uint::BITS;
let bit_mask = 1 << bit_in_word;
debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
let oldv = words[word];
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
match expr.node {
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
let base_type = ty::node_id_to_type(self.tcx, callee_id);
debug!("effect: method call case, base type is {}",
ppaux::ty_to_str(self.tcx, base_type));
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
visit::walk_expr(self, expr, depth + 1)
}
- ast::ExprPath(..) | ast::ExprSelf => {
+ ast::ExprPath(..) => {
let mut i = 0;
let def_map = self.def_map.borrow();
match def_map.get().find(&expr.id) {
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#[deriving(Eq)]
pub struct NodeIndex(uint);
-pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::max_value);
+pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);
#[deriving(Eq)]
pub struct EdgeIndex(uint);
-pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::max_value);
+pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
// Use a private field here to guarantee no more instances are created:
pub struct Direction { priv repr: uint }
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
let id = ast_util::def_id_of_def(fv.def).node;
let var_t = ty::node_id_to_type(cx.tcx, id);
- // check that only immutable variables are implicitly copied in
- check_imm_free_var(cx, fv.def, fv.span);
-
check_freevar_bounds(cx, fv.span, var_t, bounds, None);
}
});
}
-fn check_imm_free_var(cx: &Context, def: Def, sp: Span) {
- match def {
- DefLocal(_, BindByValue(MutMutable)) => {
- cx.tcx.sess.span_err(
- sp,
- "mutable variables cannot be implicitly captured");
- }
- DefLocal(..) | DefArg(..) => { /* ok */ }
- DefUpvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
- DefBinding(..) | DefSelf(..) => { /*ok*/ }
- _ => {
- cx.tcx.sess.span_bug(
- sp,
- format!("unknown def for free variable: {:?}", def));
- }
- }
-}
-
fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
debug!("type_contents({})={}",
ty_to_str(cx.tcx, ty),
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
AttributeUsage,
UnknownFeatures,
UnknownCrateType,
+ DefaultTypeParamUsage,
ManagedHeapMemory,
OwnedHeapMemory,
Experimental,
Unstable,
+ UnusedMustUse,
+ UnusedResult,
+
Warnings,
}
desc: "unknown features found in crate-level #[feature] directives",
default: deny,
}),
- ("unknown_crate_type",
+
+ ("unknown_crate_type",
+ LintSpec {
+ lint: UnknownCrateType,
+ desc: "unknown crate type found in #[crate_type] directive",
+ default: deny,
+ }),
+
+ ("unused_must_use",
+ LintSpec {
+ lint: UnusedMustUse,
+ desc: "unused result of an type flagged as #[must_use]",
+ default: warn,
+ }),
+
+ ("unused_result",
+ LintSpec {
+ lint: UnusedResult,
+ desc: "unused result of an expression in a statement",
+ default: allow,
+ }),
+
+ ("default_type_param_usage",
LintSpec {
- lint: UnknownCrateType,
- desc: "unknown crate type found in #[crate_type] directive",
+ lint: DefaultTypeParamUsage,
+ desc: "prevents explicitly setting a type parameter with a default",
default: deny,
}),
];
// rollback
self.is_doc_hidden = old_is_doc_hidden;
- pushed.times(|| {
+ for _ in range(0, pushed) {
let (lint, lvl, src) = self.lint_stack.pop().unwrap();
self.set_level(lint, lvl, src);
- })
+ }
}
fn visit_ids(&self, f: |&mut ast_util::IdVisitor<Context>|) {
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty {
- ast::TyI => (i64::min_value, i64::max_value),
- ast::TyI8 => (i8::min_value as i64, i8::max_value as i64),
- ast::TyI16 => (i16::min_value as i64, i16::max_value as i64),
- ast::TyI32 => (i32::min_value as i64, i32::max_value as i64),
- ast::TyI64 => (i64::min_value, i64::max_value)
+ ast::TyI => (i64::MIN, i64::MAX),
+ ast::TyI8 => (i8::MIN as i64, i8::MAX as i64),
+ ast::TyI16 => (i16::MIN as i64, i16::MAX as i64),
+ ast::TyI32 => (i32::MIN as i64, i32::MAX as i64),
+ ast::TyI64 => (i64::MIN, i64::MAX)
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty {
- ast::TyU => (u64::min_value, u64::max_value),
- ast::TyU8 => (u8::min_value as u64, u8::max_value as u64),
- ast::TyU16 => (u16::min_value as u64, u16::max_value as u64),
- ast::TyU32 => (u32::min_value as u64, u32::max_value as u64),
- ast::TyU64 => (u64::min_value, u64::max_value)
+ ast::TyU => (u64::MIN, u64::MAX),
+ ast::TyU8 => (u8::MIN as u64, u8::MAX as u64),
+ ast::TyU16 => (u16::MIN as u64, u16::MAX as u64),
+ ast::TyU32 => (u32::MIN as u64, u32::MAX as u64),
+ ast::TyU64 => (u64::MIN, u64::MAX)
}
}
"crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",
"no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag", "packed",
"simd", "repr", "deriving", "unsafe_destructor", "link", "phase",
- "macro_export",
+ "macro_export", "must_use",
//mod-level
"path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude",
}
}
+fn check_unused_result(cx: &Context, s: &ast::Stmt) {
+ let expr = match s.node {
+ ast::StmtSemi(expr, _) => expr,
+ _ => return
+ };
+ let t = ty::expr_ty(cx.tcx, expr);
+ match ty::get(t).sty {
+ ty::ty_nil | ty::ty_bot | ty::ty_bool => return,
+ _ => {}
+ }
+ match expr.node {
+ ast::ExprRet(..) => return,
+ _ => {}
+ }
+
+ let t = ty::expr_ty(cx.tcx, expr);
+ let mut warned = false;
+ match ty::get(t).sty {
+ ty::ty_struct(did, _) |
+ ty::ty_enum(did, _) => {
+ if ast_util::is_local(did) {
+ match cx.tcx.items.get(did.node) {
+ ast_map::NodeItem(it, _) => {
+ if attr::contains_name(it.attrs, "must_use") {
+ cx.span_lint(UnusedMustUse, s.span,
+ "unused result which must be used");
+ warned = true;
+ }
+ }
+ _ => {}
+ }
+ } else {
+ csearch::get_item_attrs(cx.tcx.sess.cstore, did, |attrs| {
+ if attr::contains_name(attrs, "must_use") {
+ cx.span_lint(UnusedMustUse, s.span,
+ "unused result which must be used");
+ warned = true;
+ }
+ });
+ }
+ }
+ _ => {}
+ }
+ if !warned {
+ cx.span_lint(UnusedResult, s.span, "unused result");
+ }
+}
+
fn check_item_non_camel_case_types(cx: &Context, it: &ast::Item) {
fn is_camel_case(cx: ty::ctxt, ident: ast::Ident) -> bool {
let ident = cx.sess.str_of(ident);
fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) {
check_path_statement(self, s);
+ check_unused_result(self, s);
visit::walk_stmt(self, s, ());
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
impl LiveNode {
pub fn is_valid(&self) -> bool {
- self.get() != uint::max_value
+ self.get() != uint::MAX
}
}
-fn invalid_node() -> LiveNode { LiveNode(uint::max_value) }
+fn invalid_node() -> LiveNode { LiveNode(uint::MAX) }
struct CaptureInfo {
ln: LiveNode,
})
};
- // Add `this`, whether explicit or implicit.
- match *fk {
- visit::FkMethod(_, _, method) => {
- match method.explicit_self.node {
- SelfValue(_) | SelfRegion(..) | SelfBox | SelfUniq(_) => {
- fn_maps.add_variable(Arg(method.self_id,
- special_idents::self_));
- }
- SelfStatic => {}
- }
- }
- visit::FkItemFn(..) | visit::FkFnBlock(..) => {}
- }
-
// gather up the various local variables, significant expressions,
// and so forth:
visit::walk_fn(v, fk, decl, body, sp, id, fn_maps);
fn visit_expr(v: &mut LivenessVisitor, expr: &Expr, this: @IrMaps) {
match expr.node {
// live nodes required for uses or definitions of variables:
- ExprPath(_) | ExprSelf => {
+ ExprPath(_) => {
let def_map = this.tcx.def_map.borrow();
let def = def_map.get().get_copy(&expr.id);
debug!("expr {}: path that leads to {:?}", expr.id, def);
ExprIndex(..) | ExprField(..) | ExprVstore(..) | ExprVec(..) |
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprLogLevel |
ExprBinary(..) | ExprAddrOf(..) |
- ExprDoBody(..) | ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
+ ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
ExprAgain(_) | ExprLit(_) | ExprRet(..) | ExprBlock(..) |
ExprAssign(..) | ExprAssignOp(..) | ExprMac(..) |
ExprStruct(..) | ExprRepeat(..) | ExprParen(..) |
match expr.node {
// Interesting cases with control flow or which gen/kill
- ExprPath(_) | ExprSelf => {
+ ExprPath(_) => {
self.access_path(expr, succ, ACC_READ | ACC_USE)
}
self.propagate_through_expr(f, succ)
}
- ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
+ ExprMethodCall(callee_id, _, _, ref args, _) => {
// calling a method with bot return type means that the method
// will fail, and hence the successors can be ignored
let t_ret = ty::ty_fn_ret(ty::node_id_to_type(self.tcx, callee_id));
let succ = if ty::type_is_bot(t_ret) {self.s.exit_ln}
else {succ};
- let succ = self.propagate_through_exprs(*args, succ);
- self.propagate_through_expr(rcvr, succ)
+ self.propagate_through_exprs(*args, succ)
}
ExprTup(ref exprs) => {
}
ExprAddrOf(_, e) |
- ExprDoBody(e) |
ExprCast(e, _) |
ExprUnary(_, _, e) |
ExprParen(e) => {
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
ExprVstore(..) | ExprVec(..) | ExprTup(..) | ExprLogLevel |
- ExprBinary(..) | ExprDoBody(..) |
+ ExprBinary(..) |
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
- ExprSelf(..) | ExprBox(..) => {
+ ExprBox(..) => {
visit::walk_expr(this, expr, ());
}
ExprForLoop(..) => fail!("non-desugared expr_for_loop")
for arg in decl.inputs.iter() {
pat_util::pat_bindings(self.tcx.def_map,
arg.pat,
- |_bm, p_id, sp, _n| {
+ |_bm, p_id, sp, path| {
let var = self.variable(p_id, sp);
- self.warn_about_unused(sp, p_id, entry_ln, var);
+ // Ignore unused self.
+ let ident = ast_util::path_to_ident(path);
+ if ident.name != special_idents::self_.name {
+ self.warn_about_unused(sp, p_id, entry_ln, var);
+ }
})
}
}
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
cat_downcast(cmt), // selects a particular enum variant (..)
cat_discr(cmt, ast::NodeId), // match discriminant (see preserve())
- cat_self(ast::NodeId), // explicit `self`
// (..) downcast is only required if the enum has more than one variant
}
// Convert a bare fn to a closure by adding NULL env.
// Result is an rvalue.
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
- self.cat_rvalue_node(expr, expr_ty)
+ self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
}
ty::AutoDerefRef(ty::AutoDerefRef {
// Equivalent to &*expr or something similar.
// Result is an rvalue.
let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
- self.cat_rvalue_node(expr, expr_ty)
+ self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
}
ty::AutoDerefRef(ty::AutoDerefRef {
ast::ExprUnary(_, ast::UnDeref, e_base) => {
let method_map = self.method_map.borrow();
if method_map.get().contains_key(&expr.id) {
- return self.cat_rvalue_node(expr, expr_ty);
+ return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty);
}
let base_cmt = self.cat_expr(e_base);
ast::ExprIndex(_, base, _) => {
let method_map = self.method_map.borrow();
if method_map.get().contains_key(&expr.id) {
- return self.cat_rvalue_node(expr, expr_ty);
+ return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty);
}
let base_cmt = self.cat_expr(base);
self.cat_index(expr, base_cmt, 0)
}
- ast::ExprPath(_) | ast::ExprSelf => {
+ ast::ExprPath(_) => {
let def_map = self.tcx.def_map.borrow();
let def = def_map.get().get_copy(&expr.id);
self.cat_def(expr.id, expr.span, expr_ty, def)
ast::ExprAddrOf(..) | ast::ExprCall(..) |
ast::ExprAssign(..) | ast::ExprAssignOp(..) |
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) |
- ast::ExprDoBody(..) | ast::ExprUnary(..) |
+ ast::ExprUnary(..) |
ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
ast::ExprLogLevel | ast::ExprBinary(..) | ast::ExprWhile(..) |
ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
- return self.cat_rvalue_node(expr, expr_ty);
+ return self.cat_rvalue_node(expr.id(), expr.span(), expr_ty);
}
ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop")
expr_ty: ty::t,
def: ast::Def)
-> cmt {
+ debug!("cat_def: id={} expr={}",
+ id, ty_to_str(self.tcx, expr_ty));
+
+
match def {
+ ast::DefStruct(..) | ast::DefVariant(..) => {
+ self.cat_rvalue_node(id, span, expr_ty)
+ }
ast::DefFn(..) | ast::DefStaticMethod(..) | ast::DefMod(_) |
ast::DefForeignMod(_) | ast::DefStatic(_, false) |
- ast::DefUse(_) | ast::DefVariant(..) |
- ast::DefTrait(_) | ast::DefTy(_) | ast::DefPrimTy(_) |
- ast::DefTyParam(..) | ast::DefStruct(..) |
- ast::DefTyParamBinder(..) | ast::DefRegion(_) |
+ ast::DefUse(_) | ast::DefTrait(_) | ast::DefTy(_) | ast::DefPrimTy(_) |
+ ast::DefTyParam(..) | ast::DefTyParamBinder(..) | ast::DefRegion(_) |
ast::DefLabel(_) | ast::DefSelfTy(..) | ast::DefMethod(..) => {
@cmt_ {
id:id,
}
}
- ast::DefSelf(self_id, mutbl) => {
- @cmt_ {
- id:id,
- span:span,
- cat:cat_self(self_id),
- mutbl: if mutbl { McDeclared } else { McImmutable },
- ty:expr_ty
- }
- }
-
ast::DefUpvar(upvar_id, inner, fn_node_id, _) => {
let ty = ty::node_id_to_type(self.tcx, fn_node_id);
match ty::get(ty).sty {
}
}
- pub fn cat_rvalue_node<N:ast_node>(&self,
- node: &N,
- expr_ty: ty::t) -> cmt {
- match self.tcx.region_maps.temporary_scope(node.id()) {
+ pub fn cat_rvalue_node(&self, id: ast::NodeId, span: Span, expr_ty: ty::t) -> cmt {
+ match self.tcx.region_maps.temporary_scope(id) {
Some(scope) => {
- self.cat_rvalue(node.id(), node.span(),
- ty::ReScope(scope), expr_ty)
+ self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty)
}
None => {
- self.cat_rvalue(node.id(), node.span(), ty::ReStatic, expr_ty)
+ self.cat_rvalue(id, span, ty::ReStatic, expr_ty)
}
}
}
}
for &slice_pat in slice.iter() {
let slice_ty = self.pat_ty(slice_pat);
- let slice_cmt = self.cat_rvalue_node(pat, slice_ty);
+ let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y));
}
for &after_pat in after.iter() {
cat_local(_) => {
~"local variable"
}
- cat_self(_) => {
- ~"self value"
- }
cat_arg(..) => {
~"argument"
}
cat_static_item |
cat_copied_upvar(..) |
cat_local(..) |
- cat_self(..) |
cat_arg(..) |
cat_deref(_, _, unsafe_ptr(..)) |
cat_deref(_, _, gc_ptr) |
cat_rvalue(..) |
cat_local(..) |
cat_arg(_) |
- cat_self(..) |
cat_deref(_, _, unsafe_ptr(..)) | // of course it is aliasable, but...
cat_deref(_, _, region_ptr(MutMutable, _)) => {
None
cat_rvalue(..) |
cat_copied_upvar(..) |
cat_local(..) |
- cat_self(..) |
cat_arg(..) => {
format!("{:?}", *self)
}
pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
match def {
- DefBinding(nid, _) |
- DefArg(nid, _) |
- DefLocal(nid, _) |
- DefSelf(nid, _) => Some(nid),
+ DefBinding(nid, _) |
+ DefArg(nid, _) |
+ DefLocal(nid, _) => Some(nid),
_ => None
}
debug!("comp_mode = {:?}", comp_mode);
match expr.node {
- ExprPath(..) | ExprSelf => {
+ ExprPath(..) => {
match comp_mode {
Move => {
let def_map = self.tcx.def_map.borrow();
self.use_fn_args(callee.id, *args);
}
- ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => { // callee.m(args)
- // Implicit self is equivalent to & mode, but every
- // other kind should be + mode.
- self.use_receiver(rcvr);
+ ExprMethodCall(callee_id, _, _, ref args, _) => { // callee.m(args)
self.use_fn_args(callee_id, *args);
}
self.consume_expr(count);
}
- ExprDoBody(base) => {
- self.use_expr(base, comp_mode);
- }
-
ExprFnBlock(ref decl, body) |
ExprProc(ref decl, body) => {
for a in decl.inputs.iter() {
return false;
}
- self.use_receiver(receiver_expr);
+ self.use_fn_arg(receiver_expr);
// for overloaded operatrs, we are always passing in a
// reference, so it's always read mode:
})
}
- pub fn use_receiver(&mut self,
- receiver_expr: @Expr) {
- self.use_fn_arg(receiver_expr);
- }
-
pub fn use_fn_args(&mut self,
_: NodeId,
arg_exprs: &[@Expr]) {
use std::hashmap::{HashSet, HashMap};
use std::util;
+use metadata::csearch;
use middle::resolve;
use middle::ty;
use middle::typeck::{method_map, method_origin, method_param};
// While we have the id of the struct definition, go ahead and parent
// all the fields.
for field in s.fields.iter() {
- let vis = match field.node.kind {
- ast::NamedField(_, vis) => vis,
- ast::UnnamedField => continue
- };
-
- // Private fields are scoped to this module, so parent them directly
- // to the module instead of the struct. This is similar to the case
- // of private enum variants.
- if vis == ast::Private {
- self.parents.insert(field.node.id, self.curparent);
-
- // Otherwise public fields are scoped to the visibility of the
- // struct itself
- } else {
- self.parents.insert(field.node.id, n);
- }
+ self.parents.insert(field.node.id, self.curparent);
}
visit::walk_struct_def(self, s, i, g, n, ())
}
let exp_map2 = self.exp_map2.borrow();
assert!(exp_map2.get().contains_key(&id), "wut {:?}", id);
for export in exp_map2.get().get(&id).iter() {
- if is_local(export.def_id) && export.reexport {
+ if is_local(export.def_id) {
self.reexports.insert(export.def_id.node);
}
}
// Checks that a field is in scope.
// FIXME #6993: change type (and name) from Ident to Name
- fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
+ fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident,
+ enum_id: Option<ast::DefId>) {
let fields = ty::lookup_struct_fields(self.tcx, id);
+ let struct_vis = if is_local(id) {
+ match self.tcx.items.get(id.node) {
+ ast_map::NodeItem(ref it, _) => it.vis,
+ ast_map::NodeVariant(ref v, ref it, _) => {
+ if v.node.vis == ast::Inherited {it.vis} else {v.node.vis}
+ }
+ _ => {
+ self.tcx.sess.span_bug(span,
+ format!("not an item or variant def"));
+ }
+ }
+ } else {
+ let cstore = self.tcx.sess.cstore;
+ match enum_id {
+ Some(enum_id) => {
+ let v = csearch::get_enum_variants(self.tcx, enum_id);
+ match v.iter().find(|v| v.id == id) {
+ Some(variant) => {
+ if variant.vis == ast::Inherited {
+ csearch::get_item_visibility(cstore, enum_id)
+ } else {
+ variant.vis
+ }
+ }
+ None => {
+ self.tcx.sess.span_bug(span, "no xcrate variant");
+ }
+ }
+ }
+ None => csearch::get_item_visibility(cstore, id)
+ }
+ };
+
for field in fields.iter() {
if field.name != ident.name { continue; }
- // public fields are public everywhere
- if field.vis != ast::Private { break }
+ // public structs have public fields by default, and private structs
+ // have private fields by default.
+ if struct_vis == ast::Public && field.vis != ast::Private { break }
+ if struct_vis != ast::Public && field.vis == ast::Public { break }
if !is_local(field.id) ||
!self.private_accessible(field.id.node) {
self.tcx.sess.span_err(span, format!("field `{}` is private",
let t = ty::type_autoderef(ty::expr_ty(self.tcx, base));
match ty::get(t).sty {
ty::ty_struct(id, _) => {
- self.check_field(expr.span, id, ident);
+ self.check_field(expr.span, id, ident, None);
}
_ => {}
}
}
- ast::ExprMethodCall(_, base, ident, _, _, _) => {
+ ast::ExprMethodCall(_, ident, _, ref args, _) => {
// see above
- let t = ty::type_autoderef(ty::expr_ty(self.tcx, base));
+ let t = ty::type_autoderef(ty::expr_ty(self.tcx, args[0]));
match ty::get(t).sty {
ty::ty_enum(_, _) | ty::ty_struct(_, _) => {
let method_map = self.method_map.borrow();
match ty::get(ty::expr_ty(self.tcx, expr)).sty {
ty::ty_struct(id, _) => {
for field in (*fields).iter() {
- self.check_field(expr.span, id, field.ident.node);
+ self.check_field(expr.span, id, field.ident.node,
+ None);
}
}
ty::ty_enum(_, _) => {
let def_map = self.tcx.def_map.borrow();
match def_map.get().get_copy(&expr.id) {
- ast::DefVariant(_, variant_id, _) => {
+ ast::DefVariant(enum_id, variant_id, _) => {
for field in fields.iter() {
self.check_field(expr.span, variant_id,
- field.ident.node);
+ field.ident.node,
+ Some(enum_id));
}
}
_ => self.tcx.sess.span_bug(expr.span,
match ty::get(ty::pat_ty(self.tcx, pattern)).sty {
ty::ty_struct(id, _) => {
for field in fields.iter() {
- self.check_field(pattern.span, id, field.ident);
+ self.check_field(pattern.span, id, field.ident,
+ None);
}
}
ty::ty_enum(_, _) => {
let def_map = self.tcx.def_map.borrow();
match def_map.get().find(&pattern.id) {
- Some(&ast::DefVariant(_, variant_id, _)) => {
+ Some(&ast::DefVariant(enum_id, variant_id, _)) => {
for field in fields.iter() {
self.check_field(pattern.span, variant_id,
- field.ident);
+ field.ident, Some(enum_id));
}
}
_ => self.tcx.sess.span_bug(pattern.span,
}
}
};
- let check_struct = |def: &@ast::StructDef| {
+ let check_struct = |def: &@ast::StructDef,
+ vis: ast::Visibility,
+ parent_vis: Option<ast::Visibility>| {
+ let public_def = match vis {
+ ast::Public => true,
+ ast::Inherited | ast::Private => parent_vis == Some(ast::Public),
+ };
for f in def.fields.iter() {
match f.node.kind {
- ast::NamedField(_, ast::Public) => {
+ ast::NamedField(_, ast::Public) if public_def => {
tcx.sess.span_err(f.span, "unnecessary `pub` \
visibility");
}
- ast::NamedField(_, ast::Private) => {
- // Fields should really be private by default...
+ ast::NamedField(_, ast::Private) if !public_def => {
+ tcx.sess.span_err(f.span, "unnecessary `priv` \
+ visibility");
}
ast::NamedField(..) | ast::UnnamedField => {}
}
}
match v.node.kind {
- ast::StructVariantKind(ref s) => check_struct(s),
+ ast::StructVariantKind(ref s) => {
+ check_struct(s, v.node.vis, Some(item.vis));
+ }
ast::TupleVariantKind(..) => {}
}
}
}
- ast::ItemStruct(ref def, _) => check_struct(def),
+ ast::ItemStruct(ref def, _) => check_struct(def, item.vis, None),
ast::ItemTrait(_, _, ref methods) => {
for m in methods.iter() {
// Step 3: Mark all destructors as reachable.
//
- // XXX(pcwalton): This is a conservative overapproximation, but fixing
+ // FIXME(pcwalton): This is a conservative overapproximation, but fixing
// this properly would result in the necessity of computing *type*
// reachability, which might result in a compile time loss.
fn mark_destructors_reachable(&self) {
}
// else, locate the innermost terminating scope
- let mut id = self.encl_scope(expr_id);
+ // if there's one. Static items, for instance, won't
+ // have an enclusing scope, hence no scope will be
+ // returned.
+ let mut id = match self.opt_encl_scope(expr_id) {
+ Some(i) => i,
+ None => { return None; }
+ };
+
let terminating_scopes = self.terminating_scopes.borrow();
while !terminating_scopes.get().contains(&id) {
match self.opt_encl_scope(id) {
// The arguments and `self` are parented to the body of the fn.
let decl_cx = Context {parent: Some(body.id),
var_parent: Some(body.id)};
- match *fk {
- visit::FkMethod(_, _, method) => {
- visitor.region_maps.record_var_scope(method.self_id, body.id);
- }
- _ => {}
- }
visit::walk_fn_decl(visitor, decl, decl_cx);
// The body of the fn itself is either a root scope (top-level fn)
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
pub struct Export2 {
name: @str, // The name of the target.
def_id: DefId, // The definition of the target.
- reexport: bool, // Whether this is a reexport.
}
// This set contains all exported definitions from external crates. The set does
// not contain any entries from local crates.
pub type ExternalExports = HashSet<DefId>;
-// XXX: dox
+// FIXME: dox
pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
pub enum LastPrivate {
ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
}
-enum SelfBinding {
- NoSelfBinding,
- HasSelfBinding(NodeId, ExplicitSelf)
-}
-
impl Visitor<()> for Resolver {
fn visit_item(&mut self, item: &Item, _: ()) {
self.resolve_item(item);
PrefixFound(@Module, uint)
}
-#[deriving(Eq)]
-enum AllowCapturingSelfFlag {
- AllowCapturingSelf, //< The "self" definition can be captured.
- DontAllowCapturingSelf, //< The "self" definition cannot be captured.
-}
-
#[deriving(Eq)]
enum NameSearchType {
/// We're doing a name search in order to resolve a `use` directive.
/// One local scope.
struct Rib {
bindings: RefCell<HashMap<Name, DefLike>>,
- self_binding: RefCell<Option<DefLike>>,
kind: RibKind,
}
fn new(kind: RibKind) -> Rib {
Rib {
bindings: RefCell::new(HashMap::new()),
- self_binding: RefCell::new(None),
kind: kind
}
}
parent: ReducedGraphParent,
parent_public: bool) {
let ident = variant.node.name;
- // XXX: this is unfortunate to have to do this privacy calculation
+ // FIXME: this is unfortunate to have to do this privacy calculation
// here. This should be living in middle::privacy, but it's
// necessary to keep around in some form becaues of glob imports...
let is_public = parent_public && variant.node.vis != ast::Private;
ignoring {:?}", def);
// Ignored; handled elsewhere.
}
- DefSelf(..) | DefArg(..) | DefLocal(..) |
- DefPrimTy(..) | DefTyParam(..) | DefBinding(..) |
+ DefArg(..) | DefLocal(..) | DefPrimTy(..) |
+ DefTyParam(..) | DefBinding(..) |
DefUse(..) | DefUpvar(..) | DefRegion(..) |
DefTyParamBinder(..) | DefLabel(..) | DefSelfTy(..) => {
fail!("didn't expect `{:?}`", def);
exports2: &mut ~[Export2],
name: Name,
namebindings: @NameBindings,
- ns: Namespace,
- reexport: bool) {
+ ns: Namespace) {
match namebindings.def_for_namespace(ns) {
Some(d) => {
- debug!("(computing exports) YES: {} '{}' => {:?}",
- if reexport { ~"reexport" } else { ~"export"},
+ debug!("(computing exports) YES: export '{}' => {:?}",
interner_get(name),
def_id_of_def(d));
exports2.push(Export2 {
- reexport: reexport,
name: interner_get(name),
def_id: def_id_of_def(d)
});
}
d_opt => {
- debug!("(computing reexports) NO: {:?}", d_opt);
+ debug!("(computing exports) NO: {:?}", d_opt);
}
}
}
for &ns in xs.iter() {
match importresolution.target_for_namespace(ns) {
Some(target) => {
- debug!("(computing exports) maybe reexport '{}'",
+ debug!("(computing exports) maybe export '{}'",
interner_get(*name));
self.add_exports_of_namebindings(exports2,
*name,
target.bindings,
- ns,
- true)
+ ns)
}
_ => ()
}
ribs: &mut ~[@Rib],
rib_index: uint,
def_like: DefLike,
- span: Span,
- allow_capturing_self: AllowCapturingSelfFlag)
+ span: Span)
-> Option<DefLike> {
let mut def;
let is_ty_param;
def = d;
is_ty_param = true;
}
- DlDef(d @ DefSelf(..))
- if allow_capturing_self == DontAllowCapturingSelf => {
- def = d;
- is_ty_param = false;
- }
_ => {
return Some(def_like);
}
fn search_ribs(&mut self,
ribs: &mut ~[@Rib],
name: Name,
- span: Span,
- allow_capturing_self: AllowCapturingSelfFlag)
+ span: Span)
-> Option<DefLike> {
// FIXME #4950: This should not use a while loop.
// FIXME #4950: Try caching?
};
match binding_opt {
Some(def_like) => {
- return self.upvarify(ribs, i, def_like, span,
- allow_capturing_self);
+ return self.upvarify(ribs, i, def_like, span);
}
None => {
// Continue.
item.id,
0,
OpaqueFunctionRibKind),
- block,
- NoSelfBinding);
+ block);
}
ItemStatic(..) => {
}
fn resolve_function(&mut self,
- rib_kind: RibKind,
- optional_declaration: Option<P<FnDecl>>,
- type_parameters: TypeParameters,
- block: P<Block>,
- self_binding: SelfBinding) {
+ rib_kind: RibKind,
+ optional_declaration: Option<P<FnDecl>>,
+ type_parameters: TypeParameters,
+ block: P<Block>) {
// Create a value rib for the function.
let function_value_rib = @Rib::new(rib_kind);
{
}
}
- // Add self to the rib, if necessary.
- match self_binding {
- NoSelfBinding => {
- // Nothing to do.
- }
- HasSelfBinding(self_node_id, explicit_self) => {
- let mutable = match explicit_self.node {
- SelfUniq(m) | SelfValue(m) if m == MutMutable => true,
- _ => false
- };
- let def_like = DlDef(DefSelf(self_node_id, mutable));
- function_value_rib.self_binding.set(Some(def_like));
- }
- }
-
// Add each argument to the rib.
match optional_declaration {
None => {
for bound in type_parameter.bounds.iter() {
self.resolve_type_parameter_bound(type_parameter.id, bound);
}
+ match type_parameter.default {
+ Some(ty) => self.resolve_type(ty),
+ None => {}
+ }
}
}
// Does this really need to take a RibKind or is it always going
// to be NormalRibKind?
fn resolve_method(&mut self,
- rib_kind: RibKind,
- method: @Method,
- outer_type_parameter_count: uint) {
+ rib_kind: RibKind,
+ method: @Method,
+ outer_type_parameter_count: uint) {
let method_generics = &method.generics;
let type_parameters =
HasTypeParameters(method_generics,
method.id,
outer_type_parameter_count,
rib_kind);
- // we only have self ty if it is a non static method
- let self_binding = match method.explicit_self.node {
- SelfStatic => NoSelfBinding,
- _ => HasSelfBinding(method.self_id, method.explicit_self)
- };
- self.resolve_function(rib_kind,
- Some(method.decl),
- type_parameters,
- method.body,
- self_binding);
+ self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
}
fn resolve_implementation(&mut self,
method.id,
outer_type_parameter_count,
NormalRibKind),
- method.body,
- HasSelfBinding(method.self_id),
- visitor);
+ method.body);
*/
}
let mut value_ribs = self.value_ribs.borrow_mut();
search_result = self.search_ribs(value_ribs.get(),
renamed,
- span,
- DontAllowCapturingSelf);
+ span);
}
TypeNS => {
let name = ident.name;
let mut type_ribs = self.type_ribs.borrow_mut();
search_result = self.search_ribs(type_ribs.get(),
name,
- span,
- AllowCapturingSelf);
+ span);
}
}
}
}
- fn resolve_self_value_in_local_ribs(&mut self, span: Span)
- -> Option<Def> {
- // FIXME #4950: This should not use a while loop.
- let mut i = {
- let value_ribs = self.value_ribs.borrow();
- value_ribs.get().len()
- };
- while i != 0 {
- i -= 1;
- let self_binding_opt = {
- let value_ribs = self.value_ribs.borrow();
- value_ribs.get()[i].self_binding.get()
- };
- match self_binding_opt {
- Some(def_like) => {
- let mut value_ribs = self.value_ribs.borrow_mut();
- match self.upvarify(value_ribs.get(),
- i,
- def_like,
- span,
- DontAllowCapturingSelf) {
- Some(DlDef(def)) => return Some(def),
- _ => {
- if self.session.has_errors() {
- // May happen inside a nested fn item, cf #6642.
- return None;
- } else {
- self.session.span_bug(span,
- "self wasn't mapped to a def?!")
- }
- }
- }
- }
- None => {}
- }
- }
-
- None
- }
-
fn resolve_item_by_identifier_in_lexical_scope(&mut self,
ident: Ident,
namespace: Namespace)
let bindings = value_ribs.get()[j].bindings.borrow();
for (&k, _) in bindings.get().iter() {
maybes.push(interner_get(k));
- values.push(uint::max_value);
+ values.push(uint::MAX);
}
}
}
if values.len() > 0 &&
- values[smallest] != uint::max_value &&
+ values[smallest] != uint::MAX &&
values[smallest] < name.len() + 2 &&
values[smallest] <= max_distance &&
name != maybes[smallest] {
ExprFnBlock(fn_decl, block) |
ExprProc(fn_decl, block) => {
self.resolve_function(FunctionRibKind(expr.id, block.id),
- Some(fn_decl),
- NoTypeParameters,
- block,
- NoSelfBinding);
+ Some(fn_decl), NoTypeParameters,
+ block);
}
ExprStruct(ref path, _, _) => {
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
let mut label_ribs = self.label_ribs.borrow_mut();
- match self.search_ribs(label_ribs.get(), label, expr.span,
- DontAllowCapturingSelf) {
+ match self.search_ribs(label_ribs.get(), label, expr.span) {
None =>
self.resolve_error(expr.span,
format!("use of undeclared label \
`{}`",
interner_get(label))),
Some(DlDef(def @ DefLabel(_))) => {
- // XXX: is AllPublic correct?
+ // FIXME: is AllPublic correct?
self.record_def(expr.id, (def, AllPublic))
}
Some(_) => {
}
}
- ExprSelf => {
- match self.resolve_self_value_in_local_ribs(expr.span) {
- None => {
- self.resolve_error(expr.span,
- "`self` is not allowed in \
- this context")
- }
- Some(def) => self.record_def(expr.id, (def, AllPublic)),
- }
- }
-
_ => {
visit::walk_expr(self, expr, ());
}
let traits = self.search_for_traits_containing_method(ident);
self.trait_map.insert(expr.id, @RefCell::new(traits));
}
- ExprMethodCall(_, _, ident, _, _, _) => {
+ ExprMethodCall(_, ident, _, _, _) => {
debug!("(recording candidate traits for expr) recording \
traits for {}",
expr.id);
ty::TypeParameterDef {
ident: self.ident,
def_id: self.def_id,
- bounds: self.bounds.subst(tcx, substs)
+ bounds: self.bounds.subst(tcx, substs),
+ default: self.default.map(|x| x.subst(tcx, substs))
}
}
}
return adt::trans_case(bcx, repr, disr_val);
}
range(l1, l2) => {
- let (l1, _) = consts::const_expr(ccx, l1);
- let (l2, _) = consts::const_expr(ccx, l2);
+ let (l1, _) = consts::const_expr(ccx, l1, true);
+ let (l2, _) = consts::const_expr(ccx, l2, true);
return range_result(rslt(bcx, l1), rslt(bcx, l2));
}
vec_len(n, vec_len_eq, _) => {
type BindingsMap = HashMap<Ident, BindingInfo>;
-#[deriving(Clone)]
struct ArmData<'a,'b> {
bodycx: &'b Block<'b>,
arm: &'a ast::Arm,
bindings_map: @BindingsMap
}
+// FIXME #11820: method resolution is unreliable with &
+impl<'a,'b> Clone for ArmData<'a, 'b> {
+ fn clone(&self) -> ArmData<'a, 'b> { *self }
+}
+
/**
* Info about Match.
* If all `pats` are matched then arm `data` will be executed.
}
ast::PatEnum(_, ref subpats) => {
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- // XXX: Must we clone?
+ // FIXME: Must we clone?
match *subpats {
None => Some(vec::from_elem(variant_size, dummy)),
_ => (*subpats).clone(),
}
return bcx;
}
-
-
C_undef(Type::array(&Type::i8(), size))
}
-// XXX this utility routine should be somewhere more general
+// FIXME this utility routine should be somewhere more general
#[inline]
fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
use driver::session::Session;
use driver::driver::{CrateAnalysis, CrateTranslation};
use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
-use lib::llvm::{llvm, True};
+use lib::llvm::{llvm, True, Vector};
use lib;
use metadata::common::LinkMeta;
use metadata::{csearch, encoder};
use util::ppaux::{Repr, ty_to_str};
use util::sha2::Sha256;
-use extra::arena::TypedArena;
+use arena::TypedArena;
use extra::time;
use std::c_str::ToCStr;
use std::cell::{Cell, RefCell};
}
}
- let f = decl_rust_fn(ccx, None, inputs, output, name);
+ let f = decl_rust_fn(ccx, false, inputs, output, name);
csearch::get_item_attrs(ccx.tcx.cstore, did, |meta_items| {
set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr(x)).to_owned_vec(), f)
});
f
}
-fn decl_rust_fn(ccx: &CrateContext,
- self_ty: Option<ty::t>,
- inputs: &[ty::t],
- output: ty::t,
- name: &str) -> ValueRef {
- let llfty = type_of_rust_fn(ccx, self_ty, inputs, output);
+pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
let uses_outptr = type_of::return_uses_outptr(ccx, output);
- let offset = if uses_outptr { 2 } else { 1 };
+ let offset = if uses_outptr { 1 } else { 0 };
+ let offset = if has_env { offset + 1 } else { offset };
for (i, &arg_ty) in inputs.iter().enumerate() {
let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
llfn
}
-pub fn decl_internal_rust_fn(ccx: &CrateContext,
- self_ty: Option<ty::t>, inputs: &[ty::t],
- output: ty::t, name: &str) -> ValueRef {
- let llfn = decl_rust_fn(ccx, self_ty, inputs, output, name);
+pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
llfn
}
// Returns a pointer to the body for the box. The box may be an opaque
// box. The result will be casted to the type of body_t, if it is statically
// known.
-//
-// The runtime equivalent is box_body() in "rust_internal.h".
-pub fn opaque_box_body(bcx: &Block, body_t: ty::t, boxptr: ValueRef)
- -> ValueRef {
- let _icx = push_ctxt("opaque_box_body");
+pub fn at_box_body(bcx: &Block, body_t: ty::t, boxptr: ValueRef) -> ValueRef {
+ let _icx = push_ctxt("at_box_body");
let ccx = bcx.ccx();
- let ty = type_of(ccx, body_t);
- let ty = Type::smart_ptr(ccx, &ty);
+ let ty = Type::at_box(ccx, type_of(ccx, body_t));
let boxptr = PointerCast(bcx, boxptr, ty.ptr_to());
GEPi(bcx, boxptr, [0u, abi::box_field_body])
}
// Get the tydesc for the body:
let static_ti = get_tydesc(ccx, t);
- glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
+ glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
// Allocate space:
let tydesc = PointerCast(bcx, static_ti.tydesc, Type::i8p());
let variant_cx =
fcx.new_temp_block(~"enum-iter-variant-" +
variant.disr_val.to_str());
- let variant_cx =
- iter_variant(variant_cx, repr, av, *variant,
- substs.tps, |x,y,z| f(x,y,z));
match adt::trans_case(cx, repr, variant.disr_val) {
_match::single_result(r) => {
AddCase(llswitch, r.val, variant_cx.llbb)
_ => ccx.sess.unimpl("value from adt::trans_case \
in iter_structural_ty")
}
+ let variant_cx =
+ iter_variant(variant_cx, repr, av, *variant,
+ substs.tps, |x,y,z| f(x,y,z));
Br(variant_cx, next_cx.llbb);
}
cx = next_cx;
// Shifts may have any size int on the rhs
unsafe {
if ast_util::is_shift_binop(op) {
- let rhs_llty = val_ty(rhs);
- let lhs_llty = val_ty(lhs);
+ let mut rhs_llty = val_ty(rhs);
+ let mut lhs_llty = val_ty(lhs);
+ if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() }
+ if lhs_llty.kind() == Vector { lhs_llty = lhs_llty.element_type() }
let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty.to_ref());
let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty.to_ref());
if lhs_sz < rhs_sz {
})
}
-pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
- C_null(Type::opaque_box(ccx).ptr_to())
-}
-
pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
Some(..) | None => {
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
let cconv = c.unwrap_or(lib::llvm::CCallConv);
- let llty = type_of_fn_from_ty(ccx, None, t);
+ let llty = type_of_fn_from_ty(ccx, t);
let mut externs = ccx.externs.borrow_mut();
get_extern_fn(externs.get(), ccx.llmod, name,
cconv, llty, fn_ty.sig.output)
path: ast_map::Path,
llfndecl: ValueRef,
id: ast::NodeId,
+ has_env: bool,
output_type: ty::t,
param_substs: Option<@param_substs>,
sp: Option<Span>)
let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
- let fcx = FunctionContext {
- llfn: llfndecl,
- llenv: unsafe {
- Cell::new(llvm::LLVMGetUndef(Type::i8p().to_ref()))
- },
- llretptr: Cell::new(None),
- entry_bcx: RefCell::new(None),
- alloca_insert_pt: Cell::new(None),
- llreturn: Cell::new(None),
- llself: Cell::new(None),
- personality: Cell::new(None),
- caller_expects_out_pointer: uses_outptr,
- llargs: RefCell::new(HashMap::new()),
- lllocals: RefCell::new(HashMap::new()),
- llupvars: RefCell::new(HashMap::new()),
- id: id,
- param_substs: param_substs,
- span: sp,
- path: path,
- block_arena: TypedArena::new(),
- ccx: ccx,
- debug_context: debug_context,
- scopes: RefCell::new(~[])
+ let mut fcx = FunctionContext {
+ llfn: llfndecl,
+ llenv: None,
+ llretptr: Cell::new(None),
+ entry_bcx: RefCell::new(None),
+ alloca_insert_pt: Cell::new(None),
+ llreturn: Cell::new(None),
+ personality: Cell::new(None),
+ caller_expects_out_pointer: uses_outptr,
+ llargs: RefCell::new(HashMap::new()),
+ lllocals: RefCell::new(HashMap::new()),
+ llupvars: RefCell::new(HashMap::new()),
+ id: id,
+ param_substs: param_substs,
+ span: sp,
+ path: path,
+ block_arena: TypedArena::new(),
+ ccx: ccx,
+ debug_context: debug_context,
+ scopes: RefCell::new(~[])
};
- fcx.llenv.set(unsafe {
- llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
- });
+
+ if has_env {
+ fcx.llenv = Some(unsafe {
+ llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
+ });
+ }
fcx
}
skip_retptr: bool,
output_type: ty::t,
param_substs: Option<@param_substs>) {
- unsafe {
- let entry_bcx = fcx.new_temp_block("entry-block");
- Load(entry_bcx, C_null(Type::i8p()));
+ let entry_bcx = fcx.new_temp_block("entry-block");
- fcx.entry_bcx.set(Some(entry_bcx));
- fcx.alloca_insert_pt.set(Some(
- llvm::LLVMGetFirstInstruction(entry_bcx.llbb)));
- }
+ fcx.entry_bcx.set(Some(entry_bcx));
+
+ // Use a dummy instruction as the insertion point for all allocas.
+ // This is later removed in FunctionContext::cleanup.
+ fcx.alloca_insert_pt.set(Some(unsafe {
+ Load(entry_bcx, C_null(Type::i8p()));
+ llvm::LLVMGetFirstInstruction(entry_bcx.llbb)
+ }));
let substd_output_type = match param_substs {
None => output_type,
// Otherwise, we normally allocate the llretptr, unless we
// have been instructed to skip it for immediate return
// values.
- fcx.llretptr.set(Some(make_return_pointer(fcx,
- substd_output_type)));
+ fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
}
}
}
pub fn new_fn_ctxt(ccx: @CrateContext,
path: ast_map::Path,
llfndecl: ValueRef,
+ has_env: bool,
output_type: ty::t,
sp: Option<Span>)
-> FunctionContext {
// FIXME(#11385): Do not call `init_function` here; it will typecheck
// but segfault.
- new_fn_ctxt_detailed(ccx, path, llfndecl, -1, output_type, None, sp)
+ new_fn_ctxt_detailed(ccx, path, llfndecl, -1, has_env, output_type, None, sp)
}
// NB: must keep 4 fns in sync:
type RvalueDatum = datum::Datum<datum::Rvalue>;
type LvalueDatum = datum::Datum<datum::Lvalue>;
-// create_datums_for_fn_args: creates rvalue datums for `self` and each of the
+// create_datums_for_fn_args: creates rvalue datums for each of the
// incoming function arguments. These will later be stored into
// appropriate lvalue datums.
-fn create_datums_for_fn_args(cx: &FunctionContext,
- self_arg: Option<ty::t>,
- arg_tys: &[ty::t])
- -> (Option<RvalueDatum>, ~[RvalueDatum]) {
+pub fn create_datums_for_fn_args(fcx: &FunctionContext,
+ arg_tys: &[ty::t])
+ -> ~[RvalueDatum] {
let _icx = push_ctxt("create_datums_for_fn_args");
- let self_datum = self_arg.map(
- |t| datum::Datum(cx.llenv.get(), t, arg_kind(cx, t)));
-
// Return an array wrapping the ValueRefs that we get from
// llvm::LLVMGetParam for each argument into datums.
- let arg_datums = arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
- let llarg = unsafe {
- llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint)
- };
- datum::Datum(llarg, arg_ty, arg_kind(cx, arg_ty))
- }).collect();
-
- (self_datum, arg_datums)
+ arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
+ let llarg = unsafe {
+ llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
+ };
+ datum::Datum(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ }).collect()
}
fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
arg_scope: cleanup::CustomScopeIndex,
bcx: &'a Block<'a>,
args: &[ast::Arg],
- self_datum: Option<RvalueDatum>,
arg_datums: ~[RvalueDatum])
-> &'a Block<'a> {
debug!("copy_args_to_allocas");
let mut bcx = bcx;
let arg_scope_id = cleanup::CustomScope(arg_scope);
- match self_datum {
- Some(slf_rv) => {
- let slf = unpack_datum!(
- bcx, slf_rv.to_lvalue_datum_in_scope(bcx, "__self",
- arg_scope_id));
- fcx.llself.set(Some(slf));
- if fcx.ccx.sess.opts.extra_debuginfo {
- debuginfo::create_self_argument_metadata(bcx, slf.ty, slf.val);
- }
- }
- _ => {}
- }
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
// For certain mode/type combinations, the raw llarg values are passed
}
}
- return bcx;
+ bcx
}
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// trans_closure: Builds an LLVM function out of a source function.
// If the function closes over its environment a closure will be
// returned.
-pub fn trans_closure(ccx: @CrateContext,
- path: ast_map::Path,
- decl: &ast::FnDecl,
- body: &ast::Block,
- llfndecl: ValueRef,
- self_arg: Option<ty::t>,
- param_substs: Option<@param_substs>,
- id: ast::NodeId,
- _attributes: &[ast::Attribute],
- output_type: ty::t,
- maybe_load_env: |&FunctionContext|) {
+pub fn trans_closure<'a>(ccx: @CrateContext,
+ path: ast_map::Path,
+ decl: &ast::FnDecl,
+ body: &ast::Block,
+ llfndecl: ValueRef,
+ param_substs: Option<@param_substs>,
+ id: ast::NodeId,
+ _attributes: &[ast::Attribute],
+ output_type: ty::t,
+ maybe_load_env: |&'a Block<'a>| -> &'a Block<'a>) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
debug!("trans_closure(..., param_substs={})",
param_substs.repr(ccx.tcx));
- let fcx = new_fn_ctxt_detailed(ccx,
- path,
- llfndecl,
- id,
- output_type,
- param_substs,
- Some(body.span));
+ let has_env = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
+ ty::ty_closure(_) => true,
+ _ => false
+ };
+
+ let fcx = new_fn_ctxt_detailed(ccx, path, llfndecl, id, has_env, output_type,
+ param_substs, Some(body.span));
init_function(&fcx, false, output_type, param_substs);
// cleanup scope for the incoming arguments
// Set up arguments to the function.
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
- let (self_datum, arg_datums) =
- create_datums_for_fn_args(&fcx, self_arg, arg_tys);
+ let arg_datums = create_datums_for_fn_args(&fcx, arg_tys);
- bcx = copy_args_to_allocas(&fcx, arg_scope, bcx,
- decl.inputs, self_datum, arg_datums);
+ bcx = copy_args_to_allocas(&fcx, arg_scope, bcx, decl.inputs, arg_datums);
- maybe_load_env(&fcx);
+ bcx = maybe_load_env(bcx);
// Up until here, IR instructions for this function have explicitly not been annotated with
// source code location, so we don't step into call setup code. From here on, source location
decl: &ast::FnDecl,
body: &ast::Block,
llfndecl: ValueRef,
- self_arg: Option<ty::t>,
param_substs: Option<@param_substs>,
id: ast::NodeId,
attrs: &[ast::Attribute]) {
let the_path_str = path_str(ccx.sess, path);
let _s = StatRecorder::new(ccx, the_path_str);
- debug!("trans_fn(self_arg={:?}, param_substs={})",
- self_arg,
- param_substs.repr(ccx.tcx));
+ debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx));
let _icx = push_ctxt("trans_fn");
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
- trans_closure(ccx,
- path.clone(),
- decl,
- body,
- llfndecl,
- self_arg,
- param_substs,
- id,
- attrs,
- output_type,
- |_fcx| { });
+ trans_closure(ccx, path.clone(), decl, body, llfndecl,
+ param_substs, id, attrs, output_type, |bcx| bcx);
}
pub fn trans_enum_variant(ccx: @CrateContext,
ty_to_str(ccx.tcx, ctor_ty)))
};
- let fcx = new_fn_ctxt_detailed(ccx,
- ~[],
- llfndecl,
- ctor_id,
- result_ty,
- param_substs,
- None);
+ let fcx = new_fn_ctxt_detailed(ccx, ~[], llfndecl, ctor_id, false,
+ result_ty, param_substs, None);
init_function(&fcx, false, result_ty, param_substs);
let arg_tys = ty::ty_fn_args(ctor_ty);
- let (_, arg_datums) = create_datums_for_fn_args(&fcx, None, arg_tys);
+ let arg_datums = create_datums_for_fn_args(&fcx, arg_tys);
let bcx = fcx.entry_bcx.get().unwrap();
llfndecl,
item.id);
} else if !generics.is_type_parameterized() {
- let llfndecl = get_item_val(ccx, item.id);
- trans_fn(ccx,
- vec::append_one((*path).clone(), PathName(item.ident)),
- decl,
- body,
- llfndecl,
- None,
- None,
- item.id,
- item.attrs);
+ let path = vec::append_one((*path).clone(), PathName(item.ident));
+ let llfn = get_item_val(ccx, item.id);
+ trans_fn(ccx, path, decl, body, llfn, None, item.id, item.attrs);
} else {
// Be sure to travel more than just one layer deep to catch nested
// items in blocks and such.
sp: Span,
sym: ~str,
node_id: ast::NodeId,
- node_type: ty::t,
- self_ty: Option<ty::t>)
+ node_type: ty::t)
-> ValueRef {
let f = match ty::get(node_type).sty {
ty::ty_bare_fn(ref f) => {
_ => fail!("expected bare rust fn or an intrinsic")
};
- let llfn = decl_rust_fn(ccx, self_ty, f.sig.inputs, f.sig.output, sym);
+ let llfn = decl_rust_fn(ccx, false, f.sig.inputs, f.sig.output, sym);
finish_register_fn(ccx, sp, sym, node_id, llfn);
llfn
}
});
~[
- C_null(Type::opaque_box(ccx).ptr_to()),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0),
llvm::LLVMGetParam(llfn, 1)
} else {
debug!("using user-defined start fn");
let args = ~[
- C_null(Type::opaque_box(ccx).ptr_to()),
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint)
];
}
}
-pub fn fill_fn_pair(bcx: &Block,
- pair: ValueRef,
- llfn: ValueRef,
- llenvptr: ValueRef) {
- let ccx = bcx.ccx();
- let code_cell = GEPi(bcx, pair, [0u, abi::fn_field_code]);
- Store(bcx, llfn, code_cell);
- let env_cell = GEPi(bcx, pair, [0u, abi::fn_field_box]);
- let llenvblobptr = PointerCast(bcx, llenvptr, Type::opaque_box(ccx).ptr_to());
- Store(bcx, llenvblobptr, env_cell);
-}
-
pub fn item_path(ccx: &CrateContext, id: &ast::NodeId) -> ast_map::Path {
ty::item_path(ccx.tcx, ast_util::local_def(*id))
}
// using the current crate's name/version
// information in the hash of the symbol
debug!("making {}", sym);
- let sym = {
+ let (sym, is_local) = {
let external_srcs = ccx.external_srcs
.borrow();
match external_srcs.get().find(&i.id) {
Some(&did) => {
debug!("but found in other crate...");
- csearch::get_symbol(ccx.sess.cstore,
- did)
+ (csearch::get_symbol(ccx.sess.cstore,
+ did), false)
}
- None => sym
+ None => (sym, true)
}
};
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
- let (v, inlineable) = consts::const_expr(ccx, expr);
+ let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
{
let mut const_values = ccx.const_values
.borrow_mut();
ast::ItemFn(_, purity, _, _, _) => {
let llfn = if purity != ast::ExternFn {
- register_fn(ccx, i.span, sym, i.id, ty, None)
+ register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_rust_fn_with_foreign_abi(ccx,
i.span,
llfn = match enm.node {
ast::ItemEnum(_, _) => {
- register_fn(ccx, (*v).span, sym, id, ty, None)
+ register_fn(ccx, (*v).span, sym, id, ty)
}
_ => fail!("NodeVariant, shouldn't happen")
};
let sym = exported_name(ccx, (*struct_path).clone(), ty,
struct_item.attrs);
let llfn = register_fn(ccx, struct_item.span,
- sym, ctor_id, ty, None);
+ sym, ctor_id, ty);
set_inline_hint(llfn);
llfn
}
let sym = exported_name(ccx, path, mty, m.attrs);
- let self_ty = match m.explicit_self.node {
- ast::SelfStatic => None,
- _ => Some(ty::node_id_to_type(ccx.tcx, m.self_id))
- };
- let llfn = register_fn(ccx, m.span, sym, id, mty, self_ty);
+ let llfn = register_fn(ccx, m.span, sym, id, mty);
set_llvm_fn_attrs(m.attrs, llfn);
llfn
}
llvm::LLVMAddGlobal(llmod, maptype.to_ref(), buf)
}
});
+ lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
+
// On windows we'd like to export the toplevel cratemap
// such that we can find it from libstd.
if targ_cfg.os == OsWin32 && is_top {
- lib::llvm::SetLinkage(map, lib::llvm::DLLExportLinkage);
- } else {
- lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
+ unsafe { llvm::LLVMRustSetDLLExportStorageClass(map) }
}
return (sym_name, map);
}
pub fn write_metadata(cx: &CrateContext, crate: &ast::Crate) -> ~[u8] {
- use extra::flate;
+ use flate;
if !cx.sess.building_library.get() {
return ~[]
let link_meta = link::build_link_meta(sess, crate.attrs, output,
&mut symbol_hasher);
- // Append ".rc" to crate name as LLVM module identifier.
+ // Append ".rs" to crate name as LLVM module identifier.
//
// LLVM code generator emits a ".file filename" directive
// for ELF backends. Value of the "filename" is set as the
// crashes if the module identifer is same as other symbols
// such as a function name in the module.
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
- let llmod_id = link_meta.crateid.name.clone() + ".rc";
+ let llmod_id = link_meta.crateid.name.clone() + ".rs";
let ccx = @CrateContext::new(sess,
llmod_id,
pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
self.count_insn("call");
+
+ debug!("Call {} with args ({})",
+ self.ccx.tn.val_to_str(llfn),
+ args.map(|&v| self.ccx.tn.val_to_str(v)).connect(", "));
+
unsafe {
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(),
args.len() as c_uint, noname());
use syntax::abi::AbiSet;
use syntax::ast_map;
-// Represents a (possibly monomorphized) top-level fn item or method
-// item. Note that this is just the fn-ptr and is not a Rust closure
-// value (which is a pair).
-pub struct FnData {
- llfn: ValueRef,
-}
-
pub struct MethodData {
llfn: ValueRef,
llself: ValueRef,
pub enum CalleeData {
Closure(Datum<Lvalue>),
- Fn(FnData),
- Method(MethodData)
+
+ // Represents a (possibly monomorphized) top-level fn item or method
+ // item. Note that this is just the fn-ptr and is not a Rust closure
+ // value (which is a pair).
+ Fn(/* llfn */ ValueRef),
+
+ TraitMethod(MethodData)
}
pub struct Callee<'a> {
match ty::get(datum.ty).sty {
ty::ty_bare_fn(..) => {
let llval = datum.to_llscalarish(bcx);
- return Callee {bcx: bcx, data: Fn(FnData {llfn: llval})};
+ return Callee {bcx: bcx, data: Fn(llval)};
}
ty::ty_closure(..) => {
let datum = unpack_datum!(
}
}
- fn fn_callee<'a>(bcx: &'a Block<'a>, fd: FnData) -> Callee<'a> {
- return Callee {bcx: bcx, data: Fn(fd)};
+ fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> {
+ return Callee {bcx: bcx, data: Fn(llfn)};
}
fn trans_def<'a>(bcx: &'a Block<'a>, def: ast::Def, ref_expr: &ast::Expr)
ast::DefArg(..) |
ast::DefLocal(..) |
ast::DefBinding(..) |
- ast::DefUpvar(..) |
- ast::DefSelf(..) => {
+ ast::DefUpvar(..) => {
datum_callee(bcx, ref_expr)
}
ast::DefMod(..) | ast::DefForeignMod(..) | ast::DefTrait(..) |
}
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, ref_id: ast::NodeId)
- -> FnData {
+ -> ValueRef {
/*!
*
* Translates a reference (with id `ref_id`) to the fn/method
ref_id: ast::NodeId, // node id of use of fn; may be zero if N/A
type_params: &[ty::t], // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
- -> FnData {
+ -> ValueRef {
/*!
* Translates a reference to a fn/method item, monomorphizing and
* inlining as it goes.
let ref_ty = common::node_id_type(bcx, ref_id);
val = PointerCast(
- bcx, val, type_of::type_of_fn_from_ty(ccx, None, ref_ty).ptr_to());
+ bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to());
}
- return FnData {llfn: val};
+ return val;
}
// Find the actual function pointer.
// This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
- let llty = type_of::type_of_fn_from_ty(ccx, None, fn_tpt.ty);
+ let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
let llptrty = llty.ptr_to();
if val_ty(val) != llptrty {
val = BitCast(bcx, val, llptrty);
}
- return FnData {llfn: val};
+ val
}
// ______________________________________________________________________
node_id_type(in_cx, id),
|cx, _| trans(cx, f),
args,
- Some(dest),
- DontAutorefArg).bcx
+ Some(dest)).bcx
}
pub fn trans_method_call<'a>(
dest: expr::Dest)
-> &'a Block<'a> {
let _icx = push_ctxt("trans_method_call");
- debug!("trans_method_call(call_ex={}, rcvr={})",
- call_ex.repr(in_cx.tcx()),
- rcvr.repr(in_cx.tcx()));
+ debug!("trans_method_call(call_ex={})", call_ex.repr(in_cx.tcx()));
trans_call_inner(
in_cx,
Some(common::expr_info(call_ex)),
}
},
args,
- Some(dest),
- DontAutorefArg).bcx
+ Some(dest)).bcx
}
pub fn trans_lang_call<'a>(
None)
},
ArgVals(args),
- dest,
- DontAutorefArg)
+ dest)
}
pub fn trans_lang_call_with_type_params<'a>(
let new_llval;
match callee.data {
- Fn(fn_data) => {
+ Fn(llfn) => {
let substituted = ty::subst_tps(callee.bcx.tcx(),
type_params,
None,
fty);
let llfnty = type_of::type_of(callee.bcx.ccx(),
substituted);
- new_llval = PointerCast(callee.bcx, fn_data.llfn, llfnty);
+ new_llval = PointerCast(callee.bcx, llfn, llfnty);
}
_ => fail!()
}
- Callee { bcx: callee.bcx, data: Fn(FnData { llfn: new_llval }) }
+ Callee { bcx: callee.bcx, data: Fn(new_llval) }
},
- ArgVals(args), Some(dest), DontAutorefArg).bcx;
+ ArgVals(args), Some(dest)).bcx;
}
pub fn trans_call_inner<'a>(
arg_cleanup_scope: cleanup::ScopeId|
-> Callee<'a>,
args: CallArgs,
- dest: Option<expr::Dest>,
- autoref_arg: AutorefArg)
+ dest: Option<expr::Dest>)
-> Result<'a> {
/*!
* This behemoth of a function translates function calls.
let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
let mut bcx = callee.bcx;
- let (llfn, llenv) = unsafe {
- match callee.data {
- Fn(d) => {
- (d.llfn, llvm::LLVMGetUndef(Type::opaque_box(ccx).ptr_to().to_ref()))
- }
- Method(d) => {
- // Weird but true: we pass self in the *environment* slot!
- (d.llfn, d.llself)
- }
- Closure(d) => {
- // Closures are represented as (llfn, llclosure) pair:
- // load the requisite values out.
- let pair = d.to_llref();
- let llfn = GEPi(bcx, pair, [0u, abi::fn_field_code]);
- let llfn = Load(bcx, llfn);
- let llenv = GEPi(bcx, pair, [0u, abi::fn_field_box]);
- let llenv = Load(bcx, llenv);
- (llfn, llenv)
- }
+ let (llfn, llenv, llself) = match callee.data {
+ Fn(llfn) => {
+ (llfn, None, None)
+ }
+ TraitMethod(d) => {
+ (d.llfn, None, Some(d.llself))
+ }
+ Closure(d) => {
+ // Closures are represented as (llfn, llclosure) pair:
+ // load the requisite values out.
+ let pair = d.to_llref();
+ let llfn = GEPi(bcx, pair, [0u, abi::fn_field_code]);
+ let llfn = Load(bcx, llfn);
+ let llenv = GEPi(bcx, pair, [0u, abi::fn_field_box]);
+ let llenv = Load(bcx, llenv);
+ (llfn, Some(llenv), None)
}
};
llargs.push(opt_llretslot.unwrap());
}
- // Push the environment.
- llargs.push(llenv);
+ // Push the environment (or a trait object's self).
+ match (llenv, llself) {
+ (Some(llenv), None) => llargs.push(llenv),
+ (None, Some(llself)) => llargs.push(llself),
+ _ => {}
+ }
// Push the arguments.
- bcx = trans_args(bcx, args, callee_ty,
- autoref_arg, &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope));
+ bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope),
+ llself.is_some());
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
match ty::get(ret_ty).sty {
// `~` pointer return values never alias because ownership
// is transferred
- ty::ty_uniq(..) |
- ty::ty_vec(_, ty::vstore_uniq) => {
+ ty::ty_uniq(..) | ty::ty_vec(_, ty::vstore_uniq) => {
attrs.push((0, NoAliasAttribute));
}
- _ => ()
+ _ => {}
}
// Invoke the actual rust fn and update bcx/llresult.
assert!(dest.is_some());
let mut llargs = ~[];
- bcx = trans_args(bcx, args, callee_ty,
- autoref_arg, &mut llargs,
- cleanup::CustomScope(arg_cleanup_scope));
+ bcx = trans_args(bcx, args, callee_ty, &mut llargs,
+ cleanup::CustomScope(arg_cleanup_scope), false);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
let arg_tys = match args {
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, *x)).collect(),
- ArgVals(_) => fail!("expected arg exprs.")
+ _ => fail!("expected arg exprs.")
};
bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(), llargs, arg_tys);
pub enum CallArgs<'a> {
ArgExprs(&'a [@ast::Expr]),
+ // HACK used only by trans_overloaded_op.
+ ArgAutorefSecond(&'a ast::Expr, Option<&'a ast::Expr>),
ArgVals(&'a [ValueRef])
}
-pub fn trans_args<'a>(
- cx: &'a Block<'a>,
+fn trans_args<'a>(cx: &'a Block<'a>,
args: CallArgs,
fn_ty: ty::t,
- autoref_arg: AutorefArg,
llargs: &mut ~[ValueRef],
- arg_cleanup_scope: cleanup::ScopeId)
- -> &'a Block<'a>
-{
+ arg_cleanup_scope: cleanup::ScopeId,
+ ignore_self: bool)
+ -> &'a Block<'a> {
let _icx = push_ctxt("trans_args");
let arg_tys = ty::ty_fn_args(fn_ty);
let variadic = ty::fn_is_variadic(fn_ty);
// This will be needed if this is a generic call, because the callee has
// to cast her view of the arguments to the caller's view.
match args {
- ArgExprs(arg_exprs) => {
- let num_formal_args = arg_tys.len();
- for (i, arg_expr) in arg_exprs.iter().enumerate() {
- let arg_ty = if i >= num_formal_args {
- assert!(variadic);
- expr_ty_adjusted(cx, *arg_expr)
- } else {
- arg_tys[i]
- };
- let arg_val = unpack_result!(bcx, {
- trans_arg_expr(bcx,
- arg_ty,
- *arg_expr,
+ ArgExprs(arg_exprs) => {
+ let num_formal_args = arg_tys.len();
+ for (i, arg_expr) in arg_exprs.iter().enumerate() {
+ if i == 0 && ignore_self {
+ continue;
+ }
+ let arg_ty = if i >= num_formal_args {
+ assert!(variadic);
+ expr_ty_adjusted(cx, *arg_expr)
+ } else {
+ arg_tys[i]
+ };
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_ty, *arg_expr,
+ arg_cleanup_scope,
+ DontAutorefArg)
+ }));
+ }
+ }
+ ArgAutorefSecond(arg_expr, arg2) => {
+ assert!(!variadic);
+
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_tys[0], arg_expr,
arg_cleanup_scope,
- autoref_arg)
- });
- llargs.push(arg_val);
+ DontAutorefArg)
+ }));
+
+ match arg2 {
+ Some(arg2_expr) => {
+ assert_eq!(arg_tys.len(), 2);
+
+ llargs.push(unpack_result!(bcx, {
+ trans_arg_expr(bcx, arg_tys[1], arg2_expr,
+ arg_cleanup_scope,
+ DoAutorefArg)
+ }));
+ }
+ None => assert_eq!(arg_tys.len(), 1)
+ }
+ }
+ ArgVals(vs) => {
+ llargs.push_all(vs);
}
- }
- ArgVals(vs) => {
- llargs.push_all(vs);
- }
}
bcx
// The exception handling personality function.
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
- let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0).llfn;
+ let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, 0);
// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
use back::abi;
-use back::link::{mangle_internal_name_by_path_and_seq};
+use back::link::mangle_internal_name_by_path_and_seq;
use lib::llvm::ValueRef;
use middle::moves;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
-use middle::trans::datum::{Datum, Lvalue};
+use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
use middle::trans::debuginfo;
use middle::trans::expr;
-use middle::trans::glue;
use middle::trans::type_of::*;
+use middle::trans::type_::Type;
use middle::ty;
+use util::ppaux::Repr;
use util::ppaux::ty_to_str;
use std::vec;
// closure".
//
// Typically an opaque closure suffices because we only manipulate it
-// by ptr. The routine Type::opaque_box().ptr_to() returns an
-// appropriate type for such an opaque closure; it allows access to
-// the box fields, but not the closure_data itself.
+// by ptr. The routine Type::at_box().ptr_to() returns an appropriate
+// type for such an opaque closure; it allows access to the box fields,
+// but not the closure_data itself.
//
// But sometimes, such as when cloning or freeing a closure, we need
// to know the full information. That is where the type descriptor
// 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<'a>(
- bcx0: &'a Block<'a>,
+fn build_closure<'a>(bcx0: &'a Block<'a>,
cap_vars: &[moves::CaptureVar],
sigil: ast::Sigil)
-> ClosureResult<'a> {
// 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: &FunctionContext,
- cdata_ty: ty::t,
+fn load_environment<'a>(bcx: &'a Block<'a>, cdata_ty: ty::t,
cap_vars: &[moves::CaptureVar],
- sigil: ast::Sigil) {
+ sigil: ast::Sigil) -> &'a Block<'a> {
let _icx = push_ctxt("closure::load_environment");
// Don't bother to create the block if there's nothing to load
if cap_vars.len() == 0 {
- return;
+ return bcx;
}
- let bcx = fcx.entry_bcx.get().unwrap();
-
// Load a pointer to the closure data, skipping over the box header:
- let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv.get());
+ let llcdata = at_box_body(bcx, cdata_ty, bcx.fcx.llenv.unwrap());
// Store the pointer to closure data in an alloca for debug info because that's what the
// llvm.dbg.declare intrinsic expects
- let env_pointer_alloca = if fcx.ccx.sess.opts.extra_debuginfo {
+ let env_pointer_alloca = if bcx.ccx().sess.opts.extra_debuginfo {
let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), cdata_ty), "__debuginfo_env_ptr");
Store(bcx, llcdata, alloc);
Some(alloc)
let def_id = ast_util::def_id_of_def(cap_var.def);
{
- let mut llupvars = fcx.llupvars.borrow_mut();
+ let mut llupvars = bcx.fcx.llupvars.borrow_mut();
llupvars.get().insert(def_id.node, upvarptr);
}
i += 1u;
}
+
+ bcx
+}
+
+fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
+ Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
+ let llenvptr = PointerCast(bcx, llenvptr, Type::i8p());
+ Store(bcx, llenvptr, GEPi(bcx, pair, [0u, abi::fn_field_box]));
}
pub fn trans_expr_fn<'a>(
let sub_path = vec::append_one(bcx.fcx.path.clone(),
PathName(special_idents::anon));
- // XXX: Bad copy.
+ // FIXME: Bad copy.
let s = mangle_internal_name_by_path_and_seq(ccx,
sub_path.clone(),
"expr_fn");
- let llfn = decl_internal_rust_fn(ccx, None, f.sig.inputs, f.sig.output, s);
+ let llfn = decl_internal_rust_fn(ccx, true, f.sig.inputs, f.sig.output, s);
// set an inline hint for all closures
set_inline_hint(llfn);
- let Result {bcx: bcx, val: closure} = match sigil {
- ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
- let cap_vars = {
- let capture_map = ccx.maps.capture_map.borrow();
- capture_map.get().get_copy(&user_id)
- };
- let ClosureResult {llbox, cdata_ty, bcx}
- = build_closure(bcx, cap_vars, sigil);
- trans_closure(ccx,
- sub_path,
- decl,
- body,
- llfn,
- None,
- bcx.fcx.param_substs,
- user_id,
- [],
- ty::ty_fn_ret(fty),
- |fcx| load_environment(fcx, cdata_ty, cap_vars, sigil));
- rslt(bcx, llbox)
- }
+ let cap_vars = {
+ let capture_map = ccx.maps.capture_map.borrow();
+ capture_map.get().get_copy(&user_id)
};
- fill_fn_pair(bcx, dest_addr, llfn, closure);
-
- return bcx;
+ let ClosureResult {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, sigil);
+ trans_closure(ccx, sub_path, decl, body, llfn,
+ bcx.fcx.param_substs, user_id,
+ [], ty::ty_fn_ret(fty),
+ |bcx| load_environment(bcx, cdata_ty, cap_vars, sigil));
+ fill_fn_pair(bcx, dest_addr, llfn, llbox);
+
+ bcx
}
-pub fn make_closure_glue<'a>(
- cx: &'a Block<'a>,
- v: ValueRef,
- t: ty::t,
- glue_fn: |&'a Block<'a>, v: ValueRef, t: ty::t|
- -> &'a Block<'a>)
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_closure_glue");
- let bcx = cx;
- let tcx = cx.tcx();
-
- let sigil = ty::ty_closure_sigil(t);
- match sigil {
- ast::BorrowedSigil => bcx,
- ast::OwnedSigil | ast::ManagedSigil => {
- let box_cell_v = GEPi(cx, v, [0u, abi::fn_field_box]);
- let box_ptr_v = Load(cx, box_cell_v);
- with_cond(cx, IsNotNull(cx, box_ptr_v), |bcx| {
- let closure_ty = ty::mk_opaque_closure_ptr(tcx, sigil);
- glue_fn(bcx, box_cell_v, closure_ty)
- })
+pub fn get_wrapper_for_bare_fn(ccx: @CrateContext,
+ closure_ty: ty::t,
+ def: ast::Def,
+ fn_ptr: ValueRef,
+ is_local: bool) -> ValueRef {
+
+ let def_id = match def {
+ ast::DefFn(did, _) | ast::DefStaticMethod(did, _, _) |
+ ast::DefVariant(_, did, _) | ast::DefStruct(did) => did,
+ _ => {
+ ccx.sess.bug(format!("get_wrapper_for_bare_fn: \
+ expected a statically resolved fn, got {:?}",
+ def));
}
- }
-}
+ };
-pub fn make_opaque_cbox_drop_glue<'a>(
- bcx: &'a Block<'a>,
- sigil: ast::Sigil,
- cboxptr: ValueRef) // opaque closure ptr
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_opaque_cbox_drop_glue");
- match sigil {
- ast::BorrowedSigil => bcx,
- ast::ManagedSigil => {
- bcx.tcx().sess.bug("trying to trans drop glue of @fn")
- }
- ast::OwnedSigil => {
- glue::make_free_glue(
- bcx, cboxptr,
- ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
+ {
+ let cache = ccx.closure_bare_wrapper_cache.borrow();
+ match cache.get().find(&fn_ptr) {
+ Some(&llval) => return llval,
+ None => {}
}
}
-}
-/// `cbox` is a pointer to a pointer to an opaque closure.
-pub fn make_opaque_cbox_free_glue<'a>(
- bcx: &'a Block<'a>,
- sigil: ast::Sigil,
- cbox: ValueRef)
- -> &'a Block<'a> {
- let _icx = push_ctxt("closure::make_opaque_cbox_free_glue");
- match sigil {
- ast::BorrowedSigil => {
- return bcx;
+ let tcx = ccx.tcx;
+
+ debug!("get_wrapper_for_bare_fn(closure_ty={})", closure_ty.repr(tcx));
+
+ let f = match ty::get(closure_ty).sty {
+ ty::ty_closure(ref f) => f,
+ _ => {
+ ccx.sess.bug(format!("get_wrapper_for_bare_fn: \
+ expected a closure ty, got {}",
+ closure_ty.repr(tcx)));
}
- ast::ManagedSigil | ast::OwnedSigil => {
- /* hard cases: fallthrough to code below */
+ };
+
+ let path = ty::item_path(tcx, def_id);
+ let name = mangle_internal_name_by_path_and_seq(ccx, path, "as_closure");
+ let llfn = if is_local {
+ decl_internal_rust_fn(ccx, true, f.sig.inputs, f.sig.output, name)
+ } else {
+ decl_rust_fn(ccx, true, f.sig.inputs, f.sig.output, name)
+ };
+
+ {
+ let mut cache = ccx.closure_bare_wrapper_cache.borrow_mut();
+ cache.get().insert(fn_ptr, llfn);
+ }
+
+ // This is only used by statics inlined from a different crate.
+ if !is_local {
+ // Don't regenerate the wrapper, just reuse the original one.
+ return llfn;
+ }
+
+ let _icx = push_ctxt("closure::get_wrapper_for_bare_fn");
+
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, true, f.sig.output, None);
+ init_function(&fcx, true, f.sig.output, None);
+ let bcx = fcx.entry_bcx.get().unwrap();
+
+ let args = create_datums_for_fn_args(&fcx, ty::ty_fn_args(closure_ty));
+ let mut llargs = ~[];
+ match fcx.llretptr.get() {
+ Some(llretptr) => {
+ llargs.push(llretptr);
}
+ None => {}
}
+ llargs.extend(&mut args.iter().map(|arg| arg.val));
- let ccx = bcx.ccx();
- with_cond(bcx, IsNotNull(bcx, cbox), |bcx| {
- // Load the type descr found in the cbox
- let lltydescty = ccx.tydesc_type.ptr_to();
- let cbox = Load(bcx, cbox);
- let tydescptr = GEPi(bcx, cbox, [0u, abi::box_field_tydesc]);
- let tydesc = Load(bcx, tydescptr);
- let tydesc = PointerCast(bcx, tydesc, lltydescty);
-
- // Drop the tuple data then free the descriptor
- let cdata = GEPi(bcx, cbox, [0u, abi::box_field_body]);
- glue::call_tydesc_glue_full(bcx, cdata, tydesc,
- abi::tydesc_field_drop_glue, None);
-
- // Free the ty descr (if necc) and the box itself
- glue::trans_exchange_free(bcx, cbox);
-
- bcx
- })
+ let retval = Call(bcx, fn_ptr, llargs, []);
+ if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
+ RetVoid(bcx);
+ } else {
+ Ret(bcx, retval);
+ }
+
+ // HACK(eddyb) finish_fn cannot be used here, we returned directly.
+ debuginfo::clear_source_location(&fcx);
+ fcx.cleanup();
+
+ llfn
+}
+
+pub fn make_closure_from_bare_fn<'a>(bcx: &'a Block<'a>,
+ closure_ty: ty::t,
+ def: ast::Def,
+ fn_ptr: ValueRef)
+ -> DatumBlock<'a, Expr> {
+ let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
+ let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def, fn_ptr, true);
+ fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p()));
+
+ DatumBlock(bcx, scratch.to_expr_datum())
}
use util::ppaux::Repr;
-use extra::arena::TypedArena;
+use arena::TypedArena;
use std::c_str::ToCStr;
use std::cast::transmute;
use std::cast;
size: ValueRef,
align: ValueRef,
name: ValueRef,
- take_glue: Cell<Option<ValueRef>>,
drop_glue: Cell<Option<ValueRef>>,
visit_glue: Cell<Option<ValueRef>>,
}
// section of the executable we're generating.
llfn: ValueRef,
- // The implicit environment argument that arrives in the function we're
- // creating.
- llenv: Cell<ValueRef>,
+ // The environment argument in a closure.
+ llenv: Option<ValueRef>,
// The place to store the return value. If the return type is immediate,
// this is an alloca in the function. Otherwise, it's the hidden first
alloca_insert_pt: Cell<Option<ValueRef>>,
llreturn: Cell<Option<BasicBlockRef>>,
- // The 'self' value currently in use in this function, if there
- // is one.
- //
- // NB: This is the type of the self *variable*, not the self *type*. The
- // self type is set only for default methods, while the self variable is
- // set for all methods.
- llself: Cell<Option<LvalueDatum>>,
-
// The a value alloca'd for calls to upcalls.rust_personality. Used when
// outputting the resume instruction.
personality: Cell<Option<ValueRef>>,
impl<'a> FunctionContext<'a> {
pub fn arg_pos(&self, arg: uint) -> uint {
- if self.caller_expects_out_pointer {
- arg + 2u
+ let arg = self.env_arg_pos() + arg;
+ if self.llenv.is_some() {
+ arg + 1
} else {
- arg + 1u
+ arg
}
}
use middle::trans::adt;
use middle::trans::base;
use middle::trans::base::push_ctxt;
+use middle::trans::closure;
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::expr;
}
}
-fn const_vec(cx: @CrateContext, e: &ast::Expr, es: &[@ast::Expr]) -> (ValueRef, Type, bool) {
+fn const_vec(cx: @CrateContext, e: &ast::Expr,
+ es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
let vec_ty = ty::expr_ty(cx.tcx, e);
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
let llunitty = type_of::type_of(cx, unit_ty);
- let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
+ let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
// If the vector contains enums, an LLVM array won't work.
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs, false)
!non_inlineable_statics.get().contains(&def_id.node))
}
-pub fn const_expr(cx: @CrateContext, e: &ast::Expr) -> (ValueRef, bool) {
- let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
+ let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
let mut llconst = llconst;
let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
+ let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
let adjustment = {
let adjustments = cx.tcx.adjustments.borrow();
adjustments.get().find_copy(&e.id)
Some(adj) => {
match *adj {
ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil) => {
- llconst = C_struct([
- llconst,
- C_null(Type::opaque_box(cx).ptr_to())
- ], false)
+ let def = ty::resolve_expr(cx.tcx, e);
+ let wrapper = closure::get_wrapper_for_bare_fn(cx,
+ ety_adjusted,
+ def,
+ llconst,
+ is_local);
+ llconst = C_struct([wrapper, C_null(Type::i8p())], false)
}
ty::AutoAddEnv(ref r, ref s) => {
cx.sess
ty::AutoDerefRef(ref adj) => {
let mut ty = ety;
let mut maybe_ptr = None;
- adj.autoderefs.times(|| {
+ for _ in range(0, adj.autoderefs) {
let (dv, dt) = const_deref(cx, llconst, ty, false);
maybe_ptr = Some(llconst);
llconst = dv;
ty = dt;
- });
+ }
match adj.autoref {
None => { }
}
}
- let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
let llty = type_of::sizing_type_of(cx, ety_adjusted);
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
let tsize = machine::llsize_of_alloc(cx, llty);
if csize != tsize {
unsafe {
- // XXX these values could use some context
+ // FIXME these values could use some context
llvm::LLVMDumpValue(llconst);
llvm::LLVMDumpValue(C_undef(llty));
}
// the bool returned is whether this expression can be inlined into other crates
// if it's assigned to a static.
-fn const_expr_unadjusted(cx: @CrateContext,
- e: &ast::Expr) -> (ValueRef, bool) {
- fn map_list(cx: @CrateContext,
- exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
- exprs.iter().map(|&e| const_expr(cx, e))
+fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
+ is_local: bool) -> (ValueRef, bool) {
+ let map_list = |exprs: &[@ast::Expr]| {
+ exprs.iter().map(|&e| const_expr(cx, e, is_local))
.fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
- (vec::append_one(L, val), all_inlineable && inlineable)
+ (vec::append_one(L, val), all_inlineable && inlineable)
})
- }
+ };
unsafe {
let _icx = push_ctxt("const_expr");
return match e.node {
ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
ast::ExprBinary(_, b, e1, e2) => {
- let (te1, _) = const_expr(cx, e1);
- let (te2, _) = const_expr(cx, e2);
+ let (te1, _) = const_expr(cx, e1, is_local);
+ let (te2, _) = const_expr(cx, e2, is_local);
let te2 = base::cast_shift_const_rhs(b, te1, te2);
}, true)
},
ast::ExprUnary(_, u, e) => {
- let (te, _) = const_expr(cx, e);
+ let (te, _) = const_expr(cx, e, is_local);
let ty = ty::expr_ty(cx.tcx, e);
let is_float = ty::type_is_fp(ty);
return (match u {
ast::ExprField(base, field, _) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let brepr = adt::represent_type(cx, bt);
- let (bv, inlineable) = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base, is_local);
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
(adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
ast::ExprIndex(_, base, index) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
- let (bv, inlineable) = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base, is_local);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
const_eval::const_uint(u) => u,
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
let basety = ty::expr_ty(cx.tcx, base);
- let (v, inlineable) = const_expr(cx, base);
+ let (v, inlineable) = const_expr(cx, base, is_local);
return (match (expr::cast_type_kind(basety),
expr::cast_type_kind(ety)) {
}, inlineable)
}
ast::ExprAddrOf(ast::MutImmutable, sub) => {
- let (e, _) = const_expr(cx, sub);
+ let (e, _) = const_expr(cx, sub, is_local);
(const_addr_of(cx, e), false)
}
ast::ExprTup(ref es) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let (vals, inlineable) = map_list(cx, *es);
+ let (vals, inlineable) = map_list(*es);
(adt::trans_const(cx, repr, 0, vals), inlineable)
}
ast::ExprStruct(_, ref fs, ref base_opt) => {
let tcx = cx.tcx;
let base_val = match *base_opt {
- Some(base) => Some(const_expr(cx, base)),
+ Some(base) => Some(const_expr(cx, base, is_local)),
None => None
};
let cs = field_tys.iter().enumerate()
.map(|(ix, &field_ty)| {
match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
- Some(f) => const_expr(cx, (*f).expr),
+ Some(f) => const_expr(cx, (*f).expr, is_local),
None => {
match base_val {
Some((bv, inlineable)) => {
})
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (v, _, inlineable) = const_vec(cx, e, *es);
+ let (v, _, inlineable) = const_vec(cx, e, *es, is_local);
(v, inlineable)
}
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
match sub.node {
ast::ExprLit(ref lit) => {
match lit.node {
- ast::LitStr(..) => { const_expr(cx, sub) }
+ ast::LitStr(..) => { const_expr(cx, sub, is_local) }
_ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (cv, llunitty, _) = const_vec(cx, e, *es);
+ let (cv, llunitty, _) = const_vec(cx, e, *es, is_local);
let llty = val_ty(cv);
let gv = "const".with_c_str(|name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
const_eval::const_uint(i) => i as uint,
_ => cx.sess.span_bug(count.span, "count must be integral const expression.")
};
- let vs = vec::from_elem(n, const_expr(cx, elem).first());
+ let vs = vec::from_elem(n, const_expr(cx, elem, is_local).first());
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs, false)
} else {
Some(ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let (arg_vals, inlineable) = map_list(cx, *args);
+ let (arg_vals, inlineable) = map_list(*args);
(adt::trans_const(cx, repr, 0, arg_vals), inlineable)
}
Some(ast::DefVariant(enum_did, variant_did, _)) => {
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- let (arg_vals, inlineable) = map_list(cx, *args);
+ let (arg_vals, inlineable) = map_list(*args);
(adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
inlineable)
}
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
}
}
- ast::ExprParen(e) => { const_expr(cx, e) }
+ ast::ExprParen(e) => { const_expr(cx, e, is_local) }
_ => cx.sess.span_bug(e.span,
"bad constant expression type in consts::const_expr")
};
impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
+ // Cache of closure wrappers for bare fn's.
+ closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
+
module_data: RefCell<HashMap<~str, ValueRef>>,
lltypes: RefCell<HashMap<ty::t, Type>>,
llsizingtypes: RefCell<HashMap<ty::t, Type>>,
let (crate_map_name, crate_map) = decl_crate_map(sess, link_meta.clone(), llmod);
let dbg_cx = if sess.opts.debuginfo {
- Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
+ Some(debuginfo::CrateDebugContext::new(llmod))
} else {
None
};
const_values: RefCell::new(HashMap::new()),
extern_const_values: RefCell::new(HashMap::new()),
impl_method_cache: RefCell::new(HashMap::new()),
+ closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
module_data: RefCell::new(HashMap::new()),
lltypes: RefCell::new(HashMap::new()),
llsizingtypes: RefCell::new(HashMap::new()),
Some(x) => {
bcx = expr::trans_into(bcx, x, dest);
}
- _ => ()
+ _ => {}
}
let cleanup_llbb = fcx.return_exit_block();
Br(bcx, cleanup_llbb);
}
ByValue => {
let v = load(bcx, l.val, l.ty);
- l.kind.post_store(bcx, l.val, l.ty);
+ bcx = l.kind.post_store(bcx, l.val, l.ty);
DatumBlock(bcx, Datum(v, l.ty, Rvalue(ByValue)))
}
}
use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
use middle::trans::adt;
-use middle::trans::base;
-use middle::trans::build;
use middle::trans::common::*;
use middle::trans::datum::{Datum, Lvalue};
use middle::trans::machine;
use middle::pat_util;
use util::ppaux;
-use std::c_str::ToCStr;
+use std::c_str::{CString, ToCStr};
use std::cell::{Cell, RefCell};
use std::hashmap::HashMap;
use std::hashmap::HashSet;
use std::sync::atomics;
use std::vec;
use syntax::codemap::{Span, Pos};
-use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
+use syntax::{abi, ast, codemap, ast_util, ast_map, opt_vec};
use syntax::parse::token;
use syntax::parse::token::special_idents;
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext {
- priv crate_file: ~str,
priv llcontext: ContextRef,
priv builder: DIBuilderRef,
priv current_debug_location: Cell<DebugLocation>,
}
impl CrateDebugContext {
- pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext {
+ pub fn new(llmod: ModuleRef) -> CrateDebugContext {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
return CrateDebugContext {
- crate_file: crate,
llcontext: llcontext,
builder: builder,
current_debug_location: Cell::new(UnknownLocation),
unsafe {
llvm::LLVMDIBuilderFinalize(DIB(cx));
llvm::LLVMDIBuilderDispose(DIB(cx));
+ // Debuginfo generation in LLVM by default uses a higher
+ // version of dwarf than OS X currently understands. We can
+ // instruct LLVM to emit an older version of dwarf, however,
+ // for OS X to understand. For more info see #11352
+ // This can be overridden using --llvm-opts -dwarf-version,N.
+ if cx.sess.targ_cfg.os == abi::OsMacos {
+ "Dwarf Version".with_c_str(
+ |s| llvm::LLVMRustAddModuleFlag(cx.llmod, s, 2));
+ }
+
+ // Prevent bitcode readers from deleting the debug info.
+ "Debug Info Version".with_c_str(
+ |s| llvm::LLVMRustAddModuleFlag(cx.llmod, s,
+ llvm::LLVMRustDebugMetadataVersion));
};
}
None => {
cx.sess.span_bug(span, "debuginfo::create_captured_var_metadata() - NodeId not found");
}
- Some(ast_map::NodeLocal(ident, _)) => ident,
- Some(ast_map::NodeArg(pat)) => {
+ Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => {
match pat.node {
ast::PatIdent(_, ref path, _) => {
ast_util::path_to_ident(path)
span);
}
-/// Creates debug information for the self argument of a method.
-///
-/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_self_argument_metadata(bcx: &Block,
- type_of_self: ty::t,
- llptr: ValueRef) {
- if fn_should_be_ignored(bcx.fcx) {
- return;
- }
-
- // Extract the span of the self argument from the method's AST
- let fnitem = bcx.ccx().tcx.items.get(bcx.fcx.id);
- let span = match fnitem {
- ast_map::NodeMethod(method, _, _) => {
- method.explicit_self.span
- }
- ast_map::NodeTraitMethod(trait_method, _, _) => {
- match *trait_method {
- ast::Provided(method) => method.explicit_self.span,
- _ => {
- bcx.ccx()
- .sess
- .bug(format!("create_self_argument_metadata: \
- unexpected sort of node: {:?}",
- fnitem))
- }
- }
- }
- _ => bcx.ccx().sess.bug(
- format!("create_self_argument_metadata: unexpected sort of node: {:?}", fnitem))
- };
-
- let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata;
-
- let argument_index = {
- let counter = &bcx.fcx.debug_context.get_ref(bcx.ccx(), span).argument_counter;
- let argument_index = counter.get();
- counter.set(argument_index + 1);
- argument_index
- };
-
- let address_operations = &[unsafe { llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref()) }];
-
- // The self argument comes in one of two forms:
- // (1) For `&self`, `~self`, and `@self` it is an alloca containing a pointer to the data. That
- // is the `{&~@}self` pointer is contained by value in the alloca, and `type_of_self` will
- // be `{&~@}Self`
- // (2) For by-value `self`, `llptr` will not be an alloca, but a pointer to the self-value. That
- // is by-value `self` is always implicitly passed by reference (sic!). So we have a couple
- // of problems here:
- // (a) There is no alloca to give to `llvm.dbg.declare` and
- // (b) `type_of_self` is `Self`, but `llptr` is of type `*Self`
- // In order to solve this problem, the else branch below creates a helper alloca which
- // contains a copy of `llptr`. We then describe the `self` parameter by pointing
- // `llvm.dbg.declare` to this helper alloca and tell it that the pointer there needs to be
- // dereferenced once to get to the actual data (similar to non-immediate by-value args).
- let variable_access = if unsafe { llvm::LLVMIsAAllocaInst(llptr) } != ptr::null() {
- DirectVariable { alloca: llptr }
- } else {
- // Create a helper alloca that allows us to track the self-argument properly. The alloca
- // contains a pointer to the self-value.
- let ptr_type = ty::mk_mut_ptr(bcx.tcx(), type_of_self);
- let helper_alloca = base::alloc_ty(bcx, ptr_type, "__self");
- build::Store(bcx, llptr, helper_alloca);
-
- IndirectVariable { alloca: helper_alloca, address_operations: address_operations }
- };
-
- declare_local(bcx,
- special_idents::self_,
- type_of_self,
- scope_metadata,
- variable_access,
- ArgumentVariable(argument_index),
- span);
-}
-
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
};
}
-fn compile_unit_metadata(cx: @CrateContext) {
- let dcx = debug_context(cx);
- let crate_name: &str = dcx.crate_file;
-
- debug!("compile_unit_metadata: {:?}", crate_name);
+fn compile_unit_metadata(cx: &CrateContext) {
+ let work_dir = &cx.sess.working_dir;
+ let compile_unit_name = match cx.sess.local_crate_source_file {
+ None => fallback_path(cx),
+ Some(ref abs_path) => {
+ if abs_path.is_relative() {
+ cx.sess.warn("debuginfo: Invalid path to crate's local root source file!");
+ fallback_path(cx)
+ } else {
+ match abs_path.path_relative_from(work_dir) {
+ Some(ref p) if p.is_relative() => {
+ // prepend "./" if necessary
+ let dotdot = bytes!("..");
+ let prefix = &[dotdot[0], ::std::path::SEP_BYTE];
+ let mut path_bytes = p.as_vec().to_owned();
+
+ if path_bytes.slice_to(2) != prefix &&
+ path_bytes.slice_to(2) != dotdot {
+ path_bytes.insert(0, prefix[0]);
+ path_bytes.insert(1, prefix[1]);
+ }
+
+ path_bytes.to_c_str()
+ }
+ _ => fallback_path(cx)
+ }
+ }
+ }
+ };
- // FIXME (#9639): This needs to handle non-utf8 paths
- let work_dir = cx.sess.working_dir.as_str().unwrap();
+ debug!("compile_unit_metadata: {:?}", compile_unit_name);
let producer = format!("rustc version {}", env!("CFG_VERSION"));
- crate_name.with_c_str(|crate_name| {
- work_dir.with_c_str(|work_dir| {
+ compile_unit_name.with_ref(|compile_unit_name| {
+ work_dir.as_vec().with_c_str(|work_dir| {
producer.with_c_str(|producer| {
"".with_c_str(|flags| {
"".with_c_str(|split_name| {
unsafe {
llvm::LLVMDIBuilderCreateCompileUnit(
- dcx.builder,
+ debug_context(cx).builder,
DW_LANG_RUST,
- crate_name,
+ compile_unit_name,
work_dir,
producer,
cx.sess.opts.optimize != session::No,
})
})
});
+
+ fn fallback_path(cx: &CrateContext) -> CString {
+ cx.link_meta.crateid.name.to_c_str()
+ }
}
fn declare_local(bcx: &Block,
.map(|(i, member_description)| {
let (member_size, member_align) = size_and_align_of(cx, member_description.llvm_type);
let member_offset = match member_description.offset {
- FixedMemberOffset { bytes } => bytes,
+ FixedMemberOffset { bytes } => bytes as u64,
ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
};
None => ~"BoxedType"
};
- let box_llvm_type = Type::smart_ptr(cx, &content_llvm_type);
+ let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
return unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
- bytes_to_bits(element_type_size * len),
+ bytes_to_bits(element_type_size * (len as u64)),
bytes_to_bits(element_type_align),
element_type_metadata,
subscripts)
ppaux::mutability_to_str(mutability) +
token::ident_to_str(&ident);
// Add type and region parameters
- let name = ppaux::parameterized(cx.tcx, name, &substs.regions, substs.tps);
+ let name = ppaux::parameterized(cx.tcx, name, &substs.regions,
+ substs.tps, def_id, true);
let (containing_scope, definition_span) =
get_namespace_and_span_for_item(cx, def_id, usage_site_span);
cx.sess.codemap.lookup_char_pos(span.lo)
}
-fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (uint, uint) {
+fn size_and_align_of(cx: &CrateContext, llvm_type: Type) -> (u64, u64) {
(machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
}
-fn bytes_to_bits(bytes: uint) -> c_ulonglong {
+fn bytes_to_bits(bytes: u64) -> c_ulonglong {
(bytes * 8) as c_ulonglong
}
match exp.node {
ast::ExprLogLevel |
- ast::ExprSelf |
ast::ExprLit(_) |
ast::ExprBreak(_) |
ast::ExprAgain(_) |
- ast::ExprPath(_) => (),
+ ast::ExprPath(_) => {}
ast::ExprVstore(sub_exp, _) |
ast::ExprCast(sub_exp, _) |
})
}
- // ast::expr_loop_body(inner_exp) |
- ast::ExprDoBody(inner_exp) => {
- let inner_expr_is_expr_fn_block = match *inner_exp {
- ast::Expr { node: ast::ExprFnBlock(..), .. } => true,
- _ => false
- };
-
- if !inner_expr_is_expr_fn_block {
- cx.sess.span_bug(inner_exp.span, "debuginfo: Inner expression was expected \
- to be an ast::expr_fn_block.");
- }
-
- walk_expr(cx, inner_exp, scope_stack, scope_map);
- }
-
ast::ExprCall(fn_exp, ref args, _) => {
walk_expr(cx, fn_exp, scope_stack, scope_map);
}
}
- ast::ExprMethodCall(node_id, receiver_exp, _, _, ref args, _) => {
+ ast::ExprMethodCall(node_id, _, _, ref args, _) => {
scope_map.insert(node_id, scope_stack.last().unwrap().scope_metadata);
- walk_expr(cx, receiver_exp, scope_stack, scope_map);
for arg_exp in args.iter() {
walk_expr(cx, *arg_exp, scope_stack, scope_map);
use middle::trans::base::*;
use middle::trans::base;
use middle::trans::build::*;
-use middle::trans::callee::DoAutorefArg;
use middle::trans::callee;
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
// code and keep it DRY that accommodates that use case at the
// moment.
- let tcx = bcx.tcx();
let closure_ty = expr_ty_adjusted(bcx, expr);
- debug!("add_env(closure_ty={})", closure_ty.repr(tcx));
- let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
- let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
- let llval = datum.to_llscalarish(bcx);
- Store(bcx, llval, llfn);
- let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
- Store(bcx, base::null_env_ptr(bcx.ccx()), llenv);
- DatumBlock(bcx, scratch.to_expr_datum())
+ let fn_ptr = datum.to_llscalarish(bcx);
+ let def = ty::resolve_expr(bcx.tcx(), expr);
+ closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
}
fn auto_slice_and_ref<'a>(
ast::ExprParen(e) => {
trans(bcx, e)
}
- ast::ExprPath(_) | ast::ExprSelf => {
+ ast::ExprPath(_) => {
trans_def(bcx, expr, bcx.def(expr.id))
}
ast::ExprField(base, ident, _) => {
let _icx = push_ctxt("trans_def_lvalue");
match def {
- ast::DefFn(..) | ast::DefStaticMethod(..) => {
+ ast::DefFn(..) | ast::DefStaticMethod(..) |
+ ast::DefStruct(_) | ast::DefVariant(..) => {
trans_def_fn_unadjusted(bcx, ref_expr, def)
}
ast::DefStatic(did, _) => {
match expr.node {
ast::ExprParen(e) => {
- return trans_into(bcx, e, dest);
+ trans_into(bcx, e, dest)
}
- ast::ExprPath(_) | ast::ExprSelf => {
- return trans_def_dps_unadjusted(bcx, expr,
- bcx.def(expr.id), dest);
+ ast::ExprPath(_) => {
+ trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
}
ast::ExprIf(cond, thn, els) => {
- return controlflow::trans_if(bcx, expr.id, cond, thn, els, dest);
+ controlflow::trans_if(bcx, expr.id, cond, thn, els, dest)
}
ast::ExprMatch(discr, ref arms) => {
- return _match::trans_match(bcx, expr, discr, *arms, dest);
+ _match::trans_match(bcx, expr, discr, *arms, dest)
}
ast::ExprBlock(blk) => {
controlflow::trans_block(bcx, blk, dest)
}
ast::ExprStruct(_, ref fields, base) => {
- return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
+ trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest)
}
ast::ExprTup(ref args) => {
let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
let numbered_fields: ~[(uint, @ast::Expr)] =
args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
- return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
+ trans_adt(bcx, repr, 0, numbered_fields, None, dest)
}
ast::ExprLit(lit) => {
match lit.node {
ast::LitStr(s, _) => {
- return tvec::trans_lit_str(bcx, expr, s, dest);
+ tvec::trans_lit_str(bcx, expr, s, dest)
}
_ => {
bcx.tcx()
ast::ExprVstore(contents, ast::ExprVstoreMutSlice) => {
fcx.push_ast_cleanup_scope(contents.id);
bcx = tvec::trans_slice_vstore(bcx, expr, contents, dest);
- return fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
+ fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
}
ast::ExprVec(..) | ast::ExprRepeat(..) => {
- return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
+ tvec::trans_fixed_vstore(bcx, expr, expr, dest)
}
ast::ExprFnBlock(decl, body) |
ast::ExprProc(decl, body) => {
debug!("translating block function {} with type {}",
expr_to_str(expr, tcx.sess.intr()),
expr_ty.repr(tcx));
- return closure::trans_expr_fn(bcx, sigil, decl, body,
- expr.id, expr.id, dest);
- }
- ast::ExprDoBody(blk) => {
- return trans_into(bcx, blk, dest);
+ closure::trans_expr_fn(bcx, sigil, decl, body,
+ expr.id, expr.id, dest)
}
ast::ExprCall(f, ref args, _) => {
- return callee::trans_call(
- bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
+ callee::trans_call(bcx, expr, f,
+ callee::ArgExprs(*args), expr.id, dest)
}
- ast::ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => {
- return callee::trans_method_call(bcx,
- expr,
- callee_id,
- rcvr,
- callee::ArgExprs(*args),
- dest);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ callee::trans_method_call(bcx, expr, callee_id, args[0],
+ callee::ArgExprs(*args), dest)
}
ast::ExprBinary(callee_id, _, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- lhs,
- ~[rhs],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, lhs,
+ Some(&*rhs), expr_ty(bcx, expr), dest)
}
ast::ExprUnary(callee_id, _, subexpr) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- subexpr,
- ~[],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, subexpr,
+ None, expr_ty(bcx, expr), dest)
}
ast::ExprIndex(callee_id, base, idx) => {
// if not overloaded, would be RvalueDatumExpr
- return trans_overloaded_op(bcx,
- expr,
- callee_id,
- base,
- ~[idx],
- expr_ty(bcx, expr),
- dest);
+ trans_overloaded_op(bcx, expr, callee_id, base,
+ Some(&*idx), expr_ty(bcx, expr), dest)
}
ast::ExprCast(val, _) => {
// DPS output mode means this is a trait cast:
match ty::get(node_id_type(bcx, expr.id)).sty {
ty::ty_trait(..) => {
let datum = unpack_datum!(bcx, trans(bcx, val));
- return meth::trans_trait_cast(bcx, datum, expr.id, dest);
+ meth::trans_trait_cast(bcx, datum, expr.id, dest)
}
_ => {
bcx.tcx().sess.span_bug(expr.span,
}
}
ast::ExprAssignOp(callee_id, op, dst, src) => {
- return trans_assign_op(bcx, expr, callee_id, op, dst, src);
+ trans_assign_op(bcx, expr, callee_id, op, dst, src)
}
ast::ExprBox(_, contents) => {
// Special case for `Gc<T>` for now. The other case, for unique
// pointers, is handled in `trans_rvalue_datum_unadjusted`.
- return trans_gc(bcx, expr, contents, dest)
+ trans_gc(bcx, expr, contents, dest)
}
_ => {
bcx.tcx().sess.span_bug(
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
- let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
- Store(bcx, fn_data.llfn, lldest);
+ let llfn = callee::trans_fn_ref(bcx, vid, ref_expr.id);
+ Store(bcx, llfn, lldest);
return bcx;
} else {
// Nullary variant.
return bcx;
}
}
- ast::DefStruct(def_id) => {
+ ast::DefStruct(_) => {
let ty = expr_ty(bcx, ref_expr);
match ty::get(ty).sty {
ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
let repr = adt::represent_type(ccx, ty);
adt::trans_start_init(bcx, repr, lldest, 0);
}
- ty::ty_bare_fn(..) => {
- let fn_data = callee::trans_fn_ref(bcx, def_id, ref_expr.id);
- Store(bcx, fn_data.llfn, lldest);
- }
- _ => ()
+ _ => {}
}
- return bcx;
+ bcx
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, format!(
{
let _icx = push_ctxt("trans_def_datum_unadjusted");
- let fn_data = match def {
+ let llfn = match def {
ast::DefFn(did, _) |
+ ast::DefStruct(did) | ast::DefVariant(_, did, _) |
ast::DefStaticMethod(did, ast::FromImpl(_), _) => {
callee::trans_fn_ref(bcx, did, ref_expr.id)
}
ast::DefStaticMethod(impl_did, ast::FromTrait(trait_did), _) => {
- meth::trans_static_method_callee(bcx,
- impl_did,
- trait_did,
- ref_expr.id)
+ meth::trans_static_method_callee(bcx, impl_did,
+ trait_did, ref_expr.id)
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, format!(
};
let fn_ty = expr_ty(bcx, ref_expr);
- DatumBlock(bcx, Datum(fn_data.llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
+ DatumBlock(bcx, Datum(llfn, fn_ty, RvalueExpr(Rvalue(ByValue))))
}
pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
let lllocals = bcx.fcx.lllocals.borrow();
take_local(bcx, lllocals.get(), nid)
}
- ast::DefSelf(nid, _) => {
- let self_info = match bcx.fcx.llself.get() {
- Some(self_info) => self_info,
- None => {
- bcx.sess().bug(format!(
- "trans_local_var: reference to self \
- out of context with id {:?}", nid));
- }
- };
-
- debug!("def_self() reference, self_info.ty={}",
- self_info.ty.repr(bcx.tcx()));
-
- self_info
- }
_ => {
bcx.sess().unimpl(format!(
"unsupported def type in trans_local_var: {:?}", def));
}
}
-fn trans_overloaded_op<'a>(
+fn trans_overloaded_op<'a, 'b>(
bcx: &'a Block<'a>,
expr: &ast::Expr,
callee_id: ast::NodeId,
- rcvr: &ast::Expr,
- args: ~[@ast::Expr],
+ rcvr: &'b ast::Expr,
+ arg: Option<&'b ast::Expr>,
ret_ty: ty::t,
dest: Dest)
-> &'a Block<'a> {
origin,
arg_cleanup_scope)
},
- callee::ArgExprs(args),
- Some(dest),
- DoAutorefArg).bcx
+ callee::ArgAutorefSecond(rcvr, arg),
+ Some(dest)).bcx
}
fn int_cast(bcx: &Block,
let llalign = cmp::min(llforeign_align, llrust_align);
debug!("llrust_size={:?}", llrust_size);
base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
- C_uint(ccx, llrust_size), llalign as u32);
+ C_uint(ccx, llrust_size as uint), llalign as u32);
}
}
id,
t.repr(tcx));
- let llfndecl = base::decl_internal_rust_fn(ccx, None, f.sig.inputs, f.sig.output, ps);
- base::set_llvm_fn_attrs(attrs, llfndecl);
- base::trans_fn(ccx,
- (*path).clone(),
- decl,
- body,
- llfndecl,
- None,
- None,
- id,
- []);
- return llfndecl;
+ let llfn = base::decl_internal_rust_fn(ccx, false, f.sig.inputs, f.sig.output, ps);
+ base::set_llvm_fn_attrs(attrs, llfn);
+ base::trans_fn(ccx, (*path).clone(), decl, body, llfn, None, id, []);
+ llfn
}
unsafe fn build_wrap_fn(ccx: @CrateContext,
return_alloca = None;
};
- // Push an (null) env pointer
- let env_pointer = base::null_env_ptr(ccx);
- debug!("env pointer={}", ccx.tn.val_to_str(env_pointer));
- llrust_args.push(env_pointer);
-
// Build up the arguments to the call to the rust function.
// Careful to adapt for cases where the native convention uses
// a pointer and Rust does not or vice versa.
use middle::trans::callee;
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
-use middle::trans::closure;
use middle::trans::common::*;
use middle::trans::build::*;
use middle::trans::expr;
Some(expr::Ignore)).bcx
}
-pub fn take_ty<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t)
+pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
-> &'a Block<'a> {
// 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 call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
+ match ty::get(t).sty {
+ ty::ty_box(_) |
+ ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
+ incr_refcnt_of_boxed(bcx, v)
+ }
+ ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
+ incr_refcnt_of_boxed(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]))
+ }
+ _ if ty::type_is_structural(t)
+ && ty::type_needs_drop(bcx.tcx(), t) => {
+ iter_structural_ty(bcx, v, t, take_ty)
+ }
+ _ => bcx
}
- return cx;
}
pub fn drop_ty<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t)
pub fn lazily_emit_all_tydesc_glue(ccx: @CrateContext,
static_ti: @tydesc_info) {
- lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, static_ti);
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti);
}
fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t {
- if (field == abi::tydesc_field_take_glue || field == abi::tydesc_field_drop_glue)
- && !ty::type_needs_drop(tcx, t) {
- return ty::mk_nil();
- }
-
- if field == abi::tydesc_field_take_glue {
- match ty::get(t).sty {
- ty::ty_str(ty::vstore_uniq) | ty::ty_vec(_, ty::vstore_uniq) |
- ty::ty_unboxed_vec(..) | ty::ty_uniq(..) => return ty::mk_nil(),
- _ => {}
- }
- }
-
- if field == abi::tydesc_field_take_glue && ty::type_is_boxed(t) {
- return ty::mk_box(tcx, ty::mk_nil());
- }
-
if field == abi::tydesc_field_drop_glue {
+ if !ty::type_needs_drop(tcx, t) {
+ return ty::mk_nil();
+ }
match ty::get(t).sty {
ty::ty_box(typ)
if !ty::type_needs_drop(tcx, typ) =>
t
}
-fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) {
+pub fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) {
let _icx = push_ctxt("lazily_emit_tydesc_glue");
let simpl = simplified_glue_type(ccx.tcx, field, ti.ty);
let simpl_ti = get_tydesc(ccx, simpl);
lazily_emit_tydesc_glue(ccx, field, simpl_ti);
- if field == abi::tydesc_field_take_glue {
- ti.take_glue.set(simpl_ti.take_glue.get());
- } else if field == abi::tydesc_field_drop_glue {
+ if field == abi::tydesc_field_drop_glue {
ti.drop_glue.set(simpl_ti.drop_glue.get());
} else if field == abi::tydesc_field_visit_glue {
ti.visit_glue.set(simpl_ti.visit_glue.get());
let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to());
- if field == abi::tydesc_field_take_glue {
- match ti.take_glue.get() {
- Some(_) => (),
- None => {
- debug!("+++ lazily_emit_tydesc_glue TAKE {}",
- ppaux::ty_to_str(ccx.tcx, ti.ty));
- let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "take");
- ti.take_glue.set(Some(glue_fn));
- make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, "take");
- debug!("--- lazily_emit_tydesc_glue TAKE {}",
- ppaux::ty_to_str(ccx.tcx, ti.ty));
- }
- }
- } else if field == abi::tydesc_field_drop_glue {
+ if field == abi::tydesc_field_drop_glue {
match ti.drop_glue.get() {
Some(_) => (),
None => {
}
// See [Note-arg-mode]
-pub fn call_tydesc_glue_full(bcx: &Block,
- v: ValueRef,
- tydesc: ValueRef,
- field: uint,
- static_ti: Option<@tydesc_info>) {
+pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
+ field: uint, static_ti: Option<@tydesc_info>) {
let _icx = push_ctxt("call_tydesc_glue_full");
let ccx = bcx.ccx();
// NB: Don't short-circuit even if this block is unreachable because
if bcx.unreachable.get() && !ccx.sess.no_landing_pads() { return; }
let static_glue_fn = match static_ti {
- None => None,
- Some(sti) => {
- lazily_emit_tydesc_glue(ccx, field, sti);
- if field == abi::tydesc_field_take_glue {
- sti.take_glue.get()
- } else if field == abi::tydesc_field_drop_glue {
- sti.drop_glue.get()
- } else if field == abi::tydesc_field_visit_glue {
- sti.visit_glue.get()
- } else {
- None
+ None => None,
+ Some(sti) => {
+ lazily_emit_tydesc_glue(ccx, field, sti);
+ if field == abi::tydesc_field_drop_glue {
+ sti.drop_glue.get()
+ } else if field == abi::tydesc_field_visit_glue {
+ sti.visit_glue.get()
+ } else {
+ None
+ }
}
- }
};
// When static type info is available, avoid casting parameter unless the
// glue is using a simplified type, because the function already has the
// right type. Otherwise cast to generic pointer.
- let llrawptr = if static_ti.is_none() || static_glue_fn.is_none() {
+ let llrawptr = if static_glue_fn.is_none() {
PointerCast(bcx, v, Type::i8p())
} else {
let ty = static_ti.unwrap().ty;
let llfn = {
match static_glue_fn {
- None => {
- // Select out the glue function to call from the tydesc
- let llfnptr = GEPi(bcx, tydesc, [0u, field]);
- Load(bcx, llfnptr)
- }
- Some(sgf) => sgf
+ None => {
+ // Select out the glue function to call from the tydesc
+ let llfnptr = GEPi(bcx, tydesc, [0u, field]);
+ Load(bcx, llfnptr)
+ }
+ Some(sgf) => sgf
}
};
- Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr], []);
+ Call(bcx, llfn, [llrawptr], []);
}
// See [Note-arg-mode]
bcx
}
-pub fn make_free_glue<'a>(bcx: &'a Block<'a>,
- v: ValueRef,
- t: ty::t)
- -> &'a Block<'a> {
- // 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 {
- ty::ty_box(body_ty) => {
- let v = Load(bcx, v);
- let body = GEPi(bcx, v, [0u, abi::box_field_body]);
- let bcx = drop_ty(bcx, body, body_ty);
- trans_free(bcx, v)
- }
- ty::ty_uniq(content_ty) => {
- let llbox = Load(bcx, v);
- let not_null = IsNotNull(bcx, llbox);
- with_cond(bcx, not_null, |bcx| {
- let bcx = drop_ty(bcx, llbox, content_ty);
- trans_exchange_free(bcx, llbox)
- })
- }
- ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) |
- ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
- make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
- }
- ty::ty_closure(_) => {
- closure::make_closure_glue(bcx, v, t, make_free_glue)
- }
- ty::ty_opaque_closure_ptr(ck) => {
- closure::make_opaque_cbox_free_glue(bcx, ck, v)
- }
- _ => bcx
- }
-}
-
-pub fn trans_struct_drop_flag<'a>(
- bcx: &'a Block<'a>,
+fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
t: ty::t,
v0: ValueRef,
dtor_did: ast::DefId,
})
}
-pub fn trans_struct_drop<'a>(
- bcx: &'a Block<'a>,
+fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
t: ty::t,
v0: ValueRef,
dtor_did: ast::DefId,
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
}
-pub fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t)
- -> &'a Block<'a> {
+fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");
let ccx = bcx.ccx();
match ty::get(t).sty {
- ty::ty_box(_) |
- ty::ty_str(ty::vstore_box) | ty::ty_vec(_, ty::vstore_box) => {
- decr_refcnt_maybe_free(bcx, v0, Some(t))
- }
- ty::ty_uniq(_) |
- ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) => {
- make_free_glue(bcx, v0, t)
- }
- ty::ty_unboxed_vec(_) => {
- tvec::make_drop_glue_unboxed(bcx, v0, t)
- }
- ty::ty_struct(did, ref substs) => {
- let tcx = bcx.tcx();
- match ty::ty_dtor(tcx, did) {
- ty::TraitDtor(dtor, true) => {
- trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
- }
- ty::TraitDtor(dtor, false) => {
- trans_struct_drop(bcx, t, v0, dtor, did, substs)
- }
- ty::NoDtor => {
- // No dtor? Just the default case
- iter_structural_ty(bcx, v0, t, drop_ty)
- }
+ ty::ty_box(body_ty) => {
+ decr_refcnt_maybe_free(bcx, v0, Some(body_ty))
+ }
+ ty::ty_str(ty::vstore_box) | ty::ty_vec(_, ty::vstore_box) => {
+ let unit_ty = ty::sequence_element_type(ccx.tcx, t);
+ let unboxed_vec_ty = ty::mk_mut_unboxed_vec(ccx.tcx, unit_ty);
+ decr_refcnt_maybe_free(bcx, v0, Some(unboxed_vec_ty))
+ }
+ ty::ty_uniq(content_ty) => {
+ let llbox = Load(bcx, v0);
+ let not_null = IsNotNull(bcx, llbox);
+ with_cond(bcx, not_null, |bcx| {
+ let bcx = drop_ty(bcx, llbox, content_ty);
+ trans_exchange_free(bcx, llbox)
+ })
+ }
+ ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) => {
+ make_drop_glue(bcx, v0, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
+ }
+ ty::ty_unboxed_vec(_) => {
+ tvec::make_drop_glue_unboxed(bcx, v0, t)
+ }
+ ty::ty_struct(did, ref substs) => {
+ let tcx = bcx.tcx();
+ match ty::ty_dtor(tcx, did) {
+ ty::TraitDtor(dtor, true) => {
+ trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
+ }
+ ty::TraitDtor(dtor, false) => {
+ trans_struct_drop(bcx, t, v0, dtor, did, substs)
+ }
+ ty::NoDtor => {
+ // No dtor? Just the default case
+ iter_structural_ty(bcx, v0, t, drop_ty)
+ }
+ }
+ }
+ ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
+ let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
+ decr_refcnt_maybe_free(bcx, llbox_ptr, None)
+ }
+ ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
+ let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
+ // Only drop the value when it is non-null
+ with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
+ let lldtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
+ let lldtor = Load(bcx, lldtor_ptr);
+ Call(bcx, lldtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []);
+ bcx
+ })
+ }
+ ty::ty_closure(ref f) if f.sigil == ast::OwnedSigil => {
+ let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
+ let env = Load(bcx, box_cell_v);
+ let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to();
+ let env = PointerCast(bcx, env, env_ptr_ty);
+ with_cond(bcx, IsNotNull(bcx, env), |bcx| {
+ // Load the type descr found in the env
+ let lltydescty = ccx.tydesc_type.ptr_to();
+ let tydescptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
+ let tydesc = Load(bcx, tydescptr);
+ let tydesc = PointerCast(bcx, tydesc, lltydescty);
+
+ // Drop the tuple data then free the descriptor
+ let cdata = GEPi(bcx, env, [0u, abi::box_field_body]);
+ call_tydesc_glue_full(bcx, cdata, tydesc,
+ abi::tydesc_field_drop_glue, None);
+
+ // Free the ty descr (if necc) and the env itself
+ trans_exchange_free(bcx, env)
+ })
+ }
+ _ => {
+ if ty::type_needs_drop(ccx.tcx, t) &&
+ ty::type_is_structural(t) {
+ iter_structural_ty(bcx, v0, t, drop_ty)
+ } else {
+ bcx
+ }
}
- }
- ty::ty_closure(_) => {
- closure::make_closure_glue(bcx, v0, t, drop_ty)
- }
- ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
- let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
- decr_refcnt_maybe_free(bcx, llbox_ptr, None)
- }
- ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
- let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
- // Only drop the value when it is non-null
- with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
- let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
-
- // Cast the vtable to a pointer to a pointer to a tydesc.
- let llvtable = PointerCast(bcx, llvtable,
- ccx.tydesc_type.ptr_to().ptr_to());
- let lltydesc = Load(bcx, llvtable);
- call_tydesc_glue_full(bcx,
- lluniquevalue,
- lltydesc,
- abi::tydesc_field_drop_glue,
- None);
- bcx
- })
- }
- ty::ty_opaque_closure_ptr(ck) => {
- closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
- }
- _ => {
- if ty::type_needs_drop(ccx.tcx, t) &&
- ty::type_is_structural(t) {
- iter_structural_ty(bcx, v0, t, drop_ty)
- } else { bcx }
- }
}
}
Store(decr_bcx, rc, rc_ptr);
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
+ let v = Load(free_bcx, box_ptr_ptr);
+ let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
let free_bcx = match t {
- Some(t) => make_free_glue(free_bcx, box_ptr_ptr, t),
+ Some(t) => drop_ty(free_bcx, body, t),
None => {
- let v = Load(free_bcx, box_ptr_ptr);
- let td = Load(free_bcx, GEPi(free_bcx, v, [0u, abi::box_field_tydesc]));
- let valptr = GEPi(free_bcx, v, [0u, abi::box_field_body]);
// Generate code that, dynamically, indexes into the
// tydesc and calls the drop glue that got set dynamically
- call_tydesc_glue_full(free_bcx, valptr, td, abi::tydesc_field_drop_glue, None);
- trans_free(free_bcx, v)
+ let td = Load(free_bcx, GEPi(free_bcx, v, [0u, abi::box_field_tydesc]));
+ call_tydesc_glue_full(free_bcx, body, td, abi::tydesc_field_drop_glue, None);
+ free_bcx
}
};
+ let free_bcx = trans_free(free_bcx, v);
Br(free_bcx, next_bcx.llbb);
next_bcx
}
-fn make_take_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) -> &'a Block<'a> {
- 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_box(_) |
- ty::ty_vec(_, ty::vstore_box) | ty::ty_str(ty::vstore_box) => {
- incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
- }
- ty::ty_vec(_, ty::vstore_slice(_))
- | ty::ty_str(ty::vstore_slice(_)) => {
- bcx
- }
- ty::ty_closure(_) => bcx,
- ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
- let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
- incr_refcnt_of_boxed(bcx, llbox);
- bcx
- }
- ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
- let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
- let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
-
- // Cast the vtable to a pointer to a pointer to a tydesc.
- let llvtable = PointerCast(bcx, llvtable,
- bcx.ccx().tydesc_type.ptr_to().ptr_to());
- let lltydesc = Load(bcx, llvtable);
- call_tydesc_glue_full(bcx,
- lluniquevalue,
- lltydesc,
- abi::tydesc_field_take_glue,
- None);
- bcx
- }
- ty::ty_opaque_closure_ptr(_) => bcx,
- _ if ty::type_is_structural(t) => {
- iter_structural_ty(bcx, v, t, take_ty)
- }
- _ => bcx
- }
-}
-
-fn incr_refcnt_of_boxed(cx: &Block, box_ptr: ValueRef) {
+fn incr_refcnt_of_boxed<'a>(bcx: &'a Block<'a>,
+ box_ptr_ptr: ValueRef) -> &'a Block<'a> {
let _icx = push_ctxt("incr_refcnt_of_boxed");
- let ccx = cx.ccx();
- let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]);
- let rc = Load(cx, rc_ptr);
- let rc = Add(cx, rc, C_int(ccx, 1));
- Store(cx, rc, rc_ptr);
+ let ccx = bcx.ccx();
+ let box_ptr = Load(bcx, box_ptr_ptr);
+ let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
+ let rc = Load(bcx, rc_ptr);
+ let rc = Add(bcx, rc, C_int(ccx, 1));
+ Store(bcx, rc, rc_ptr);
+ bcx
}
size: llsize,
align: llalign,
name: ty_name,
- take_glue: Cell::new(None),
drop_glue: Cell::new(None),
visit_glue: Cell::new(None),
};
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx, t));
let _s = StatRecorder::new(ccx, glue_name);
- let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, false, ty::mk_nil(), None);
init_function(&fcx, false, ty::mk_nil(), None);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
// before being put into the tydesc because we only have a singleton
// tydesc type. Then we'll recast each function to its real type when
// calling it.
- let take_glue =
- match ti.take_glue.get() {
- None => {
- ccx.stats.n_null_glues.set(ccx.stats.n_null_glues.get() +
- 1);
- C_null(glue_fn_ty)
- }
- Some(v) => {
- unsafe {
- ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() +
- 1);
- llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
- }
- }
- };
let drop_glue =
match ti.drop_glue.get() {
None => {
let tydesc = C_named_struct(ccx.tydesc_type,
[ti.size, // size
ti.align, // align
- take_glue, // take_glue
drop_glue, // drop_glue
visit_glue, // visit_glue
ti.name]); // name
use middle::trans::base::{push_ctxt, trans_item, get_item_val, trans_fn};
use middle::trans::common::*;
use middle::ty;
-use util::ppaux::ty_to_str;
use std::vec;
use syntax::ast;
let llfn = get_item_val(ccx, mth.id);
let path = vec::append_one(
ty::item_path(ccx.tcx, impl_did), PathName(mth.ident));
- let self_kind = match mth.explicit_self.node {
- ast::SelfStatic => None,
- _ => {
- let self_ty = ty::node_id_to_type(ccx.tcx,
- mth.self_id);
- debug!("calling inline trans_fn with self_ty {}",
- ty_to_str(ccx.tcx, self_ty));
- Some(self_ty)
- }
- };
- trans_fn(ccx,
- path,
- mth.decl,
- mth.body,
- llfn,
- self_kind,
- None,
- mth.id,
- []);
+ trans_fn(ccx, path, mth.decl, mth.body, llfn, None, mth.id, []);
}
local_def(mth.id)
}
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
- let fcx = new_fn_ctxt_detailed(ccx,
- path,
- decl,
- item.id,
- output_type,
- Some(substs),
- Some(item.span));
+ let fcx = new_fn_ctxt_detailed(ccx, path, decl, item.id, false, output_type,
+ Some(substs), Some(item.span));
init_function(&fcx, true, output_type, Some(substs));
set_always_inline(fcx.llfn);
"size_of" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)));
+ Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty) as uint));
}
"move_val_init" => {
// Create a datum reflecting the value being moved.
"min_align_of" => {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty)));
+ Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint));
}
"pref_align_of"=> {
let tp_ty = substs.tys[0];
let lltp_ty = type_of::type_of(ccx, tp_ty);
- Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)));
+ Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint));
}
"get_tydesc" => {
let tp_ty = substs.tys[0];
_ => fail!("transmute has non-expr arg"),
}
};
- let pluralize = |n| if 1u == n { "" } else { "s" };
+ let pluralize = |n| if 1 == n { "" } else { "s" };
ccx.sess.span_fatal(sp,
format!("transmute called on types with \
different sizes: {} ({} bit{}) to \
RetVoid(bcx);
}
"morestack_addr" => {
- // XXX This is a hack to grab the address of this particular
+ // FIXME This is a hack to grab the address of this particular
// native function. There should be a general in-language
// way to do this
- let llfty = type_of_rust_fn(bcx.ccx(), None, [], ty::mk_nil());
+ let llfty = type_of_rust_fn(bcx.ccx(), false, [], ty::mk_nil());
let morestack_addr = decl_cdecl_fn(bcx.ccx().llmod, "__morestack",
llfty, ty::mk_nil());
let morestack_addr = PointerCast(bcx, morestack_addr,
// compute sizeof / alignof
// Returns the number of bytes clobbered by a Store to this type.
-pub fn llsize_of_store(cx: &CrateContext, ty: Type) -> uint {
+pub fn llsize_of_store(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- return llvm::LLVMStoreSizeOfType(cx.td.lltd, ty.to_ref()) as uint;
+ return llvm::LLVMStoreSizeOfType(cx.td.lltd, ty.to_ref()) as u64;
}
}
// Returns the number of bytes between successive elements of type T in an
// array of T. This is the "ABI" size. It includes any ABI-mandated padding.
-pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> uint {
+pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- return llvm::LLVMABISizeOfType(cx.td.lltd, ty.to_ref()) as uint;
+ return llvm::LLVMABISizeOfType(cx.td.lltd, ty.to_ref()) as u64;
}
}
// that LLVM *does* distinguish between e.g. a 1-bit value and an 8-bit value
// at the codegen level! In general you should prefer `llbitsize_of_real`
// below.
-pub fn llsize_of_real(cx: &CrateContext, ty: Type) -> uint {
+pub fn llsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as uint;
- if nbits & 7u != 0u {
+ let nbits = llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as u64;
+ if nbits & 7 != 0 {
// Not an even number of bytes, spills into "next" byte.
- 1u + (nbits >> 3)
+ 1 + (nbits >> 3)
} else {
nbits >> 3
}
}
/// Returns the "real" size of the type in bits.
-pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> uint {
+pub fn llbitsize_of_real(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as uint
+ llvm::LLVMSizeOfTypeInBits(cx.td.lltd, ty.to_ref()) as u64
}
}
// there's no need for that contrivance. The instruction
// selection DAG generator would flatten that GEP(1) node into a
// constant of the type's alloc size, so let's save it some work.
- return C_uint(cx, llsize_of_alloc(cx, ty));
+ return C_uint(cx, llsize_of_alloc(cx, ty) as uint);
}
// Returns the "default" size of t (see above), or 1 if the size would
// The preferred alignment may be larger than the alignment used when
// packing the type into structs. This will be used for things like
// allocations inside a stack frame, which LLVM has a free hand in.
-pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> uint {
+pub fn llalign_of_pref(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, ty.to_ref()) as uint;
+ return llvm::LLVMPreferredAlignmentOfType(cx.td.lltd, ty.to_ref()) as u64;
}
}
// Returns the minimum alignment of a type required by the platform.
// This is the alignment that will be used for struct fields, arrays,
// and similar ABI-mandated things.
-pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> uint {
+pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> u64 {
unsafe {
- return llvm::LLVMABIAlignmentOfType(cx.td.lltd, ty.to_ref()) as uint;
+ return llvm::LLVMABIAlignmentOfType(cx.td.lltd, ty.to_ref()) as u64;
}
}
}
}
-pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> uint {
+pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> u64 {
unsafe {
- return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as uint;
+ return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as u64;
}
}
methods: &[@ast::Method],
generics: &ast::Generics,
id: ast::NodeId) {
- let _icx = push_ctxt("impl::trans_impl");
+ let _icx = push_ctxt("meth::trans_impl");
let tcx = ccx.tcx;
debug!("trans_impl(path={}, name={}, id={:?})",
let path = vec::append_one(sub_path.clone(),
PathName(method.ident));
- trans_method(ccx,
- path,
- *method,
- None,
- |_| llfn);
+ trans_fn(ccx, path, method.decl, method.body,
+ llfn, None, method.id, []);
} else {
let mut v = TransItemVisitor{ ccx: ccx };
visit::walk_method_helper(&mut v, *method, ());
/// * `path`: the path to the method
/// * `method`: the AST node for the method
/// * `param_substs`: if this is a generic method, the current values for
-/// type parameters and so forth, else none
-/// * `llfn`: a closure returning the LLVM ValueRef for the method
-/// * `impl_id`: the node ID of the impl this method is inside
+/// type parameters and so forth, else None
+/// * `llfn`: the LLVM ValueRef for the method
///
-/// XXX(pcwalton) Can we take `path` by reference?
-pub fn trans_method(ccx: @CrateContext,
- path: Path,
- method: &ast::Method,
+/// FIXME(pcwalton) Can we take `path` by reference?
+pub fn trans_method(ccx: @CrateContext, path: Path, method: &ast::Method,
param_substs: Option<@param_substs>,
- llfn_with_self: |Option<ty::t>| -> ValueRef) -> ValueRef {
- // figure out how self is being passed
- let self_ty = match method.explicit_self.node {
- ast::SelfStatic => None,
- _ => {
- // determine the (monomorphized) type that `self` maps to for
- // this method
- let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
- let self_ty = match param_substs {
- None => self_ty,
- Some(param_substs) => {
- ty::subst_tps(ccx.tcx,
- param_substs.tys,
- param_substs.self_ty,
- self_ty)
- }
- };
- debug!("calling trans_fn with self_ty {}", self_ty.repr(ccx.tcx));
- Some(self_ty)
- }
- };
-
- let llfn = llfn_with_self(self_ty);
-
- // generate the actual code
- trans_fn(ccx,
- path,
- method.decl,
- method.body,
- llfn,
- self_ty,
- param_substs,
- method.id,
- []);
+ llfn: ValueRef) -> ValueRef {
+ trans_fn(ccx, path, method.decl, method.body,
+ llfn, param_substs, method.id, []);
llfn
}
mentry: typeck::method_map_entry,
arg_cleanup_scope: cleanup::ScopeId)
-> Callee<'a> {
- let _icx = push_ctxt("impl::trans_method_callee");
+ let _icx = push_ctxt("meth::trans_method_callee");
- debug!("trans_method_callee(callee_id={:?}, this={}, mentry={})",
+ debug!("trans_method_callee(callee_id={:?}, mentry={})",
callee_id,
- bcx.expr_to_str(this),
mentry.repr(bcx.tcx()));
match mentry.origin {
typeck::method_static(did) => {
- let self_ty = monomorphize_type(bcx, mentry.self_ty);
- let Result {bcx, val} = trans_arg_expr(bcx, self_ty, this,
- arg_cleanup_scope,
- DontAutorefArg);
- // HACK should not need the pointer cast, eventually trans_fn_ref
- // should return a function type with the right type for self.
- let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
- let fn_ty = node_id_type(bcx, callee_id);
- let llfn_ty = type_of_fn_from_ty(bcx.ccx(), Some(self_ty), fn_ty).ptr_to();
- let llfn_val = PointerCast(bcx, callee_fn.llfn, llfn_ty);
Callee {
bcx: bcx,
- data: Method(MethodData {
- llfn: llfn_val,
- llself: val,
- })
+ data: Fn(callee::trans_fn_ref(bcx, did, callee_id))
}
}
typeck::method_param(typeck::method_param {
trait_id);
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
- trans_monomorphized_callee(bcx, callee_id, this, mentry,
- trait_id, off, vtbl,
- arg_cleanup_scope)
+ trans_monomorphized_callee(bcx, callee_id,
+ trait_id, off, vtbl)
}
// how to get rid of this?
None => fail!("trans_method_callee: missing param_substs")
method_id: ast::DefId,
trait_id: ast::DefId,
callee_id: ast::NodeId)
- -> FnData {
- let _icx = push_ctxt("impl::trans_static_method_callee");
+ -> ValueRef {
+ let _icx = push_ctxt("meth::trans_static_method_callee");
let ccx = bcx.ccx();
debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
bcx, mth_id, callee_id,
*rcvr_substs, rcvr_origins);
- let FnData {llfn: lval} =
- trans_fn_ref_with_vtables(bcx,
- mth_id,
- callee_id,
- callee_substs,
- Some(callee_origins));
+ let llfn = trans_fn_ref_with_vtables(bcx, mth_id, callee_id,
+ callee_substs,
+ Some(callee_origins));
let callee_ty = node_id_type(bcx, callee_id);
- let llty = type_of_fn_from_ty(ccx, None, callee_ty).ptr_to();
- FnData {llfn: PointerCast(bcx, lval, llty)}
+ let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
+ PointerCast(bcx, llfn, llty)
}
_ => {
fail!("vtable_param left in monomorphized \
meth.def_id
}
-pub fn trans_monomorphized_callee<'a>(
- bcx: &'a Block<'a>,
+fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
callee_id: ast::NodeId,
- base: &ast::Expr,
- mentry: typeck::method_map_entry,
trait_id: ast::DefId,
n_method: uint,
- vtbl: typeck::vtable_origin,
- arg_cleanup_scope: cleanup::ScopeId)
+ vtbl: typeck::vtable_origin)
-> Callee<'a> {
- let _icx = push_ctxt("impl::trans_monomorphized_callee");
+ let _icx = push_ctxt("meth::trans_monomorphized_callee");
return match vtbl {
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(bcx.ccx(), impl_did, mname.name);
- // obtain the `self` value:
- let self_ty = monomorphize_type(bcx, mentry.self_ty);
- let Result {bcx, val} = trans_arg_expr(bcx, self_ty, base,
- arg_cleanup_scope,
- DontAutorefArg);
-
// create a concatenated set of substitutions which includes
// those from the impl and those from the method:
let (callee_substs, callee_origins) =
*rcvr_substs, rcvr_origins);
// translate the function
- let callee = trans_fn_ref_with_vtables(bcx,
- mth_id,
- callee_id,
- callee_substs,
- Some(callee_origins));
+ let llfn = trans_fn_ref_with_vtables(bcx,
+ mth_id,
+ callee_id,
+ callee_substs,
+ Some(callee_origins));
- // create a llvalue that represents the fn ptr
- // HACK should not need the pointer cast (add self in trans_fn_ref_with_vtables).
- let fn_ty = node_id_type(bcx, callee_id);
- let llfn_ty = type_of_fn_from_ty(ccx, Some(self_ty), fn_ty).ptr_to();
- let llfn_val = PointerCast(bcx, callee.llfn, llfn_ty);
-
- // combine the self environment with the rest
- Callee {
- bcx: bcx,
- data: Method(MethodData {
- llfn: llfn_val,
- llself: val,
- })
- }
+ Callee { bcx: bcx, data: Fn(llfn) }
}
typeck::vtable_param(..) => {
fail!("vtable_param left in monomorphized function's vtable substs");
return (ty_substs, vtables);
}
-pub fn trans_trait_callee<'a>(
- bcx: &'a Block<'a>,
+fn trans_trait_callee<'a>(bcx: &'a Block<'a>,
callee_id: ast::NodeId,
n_method: uint,
self_expr: &ast::Expr,
* pair.
*/
- let _icx = push_ctxt("impl::trans_trait_callee");
+ let _icx = push_ctxt("meth::trans_trait_callee");
let mut bcx = bcx;
// Translate self_datum and take ownership of the value by
* a by-ref pointer to the object pair.
*/
- let _icx = push_ctxt("impl::trans_trait_callee");
+ let _icx = push_ctxt("meth::trans_trait_callee");
let ccx = bcx.ccx();
// Load the data pointer from the object.
debug!("(translating trait callee) loading second index from pair");
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
let llbox = Load(bcx, llboxptr);
- let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
+ let llself = PointerCast(bcx, llbox, Type::i8p());
// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
- let llcallee_ty = type_of_fn_from_ty(ccx, None, callee_ty);
+ // Replace the self type (&Self or ~Self) with an opaque pointer.
+ let llcallee_ty = match ty::get(callee_ty).sty {
+ ty::ty_bare_fn(ref f) if f.abis.is_rust() => {
+ type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
+ }
+ _ => {
+ ccx.sess.bug("meth::trans_trait_callee given non-bare-rust-fn");
+ }
+ };
let llvtable = Load(bcx,
PointerCast(bcx,
GEPi(bcx, llpair,
return Callee {
bcx: bcx,
- data: Method(MethodData {
+ data: TraitMethod(MethodData {
llfn: mptr,
llself: llself,
})
origins: typeck::vtable_param_res)
-> ValueRef {
let ccx = bcx.ccx();
- let _icx = push_ctxt("impl::get_vtable");
+ let _icx = push_ctxt("meth::get_vtable");
// Check the cache.
let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
// Generate a type descriptor for the vtable.
let tydesc = get_tydesc(ccx, self_ty);
- glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
+ glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, tydesc);
let vtable = make_vtable(ccx, tydesc, methods);
ptrs: &[ValueRef])
-> ValueRef {
unsafe {
- let _icx = push_ctxt("impl::make_vtable");
+ let _icx = push_ctxt("meth::make_vtable");
- let mut components = ~[ tydesc.tydesc ];
+ let mut components = ~[tydesc.drop_glue.get().unwrap()];
for &ptr in ptrs.iter() {
components.push(ptr)
}
tcx.sess.str_of(ident));
C_null(Type::nil().ptr_to())
} else {
- trans_fn_ref_with_vtables(bcx, m_id, 0,
- substs, Some(vtables)).llfn
+ trans_fn_ref_with_vtables(bcx, m_id, 0, substs, Some(vtables))
}
})
}
*/
let mut bcx = bcx;
- let _icx = push_ctxt("impl::trans_cast");
+ let _icx = push_ctxt("meth::trans_cast");
let lldest = match dest {
Ignore => {
let s = mangle_exported_name(ccx, pt.clone(), mono_ty);
debug!("monomorphize_fn mangled to {}", s);
- let mk_lldecl = |self_ty| {
- let lldecl = decl_internal_rust_fn(ccx, self_ty, f.sig.inputs, f.sig.output, s);
+ let mk_lldecl = || {
+ let lldecl = decl_internal_rust_fn(ccx, false,
+ f.sig.inputs,
+ f.sig.output, s);
let mut monomorphized = ccx.monomorphized.borrow_mut();
monomorphized.get().insert(hash_id, lldecl);
lldecl
node: ast::ItemFn(decl, _, _, _, body),
..
} => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_llvm_fn_attrs(i.attrs, d);
- trans_fn(ccx,
- pt,
- decl,
- body,
- d,
- None,
- Some(psubsts),
- fn_id.node,
- []);
+ trans_fn(ccx, pt, decl, body, d, Some(psubsts), fn_id.node, []);
d
}
_ => {
}
}
ast_map::NodeForeignItem(i, _, _, _) => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
intrinsic::trans_intrinsic(ccx, d, i, pt, psubsts, i.attrs,
ref_id);
d
ast_map::NodeVariant(v, enum_item, _) => {
let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id));
let this_tv = *tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_inline_hint(d);
match v.node.kind {
ast::TupleVariantKind(ref args) => {
d
}
ast_map::NodeMethod(mth, _, _) => {
- meth::trans_method(ccx, pt, mth, Some(psubsts), |self_ty| {
- let d = mk_lldecl(self_ty);
- set_llvm_fn_attrs(mth.attrs, d);
- d
- })
+ let d = mk_lldecl();
+ set_llvm_fn_attrs(mth.attrs, d);
+ trans_fn(ccx, pt, mth.decl, mth.body, d, Some(psubsts), mth.id, []);
+ d
}
ast_map::NodeTraitMethod(method, _, pt) => {
match *method {
ast::Provided(mth) => {
- meth::trans_method(ccx,
- (*pt).clone(),
- mth,
- Some(psubsts),
- |self_ty| {
- let d = mk_lldecl(self_ty);
- set_llvm_fn_attrs(mth.attrs, d);
- d
- })
+ let d = mk_lldecl();
+ set_llvm_fn_attrs(mth.attrs, d);
+ trans_fn(ccx, (*pt).clone(), mth.decl, mth.body,
+ d, Some(psubsts), mth.id, []);
+ d
}
_ => {
ccx.tcx.sess.bug(format!("Can't monomorphize a {:?}",
}
}
ast_map::NodeStructCtor(struct_def, _, _) => {
- let d = mk_lldecl(None);
+ let d = mk_lldecl();
set_inline_hint(d);
base::trans_tuple_struct(ccx,
struct_def.fields,
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
-use middle::trans::callee::{ArgVals, DontAutorefArg};
+use middle::trans::callee::ArgVals;
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::datum::*;
let tr = type_of(self.bcx.ccx(), t);
let s = machine::llsize_of_real(self.bcx.ccx(), tr);
let a = machine::llalign_of_min(self.bcx.ccx(), tr);
- return ~[self.c_uint(s),
- self.c_uint(a)];
+ return ~[self.c_uint(s as uint),
+ self.c_uint(a as uint)];
}
pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef {
mth_ty,
mth_idx,
v),
- ArgVals(args), None, DontAutorefArg));
+ ArgVals(args), None));
let result = bool_to_i1(bcx, result);
let next_bcx = fcx.new_temp_block("next");
CondBr(bcx, result, next_bcx.llbb, self.final_bcx.llbb);
sub_path,
"get_disr");
- let llfdecl = decl_internal_rust_fn(ccx, None, [opaqueptrty], ty::mk_u64(), sym);
- let fcx = new_fn_ctxt(ccx,
- ~[],
- llfdecl,
- ty::mk_u64(),
- None);
+ let llfdecl = decl_internal_rust_fn(ccx, false,
+ [opaqueptrty],
+ ty::mk_u64(), sym);
+ let fcx = new_fn_ctxt(ccx, ~[], llfdecl, false, ty::mk_u64(), None);
init_function(&fcx, false, ty::mk_u64(), None);
let arg = unsafe {
self.visit("param", extra)
}
ty::ty_self(..) => self.leaf("self"),
- ty::ty_type => self.leaf("type"),
- ty::ty_opaque_closure_ptr(ck) => {
- let ckval = ast_sigil_constant(ck);
- let extra = ~[self.c_uint(ckval)];
- self.visit("closure_ptr", extra)
- }
+ ty::ty_type => self.leaf("type")
}
}
unit_ty: ty::t,
llunit_ty: Type,
llunit_size: ValueRef,
- llunit_alloc_size: uint
+ llunit_alloc_size: u64
}
impl VecTypes {
args.len() as c_uint, True))
}
- pub fn func_pair(cx: &CrateContext, fn_ty: &Type) -> Type {
- Type::struct_([fn_ty.ptr_to(), Type::opaque_cbox_ptr(cx)], false)
- }
-
pub fn ptr(ty: Type) -> Type {
ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
}
}
pub fn vtable() -> Type {
- Type::array(&Type::i8().ptr_to(), 1)
+ Type::array(&Type::i8p().ptr_to(), 1)
}
pub fn generic_glue_fn(cx: &CrateContext) -> Type {
}
pub fn glue_fn(t: Type) -> Type {
- Type::func([ Type::nil().ptr_to(), t ],
- &Type::void())
+ Type::func([t], &Type::void())
}
pub fn tydesc(arch: Architecture) -> Type {
// Must mirror:
//
// std::unstable::intrinsics::TyDesc
- // type_desc in rt
let elems = [int_ty, // size
int_ty, // align
- glue_fn_ty, // take
glue_fn_ty, // drop
glue_fn_ty, // visit
Type::struct_([Type::i8p(), Type::int(arch)], false)]; // name
Type::vec(arch, &Type::i8())
}
- #[inline]
- pub fn box_header_fields(ctx: &CrateContext) -> ~[Type] {
- ~[
+ // The box pointed to by @T.
+ pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
+ Type::struct_([
ctx.int_type, ctx.tydesc_type.ptr_to(),
- Type::i8().ptr_to(), Type::i8().ptr_to()
- ]
- }
-
- pub fn box_header(ctx: &CrateContext) -> Type {
- Type::struct_(Type::box_header_fields(ctx), false)
- }
-
- pub fn smart_ptr(ctx: &CrateContext, ty: &Type) -> Type {
- Type::struct_(Type::box_header_fields(ctx) + &[*ty], false)
- }
-
- pub fn opaque() -> Type {
- Type::i8()
- }
-
- pub fn opaque_box(ctx: &CrateContext) -> Type {
- Type::smart_ptr(ctx, &Type::opaque())
- }
-
- pub fn opaque_cbox_ptr(cx: &CrateContext) -> Type {
- Type::opaque_box(cx).ptr_to()
+ Type::i8p(), Type::i8p(), ty
+ ], false)
}
pub fn opaque_trait(ctx: &CrateContext, store: ty::TraitStore) -> Type {
- let tydesc_ptr = ctx.tydesc_type.ptr_to();
+ let vtable = Type::glue_fn(Type::i8p()).ptr_to().ptr_to();
let box_ty = match store {
- ty::BoxTraitStore => Type::opaque_box(ctx),
+ ty::BoxTraitStore => Type::at_box(ctx, Type::i8()),
ty::UniqTraitStore => Type::i8(),
ty::RegionTraitStore(..) => Type::i8()
};
- Type::struct_([tydesc_ptr, box_ty.ptr_to()], false)
+ Type::struct_([vtable, box_ty.ptr_to()], false)
}
pub fn kind(&self) -> TypeKind {
}
}
-pub fn type_of_explicit_args(ccx: &CrateContext,
- inputs: &[ty::t]) -> ~[Type] {
- inputs.map(|&arg_ty| type_of_explicit_arg(ccx, arg_ty))
-}
-
-pub fn type_of_rust_fn(cx: &CrateContext,
- self_ty: Option<ty::t>,
- inputs: &[ty::t],
- output: ty::t) -> Type {
+pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
+ inputs: &[ty::t], output: ty::t) -> Type {
let mut atys: ~[Type] = ~[];
// Arg 0: Output pointer.
}
// Arg 1: Environment
- let env = match self_ty {
- Some(t) => type_of_explicit_arg(cx, t),
- None => Type::opaque_box(cx).ptr_to()
- };
- atys.push(env);
+ if has_env {
+ atys.push(Type::i8p());
+ }
// ... then explicit args.
- atys.push_all(type_of_explicit_args(cx, inputs));
+ let mut input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
+ atys.extend(&mut input_tys);
// Use the output as the actual return value if it's immediate.
if use_out_pointer || return_type_is_void(cx, output) {
}
// Given a function type and a count of ty params, construct an llvm type
-pub fn type_of_fn_from_ty(cx: &CrateContext, self_ty: Option<ty::t>, fty: ty::t) -> Type {
- return match ty::get(fty).sty {
+pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
+ match ty::get(fty).sty {
ty::ty_closure(ref f) => {
- type_of_rust_fn(cx, None, f.sig.inputs, f.sig.output)
+ type_of_rust_fn(cx, true, f.sig.inputs, f.sig.output)
}
ty::ty_bare_fn(ref f) => {
if f.abis.is_rust() || f.abis.is_intrinsic() {
- type_of_rust_fn(cx, self_ty, f.sig.inputs, f.sig.output)
+ type_of_rust_fn(cx, false, f.sig.inputs, f.sig.output)
} else {
foreign::lltype_for_foreign_fn(cx, fty)
}
_ => {
cx.sess.bug("type_of_fn_from_ty given non-closure, non-bare-fn")
}
- };
+ }
}
// A "sizing type" is an LLVM type, the size and alignment of which are
ty::ty_uniq(..) |
ty::ty_ptr(..) |
ty::ty_rptr(..) |
- ty::ty_type |
- ty::ty_opaque_closure_ptr(..) => Type::i8p(),
+ ty::ty_type => Type::i8p(),
ty::ty_str(ty::vstore_slice(..)) |
ty::ty_vec(_, ty::vstore_slice(..)) => {
adt::incomplete_type_of(cx, repr, name)
}
ty::ty_str(ty::vstore_box) => {
- Type::smart_ptr(cx,
- &Type::vec(cx.sess.targ_cfg.arch,
- &Type::i8())).ptr_to()
+ Type::at_box(cx, Type::vec(cx.sess.targ_cfg.arch, &Type::i8())).ptr_to()
}
ty::ty_vec(ref mt, ty::vstore_box) => {
let e_ty = type_of(cx, mt.ty);
- let v_ty = Type::vec(cx.sess.targ_cfg.arch, &e_ty);
- Type::smart_ptr(cx, &v_ty).ptr_to()
+ Type::at_box(cx, Type::vec(cx.sess.targ_cfg.arch, &e_ty)).ptr_to()
}
ty::ty_box(typ) => {
- let ty = type_of(cx, typ);
- Type::smart_ptr(cx, &ty).ptr_to()
+ Type::at_box(cx, type_of(cx, typ)).ptr_to()
}
ty::ty_uniq(typ) => {
type_of(cx, typ).ptr_to()
}
ty::ty_bare_fn(_) => {
- type_of_fn_from_ty(cx, None, t).ptr_to()
+ type_of_fn_from_ty(cx, t).ptr_to()
}
ty::ty_closure(_) => {
- let ty = type_of_fn_from_ty(cx, None, t);
- Type::func_pair(cx, &ty)
+ let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
+ Type::struct_([fn_ty, Type::i8p()], false)
}
ty::ty_trait(_, _, store, _, _) => Type::opaque_trait(cx, store),
ty::ty_type => cx.tydesc_type.ptr_to(),
let repr = adt::represent_type(cx, t);
adt::type_of(cx, repr)
}
- ty::ty_opaque_closure_ptr(_) => Type::opaque_box(cx).ptr_to(),
ty::ty_struct(did, ref substs) => {
if ty::type_is_simd(cx.tcx, t) {
let et = ty::simd_type(cx.tcx, t);
an_enum => { "enum" }
};
let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did),
- &ty::NonerasedRegions(opt_vec::Empty), tps);
+ &ty::NonerasedRegions(opt_vec::Empty),
+ tps, did, false);
if did.crate == 0 {
format!("{}.{}", name, tstr)
} else {
pub struct Method {
ident: ast::Ident,
generics: ty::Generics,
- transformed_self_ty: Option<ty::t>,
fty: BareFnTy,
explicit_self: ast::ExplicitSelf_,
vis: ast::Visibility,
impl Method {
pub fn new(ident: ast::Ident,
generics: ty::Generics,
- transformed_self_ty: Option<ty::t>,
fty: BareFnTy,
explicit_self: ast::ExplicitSelf_,
vis: ast::Visibility,
container: MethodContainer,
provided_source: Option<ast::DefId>)
-> Method {
- // Check the invariants.
- if explicit_self == ast::SelfStatic {
- assert!(transformed_self_ty.is_none());
- } else {
- assert!(transformed_self_ty.is_some());
- }
-
Method {
ident: ident,
generics: generics,
- transformed_self_ty: transformed_self_ty,
fty: fty,
explicit_self: explicit_self,
vis: vis,
/// The data structure to keep track of all the information that typechecker
/// generates so that so that it can be reused and doesn't have to be redone
/// later on.
-struct ctxt_ {
+pub struct ctxt_ {
diag: @syntax::diagnostic::SpanHandler,
interner: RefCell<HashMap<intern_key, ~t_box_>>,
next_id: Cell<uint>,
// "Fake" types, used for trans purposes
ty_type, // type_desc*
- ty_opaque_closure_ptr(Sigil), // ptr to env for || and proc
ty_unboxed_vec(mt),
}
pub struct TypeParameterDef {
ident: ast::Ident,
def_id: ast::DefId,
- bounds: @ParamBounds
+ bounds: @ParamBounds,
+ default: Option<ty::t>
}
#[deriving(Encodable, Decodable, Clone)]
flags |= get(mt.ty).flags;
}
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
- &ty_str(_) | &ty_type | &ty_opaque_closure_ptr(_) => {}
+ &ty_str(_) | &ty_type => {}
// You might think that we could just return ty_err for
// any type containing ty_err as a component, and get
// rid of the has_ty_err flag -- likewise for ty_bot (with
pub fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) }
-pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
- mk_t(cx, ty_opaque_closure_ptr(sigil))
-}
-
pub fn walk_ty(ty: t, f: |t|) {
maybe_walk_ty(ty, |t| { f(t); true });
}
return;
}
match get(ty).sty {
- ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_str(_) | ty_type | ty_self(_) |
- ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => {}
- ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
- ty_vec(ref tm, _) | ty_unboxed_vec(ref tm) | ty_ptr(ref tm) |
- ty_rptr(_, ref tm) => {
- maybe_walk_ty(tm.ty, f);
- }
- ty_enum(_, ref substs) | ty_struct(_, ref substs) |
- ty_trait(_, ref substs, _, _, _) => {
- for subty in (*substs).tps.iter() { maybe_walk_ty(*subty, |x| f(x)); }
- }
- ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
- ty_bare_fn(ref ft) => {
- for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
- maybe_walk_ty(ft.sig.output, f);
- }
- ty_closure(ref ft) => {
- for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
- maybe_walk_ty(ft.sig.output, f);
- }
+ ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
+ ty_str(_) | ty_type | ty_self(_) |
+ ty_infer(_) | ty_param(_) | ty_err => {}
+ ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
+ ty_vec(ref tm, _) | ty_unboxed_vec(ref tm) | ty_ptr(ref tm) |
+ ty_rptr(_, ref tm) => {
+ maybe_walk_ty(tm.ty, f);
+ }
+ ty_enum(_, ref substs) | ty_struct(_, ref substs) |
+ ty_trait(_, ref substs, _, _, _) => {
+ for subty in (*substs).tps.iter() { maybe_walk_ty(*subty, |x| f(x)); }
+ }
+ ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
+ ty_bare_fn(ref ft) => {
+ for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
+ maybe_walk_ty(ft.sig.output, f);
+ }
+ ty_closure(ref ft) => {
+ for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
+ maybe_walk_ty(ft.sig.output, f);
+ }
}
}
pub fn type_is_unique(ty: t) -> bool {
match get(ty).sty {
- ty_uniq(_) |
- ty_vec(_, vstore_uniq) |
- ty_str(vstore_uniq) |
- ty_opaque_closure_ptr(ast::OwnedSigil) => true,
- _ => return false
+ ty_uniq(_) | ty_vec(_, vstore_uniq) | ty_str(vstore_uniq) => true,
+ _ => false
}
}
TC::All
}
ty_unboxed_vec(mt) => TC::InteriorUnsized | tc_mt(cx, mt, cache),
- ty_opaque_closure_ptr(sigil) => {
- match sigil {
- ast::BorrowedSigil => TC::ReachesBorrowed,
- ast::ManagedSigil => TC::Managed,
- ast::OwnedSigil => TC::OwnsOwned,
- }
- }
ty_type => TC::None,
ty_param(_) |
ty_self(_) |
ty_type |
- ty_opaque_closure_ptr(_) |
ty_vec(_, _) |
ty_unboxed_vec(_) => {
false
!subtypes_require(cx, &mut seen, r_ty, r_ty)
}
-pub fn type_structurally_contains(cx: ctxt, ty: t, test: |x: &sty| -> bool)
- -> bool {
- let sty = &get(ty).sty;
- debug!("type_structurally_contains: {}",
- ::util::ppaux::ty_to_str(cx, ty));
- if test(sty) { return true; }
- match *sty {
- ty_enum(did, ref substs) => {
- for variant in (*enum_variants(cx, did)).iter() {
- for aty in variant.args.iter() {
- let sty = subst(cx, substs, *aty);
- if type_structurally_contains(cx, sty, |x| test(x)) { return true; }
+/// Describes whether a type is representable. For types that are not
+/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
+/// distinguish between types that are recursive with themselves and types that
+/// contain a different recursive type. These cases can therefore be treated
+/// differently when reporting errors.
+#[deriving(Eq)]
+pub enum Representability {
+ Representable,
+ SelfRecursive,
+ ContainsRecursive,
+}
+
+/// Check whether a type is representable. This means it cannot contain unboxed
+/// structural recursion. This check is needed for structs and enums.
+pub fn is_type_representable(cx: ctxt, ty: t) -> Representability {
+
+ // Iterate until something non-representable is found
+ fn find_nonrepresentable<It: Iterator<t>>(cx: ctxt, seen: &mut ~[DefId],
+ mut iter: It) -> Representability {
+ for ty in iter {
+ let r = type_structurally_recursive(cx, seen, ty);
+ if r != Representable {
+ return r
}
}
- return false;
- }
- ty_struct(did, ref substs) => {
- let r = lookup_struct_fields(cx, did);
- for field in r.iter() {
- let ft = lookup_field_type(cx, did, field.id, substs);
- if type_structurally_contains(cx, ft, |x| test(x)) { return true; }
+ Representable
+ }
+
+ // Does the type `ty` directly (without indirection through a pointer)
+ // contain any types on stack `seen`?
+ fn type_structurally_recursive(cx: ctxt, seen: &mut ~[DefId],
+ ty: t) -> Representability {
+ debug!("type_structurally_recursive: {}",
+ ::util::ppaux::ty_to_str(cx, ty));
+
+ // Compare current type to previously seen types
+ match get(ty).sty {
+ ty_struct(did, _) |
+ ty_enum(did, _) => {
+ for (i, &seen_did) in seen.iter().enumerate() {
+ if did == seen_did {
+ return if i == 0 { SelfRecursive }
+ else { ContainsRecursive }
+ }
+ }
+ }
+ _ => (),
}
- return false;
- }
- ty_tup(ref ts) => {
- for tt in ts.iter() {
- if type_structurally_contains(cx, *tt, |x| test(x)) { return true; }
+ // Check inner types
+ match get(ty).sty {
+ // Tuples
+ ty_tup(ref ts) => {
+ find_nonrepresentable(cx, seen, ts.iter().map(|t| *t))
+ }
+ // Fixed-length vectors.
+ // FIXME(#11924) Behavior undecided for zero-length vectors.
+ ty_vec(mt, vstore_fixed(_)) => {
+ type_structurally_recursive(cx, seen, mt.ty)
+ }
+
+ // Push struct and enum def-ids onto `seen` before recursing.
+ ty_struct(did, ref substs) => {
+ seen.push(did);
+ let fields = struct_fields(cx, did, substs);
+ let r = find_nonrepresentable(cx, seen,
+ fields.iter().map(|f| f.mt.ty));
+ seen.pop();
+ r
+ }
+ ty_enum(did, ref substs) => {
+ seen.push(did);
+ let vs = enum_variants(cx, did);
+
+ let mut r = Representable;
+ for variant in vs.iter() {
+ let iter = variant.args.iter().map(|aty| subst(cx, substs, *aty));
+ r = find_nonrepresentable(cx, seen, iter);
+
+ if r != Representable { break }
+ }
+
+ seen.pop();
+ r
+ }
+
+ _ => Representable,
}
- return false;
- }
- ty_vec(ref mt, vstore_fixed(_)) => {
- return type_structurally_contains(cx, mt.ty, test);
- }
- _ => return false
}
-}
-pub fn type_structurally_contains_uniques(cx: ctxt, ty: t) -> bool {
- return type_structurally_contains(cx, ty, |sty| {
- match *sty {
- ty_uniq(_) |
- ty_vec(_, vstore_uniq) |
- ty_str(vstore_uniq) => true,
- _ => false,
- }
- });
+ debug!("is_type_representable: {}",
+ ::util::ppaux::ty_to_str(cx, ty));
+
+ // To avoid a stack overflow when checking an enum variant or struct that
+ // contains a different, structurally recursive type, maintain a stack
+ // of seen types and check recursion for each of them (issues #3008, #3779).
+ let mut seen: ~[DefId] = ~[];
+ type_structurally_recursive(cx, &mut seen, ty)
}
pub fn type_is_trait(ty: t) -> bool {
ty_enum(did, ref substs) => {
let variants = enum_variants(cx, did);
for variant in (*variants).iter() {
- // XXX(pcwalton): This is an inefficient way to do this. Don't
+ // FIXME(pcwalton): This is an inefficient way to do this. Don't
// synthesize a tuple!
//
// Perform any type parameter substitutions.
result = type_is_pod(cx, mt.ty);
}
ty_param(_) => result = false,
- ty_opaque_closure_ptr(_) => result = true,
ty_struct(did, ref substs) => {
let fields = lookup_struct_fields(cx, did);
result = fields.iter().all(|f| {
}
}
-// XXX(pcwalton): Makes a copy, bleh. Probably better to not do that.
+// FIXME(pcwalton): Makes a copy, bleh. Probably better to not do that.
pub fn node_id_to_type_params(cx: ctxt, id: ast::NodeId) -> ~[t] {
let node_type_substs = cx.node_type_substs.borrow();
match node_type_substs.get().find(&id) {
}
match expr.node {
- ast::ExprPath(..) | ast::ExprSelf => {
+ ast::ExprPath(..) => {
match resolve_expr(tcx, expr) {
- ast::DefVariant(..) | ast::DefStruct(..) => RvalueDpsExpr,
+ ast::DefVariant(tid, vid, _) => {
+ let variant_info = enum_variant_with_id(tcx, tid, vid);
+ if variant_info.args.len() > 0u {
+ // N-ary variant.
+ RvalueDatumExpr
+ } else {
+ // Nullary variant.
+ RvalueDpsExpr
+ }
+ }
+
+ ast::DefStruct(_) => {
+ match get(expr_ty(tcx, expr)).sty {
+ ty_bare_fn(..) => RvalueDatumExpr,
+ _ => RvalueDpsExpr
+ }
+ }
// Fn pointers are just scalar values.
ast::DefFn(..) | ast::DefStaticMethod(..) => RvalueDatumExpr,
// Note: there is actually a good case to be made that
- // def_args, particularly those of immediate type, ought to
+ // DefArg's, particularly those of immediate type, ought to
// considered rvalues.
ast::DefStatic(..) |
ast::DefBinding(..) |
ast::DefUpvar(..) |
ast::DefArg(..) |
- ast::DefLocal(..) |
- ast::DefSelf(..) => LvalueExpr,
+ ast::DefLocal(..) => LvalueExpr,
def => {
tcx.sess.span_bug(expr.span, format!(
ast::ExprMatch(..) |
ast::ExprFnBlock(..) |
ast::ExprProc(..) |
- ast::ExprDoBody(..) |
ast::ExprBlock(..) |
ast::ExprRepeat(..) |
ast::ExprVstore(_, ast::ExprVstoreSlice) |
pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
match get(t).sty {
- ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
- ty_uint(_) | ty_float(_) | ty_str(_) |
- ty_type | ty_opaque_closure_ptr(_) => {
- ::util::ppaux::ty_to_str(cx, t)
- }
-
- ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
- ty_box(_) => ~"@-ptr",
- ty_uniq(_) => ~"~-ptr",
- ty_vec(_, _) => ~"vector",
- ty_unboxed_vec(_) => ~"unboxed vector",
- ty_ptr(_) => ~"*-ptr",
- ty_rptr(_, _) => ~"&-ptr",
- ty_bare_fn(_) => ~"extern fn",
- ty_closure(_) => ~"fn",
- ty_trait(id, _, _, _, _) => format!("trait {}", item_path_str(cx, id)),
- ty_struct(id, _) => format!("struct {}", item_path_str(cx, id)),
- ty_tup(_) => ~"tuple",
- ty_infer(TyVar(_)) => ~"inferred type",
- ty_infer(IntVar(_)) => ~"integral variable",
- ty_infer(FloatVar(_)) => ~"floating-point variable",
- ty_param(_) => ~"type parameter",
- ty_self(_) => ~"self",
- ty_err => ~"type error"
+ ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
+ ty_uint(_) | ty_float(_) | ty_str(_) | ty_type => {
+ ::util::ppaux::ty_to_str(cx, t)
+ }
+
+ ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
+ ty_box(_) => ~"@-ptr",
+ ty_uniq(_) => ~"~-ptr",
+ ty_vec(_, _) => ~"vector",
+ ty_unboxed_vec(_) => ~"unboxed vector",
+ ty_ptr(_) => ~"*-ptr",
+ ty_rptr(_, _) => ~"&-ptr",
+ ty_bare_fn(_) => ~"extern fn",
+ ty_closure(_) => ~"fn",
+ ty_trait(id, _, _, _, _) => format!("trait {}", item_path_str(cx, id)),
+ ty_struct(id, _) => format!("struct {}", item_path_str(cx, id)),
+ ty_tup(_) => ~"tuple",
+ ty_infer(TyVar(_)) => ~"inferred type",
+ ty_infer(IntVar(_)) => ~"integral variable",
+ ty_infer(FloatVar(_)) => ~"floating-point variable",
+ ty_param(_) => ~"type parameter",
+ ty_self(_) => ~"self",
+ ty_err => ~"type error"
}
}
ty_infer(_) => unreachable!(),
ty_err => hash.input([23]),
ty_type => hash.input([24]),
- ty_opaque_closure_ptr(s) => {
- hash.input([25]);
- iter(&mut hash, &s);
- }
ty_unboxed_vec(m) => {
- hash.input([26]);
+ hash.input([25]);
mt(&mut hash, m);
}
}
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char |
ty::ty_int(_) | ty::ty_uint(_) |
ty::ty_float(_) | ty::ty_type |
- ty::ty_opaque_closure_ptr(_) |
ty::ty_err | ty::ty_infer(_) |
ty::ty_param(..) | ty::ty_self(_) => {
(*sty).clone()
use middle::const_eval;
+use middle::lint;
use middle::ty::{substs};
use middle::ty::{ty_param_substs_and_ty};
use middle::ty;
};
// Convert the type parameters supplied by the user.
- let supplied_type_parameter_count =
- path.segments.iter().flat_map(|s| s.types.iter()).len();
- if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
- this.tcx().sess.span_fatal(
- path.span,
- format!("wrong number of type arguments: expected {} but found {}",
- decl_generics.type_param_defs.len(),
- supplied_type_parameter_count));
+ let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).len();
+ let formal_ty_param_count = decl_generics.type_param_defs.len();
+ let required_ty_param_count = decl_generics.type_param_defs.iter()
+ .take_while(|x| x.default.is_none())
+ .len();
+ if supplied_ty_param_count < required_ty_param_count {
+ let expected = if required_ty_param_count < formal_ty_param_count {
+ "expected at least"
+ } else {
+ "expected"
+ };
+ this.tcx().sess.span_fatal(path.span,
+ format!("wrong number of type arguments: {} {} but found {}",
+ expected, required_ty_param_count, supplied_ty_param_count));
+ } else if supplied_ty_param_count > formal_ty_param_count {
+ let expected = if required_ty_param_count < formal_ty_param_count {
+ "expected at most"
+ } else {
+ "expected"
+ };
+ this.tcx().sess.span_fatal(path.span,
+ format!("wrong number of type arguments: {} {} but found {}",
+ expected, formal_ty_param_count, supplied_ty_param_count));
}
- let tps = path.segments
- .iter()
- .flat_map(|s| s.types.iter())
- .map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
- .collect();
+ if supplied_ty_param_count > required_ty_param_count {
+ let id = path.segments.iter().flat_map(|s| s.types.iter())
+ .nth(required_ty_param_count).unwrap().id;
+ this.tcx().sess.add_lint(lint::DefaultTypeParamUsage, id, path.span,
+ ~"provided type arguments with defaults");
+ }
+
+ let defaults = decl_generics.type_param_defs.slice_from(supplied_ty_param_count)
+ .iter().map(|&x| x.default.unwrap());
+ let tps = path.segments.iter().flat_map(|s| s.types.iter())
+ .map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
+ .chain(defaults).collect();
substs {
regions: ty::NonerasedRegions(regions),
self_ty: self_ty,
return typ;
}
-pub fn ty_of_arg<AC:AstConv,
- RS:RegionScope>(
- this: &AC,
- rscope: &RS,
- a: &ast::Arg,
- expected_ty: Option<ty::t>)
- -> ty::t {
+pub fn ty_of_arg<AC: AstConv, RS: RegionScope>(this: &AC, rscope: &RS, a: &ast::Arg,
+ expected_ty: Option<ty::t>) -> ty::t {
match a.ty.node {
ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
ast::TyInfer => this.ty_infer(a.ty.span),
purity: ast::Purity,
untransformed_self_ty: ty::t,
explicit_self: ast::ExplicitSelf,
- decl: &ast::FnDecl) -> (Option<ty::t>, ty::BareFnTy)
-{
- let self_info = SelfInfo {
+ decl: &ast::FnDecl) -> ty::BareFnTy {
+ ty_of_method_or_bare_fn(this, id, purity, AbiSet::Rust(), Some(SelfInfo {
untransformed_self_ty: untransformed_self_ty,
explicit_self: explicit_self
- };
- let (a, b) = ty_of_method_or_bare_fn(
- this, id, purity, AbiSet::Rust(), Some(&self_info), decl);
- (a.unwrap(), b)
+ }), decl)
}
-pub fn ty_of_bare_fn<AC:AstConv>(
- this: &AC,
- id: ast::NodeId,
- purity: ast::Purity,
- abi: AbiSet,
- decl: &ast::FnDecl) -> ty::BareFnTy
-{
- let (_, b) = ty_of_method_or_bare_fn(this, id, purity,
- abi, None, decl);
- b
+pub fn ty_of_bare_fn<AC:AstConv>(this: &AC, id: ast::NodeId,
+ purity: ast::Purity, abi: AbiSet,
+ decl: &ast::FnDecl) -> ty::BareFnTy {
+ ty_of_method_or_bare_fn(this, id, purity, abi, None, decl)
}
-fn ty_of_method_or_bare_fn<AC:AstConv>(
- this: &AC,
- id: ast::NodeId,
- purity: ast::Purity,
- abi: AbiSet,
- opt_self_info: Option<&SelfInfo>,
- decl: &ast::FnDecl) -> (Option<Option<ty::t>>, ty::BareFnTy)
-{
+fn ty_of_method_or_bare_fn<AC:AstConv>(this: &AC, id: ast::NodeId,
+ purity: ast::Purity, abi: AbiSet,
+ opt_self_info: Option<SelfInfo>,
+ decl: &ast::FnDecl) -> ty::BareFnTy {
debug!("ty_of_method_or_bare_fn");
// new region names that appear inside of the fn decl are bound to
// that function type
let rb = rscope::BindingRscope::new(id);
- let opt_transformed_self_ty = opt_self_info.map(|self_info| {
- transform_self_ty(this, &rb, self_info)
- });
-
- let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None));
-
- let output_ty = match decl.output.node {
- ast::TyInfer => this.ty_infer(decl.output.span),
- _ => ast_ty_to_ty(this, &rb, decl.output)
- };
-
- return (opt_transformed_self_ty,
- ty::BareFnTy {
- purity: purity,
- abis: abi,
- sig: ty::FnSig {binder_id: id,
- inputs: input_tys,
- output: output_ty,
- variadic: decl.variadic}
- });
-
- fn transform_self_ty<AC:AstConv,RS:RegionScope>(
- this: &AC,
- rscope: &RS,
- self_info: &SelfInfo) -> Option<ty::t>
- {
+ let self_ty = opt_self_info.and_then(|self_info| {
match self_info.explicit_self.node {
ast::SelfStatic => None,
- ast::SelfValue(_) => {
+ ast::SelfValue => {
Some(self_info.untransformed_self_ty)
}
ast::SelfRegion(ref lifetime, mutability) => {
let region =
- opt_ast_region_to_region(this, rscope,
+ opt_ast_region_to_region(this, &rb,
self_info.explicit_self.span,
lifetime);
Some(ty::mk_rptr(this.tcx(), region,
ast::SelfBox => {
Some(ty::mk_box(this.tcx(), self_info.untransformed_self_ty))
}
- ast::SelfUniq(_) => {
+ ast::SelfUniq => {
Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty))
}
}
- }
+ });
+
+ // HACK(eddyb) replace the fake self type in the AST with the actual type.
+ let input_tys = if self_ty.is_some() {
+ decl.inputs.slice_from(1)
+ } else {
+ decl.inputs.as_slice()
+ };
+ let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None));
+
+ let self_and_input_tys = self_ty.move_iter().chain(input_tys).collect();
+
+ let output_ty = match decl.output.node {
+ ast::TyInfer => this.ty_infer(decl.output.span),
+ _ => ast_ty_to_ty(this, &rb, decl.output)
+ };
+
+ return ty::BareFnTy {
+ purity: purity,
+ abis: abi,
+ sig: ty::FnSig {
+ binder_id: id,
+ inputs: self_and_input_tys,
+ output: output_ty,
+ variadic: decl.variadic
+ }
+ };
}
pub fn ty_of_closure<AC:AstConv,RS:RegionScope>(
*/
+use middle::subst::Subst;
use middle::resolve;
use middle::ty::*;
use middle::ty;
|new_trait_ref, m, method_num, _bound_num| {
let vtable_index =
self.get_method_index(new_trait_ref, trait_ref, method_num);
+ let mut m = (*m).clone();
// We need to fix up the transformed self type.
- let transformed_self_ty =
+ m.fty.sig.inputs[0] =
self.construct_transformed_self_ty_for_object(
- did, &rcvr_substs, m);
- let m = @Method {
- transformed_self_ty: Some(transformed_self_ty),
- .. (*m).clone()
- };
+ did, &rcvr_substs, &m);
Candidate {
rcvr_match_condition: RcvrMatchesIfObject(did),
rcvr_substs: new_trait_ref.substs.clone(),
- method_ty: m,
+ method_ty: @m,
origin: method_object(method_object {
trait_id: new_trait_ref.def_id,
object_trait_id: did,
ty_err => None,
- ty_opaque_closure_ptr(_) | ty_unboxed_vec(_) |
- ty_type | ty_infer(TyVar(_)) => {
+ ty_unboxed_vec(_) | ty_type | ty_infer(TyVar(_)) => {
self.bug(format!("Unexpected type: {}",
self.ty_to_str(self_ty)));
}
rcvr_ty: ty::t,
candidates: &mut ~[Candidate])
-> Option<method_map_entry> {
- // XXX(pcwalton): Do we need to clone here?
+ // FIXME(pcwalton): Do we need to clone here?
let relevant_candidates: ~[Candidate] =
candidates.iter().map(|c| (*c).clone()).
filter(|c| self.is_relevant(rcvr_ty, c)).collect();
fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
-> method_map_entry {
+ // This method performs two sets of substitutions, one after the other:
+ // 1. Substitute values for any type/lifetime parameters from the impl and
+ // method declaration into the method type. This is the function type
+ // before it is called; it may still include late bound region variables.
+ // 2. Instantiate any late bound lifetime parameters in the method itself
+ // with fresh region variables.
+
let tcx = self.tcx();
- let fty = ty::mk_bare_fn(tcx, candidate.method_ty.fty.clone());
- debug!("confirm_candidate(expr={}, candidate={}, fty={})",
+ debug!("confirm_candidate(expr={}, candidate={})",
self.expr.repr(tcx),
- self.cand_to_str(candidate),
- self.ty_to_str(fty));
+ self.cand_to_str(candidate));
- self.enforce_object_limitations(fty, candidate);
+ self.enforce_object_limitations(candidate);
self.enforce_drop_trait_limitations(candidate);
// static methods should never have gotten this far:
assert!(candidate.method_ty.explicit_self != SelfStatic);
- let transformed_self_ty = match candidate.origin {
- method_object(..) => {
- // For annoying reasons, we've already handled the
- // substitution for object calls.
- candidate.method_ty.transformed_self_ty.unwrap()
- }
- _ => {
- ty::subst(tcx, &candidate.rcvr_substs,
- candidate.method_ty.transformed_self_ty.unwrap())
- }
- };
-
// Determine the values for the type parameters of the method.
// If they were not explicitly supplied, just construct fresh
// type variables.
self_ty: candidate.rcvr_substs.self_ty,
};
+ let ref bare_fn_ty = candidate.method_ty.fty;
+
// Compute the method type with type parameters substituted
debug!("fty={} all_substs={}",
- self.ty_to_str(fty),
+ bare_fn_ty.repr(tcx),
ty::substs_to_str(tcx, &all_substs));
- let fty = ty::subst(tcx, &all_substs, fty);
- debug!("after subst, fty={}", self.ty_to_str(fty));
- // Replace any bound regions that appear in the function
- // signature with region variables
- let bare_fn_ty = match ty::get(fty).sty {
- ty::ty_bare_fn(ref f) => f,
- ref s => {
- tcx.sess.span_bug(
- self.expr.span,
- format!("Invoking method with non-bare-fn ty: {:?}", s));
+ let fn_sig = &bare_fn_ty.sig;
+ let inputs = match candidate.origin {
+ method_object(..) => {
+ // For annoying reasons, we've already handled the
+ // substitution of self for object calls.
+ let args = fn_sig.inputs.slice_from(1).iter().map(|t| {
+ t.subst(tcx, &all_substs)
+ });
+ Some(fn_sig.inputs[0]).move_iter().chain(args).collect()
}
+ _ => fn_sig.inputs.subst(tcx, &all_substs)
};
- let (_, opt_transformed_self_ty, fn_sig) =
- replace_bound_regions_in_fn_sig(
- tcx, Some(transformed_self_ty), &bare_fn_ty.sig,
- |br| self.fcx.infcx().next_region_var(
- infer::BoundRegionInFnCall(self.expr.span, br)));
- let transformed_self_ty = opt_transformed_self_ty.unwrap();
+ let fn_sig = ty::FnSig {
+ binder_id: fn_sig.binder_id,
+ inputs: inputs,
+ output: fn_sig.output.subst(tcx, &all_substs),
+ variadic: fn_sig.variadic
+ };
+
+ debug!("after subst, fty={}", fn_sig.repr(tcx));
+
+ // Replace any bound regions that appear in the function
+ // signature with region variables
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig( tcx, &fn_sig, |br| {
+ self.fcx.infcx().next_region_var(
+ infer::BoundRegionInFnCall(self.expr.span, br))
+ });
+ let transformed_self_ty = fn_sig.inputs[0];
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
sig: fn_sig,
purity: bare_fn_ty.purity,
// should never fail.
match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span),
rcvr_ty, transformed_self_ty) {
- result::Ok(_) => (),
+ result::Ok(_) => {}
result::Err(_) => {
self.bug(format!("{} was a subtype of {} but now is not?",
self.ty_to_str(rcvr_ty),
self.fcx.write_ty(self.callee_id, fty);
self.fcx.write_substs(self.callee_id, all_substs);
method_map_entry {
- self_ty: transformed_self_ty,
- explicit_self: candidate.method_ty.explicit_self,
- origin: candidate.origin,
+ origin: candidate.origin
}
}
* result to be `&'a Foo`. Assuming that `u_method` is being
* called, we want the result to be `~Foo`. Of course,
* this transformation has already been done as part of
- * `method_ty.transformed_self_ty`, but there the type
+ * `method_ty.fty.sig.inputs[0]`, but there the type
* is expressed in terms of `Self` (i.e., `&'a Self`, `~Self`).
* Because objects are not standalone types, we can't just substitute
* `s/Self/Foo/`, so we must instead perform this kind of hokey
ast::SelfStatic => {
self.bug(~"static method for object type receiver");
}
- ast::SelfValue(_) => {
+ ast::SelfValue => {
ty::mk_err() // error reported in `enforce_object_limitations()`
}
- ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq(..) => {
- let transformed_self_ty =
- method_ty.transformed_self_ty.clone().unwrap();
+ ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq => {
+ let transformed_self_ty = method_ty.fty.sig.inputs[0];
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion
ty::mk_trait(self.tcx(), trait_def_id,
}
}
- fn enforce_object_limitations(&self,
- method_fty: ty::t,
- candidate: &Candidate)
- {
+ fn enforce_object_limitations(&self, candidate: &Candidate) {
/*!
* There are some limitations to calling functions through an
* object, because (a) the self type is not known
through an object");
}
- ast::SelfValue(_) => { // reason (a) above
+ ast::SelfValue => { // reason (a) above
self.tcx().sess.span_err(
self.expr.span,
"cannot call a method with a by-value receiver \
through an object");
}
- ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq(..) => {}
+ ast::SelfRegion(..) | ast::SelfBox | ast::SelfUniq => {}
}
- if ty::type_has_self(method_fty) { // reason (a) above
- self.tcx().sess.span_err(
- self.expr.span,
- "cannot call a method whose type contains a \
- self-type through an object");
+ // reason (a) above
+ let check_for_self_ty = |ty| {
+ if ty::type_has_self(ty) {
+ self.tcx().sess.span_err(
+ self.expr.span,
+ "cannot call a method whose type contains a \
+ self-type through an object");
+ true
+ } else {
+ false
+ }
+ };
+ let ref sig = candidate.method_ty.fty.sig;
+ let mut found_self_ty = false;
+ for &input_ty in sig.inputs.iter() {
+ if check_for_self_ty(input_ty) {
+ found_self_ty = true;
+ break;
+ }
+ }
+ if !found_self_ty {
+ check_for_self_ty(sig.output);
}
if candidate.method_ty.generics.has_type_params() { // reason (b) above
let destructors = self.tcx().destructors.borrow();
bad = destructors.get().contains(&method_id);
}
- // XXX: does this properly enforce this on everything now
+ // FIXME: does this properly enforce this on everything now
// that self has been merged in? -sully
method_param(method_param { trait_id: trait_id, .. }) |
method_object(method_object { trait_id: trait_id, .. }) => {
false
}
- SelfValue(_) => {
+ SelfValue => {
rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
}
}
}
- SelfUniq(_) => {
+ SelfUniq => {
debug!("(is relevant?) explicit self is a unique pointer");
match ty::get(rcvr_ty).sty {
ty::ty_uniq(typ) => {
use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
use middle::lang_items::{ManagedHeapLangItem};
use middle::lint::UnreachableCode;
+use middle::lint;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::subst::Subst;
pub mod demand;
pub mod method;
-pub struct SelfInfo {
- self_ty: ty::t,
- self_id: ast::NodeId,
- span: Span
-}
-
/// Fields that are part of a `FnCtxt` which are inherited by
/// closures defined within the function. For example:
///
/// fn foo() {
-/// do bar() { ... }
+/// bar(proc() { ... })
/// }
///
/// Here, the function `foo()` and the closure passed to
visit::walk_crate(&mut visit, crate, ());
}
-pub fn check_bare_fn(ccx: @CrateCtxt,
- decl: &ast::FnDecl,
- body: &ast::Block,
- id: ast::NodeId,
- self_info: Option<SelfInfo>,
- fty: ty::t,
- param_env: ty::ParameterEnvironment) {
+fn check_bare_fn(ccx: @CrateCtxt,
+ decl: &ast::FnDecl,
+ body: &ast::Block,
+ id: ast::NodeId,
+ fty: ty::t,
+ param_env: ty::ParameterEnvironment) {
match ty::get(fty).sty {
ty::ty_bare_fn(ref fn_ty) => {
let fcx =
- check_fn(ccx, self_info, fn_ty.purity,
- &fn_ty.sig, decl, id, body, Vanilla,
- @Inherited::new(ccx.tcx, param_env));
+ check_fn(ccx, fn_ty.purity, &fn_ty.sig, decl, id, body,
+ Vanilla, @Inherited::new(ccx.tcx, param_env));
vtable::resolve_in_block(fcx, body);
regionck::regionck_fn(fcx, body);
- writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
+ writeback::resolve_type_vars_in_fn(fcx, decl, body);
}
_ => ccx.tcx.sess.impossible_case(body.span,
"check_bare_fn: function type expected")
}
-pub fn check_fn(ccx: @CrateCtxt,
- opt_self_info: Option<SelfInfo>,
- purity: ast::Purity,
- fn_sig: &ty::FnSig,
- decl: &ast::FnDecl,
- id: ast::NodeId,
- body: &ast::Block,
- fn_kind: FnKind,
- inherited: @Inherited) -> @FnCtxt
+fn check_fn(ccx: @CrateCtxt,
+ purity: ast::Purity,
+ fn_sig: &ty::FnSig,
+ decl: &ast::FnDecl,
+ id: ast::NodeId,
+ body: &ast::Block,
+ fn_kind: FnKind,
+ inherited: @Inherited) -> @FnCtxt
{
/*!
* Helper used by check_bare_fn and check_expr_fn. Does the
let tcx = ccx.tcx;
let err_count_on_creation = tcx.sess.err_count();
- // First, we have to replace any bound regions in the fn and self
- // types with free ones. The free region references will be bound
- // the node_id of the body block.
- let (opt_self_info, fn_sig) = {
- let opt_self_ty = opt_self_info.map(|i| i.self_ty);
- let (_, opt_self_ty, fn_sig) =
- replace_bound_regions_in_fn_sig(
- tcx, opt_self_ty, fn_sig,
- |br| ty::ReFree(ty::FreeRegion {scope_id: body.id,
- bound_region: br}));
- let opt_self_info =
- opt_self_info.map(
- |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si});
- (opt_self_info, fn_sig)
- };
+ // First, we have to replace any bound regions in the fn type with free ones.
+ // The free region references will be bound the node_id of the body block.
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig(tcx, fn_sig, |br| {
+ ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
+ });
- relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
+ relate_free_regions(tcx, &fn_sig);
- let arg_tys = fn_sig.inputs.map(|a| *a);
+ let arg_tys = fn_sig.inputs.as_slice();
let ret_ty = fn_sig.output;
- debug!("check_fn(arg_tys={:?}, ret_ty={:?}, opt_self_ty={:?})",
+ debug!("check_fn(arg_tys={:?}, ret_ty={:?})",
arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
- ppaux::ty_to_str(tcx, ret_ty),
- opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
+ ppaux::ty_to_str(tcx, ret_ty));
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
- let fcx: @FnCtxt = {
- @FnCtxt {
- err_count_on_creation: err_count_on_creation,
- ret_ty: ret_ty,
- ps: RefCell::new(PurityState::function(purity, id)),
- region_lb: Cell::new(body.id),
- fn_kind: fn_kind,
- inh: inherited,
- ccx: ccx
- }
+ let fcx = @FnCtxt {
+ err_count_on_creation: err_count_on_creation,
+ ret_ty: ret_ty,
+ ps: RefCell::new(PurityState::function(purity, id)),
+ region_lb: Cell::new(body.id),
+ fn_kind: fn_kind,
+ inh: inherited,
+ ccx: ccx
};
- gather_locals(fcx, decl, body, arg_tys, opt_self_info);
- check_block_with_expected(fcx, body, Some(ret_ty));
-
- // We unify the tail expr's type with the
- // function result type, if there is a tail expr.
- match body.expr {
- Some(tail_expr) => {
- let tail_expr_ty = fcx.expr_ty(tail_expr);
- // Special case: we print a special error if there appears
- // to be do-block/for-loop confusion
- demand::suptype_with_fn(fcx, tail_expr.span, false,
- fcx.ret_ty, tail_expr_ty,
- |sp, e, a, s| {
- fcx.report_mismatched_return_types(sp, e, a, s) });
- }
- None => ()
- }
-
- for self_info in opt_self_info.iter() {
- fcx.write_ty(self_info.self_id, self_info.self_ty);
- }
- for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
- fcx.write_ty(input.id, *arg);
- }
-
- return fcx;
-
- fn gather_locals(fcx: @FnCtxt,
- decl: &ast::FnDecl,
- body: &ast::Block,
- arg_tys: &[ty::t],
- opt_self_info: Option<SelfInfo>) {
- let tcx = fcx.ccx.tcx;
+ {
let mut visit = GatherLocalsVisitor { fcx: fcx, tcx: tcx, };
-
- // Add the self parameter
- for self_info in opt_self_info.iter() {
- visit.assign(self_info.self_id, Some(self_info.self_ty));
- let locals = fcx.inh.locals.borrow();
- debug!("self is assigned to {}",
- fcx.infcx().ty_to_str(
- locals.get().get_copy(&self_info.self_id)));
- }
-
// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
// Create type variables for each argument.
pat_util::pat_bindings(tcx.def_map,
input.pat,
|_bm, pat_id, _sp, _path| {
- visit.assign(pat_id, None);
- });
+ visit.assign(pat_id, None);
+ });
// Check the pattern.
let pcx = pat_ctxt {
visit.visit_block(body, ());
}
+
+ check_block_with_expected(fcx, body, Some(ret_ty));
+
+ // We unify the tail expr's type with the
+ // function result type, if there is a tail expr.
+ match body.expr {
+ Some(tail_expr) => {
+ // Special case: we print a special error if there appears
+ // to be do-block/for-loop confusion
+ demand::suptype_with_fn(fcx, tail_expr.span, false,
+ fcx.ret_ty, fcx.expr_ty(tail_expr),
+ |sp, e, a, s| {
+ fcx.report_mismatched_return_types(sp, e, a, s);
+ });
+ }
+ None => {}
+ }
+
+ for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
+ fcx.write_ty(input.id, *arg);
+ }
+
+ fcx
}
pub fn check_no_duplicate_fields(tcx: ty::ctxt,
pub fn check_struct(ccx: @CrateCtxt, id: ast::NodeId, span: Span) {
let tcx = ccx.tcx;
- // Check that the class is instantiable
+ // Check that the struct is representable
+ check_representable(tcx, span, id, "struct");
+
+ // Check that the struct is instantiable
check_instantiable(tcx, span, id);
if ty::lookup_simd(tcx, local_def(id)) {
[],
body.id);
- check_bare_fn(ccx, decl, body, it.id, None, fn_tpt.ty, param_env);
+ check_bare_fn(ccx, decl, body, it.id, fn_tpt.ty, param_env);
}
ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
debug!("ItemImpl {} with id {}", ccx.tcx.sess.str_of(it.ident), it.id);
item_generics.region_param_defs,
method.body.id);
- // Compute the self type and fty from point of view of inside fn
- let opt_self_info = method_ty.transformed_self_ty.map(|ty| {
- SelfInfo {self_ty: ty.subst(ccx.tcx, ¶m_env.free_substs),
- self_id: method.self_id,
- span: method.explicit_self.span}
- });
+ // Compute the fty from point of view of inside fn
let fty = ty::node_id_to_type(ccx.tcx, method.id);
let fty = fty.subst(ccx.tcx, ¶m_env.free_substs);
- check_bare_fn(
- ccx,
- method.decl,
- method.body,
- method.id,
- opt_self_info,
- fty,
- param_env);
+ check_bare_fn(ccx, method.decl, method.body, method.id, fty, param_env);
}
fn check_impl_methods_against_trait(ccx: @CrateCtxt,
* - trait_m: the method in the trait
* - trait_substs: the substitutions used on the type of the trait
*/
-pub fn compare_impl_method(tcx: ty::ctxt,
- impl_generics: &ty::Generics,
- impl_m: @ty::Method,
- impl_m_span: Span,
- impl_m_body_id: ast::NodeId,
- trait_m: &ty::Method,
- trait_substs: &ty::substs) {
+fn compare_impl_method(tcx: ty::ctxt,
+ impl_generics: &ty::Generics,
+ impl_m: @ty::Method,
+ impl_m_span: Span,
+ impl_m_body_id: ast::NodeId,
+ trait_m: &ty::Method,
+ trait_substs: &ty::substs) {
debug!("compare_impl_method()");
let infcx = infer::new_infer_ctxt(tcx);
regions: ty::NonerasedRegions(dummy_impl_regions),
self_ty: None };
- // We are going to create a synthetic fn type that includes
- // both the method's self argument and its normal arguments.
- // So a method like `fn(&self, a: uint)` would be converted
- // into a function `fn(self: &T, a: uint)`.
- let mut trait_fn_args = ~[];
- let mut impl_fn_args = ~[];
-
- // For both the trait and the impl, create an argument to
- // represent the self argument (unless this is a static method).
- // This argument will have the *transformed* self type.
- for &t in trait_m.transformed_self_ty.iter() {
- trait_fn_args.push(t);
- }
- for &t in impl_m.transformed_self_ty.iter() {
- impl_fn_args.push(t);
- }
-
- // Add in the normal arguments.
- trait_fn_args.push_all(trait_m.fty.sig.inputs);
- impl_fn_args.push_all(impl_m.fty.sig.inputs);
-
- // Create a bare fn type for trait/impl that includes self argument
- let trait_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: trait_m.fty.purity,
- abis: trait_m.fty.abis,
- sig: ty::FnSig {
- binder_id: trait_m.fty.sig.binder_id,
- inputs: trait_fn_args,
- output: trait_m.fty.sig.output,
- variadic: false
- }
- });
- let impl_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: impl_m.fty.purity,
- abis: impl_m.fty.abis,
- sig: ty::FnSig {
- binder_id: impl_m.fty.sig.binder_id,
- inputs: impl_fn_args,
- output: impl_m.fty.sig.output,
- variadic: false
- }
- });
+ // Create a bare fn type for trait/impl
+ // It'd be nice to refactor so as to provide the bare fn types instead.
+ let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
+ let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
// Perform substitutions so that the trait/impl methods are expressed
// in terms of the same set of type/region parameters:
// Make sure the number of type parameters supplied on the trait
// or implementation segment equals the number of type parameters
// on the trait or implementation definition.
- let trait_type_parameter_count = generics.type_param_defs.len();
- let supplied_type_parameter_count = trait_segment.types.len();
- if trait_type_parameter_count != supplied_type_parameter_count {
- let trait_count_suffix = if trait_type_parameter_count == 1 {
+ let formal_ty_param_count = generics.type_param_defs.len();
+ let required_ty_param_count = generics.type_param_defs.iter()
+ .take_while(|x| x.default.is_none())
+ .len();
+ let supplied_ty_param_count = trait_segment.types.len();
+ if supplied_ty_param_count < required_ty_param_count {
+ let trait_count_suffix = if required_ty_param_count == 1 {
""
} else {
"s"
};
- let supplied_count_suffix =
- if supplied_type_parameter_count == 1 {
- ""
- } else {
- "s"
- };
- function_context.tcx()
- .sess
- .span_err(path.span,
- format!("the {} referenced by this \
- path has {} type \
- parameter{}, but {} type \
- parameter{} were supplied",
- name,
- trait_type_parameter_count,
- trait_count_suffix,
- supplied_type_parameter_count,
- supplied_count_suffix))
+ let supplied_count_suffix = if supplied_ty_param_count == 1 {
+ ""
+ } else {
+ "s"
+ };
+ let needs = if required_ty_param_count < generics.type_param_defs.len() {
+ "needs at least"
+ } else {
+ "needs"
+ };
+ function_context.tcx().sess.span_err(path.span,
+ format!("the {} referenced by this path {} {} type \
+ parameter{}, but {} type parameter{} were supplied",
+ name, needs,
+ required_ty_param_count, trait_count_suffix,
+ supplied_ty_param_count, supplied_count_suffix))
+ } else if supplied_ty_param_count > formal_ty_param_count {
+ let trait_count_suffix = if formal_ty_param_count == 1 {
+ ""
+ } else {
+ "s"
+ };
+ let supplied_count_suffix = if supplied_ty_param_count == 1 {
+ ""
+ } else {
+ "s"
+ };
+ let needs = if required_ty_param_count < generics.type_param_defs.len() {
+ "needs at most"
+ } else {
+ "needs"
+ };
+ function_context.tcx().sess.span_err(path.span,
+ format!("the {} referenced by this path {} {} type \
+ parameter{}, but {} type parameter{} were supplied",
+ name, needs,
+ formal_ty_param_count, trait_count_suffix,
+ supplied_ty_param_count, supplied_count_suffix))
}
}
_ => {
sugar: ast::CallSugar,
deref_args: DerefArgs) -> ty::t
{
+ // HACK(eddyb) ignore provided self (it has special typeck rules).
+ let args = args.slice_from(1);
if ty::type_is_error(method_fn_ty) {
let err_inputs = err_args(args.len());
check_argument_types(fcx, sp, err_inputs, callee_expr,
} else {
match ty::get(method_fn_ty).sty {
ty::ty_bare_fn(ref fty) => {
- check_argument_types(fcx, sp, fty.sig.inputs, callee_expr,
- args, sugar, deref_args, fty.sig.variadic);
+ // HACK(eddyb) ignore self in the definition (see above).
+ check_argument_types(fcx, sp, fty.sig.inputs.slice_from(1),
+ callee_expr, args, sugar, deref_args,
+ fty.sig.variadic);
fty.sig.output
}
_ => {
} else {
let suffix = match sugar {
ast::NoSugar => "",
- ast::DoSugar => " (including the closure passed by \
- the `do` keyword)",
ast::ForSugar => " (including the closure passed by \
the `for` keyword)"
};
for (i, arg) in args.iter().take(t).enumerate() {
let is_block = match arg.node {
ast::ExprFnBlock(..) |
- ast::ExprProc(..) |
- ast::ExprDoBody(..) => true,
+ ast::ExprProc(..) => true,
_ => false
};
// Replace any bound regions that appear in the function
// signature with region variables
- let (_, _, fn_sig) =
- replace_bound_regions_in_fn_sig(fcx.tcx(),
- None,
- fn_sig,
- |br| fcx.infcx()
- .next_region_var(
- infer::BoundRegionInFnCall(call_expr.span, br)));
+ let (_, fn_sig) = replace_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
+ fcx.infcx()
+ .next_region_var(infer::BoundRegionInFnCall(call_expr.span, br))
+ });
// Call the generic checker.
check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
fn check_method_call(fcx: @FnCtxt,
callee_id: ast::NodeId,
expr: &ast::Expr,
- rcvr: &ast::Expr,
method_name: ast::Ident,
args: &[@ast::Expr],
tps: &[ast::P<ast::Ty>],
sugar: ast::CallSugar) {
+ let rcvr = args[0];
check_expr(fcx, rcvr);
// no need to check for bot/err -- callee does that
fn lookup_op_method(fcx: @FnCtxt,
callee_id: ast::NodeId,
op_ex: &ast::Expr,
- self_ex: &ast::Expr,
self_t: ty::t,
opname: ast::Name,
args: &[@ast::Expr],
_expected_result: Option<ty::t>
)
-> ty::t {
- match method::lookup(fcx, op_ex, self_ex,
+ match method::lookup(fcx, op_ex, args[0],
callee_id, opname, self_t, [],
deref_args, CheckTraitsOnly, autoderef_receiver) {
Some(ref origin) => {
callee_id: ast::NodeId,
expr: &ast::Expr,
op: ast::BinOp,
- lhs: &ast::Expr,
+ lhs: @ast::Expr,
rhs: @ast::Expr,
// Used only in the error case
expected_result: Option<ty::t>,
fn check_user_binop(fcx: @FnCtxt,
callee_id: ast::NodeId,
ex: &ast::Expr,
- lhs_expr: &ast::Expr,
+ lhs_expr: @ast::Expr,
lhs_resolved_t: ty::t,
op: ast::BinOp,
rhs: @ast::Expr,
ast_util::binop_to_str(op), actual)},
lhs_resolved_t, None)
};
- return lookup_op_method(fcx, callee_id, ex, lhs_expr, lhs_resolved_t,
- token::intern(*name),
- &[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound,
- expected_result);
+ return lookup_op_method(fcx, callee_id, ex, lhs_resolved_t,
+ token::intern(*name), [lhs_expr, rhs],
+ DoDerefArgs,DontAutoderefReceiver,
+ if_op_unbound, expected_result);
}
None => ()
};
op_str: &str,
mname: &str,
ex: &ast::Expr,
- rhs_expr: &ast::Expr,
+ rhs_expr: @ast::Expr,
rhs_t: ty::t,
expected_t: Option<ty::t>)
-> ty::t {
lookup_op_method(
- fcx, callee_id, ex, rhs_expr, rhs_t,
- token::intern(mname), &[],
- DoDerefArgs, DontAutoderefReceiver,
+ fcx, callee_id, ex, rhs_t, token::intern(mname),
+ [rhs_expr], DoDerefArgs, DontAutoderefReceiver,
|| {
fcx.type_error_message(ex.span, |actual| {
format!("cannot apply unary operator `{}` to type `{}`",
expected_bounds) = {
match expected_sty {
Some(ty::ty_closure(ref cenv)) => {
- let (_, _, sig) =
+ let (_, sig) =
replace_bound_regions_in_fn_sig(
- tcx, None, &cenv.sig,
+ tcx, &cenv.sig,
|_| fcx.inh.infcx.fresh_bound_region(expr.id));
(Some(sig), cenv.purity, cenv.sigil,
cenv.onceness, cenv.bounds)
(purity, expr.id),
sigil);
- check_fn(fcx.ccx, None, inherited_purity, &fty_sig,
+ check_fn(fcx.ccx, inherited_purity, &fty_sig,
decl, id, body, fn_kind, fcx.inh);
}
let mut checked = false;
match place.node {
ast::ExprPath(ref path) => {
- // XXX(pcwalton): For now we hardcode the two permissible
+ // FIXME(pcwalton): For now we hardcode the two permissible
// places: the exchange heap and the managed heap.
let definition = lookup_def(fcx, path.span, place.id);
let def_id = ast_util::def_id_of_def(definition);
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
}
- ast::ExprSelf => {
- let definition = lookup_def(fcx, expr.span, id);
- let ty_param_bounds_and_ty =
- ty_param_bounds_and_ty_for_def(fcx, expr.span, definition);
- fcx.write_ty(id, ty_param_bounds_and_ty.ty);
- }
ast::ExprInlineAsm(ref ia) => {
for &(_, input) in ia.inputs.iter() {
check_expr(fcx, input);
Vanilla,
expected);
}
- ast::ExprDoBody(b) => {
- let expected_sty = unpack_expected(fcx,
- expected,
- |x| Some((*x).clone()));
- let inner_ty = match expected_sty {
- Some(ty::ty_closure(ref closure_ty))
- if closure_ty.sigil == ast::OwnedSigil => {
- expected.unwrap()
- }
- _ => match expected {
- Some(expected_t) => {
- fcx.type_error_message(expr.span, |actual| {
- format!("last argument in `do` call \
- has non-procedure type: {}",
- actual)
- }, expected_t, None);
- let err_ty = ty::mk_err();
- fcx.write_ty(id, err_ty);
- err_ty
- }
- None => {
- fcx.tcx().sess.impossible_case(
- expr.span,
- "do body must have expected type")
- }
- }
- };
- match b.node {
- ast::ExprFnBlock(decl, body) => {
- check_expr_fn(fcx, b, None,
- decl, body, DoBlock, Some(inner_ty));
- demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
- }
- // argh
- _ => fail!("expected fn ty")
- }
- fcx.write_ty(expr.id, fcx.node_ty(b.id));
- }
ast::ExprBlock(b) => {
check_block_with_expected(fcx, b, expected);
fcx.write_ty(id, fcx.node_ty(b.id));
fcx.write_bot(id);
}
}
- ast::ExprMethodCall(callee_id, rcvr, ident, ref tps, ref args, sugar) => {
- check_method_call(fcx, callee_id, expr, rcvr, ident, *args, *tps, sugar);
- let f_ty = fcx.expr_ty(rcvr);
+ ast::ExprMethodCall(callee_id, ident, ref tps, ref args, sugar) => {
+ check_method_call(fcx, callee_id, expr, ident, *args, *tps, sugar);
let arg_tys = args.map(|a| fcx.expr_ty(*a));
let (args_bot, args_err) = arg_tys.iter().fold((false, false),
|(rest_bot, rest_err), a| {
(rest_bot || ty::type_is_bot(*a),
rest_err || ty::type_is_error(*a))});
- if ty::type_is_error(f_ty) || args_err {
+ if args_err {
fcx.write_error(id);
- }
- else if ty::type_is_bot(f_ty) || args_bot {
+ } else if args_bot {
fcx.write_bot(id);
}
}
let ret_ty = lookup_op_method(fcx,
callee_id,
expr,
- base,
resolved,
index_ident.name,
- &[idx],
+ [base, idx],
DoDerefArgs,
AutoderefReceiver,
error_message,
writeback::resolve_type_vars_in_expr(fcx, e);
}
+/// Checks whether a type can be represented in memory. In particular, it
+/// identifies types that contain themselves without indirection through a
+/// pointer, which would mean their size is unbounded. This is different from
+/// the question of whether a type can be instantiated. See the definition of
+/// `check_instantiable`.
+pub fn check_representable(tcx: ty::ctxt,
+ sp: Span,
+ item_id: ast::NodeId,
+ designation: &str) {
+ let rty = ty::node_id_to_type(tcx, item_id);
+
+ // Check that it is possible to represent this type. This call identifies
+ // (1) types that contain themselves and (2) types that contain a different
+ // recursive type. It is only necessary to throw an error on those that
+ // contain themselves. For case 2, there must be an inner type that will be
+ // caught by case 1.
+ match ty::is_type_representable(tcx, rty) {
+ ty::SelfRecursive => {
+ tcx.sess.span_err(
+ sp, format!("illegal recursive {} type; \
+ wrap the inner value in a box to make it representable",
+ designation));
+ }
+ ty::Representable | ty::ContainsRecursive => (),
+ }
+}
+
/// Checks whether a type can be created without an instance of itself.
/// This is similar but different from the question of whether a type
/// can be represented. For example, the following type:
return variants;
}
- let rty = ty::node_id_to_type(ccx.tcx, id);
let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { crate: ast::LOCAL_CRATE, node: id });
if hint != attr::ReprAny && vs.len() <= 1 {
ccx.tcx.sess.span_err(sp, format!("unsupported representation for {}variant enum",
enum_var_cache.get().insert(local_def(id), @variants);
}
- // Check that it is possible to represent this enum:
- let mut outer = true;
- let did = local_def(id);
- if ty::type_structurally_contains(ccx.tcx, rty, |sty| {
- match *sty {
- ty::ty_enum(id, _) if id == did => {
- if outer { outer = false; false }
- else { true }
- }
- _ => false
- }
- }) {
- ccx.tcx.sess.span_err(sp,
- "illegal recursive enum type; \
- wrap the inner value in a box to make it representable");
- }
+ // Check that it is possible to represent this enum.
+ check_representable(ccx.tcx, sp, id, "enum");
// Check that it is possible to instantiate this enum:
//
defn: ast::Def)
-> ty_param_bounds_and_ty {
match defn {
- ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid, _) |
+ ast::DefArg(nid, _) | ast::DefLocal(nid, _) |
ast::DefBinding(nid, _) => {
let typ = fcx.local_ty(sp, nid);
return no_params(typ);
debug!(">>> instantiate_path");
let ty_param_count = tpt.generics.type_param_defs.len();
+ let ty_param_req = tpt.generics.type_param_defs.iter()
+ .take_while(|x| x.default.is_none())
+ .len();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
// Here we calculate the "user type parameter count", which is the number
// of type parameters actually manifest in the AST. This will differ from
// the internal type parameter count when there are self types involved.
- let (user_type_parameter_count, self_parameter_index) = match def {
+ let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
let generics = generics_of_static_method_container(fcx.ccx.tcx,
provenance);
- (ty_param_count - 1, Some(generics.type_param_defs.len()))
+ (ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs.len()))
}
- _ => (ty_param_count, None),
+ _ => (ty_param_count, ty_param_req, None),
};
// determine values for type parameters, using the values given by
fcx.ccx.tcx.sess.span_err
(span, "this item does not take type parameters");
fcx.infcx().next_ty_vars(ty_param_count)
- } else if ty_substs_len > user_type_parameter_count {
+ } else if ty_substs_len > user_ty_param_count {
+ let expected = if user_ty_param_req < user_ty_param_count {
+ "expected at most"
+ } else {
+ "expected"
+ };
fcx.ccx.tcx.sess.span_err
(span,
- format!("too many type parameters provided: expected {}, found {}",
- user_type_parameter_count, ty_substs_len));
+ format!("too many type parameters provided: {} {}, found {}",
+ expected, user_ty_param_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
- } else if ty_substs_len < user_type_parameter_count {
+ } else if ty_substs_len < user_ty_param_req {
+ let expected = if user_ty_param_req < user_ty_param_count {
+ "expected at least"
+ } else {
+ "expected"
+ };
fcx.ccx.tcx.sess.span_err
(span,
- format!("not enough type parameters provided: expected {}, found {}",
- user_type_parameter_count, ty_substs_len));
+ format!("not enough type parameters provided: {} {}, found {}",
+ expected, user_ty_param_req, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else {
+ if ty_substs_len > user_ty_param_req {
+ fcx.tcx().sess.add_lint(lint::DefaultTypeParamUsage, node_id, pth.span,
+ ~"provided type arguments with defaults");
+ }
+
// Build up the list of type parameters, inserting the self parameter
// at the appropriate position.
let mut result = ~[];
let mut pushed = false;
- for (i, &ast_type) in pth.segments
- .iter()
- .flat_map(|segment| segment.types.iter())
- .enumerate() {
+ let defaults = tpt.generics.type_param_defs.iter()
+ .enumerate().filter_map(|(i, x)| {
+ match self_parameter_index {
+ Some(index) if index == i => None,
+ _ => Some(x.default)
+ }
+ }).skip(ty_substs_len).map(|x| match x {
+ Some(default) => default,
+ None => {
+ fcx.tcx().sess.span_bug(span,
+ "missing default for a not explicitely provided type param")
+ }
+ });
+ for (i, ty) in pth.segments.iter()
+ .flat_map(|segment| segment.types.iter())
+ .map(|&ast_type| fcx.to_ty(ast_type))
+ .chain(defaults).enumerate() {
match self_parameter_index {
Some(index) if index == i => {
result.push(fcx.infcx().next_ty_vars(1)[0]);
}
_ => {}
}
- result.push(fcx.to_ty(ast_type))
+ result.push(ty)
}
// If the self parameter goes at the end, insert it there.
use util::ppaux::{ty_to_str, region_to_str, Repr};
use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil};
-use syntax::ast::{DefArg, DefBinding, DefLocal, DefSelf, DefUpvar};
+use syntax::ast::{DefArg, DefBinding, DefLocal, DefUpvar};
use syntax::ast;
use syntax::codemap::Span;
use syntax::visit;
let tcx = fcx.tcx();
match def {
DefLocal(node_id, _) | DefArg(node_id, _) |
- DefSelf(node_id, _) | DefBinding(node_id, _) => {
+ DefBinding(node_id, _) => {
tcx.region_maps.var_region(node_id)
}
DefUpvar(_, subdef, closure_id, body_id) => {
visit::walk_expr(rcx, expr, ());
}
- ast::ExprMethodCall(callee_id, arg0, _, _, ref args, _) => {
- constrain_call(rcx, callee_id, expr, Some(arg0), *args, false);
+ ast::ExprMethodCall(callee_id, _, _, ref args, _) => {
+ constrain_call(rcx, callee_id, expr, Some(args[0]),
+ args.slice_from(1), false);
visit::walk_expr(rcx, expr, ());
}
guarantor(rcx, e)
}
- ast::ExprPath(..) | ast::ExprSelf => {
- // Either a variable or constant and hence resides
- // in constant memory or on the stack frame. Either way,
- // not guaranteed by a region pointer.
- None
- }
+ // Either a variable or constant and hence resides
+ // in constant memory or on the stack frame. Either way,
+ // not guaranteed by a region pointer.
+ ast::ExprPath(..) => None,
// All of these expressions are rvalues and hence their
// value is not guaranteed by a region pointer.
ast::ExprMatch(..) |
ast::ExprFnBlock(..) |
ast::ExprProc(..) |
- ast::ExprDoBody(..) |
ast::ExprBlock(..) |
ast::ExprRepeat(..) |
ast::ExprVec(..) => {
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
- opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
mapf: |ty::BoundRegion| -> ty::Region)
- -> (HashMap<ty::BoundRegion,ty::Region>, Option<ty::t>, ty::FnSig) {
- debug!("replace_bound_regions_in_fn_sig(self_ty={}, fn_sig={})",
- opt_self_ty.repr(tcx),
- fn_sig.repr(tcx));
+ -> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
+ debug!("replace_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
let mut map = HashMap::new();
- let (fn_sig, opt_self_ty) = {
+ let fn_sig = {
let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
- debug!("region r={}", r.to_str());
- match r {
+ debug!("region r={}", r.to_str());
+ match r {
ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
*map.find_or_insert_with(br, |_| mapf(br))
}
_ => r
- }});
- (ty_fold::super_fold_sig(&mut f, fn_sig),
- ty_fold::fold_opt_ty(&mut f, opt_self_ty))
+ }
+ });
+ ty_fold::super_fold_sig(&mut f, fn_sig)
};
debug!("resulting map: {}", map.to_str());
- (map, opt_self_ty, fn_sig)
+ (map, fn_sig)
}
pub fn relate_nested_regions(tcx: ty::ctxt,
}
}
-pub fn relate_free_regions(
- tcx: ty::ctxt,
- self_ty: Option<ty::t>,
- fn_sig: &ty::FnSig)
-{
+pub fn relate_free_regions(tcx: ty::ctxt, fn_sig: &ty::FnSig) {
/*!
* This function populates the region map's `free_region_map`.
* It walks over the transformed self type and argument types
for arg in fn_sig.inputs.iter() {
all_tys.push(*arg);
}
- for &t in self_ty.iter() {
- all_tys.push(t);
- }
for &t in all_tys.iter() {
debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t));
ty::populate_implementations_for_trait_if_necessary(tcx,
trait_ref.def_id);
- // XXX: this is a bad way to do this, since we do
+ // FIXME: this is a bad way to do this, since we do
// pointless allocations.
let impls = {
let trait_impls = tcx.trait_impls.borrow();
// we're trying to cast to some_trait. If not, then we try
// the next impl.
//
- // XXX: document a bit more what this means
+ // FIXME: document a bit more what this means
//
// FIXME(#5781) this should be mk_eqty not mk_subty
let ty::ty_param_substs_and_ty {
ast::ExprUnary(callee_id, _, _) |
ast::ExprAssignOp(callee_id, _, _, _) |
ast::ExprIndex(callee_id, _, _) |
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
match ty::method_call_type_param_defs(cx.tcx, fcx.inh.method_map, ex.id) {
Some(type_param_defs) => {
debug!("vtable resolution on parameter bounds for method call {}",
use middle::pat_util;
use middle::ty;
use middle::typeck::astconv::AstConv;
-use middle::typeck::check::{FnCtxt, SelfInfo};
+use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::{vtable_res, vtable_origin};
use middle::typeck::{vtable_static, vtable_param};
-use middle::typeck::method_map_entry;
use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx;
use util::ppaux;
})
}
-fn resolve_method_map_entry(fcx: @FnCtxt, sp: Span, id: ast::NodeId) {
+fn resolve_method_map_entry(fcx: @FnCtxt, id: ast::NodeId) {
// Resolve any method map entry
let method_map_entry_opt = {
let method_map = fcx.inh.method_map.borrow();
match method_map_entry_opt {
None => {}
Some(mme) => {
- {
- let r = resolve_type_vars_in_type(fcx, sp, mme.self_ty);
- for t in r.iter() {
- let method_map = fcx.ccx.method_map;
- let new_entry = method_map_entry { self_ty: *t, ..mme };
- debug!("writeback::resolve_method_map_entry(id={:?}, \
- new_entry={:?})",
- id, new_entry);
- let mut method_map = method_map.borrow_mut();
- method_map.get().insert(id, new_entry);
- }
- }
+ debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})", id, mme);
+ let mut method_map = fcx.ccx.method_map.borrow_mut();
+ method_map.get().insert(id, mme);
}
}
}
resolve_all | force_all) {
Err(e) => {
// This should not, I think, happen:
- fcx.ccx.tcx.sess.span_err(
+ tcx.sess.span_err(
sp,
format!("cannot resolve bound for closure: \
{}",
infer::fixup_err_to_str(e)));
}
Ok(r1) => {
+ // FIXME(eddyb) #2190 Allow only statically resolved
+ // bare functions to coerce to a closure to avoid
+ // constructing (slower) indirect call wrappers.
+ {
+ let def_map = tcx.def_map.borrow();
+ match def_map.get().find(&id) {
+ Some(&ast::DefFn(..)) |
+ Some(&ast::DefStaticMethod(..)) |
+ Some(&ast::DefVariant(..)) |
+ Some(&ast::DefStruct(_)) => {}
+ _ => tcx.sess.span_err(sp,
+ "cannot coerce non-statically resolved bare fn")
+ }
+ }
+
let resolved_adj = @ty::AutoAddEnv(r1, s);
debug!("Adjustments for node {}: {:?}",
id,
resolved_adj);
- let mut adjustments = fcx.tcx()
- .adjustments
+ let mut adjustments = tcx.adjustments
.borrow_mut();
adjustments.get().insert(id, resolved_adj);
}
Ok(r1) => r1,
Err(e) => {
// This should not, I think, happen.
- fcx.ccx.tcx.sess.span_err(
+ tcx.sess.span_err(
sp,
format!("cannot resolve scope of borrow: \
{}",
autoref: resolved_autoref,
});
debug!("Adjustments for node {}: {:?}", id, resolved_adj);
- let mut adjustments = fcx.tcx().adjustments.borrow_mut();
+ let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, resolved_adj);
}
ty::AutoObject(..) => {
debug!("Adjustments for node {}: {:?}", id, adjustment);
- let mut adjustments = fcx.tcx().adjustments.borrow_mut();
+ let mut adjustments = tcx.adjustments.borrow_mut();
adjustments.get().insert(id, adjustment);
}
}
resolve_type_vars_for_node(wbcx, e.span, e.id);
- resolve_method_map_entry(wbcx.fcx, e.span, e.id);
+ resolve_method_map_entry(wbcx.fcx, e.id);
{
let r = e.get_callee_id();
for callee_id in r.iter() {
- resolve_method_map_entry(wbcx.fcx, e.span, *callee_id);
+ resolve_method_map_entry(wbcx.fcx, *callee_id);
}
}
maybe_resolve_type_vars_for_node(wbcx, e.span, callee_id);
}
- ast::ExprMethodCall(callee_id, _, _, _, _, _) => {
+ ast::ExprMethodCall(callee_id, _, _, _, _) => {
// We must always have written in a callee ID type for these.
resolve_type_vars_for_node(wbcx, e.span, callee_id);
}
return wbcx.success;
}
-pub fn resolve_type_vars_in_fn(fcx: @FnCtxt,
- decl: &ast::FnDecl,
- blk: &ast::Block,
- self_info: Option<SelfInfo>) -> bool {
+pub fn resolve_type_vars_in_fn(fcx: @FnCtxt, decl: &ast::FnDecl,
+ blk: &ast::Block) -> bool {
let mut wbcx = WbCtxt { fcx: fcx, success: true };
let wbcx = &mut wbcx;
wbcx.visit_block(blk, ());
- for self_info in self_info.iter() {
- resolve_type_vars_for_node(wbcx,
- self_info.span,
- self_info.self_id);
- }
for arg in decl.inputs.iter() {
wbcx.visit_pat(arg.pat, ());
// Privacy needs the type for the whole pattern, not just each binding
use middle::ty::{ty_param, ty_param_bounds_and_ty, ty_ptr};
use middle::ty::{ty_rptr, ty_self, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure};
-use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec};
-use middle::ty::{type_is_ty_var};
+use middle::ty::{ty_unboxed_vec, type_is_ty_var};
use middle::subst::Subst;
use middle::ty;
use middle::ty::{Impl, Method};
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
ty_infer(..) | ty_param(..) | ty_self(..) | ty_type |
- ty_opaque_closure_ptr(..) | ty_unboxed_vec(..) | ty_err | ty_box(_) |
+ ty_unboxed_vec(..) | ty_err | ty_box(_) |
ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
debug!("(getting base type) no base type; found {:?}",
get(original_type).sty);
// Nothing to do.
}
Some(base_type_def_id) => {
- // XXX: Gather up default methods?
+ // FIXME: Gather up default methods?
if associated_traits.len() == 0 {
self.add_inherent_impl(base_type_def_id, implementation);
}
// method types *can* appear in the generic bounds
method.generics.subst(tcx, &combined_substs),
- // method tps cannot appear in the self_ty, so use `substs` from trait ref
- method.transformed_self_ty.subst(tcx, &trait_ref.substs),
-
// method types *can* appear in the fty
method.fty.subst(tcx, &combined_substs),
bounds: @ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[self_trait_ref]
- }
+ },
+ default: None
});
// add in the type parameters from the method
m_decl: &ast::FnDecl) -> ty::Method
{
let trait_self_ty = ty::mk_self(this.tcx, local_def(trait_id));
- let (transformed_self_ty, fty) =
- astconv::ty_of_method(this, *m_id, *m_purity,
- trait_self_ty, *m_explicit_self, m_decl);
+ let fty = astconv::ty_of_method(this, *m_id, *m_purity, trait_self_ty,
+ *m_explicit_self, m_decl);
let num_trait_type_params = trait_generics.type_param_defs.len();
ty::Method::new(
*m_ident,
// FIXME(#5121) -- distinguish early vs late lifetime params
ty_generics(this, m_generics, num_trait_type_params),
- transformed_self_ty,
fty,
m_explicit_self.node,
// assume public, because this is only invoked on trait methods
rcvr_generics: &ast::Generics,
rcvr_visibility: ast::Visibility) -> ty::Method
{
- let (transformed_self_ty, fty) =
- astconv::ty_of_method(ccx, m.id, m.purity,
- untransformed_rcvr_ty,
- m.explicit_self, m.decl);
+ let fty = astconv::ty_of_method(ccx, m.id, m.purity,
+ untransformed_rcvr_ty,
+ m.explicit_self, m.decl);
// if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl
m.ident,
// FIXME(#5121) -- distinguish early vs late lifetime params
ty_generics(ccx, &m.generics, num_rcvr_type_params),
- transformed_self_ty,
fty,
m.explicit_self.node,
method_vis,
let param_ty = ty::param_ty {idx: base_index + offset,
def_id: local_def(param.id)};
let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds);
+ let default = param.default.map(|x| ast_ty_to_ty(ccx, &ExplicitRscope, x));
let def = ty::TypeParameterDef {
ident: param.ident,
def_id: local_def(param.id),
- bounds: bounds
+ bounds: bounds,
+ default: default
};
debug!("def for param: {}", def.repr(ccx.tcx));
})))
}
- pub fn coerce_from_bare_fn(&self,
- a: ty::t,
- fn_ty_a: &ty::BareFnTy,
- b: ty::t)
- -> CoerceResult {
- self.unpack_actual_value(b, |sty_b| {
- self.coerce_from_bare_fn_post_unpack(a, fn_ty_a, b, sty_b)
- })
- }
-
- pub fn coerce_from_bare_fn_post_unpack(&self,
- a: ty::t,
- fn_ty_a: &ty::BareFnTy,
- b: ty::t,
- sty_b: &ty::sty)
- -> CoerceResult {
+ fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
+ -> CoerceResult {
/*!
*
* Attempts to coerce from a bare Rust function (`extern
- * "rust" fn`) into a closure.
+ * "Rust" fn`) into a closure or a `proc`.
*/
- debug!("coerce_from_bare_fn(a={}, b={})",
- a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+ self.unpack_actual_value(b, |sty_b| {
- if !fn_ty_a.abis.is_rust() || fn_ty_a.purity != ast::ImpureFn {
- return self.subtype(a, b);
- }
+ debug!("coerce_from_bare_fn(a={}, b={})",
+ a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
- let fn_ty_b = match *sty_b {
- ty::ty_closure(ref f) => (*f).clone(),
- _ => return self.subtype(a, b),
- };
+ if !fn_ty_a.abis.is_rust() || fn_ty_a.purity != ast::ImpureFn {
+ return self.subtype(a, b);
+ }
- let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil);
- let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
- ty::ClosureTy {
- sig: fn_ty_a.sig.clone(),
- ..fn_ty_b
- });
- if_ok!(self.subtype(a_closure, b));
- Ok(Some(adj))
+ let fn_ty_b = match *sty_b {
+ ty::ty_closure(ref f) => (*f).clone(),
+ _ => return self.subtype(a, b)
+ };
+
+ let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil);
+ let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
+ ty::ClosureTy {
+ sig: fn_ty_a.sig.clone(),
+ ..fn_ty_b
+ });
+ if_ok!(self.subtype(a_closure, b));
+ Ok(Some(adj))
+ })
}
pub fn coerce_unsafe_ptr(&self,
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
-use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
+use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
use middle::typeck::infer::region_inference::{RegionVarBindings};
-> (ty::FnSig,
HashMap<ty::BoundRegion,
ty::Region>) {
- let (map, _, fn_sig) =
- replace_bound_regions_in_fn_sig(self.tcx, None, fsig, |br| {
+ let (map, fn_sig) =
+ replace_bound_regions_in_fn_sig(self.tcx, fsig, |br| {
let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region {} maps to {:?}",
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// idea is to report errors that derive from independent
// regions of the graph, but not those that derive from
// overlapping locations.
- let mut dup_vec = vec::from_elem(self.num_vars(), uint::max_value);
+ let mut dup_vec = vec::from_elem(self.num_vars(), uint::MAX);
let mut opt_graph = None;
let classification = var_data[node_idx.to_uint()].classification;
// check whether we've visited this node on some previous walk
- if dup_vec[node_idx.to_uint()] == uint::max_value {
+ if dup_vec[node_idx.to_uint()] == uint::MAX {
dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint();
} else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() {
state.dup_found = true;
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
- let (skol_map, _, b_sig) = {
- replace_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, None, b, |br| {
+ let (skol_map, b_sig) = {
+ replace_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| {
let skol = self.get_ref().infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {:?}",
bound_region_to_str(self.get_ref().infcx.tcx, "", false, br),
let matches = getopts(~[~"-Z", ~"verbose"], optgroups()).get();
let diag = diagnostic::collect(messages);
let sessopts = build_session_options(~"rustc", &matches, diag);
- let sess = build_session(sessopts, diag);
+ let sess = build_session(sessopts, None, diag);
let cfg = build_configuration(sess, ~"whatever", str_input(~""));
let dm = HashMap();
let amap = HashMap();
#[deriving(Clone)]
pub struct method_map_entry {
- // the type of the self parameter, which is not reflected in the fn type
- // (FIXME #3446)
- self_ty: ty::t,
-
- // the type of explicit self on the method
- explicit_self: ast::ExplicitSelf_,
-
// method details being invoked
origin: method_origin,
}
pub fn lookup_def_tcx(tcx: ty::ctxt, sp: Span, id: ast::NodeId) -> ast::Def {
let def_map = tcx.def_map.borrow();
match def_map.get().find(&id) {
- Some(&x) => x,
- _ => {
- tcx.sess.span_fatal(sp, "internal error looking up a definition")
- }
+ Some(&x) => x,
+ _ => {
+ tcx.sess.span_fatal(sp, "internal error looking up a definition")
+ }
}
}
*/
use std::hashmap::HashMap;
-use extra::arena;
-use extra::arena::Arena;
+use arena;
+use arena::Arena;
use middle::ty;
use std::vec;
use syntax::ast;
ast::ItemTrait(..) => {
let methods = ty::trait_methods(tcx, did);
for method in methods.iter() {
- match method.transformed_self_ty {
- Some(self_ty) => {
- // The implicit self parameter is basically
- // equivalent to a normal parameter declared
- // like:
- //
- // self : self_ty
- //
- // where self_ty is `&Self` or `&mut Self`
- // or whatever.
- self.add_constraints_from_ty(
- self_ty, self.contravariant);
- }
- None => {}
- }
-
self.add_constraints_from_sig(
&method.fty.sig, self.covariant);
}
self.add_constraints_from_sig(sig, variance);
}
- ty::ty_infer(..) | ty::ty_err | ty::ty_type |
- ty::ty_opaque_closure_ptr(..) | ty::ty_unboxed_vec(..) => {
+ ty::ty_infer(..) | ty::ty_err |
+ ty::ty_type | ty::ty_unboxed_vec(..) => {
self.tcx().sess.bug(
format!("Unexpected type encountered in \
variance inference: {}",
ReEmpty};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
-use middle::ty::{ty_nil, ty_opaque_closure_ptr, ty_param};
-use middle::ty::{ty_ptr, ty_rptr, ty_self, ty_tup, ty_type, ty_uniq};
-use middle::ty::{ty_trait, ty_int};
-use middle::ty::{ty_uint, ty_unboxed_vec, ty_infer};
+use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_self, ty_tup, ty_type};
+use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_unboxed_vec, ty_infer};
use middle::ty;
use middle::typeck;
use syntax::abi::AbiSet;
ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr());
- parameterized(cx, base, &substs.regions, substs.tps)
+ parameterized(cx, base, &substs.regions, substs.tps, did, false)
}
ty_trait(did, ref substs, s, mutbl, ref bounds) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr());
- let ty = parameterized(cx, base, &substs.regions, substs.tps);
+ let ty = parameterized(cx, base, &substs.regions,
+ substs.tps, did, true);
let bound_sep = if bounds.is_empty() { "" } else { ":" };
let bound_str = bounds.repr(cx);
format!("{}{}{}{}{}", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
ty_vec(ref mt, vs) => {
vstore_ty_to_str(cx, mt, vs)
}
- ty_str(vs) => format!("{}{}", vstore_to_str(cx, vs), "str"),
- ty_opaque_closure_ptr(ast::BorrowedSigil) => ~"&closure",
- ty_opaque_closure_ptr(ast::ManagedSigil) => ~"@closure",
- ty_opaque_closure_ptr(ast::OwnedSigil) => ~"~closure",
+ ty_str(vs) => format!("{}{}", vstore_to_str(cx, vs), "str")
}
}
pub fn parameterized(cx: ctxt,
base: &str,
regions: &ty::RegionSubsts,
- tps: &[ty::t]) -> ~str {
+ tps: &[ty::t],
+ did: ast::DefId,
+ is_trait: bool) -> ~str {
let mut strs = ~[];
match *regions {
}
}
- for t in tps.iter() {
+ let generics = if is_trait {
+ ty::lookup_trait_def(cx, did).generics
+ } else {
+ ty::lookup_item_type(cx, did).generics
+ };
+ let ty_params = generics.type_param_defs.iter();
+ let num_defaults = ty_params.zip(tps.iter()).rev().take_while(|&(def, &actual)| {
+ match def.default {
+ Some(default) => default == actual,
+ None => false
+ }
+ }).len();
+
+ for t in tps.slice_to(tps.len() - num_defaults).iter() {
strs.push(ty_to_str(cx, *t))
}
impl Repr for ty::Method {
fn repr(&self, tcx: ctxt) -> ~str {
- format!("method(ident: {}, generics: {}, transformed_self_ty: {}, \
- fty: {}, explicit_self: {}, vis: {}, def_id: {})",
+ format!("method(ident: {}, generics: {}, fty: {}, \
+ explicit_self: {}, vis: {}, def_id: {})",
self.ident.repr(tcx),
self.generics.repr(tcx),
- self.transformed_self_ty.repr(tcx),
self.fty.repr(tcx),
self.explicit_self.repr(tcx),
self.vis.repr(tcx),
impl Repr for typeck::method_map_entry {
fn repr(&self, tcx: ctxt) -> ~str {
- format!("method_map_entry \\{self_arg: {}, \
- explicit_self: {}, \
- origin: {}\\}",
- self.self_ty.repr(tcx),
- self.explicit_self.repr(tcx),
- self.origin.repr(tcx))
+ format!("method_map_entry \\{origin: {}\\}", self.origin.repr(tcx))
}
}
if tcx.sess.verbose() && self.substs.self_ty.is_some() {
let mut all_tps = self.substs.tps.clone();
for &t in self.substs.self_ty.iter() { all_tps.push(t); }
- parameterized(tcx, base, &self.substs.regions, all_tps)
+ parameterized(tcx, base, &self.substs.regions,
+ all_tps, self.def_id, true)
} else {
- parameterized(tcx, base, &self.substs.regions, self.substs.tps)
+ parameterized(tcx, base, &self.substs.regions,
+ self.substs.tps, self.def_id, true)
}
}
}
unsafe {
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
let mut y: *i32 = transmute(input.unsafe_ref(0));
- dst.len().times(|| {
+ for _ in range(0, dst.len()) {
*x = to_be32(*y);
x = x.offset(1);
y = y.offset(1);
- });
+ }
}
}
/// A FixedBuffer of 64 bytes useful for implementing Sha256 which has a 64 byte blocksize.
struct FixedBuffer64 {
- priv buffer: [u8, ..64],
- priv buffer_idx: uint,
+ buffer: [u8, ..64],
+ buffer_idx: uint,
}
impl FixedBuffer64 {
impl Clean<Item> for ast::Method {
fn clean(&self) -> Item {
+ let inputs = match self.explicit_self.node {
+ ast::SelfStatic => self.decl.inputs.as_slice(),
+ _ => self.decl.inputs.slice_from(1)
+ };
+ let decl = FnDecl {
+ inputs: inputs.iter().map(|x| x.clean()).collect(),
+ output: (self.decl.output.clean()),
+ cf: self.decl.cf.clean(),
+ attrs: ~[]
+ };
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
generics: self.generics.clean(),
self_: self.explicit_self.clean(),
purity: self.purity.clone(),
- decl: self.decl.clean(),
+ decl: decl,
}),
}
}
impl Clean<Item> for ast::TypeMethod {
fn clean(&self) -> Item {
+ let inputs = match self.explicit_self.node {
+ ast::SelfStatic => self.decl.inputs.as_slice(),
+ _ => self.decl.inputs.slice_from(1)
+ };
+ let decl = FnDecl {
+ inputs: inputs.iter().map(|x| x.clean()).collect(),
+ output: (self.decl.output.clean()),
+ cf: self.decl.cf.clean(),
+ attrs: ~[]
+ };
Item {
name: Some(self.ident.clean()),
attrs: self.attrs.clean(),
visibility: None,
inner: TyMethodItem(TyMethod {
purity: self.purity.clone(),
- decl: self.decl.clean(),
+ decl: decl,
self_: self.explicit_self.clean(),
generics: self.generics.clean(),
}),
fn clean(&self) -> SelfTy {
match self.node {
ast::SelfStatic => SelfStatic,
- ast::SelfValue(_) => SelfValue,
- ast::SelfUniq(_) => SelfOwned,
+ ast::SelfValue => SelfValue,
+ ast::SelfUniq => SelfOwned,
ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
ast::SelfBox => SelfManaged,
}
let (def_id, kind) = match *d {
ast::DefFn(i, _) => (i, TypeFunction),
- ast::DefSelf(i, _) | ast::DefSelfTy(i) => return Self(i),
+ ast::DefSelfTy(i) => return Self(i),
ast::DefTy(i) => (i, TypeEnum),
ast::DefTrait(i) => {
debug!("saw DefTrait in def_to_id");
syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
let sess = driver::driver::build_session_(sessopts,
+ Some(cpath.clone()),
parsesess.cm,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter,
+ @diagnostic::DefaultEmitter,
span_diagnostic_handler);
let mut cfg = build_configuration(sess);
},
arrow = match decl.decl.output { clean::Unit => "no", _ => "yes" },
ret = decl.decl.output);
- // XXX: where are bounds and lifetimes printed?!
+ // FIXME: where are bounds and lifetimes printed?!
}
clean::BareFunction(ref decl) => {
write!(f.buf, "{}{}fn{}{}",
impl fmt::Default for clean::ImportSource {
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
match v.did {
- // XXX: shouldn't be restricted to just local imports
+ // FIXME: shouldn't be restricted to just local imports
Some(did) if ast_util::is_local(did) => {
resolved_path(f.buf, did.node, &v.path, true);
}
impl fmt::Default for clean::ViewListIdent {
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
match v.source {
- // XXX: shouldn't be limited to just local imports
+ // FIXME: shouldn't be limited to just local imports
Some(did) if ast_util::is_local(did) => {
let path = clean::Path {
global: false,
//! functionality through a unit-struct, `Markdown`, which has an implementation
//! of `fmt::Default`. Example usage:
//!
-//! ```rust
+//! ```rust,ignore
+//! use rustdoc::html::markdown::Markdown;
+//!
//! let s = "My *markdown* _text_";
//! let html = format!("{}", Markdown(s));
//! // ... something using html
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
- fn crate(mut self, mut crate: clean::Crate, cache: Cache) {
+ fn crate(self, mut crate: clean::Crate, cache: Cache) {
let mut item = match crate.module.take() {
Some(i) => i,
None => return
$('.js-only').removeClass('js-only');
+ function getQueryStringParams() {
+ var params = {};
+ window.location.search.substring(1).split("&").
+ map(function(s) {
+ var pair = s.split("=");
+ params[decodeURIComponent(pair[0])] =
+ typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
+ });
+ return params;
+ }
+
+ function browserSupportsHistoryApi() {
+ return window.history && typeof window.history.pushState === "function";
+ }
+
function resizeShortBlocks() {
if (resizeTimeout) {
clearTimeout(resizeTimeout);
});
function initSearch(searchIndex) {
- var currentResults, index;
+ var currentResults, index, params = getQueryStringParams();
- // clear cached values from the search bar
- $(".search-input")[0].value = '';
+ // Populate search bar with query string search term when provided.
+ $(".search-input")[0].value = params.search || '';
/**
* Executes the query and builds an index of results
results = [],
maxResults = 200,
resultIndex;
+ var params = getQueryStringParams();
query = getQuery();
if (e) {
return;
}
+ // Because searching is incremental by character, only the most recent search query
+ // is added to the browser history.
+ if (browserSupportsHistoryApi()) {
+ if (!history.state && !params.search) {
+ history.pushState(query, "", "?search=" + encodeURIComponent(query.query));
+ } else {
+ history.replaceState(query, "", "?search=" + encodeURIComponent(query.query));
+ }
+ }
+
resultIndex = execQuery(query, 20000, index);
len = resultIndex.length;
for (i = 0; i < len; i += 1) {
clearTimeout(keyUpTimeout);
keyUpTimeout = setTimeout(search, 100);
});
+ // Push and pop states are used to add search results to the browser history.
+ if (browserSupportsHistoryApi()) {
+ $(window).on('popstate', function(e) {
+ var params = getQueryStringParams();
+ // When browsing back from search results the main page visibility must be reset.
+ if (!params.search) {
+ $('#main.content').removeClass('hidden');
+ $('#search.content').addClass('hidden');
+ }
+ // When browsing forward to search results the previous search will be repeated,
+ // so the currentResults are cleared to ensure the search is successful.
+ currentResults = null;
+ // Synchronize search bar with query string state and perform the search.
+ $('.search-input').val(params.search);
+ // Some browsers fire 'onpopstate' for every page load (Chrome), while others fire the
+ // event only when actually popping a state (Firefox), which is why search() is called
+ // both here and at the end of the startSearch() function.
+ search();
+ });
+ }
+ search();
}
index = buildIndex(searchIndex);
let cfgs = matches.opt_strs("cfg");
let cr = Path::new(cratefile);
info!("starting to run rustc");
- let (crate, analysis) = do std::task::try {
+ let (crate, analysis) = std::task::try(proc() {
let cr = cr;
core::run_core(libs.move_iter().collect(), cfgs, &cr)
- }.unwrap();
+ }).unwrap();
info!("finished with rustc");
local_data::set(analysiskey, analysis);
}
None => return Err(~"malformed json"),
};
- // XXX: this should read from the "plugins" field, but currently
+ // FIXME: this should read from the "plugins" field, but currently
// Json doesn't implement decodable...
let plugin_output = ~[];
Ok((crate, plugin_output))
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
let lines = s.lines_any().collect::<~[&str]>();
let mut saw_first_line = false;
let mut saw_second_line = false;
- let min_indent = lines.iter().fold(uint::max_value, |min_indent, line| {
+ let min_indent = lines.iter().fold(uint::MAX, |min_indent, line| {
// After we see the first non-whitespace line, look at
// the line we have. If it is not whitespace, and therefore
!line.is_whitespace();
let min_indent = if ignore_previous_indents {
- uint::max_value
+ uint::MAX
} else {
min_indent
};
pub fn run(input: &str, matches: &getopts::Matches) -> int {
let parsesess = parse::new_parse_sess(None);
- let input = driver::FileInput(Path::new(input));
+ let input_path = Path::new(input);
+ let input = driver::FileInput(input_path.clone());
let libs = matches.opt_strs("L").map(|s| Path::new(s.as_slice()));
let libs = @RefCell::new(libs.move_iter().collect());
diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
let sess = driver::build_session_(sessopts,
+ Some(input_path),
parsesess.cm,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter,
+ @diagnostic::DefaultEmitter,
span_diagnostic_handler);
let cfg = driver::build_configuration(sess);
diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
let sess = driver::build_session_(sessopts,
+ None,
parsesess.cm,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter,
+ @diagnostic::DefaultEmitter,
span_diagnostic_handler);
let outdir = TempDir::new("rustdoctest").expect("rustdoc needs a tempdir");
};
let input = driver::FileInput(script.clone());
let sess = driver::build_session(options,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter);
+ Some(script.clone()),
+ @diagnostic::DefaultEmitter);
let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let loader = &mut Loader::new(sess);
debug!("Will store workcache in {}", ws.display());
// Wrap the rest in task::try in case of a condition failure in a task
- let result = do task::try {
+ let result = task::try(proc() {
BuildContext {
context: context,
sysroot: sysroot.clone(), // Currently, only tests override this
workcache_context: api::default_context(sysroot.clone(),
default_workspace()).workcache_context
}.run(command, args.clone())
- };
+ });
// FIXME #9262: This is using the same error code for all errors,
// and at least one test case succeeds if rustpkg returns COPY_FAILED_CODE,
// when actually, it might set the exit code for that even if a different
}
struct Prefixes {
- priv components: ~[~str],
- priv remaining: ~[~str]
+ components: ~[~str],
+ remaining: ~[~str]
}
impl Iterator<(Path, Path)> for Prefixes {
subcfgs,
opt,
what);
- // XXX: result is an Option<Path>. The following code did not take that
+ // FIXME: result is an Option<Path>. The following code did not take that
// into account. I'm not sure if the workcache really likes seeing the
// output as "Some(\"path\")". But I don't know what to do about it.
// FIXME (#9639): This needs to handle non-utf8 paths
unsafe {
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
let mut y: *i32 = transmute(input.unsafe_ref(0));
- dst.len().times(|| {
+ for _ in range(0, dst.len()) {
*x = to_be32(*y);
x = x.offset(1);
y = y.offset(1);
- })
+ }
}
}
debug!("assert_lib_exists: checking whether {:?} exists", lib);
lib.is_some() && {
let libname = lib.get_ref();
- libname.exists() && is_rwx(libname)
+ libname.exists()
}
}
let lib = built_library_in_workspace(&crate_id, repo);
lib.is_some() && {
let libname = lib.get_ref();
- libname.exists() && is_rwx(libname)
+ libname.exists()
}
}
let ctxt = fake_ctxt(sysroot, &temp_workspace);
// Uses task::try because of #9001
- let result = do task::try {
+ let result = task::try(proc() {
let pkg_src = PkgSrc::new(temp_workspace.clone(),
temp_workspace.clone(),
false,
crateid.clone());
ctxt.install(pkg_src, &WhatToBuild::new(MaybeCustom, Everything));
- };
+ });
assert!(result.unwrap_err()
.to_str().contains("supplied path for package dir does not exist"));
}
let lib = installed_library_in_workspace(&temp_pkg_id, temp_workspace);
debug!("lib = {:?}", lib);
assert!(lib.as_ref().map_or(false, |l| l.exists()));
- assert!(lib.as_ref().map_or(false, |l| is_rwx(l)));
// And that the test and bench executables aren't installed
assert!(!target_test_in_workspace(&temp_pkg_id, temp_workspace).exists());
Some(p) => {
debug!("installed: {}", p.display());
let suffix = format!("0.3{}", os::consts::DLL_SUFFIX);
- p.as_vec().ends_with(suffix.as_bytes())
+ p.as_vec().ends_with(suffix.as_bytes()) ||
+ p.as_vec().ends_with(bytes!("0.3.rlib"))
}
None => false
});
let matches = getopts([], optgroups());
let options = build_session_options(~"rustpkg",
matches.as_ref().unwrap(),
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter);
- let sess = build_session(options,
- @diagnostic::DefaultEmitter as
- @diagnostic::Emitter);
+ @diagnostic::DefaultEmitter);
+ let sess = build_session(options, None, @diagnostic::DefaultEmitter);
let test_sys = test_sysroot();
// FIXME (#9639): This needs to handle non-utf8 paths
let cc = get_cc_prog(sess);
built_library_in_workspace(&temp_pkg_id,
&ws).expect("test_install_git: built lib should exist");
assert!(built_lib.exists());
- assert!(is_rwx(&built_lib));
// Make sure sources are (a) under "build" and (b) read-only
let temp_dir = format!("{}-{}", temp_pkg_id.path, temp_pkg_id.version_or_default());
prep.declare_input("file",
foo_c_name.as_str().unwrap().to_owned(),
digest_file_with_date(&foo_c_name));
- let out_path = do prep.exec |exec| {
+ let out_path = prep.exec(|exec| {
let out_path = api::build_library_in_workspace(exec,
&mut sub_cx.clone(),
"cdep",
"foo");
let out_p = Path::new(out_path.unwrap());
out_p.as_str().unwrap().to_owned()
- };
+ });
out_path
});
let out_lib_path = Path::new(out_lib_path);
context.add_library_path(out_lib_path.dir_path());
let context_clone = context.clone();
- let task_res = do task::try {
+ let task_res = task::try(proc() {
let mut cc = context_clone.clone();
api::install_pkg(&mut cc,
os::getcwd(),
~"cdep",
None,
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
- };
+ });
if task_res.is_err() {
os::set_exit_status(COPY_FAILED_CODE);
debug!("About to build session...");
let sess = driver::build_session(options,
+ Some(in_file.clone()),
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
use ai = std::io::net::addrinfo;
use std::cast;
+use std::libc;
use std::libc::c_int;
use std::ptr::null;
use std::rt::task::BlockedTask;
use uvll;
struct Addrinfo {
- handle: *uvll::addrinfo,
+ handle: *libc::addrinfo,
}
struct Ctx {
let socktype = 0;
let protocol = 0;
- uvll::addrinfo {
+ libc::addrinfo {
ai_flags: flags,
ai_family: hint.family as c_int,
ai_socktype: socktype,
ai_next: null(),
}
});
- let hint_ptr = hint.as_ref().map_or(null(), |x| x as *uvll::addrinfo);
+ let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
let mut req = Request::new(uvll::UV_GETADDRINFO);
return match unsafe {
extern fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
- res: *uvll::addrinfo) {
+ res: *libc::addrinfo) {
let req = Request::wrap(req);
assert!(status != uvll::ECANCELED);
let cx: &mut Ctx = unsafe { req.get_data() };
return addrs;
}
}
-
-// cannot give tcp/ip permission without help of apk
-#[cfg(test, not(target_os="android"))]
-mod test {
- use std::io::net::ip::{SocketAddr, Ipv4Addr};
- use super::super::local_loop;
- use super::GetAddrInfoRequest;
-
- #[test]
- fn getaddrinfo_test() {
- let loop_ = &mut local_loop().loop_;
- match GetAddrInfoRequest::run(loop_, Some("localhost"), None, None) {
- Ok(infos) => {
- let mut found_local = false;
- let local_addr = &SocketAddr {
- ip: Ipv4Addr(127, 0, 0, 1),
- port: 0
- };
- for addr in infos.iter() {
- found_local = found_local || addr.address == *local_addr;
- }
- assert!(found_local);
- }
- Err(e) => fail!("{:?}", e),
- }
- }
-
- #[test]
- fn issue_10663() {
- let loop_ = &mut local_loop().loop_;
- // Something should happen here, but this certainly shouldn't cause
- // everything to die. The actual outcome we don't care too much about.
- GetAddrInfoRequest::run(loop_, Some("irc.n0v4.com"), None,
- None);
- }
-}
let watcher = AsyncWatcher::new(&mut local_loop().loop_,
cb as ~Callback);
- let thread = do Thread::start {
+ let thread = Thread::start(proc() {
let mut watcher = watcher;
watcher.fire();
- };
+ });
assert_eq!(port.recv(), 1);
thread.join();
}
}
rtio::CloseSynchronously => {
- execute_nop(|req, cb| unsafe {
+ let _ = execute_nop(|req, cb| unsafe {
uvll::uv_fs_close(self.loop_.handle, req, self.fd, cb)
});
}
/// task back to its appropriate home (if applicable). The field is used to
/// assert that we are where we think we are.
struct HomingMissile {
- priv io_home: uint,
+ io_home: uint,
}
impl HomingMissile {
event_loop_factory: None,
});
- do pool.spawn(TaskOpts::new()) {
+ pool.spawn(TaskOpts::new(), proc() {
let listener = UdpWatcher::bind(local_loop(), next_test_ip4());
chan.send(listener.unwrap());
- }
+ });
- let task = do pool.task(TaskOpts::new()) {
+ let task = pool.task(TaskOpts::new(), proc() {
port.recv();
- };
+ });
pool.spawn_sched().send(sched::TaskFromFriend(task));
pool.shutdown();
event_loop_factory: None,
});
- do pool.spawn(TaskOpts::new()) {
+ pool.spawn(TaskOpts::new(), proc() {
let addr1 = next_test_ip4();
let addr2 = next_test_ip4();
let listener = UdpWatcher::bind(local_loop(), addr2);
chan.send((listener.unwrap(), addr1));
let mut listener = UdpWatcher::bind(local_loop(), addr1).unwrap();
listener.sendto([1, 2, 3, 4], addr2);
- }
+ });
- let task = do pool.task(TaskOpts::new()) {
+ let task = pool.task(TaskOpts::new(), proc() {
let (mut watcher, addr) = port.recv();
let mut buf = [0, ..10];
assert_eq!(watcher.recvfrom(buf).unwrap(), (4, addr));
- };
+ });
pool.spawn_sched().send(sched::TaskFromFriend(task));
pool.shutdown();
}
}
-/// XXX: Loop(*handle) is buggy with destructors. Normal structs
+/// FIXME: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
/// but the results are not correct.
pub struct Loop {
}
}
-// XXX: Need to define the error constants like EOF so they can be
+// FIXME: Need to define the error constants like EOF so they can be
// compared to the UvError type
pub struct UvError(c_int);
uvll::EADDRNOTAVAIL => io::ConnectionRefused,
err => {
uvdebug!("uverr.code {}", err as int);
- // XXX: Need to map remaining uv error types
+ // FIXME: Need to map remaining uv error types
io::OtherIoError
}
};
#[test]
fn loop_smoke_test() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let mut loop_ = Loop::new();
loop_.run();
loop_.close();
- }
+ });
}
}
}
impl rtio::RtioTcpListener for TcpListener {
- fn listen(mut ~self) -> Result<~rtio::RtioTcpAcceptor, IoError> {
+ fn listen(~self) -> Result<~rtio::RtioTcpAcceptor, IoError> {
// create the acceptor object from ourselves
let mut acceptor = ~TcpAcceptor { listener: self };
let _m = acceptor.fire_homing_missile();
- // XXX: the 128 backlog should be configurable
+ // FIXME: the 128 backlog should be configurable
match unsafe { uvll::uv_listen(acceptor.listener.handle, 128, listen_cb) } {
0 => Ok(acceptor as ~rtio::RtioTcpAcceptor),
n => Err(uv_error_to_io_error(UvError(n))),
let (port, chan) = Chan::new();
let addr = next_test_ip4();
- do spawn {
+ spawn(proc() {
let w = match TcpListener::bind(local_loop(), addr) {
Ok(w) => w, Err(e) => fail!("{:?}", e)
};
}
Err(e) => fail!("{:?}", e)
}
- }
+ });
port.recv();
let mut w = match TcpWatcher::connect(local_loop(), addr) {
let (port, chan) = Chan::new();
let addr = next_test_ip6();
- do spawn {
+ spawn(proc() {
let w = match TcpListener::bind(local_loop(), addr) {
Ok(w) => w, Err(e) => fail!("{:?}", e)
};
}
Err(e) => fail!("{:?}", e)
}
- }
+ });
port.recv();
let mut w = match TcpWatcher::connect(local_loop(), addr) {
let client = next_test_ip4();
let server = next_test_ip4();
- do spawn {
+ spawn(proc() {
match UdpWatcher::bind(local_loop(), server) {
Ok(mut w) => {
chan.send(());
}
Err(e) => fail!("{:?}", e)
}
- }
+ });
port.recv();
let mut w = match UdpWatcher::bind(local_loop(), client) {
let client = next_test_ip6();
let server = next_test_ip6();
- do spawn {
+ spawn(proc() {
match UdpWatcher::bind(local_loop(), server) {
Ok(mut w) => {
chan.send(());
}
Err(e) => fail!("{:?}", e)
}
- }
+ });
port.recv();
let mut w = match UdpWatcher::bind(local_loop(), client) {
static MAX: uint = 5000;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let listener = TcpListener::bind(local_loop(), addr).unwrap();
let mut acceptor = listener.listen().unwrap();
chan.send(());
uvdebug!("wrote bytes");
total_bytes_written += buf.len();
}
- }
+ });
port.recv();
let mut stream = TcpWatcher::connect(local_loop(), addr).unwrap();
let client_addr = next_test_ip4();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut client = UdpWatcher::bind(local_loop(), client_addr).unwrap();
port.recv();
assert!(client.sendto([1], server_addr).is_ok());
assert!(client.sendto([2], server_addr).is_ok());
- }
+ });
let mut server = UdpWatcher::bind(local_loop(), server_addr).unwrap();
chan.send(());
let (p1, c1) = Chan::new();
let (p2, c2) = Chan::new();
- do spawn {
+ spawn(proc() {
let l = local_loop();
let mut server_out = UdpWatcher::bind(l, server_out_addr).unwrap();
let mut server_in = UdpWatcher::bind(l, server_in_addr).unwrap();
assert_eq!(src, client_out_addr);
}
assert!(total_bytes_sent >= MAX);
- }
+ });
let l = local_loop();
let mut client_out = UdpWatcher::bind(l, client_out_addr).unwrap();
let addr = next_test_ip4();
let (port, chan) = Chan::<Port<()>>::new();
- do spawn {
+ spawn(proc() {
let port2 = port.recv();
let mut stream = TcpWatcher::connect(local_loop(), 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]);
port2.recv();
- }
+ });
let listener = TcpListener::bind(local_loop(), addr).unwrap();
let mut acceptor = listener.listen().unwrap();
fn test_simple_tcp_server_and_client_on_diff_threads() {
let addr = next_test_ip4();
- do spawn {
+ spawn(proc() {
let listener = TcpListener::bind(local_loop(), addr).unwrap();
let mut acceptor = listener.listen().unwrap();
let mut stream = acceptor.accept().unwrap();
for i in range(0u, nread) {
assert_eq!(buf[i], i as u8);
}
- }
+ });
let mut stream = TcpWatcher::connect(local_loop(), addr);
while stream.is_err() {
let (port, chan) = Chan::new();
let addr = next_test_ip4();
- do spawn {
+ spawn(proc() {
let w = TcpListener::bind(local_loop(), addr).unwrap();
let mut w = w.listen().unwrap();
chan.send(());
w.accept();
- }
+ });
port.recv();
let _w = TcpWatcher::connect(local_loop(), addr).unwrap();
fail!();
// force the handle to be created on a different scheduler, failure in
// the original task will force a homing operation back to this
// scheduler.
- do spawn {
+ spawn(proc() {
let w = UdpWatcher::bind(local_loop(), addr).unwrap();
chan.send(w);
- }
+ });
let _w = port.recv();
fail!();
}
impl RtioUnixListener for PipeListener {
- fn listen(mut ~self) -> Result<~RtioUnixAcceptor, IoError> {
+ fn listen(~self) -> Result<~RtioUnixAcceptor, IoError> {
// create the acceptor object from ourselves
let mut acceptor = ~PipeAcceptor { listener: self };
let _m = acceptor.fire_homing_missile();
- // XXX: the 128 backlog should be configurable
+ // FIXME: the 128 backlog should be configurable
match unsafe { uvll::uv_listen(acceptor.listener.pipe, 128, listen_cb) } {
0 => Ok(acceptor as ~RtioUnixAcceptor),
n => Err(uv_error_to_io_error(UvError(n))),
let path2 = path.clone();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let p = PipeListener::bind(local_loop(), &path2.to_c_str()).unwrap();
let mut p = p.listen().unwrap();
chan.send(());
assert!(client.read(buf).unwrap() == 1);
assert_eq!(buf[0], 1);
assert!(client.write([2]).is_ok());
- }
+ });
port.recv();
let mut c = PipeWatcher::connect(local_loop(), &path.to_c_str()).unwrap();
assert!(c.write([1]).is_ok());
let path2 = path.clone();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let p = PipeListener::bind(local_loop(), &path2.to_c_str()).unwrap();
let mut p = p.listen().unwrap();
chan.send(());
p.accept();
- }
+ });
port.recv();
let _c = PipeWatcher::connect(local_loop(), &path.to_c_str()).unwrap();
fail!()
let _signal = SignalWatcher::new(local_loop(), signal::Interrupt,
chan);
- do spawn {
+ spawn(proc() {
port.try_recv();
- }
+ });
// when we drop the SignalWatcher we're going to destroy the channel,
// which must wake up the task on the other end
};
// Stop reading so that no read callbacks are
// triggered before the user calls `read` again.
- // XXX: Is there a performance impact to calling
+ // FIXME: Is there a performance impact to calling
// stop here?
unsafe { assert_eq!(uvll::uv_read_stop(handle), 0); }
rcx.result = nread;
let mut timer = TimerWatcher::new(local_loop());
let timer_port = timer.period(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
// when we drop the TimerWatcher we're going to destroy the channel,
// which must wake up the task on the other end
let mut timer = TimerWatcher::new(local_loop());
let timer_port = timer.period(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
timer.oneshot(1);
}
let mut timer = TimerWatcher::new(local_loop());
let timer_port = timer.period(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
timer.sleep(1);
}
#[test]
fn test_callback_run_once() {
use std::rt::rtio::EventLoop;
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let mut event_loop = UvEventLoop::new();
let mut count = 0;
let count_ptr: *mut int = &mut count;
- do event_loop.callback {
+ event_loop.callback(proc() {
unsafe { *count_ptr += 1 }
- }
+ });
event_loop.run();
assert_eq!(count, 1);
- }
+ });
}
pub struct UvIoFactory {
#[allow(non_camel_case_types)]; // C types
use std::libc::{size_t, c_int, c_uint, c_void, c_char, c_double};
-use std::libc::{ssize_t, sockaddr, free};
+use std::libc::{ssize_t, sockaddr, free, addrinfo};
use std::libc;
use std::rt::global_heap::malloc_raw;
signum: c_int);
pub type uv_fs_cb = extern "C" fn(req: *uv_fs_t);
-// XXX: This is a standard C type. Could probably be defined in libc
-#[cfg(target_os = "android")]
-#[cfg(target_os = "linux")]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: libc::socklen_t,
- ai_addr: *sockaddr,
- ai_canonname: *char,
- ai_next: *addrinfo
-}
-
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: libc::socklen_t,
- ai_canonname: *char,
- ai_addr: *sockaddr,
- ai_next: *addrinfo
-}
-
-#[cfg(windows)]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: size_t,
- ai_canonname: *char,
- ai_addr: *sockaddr,
- ai_next: *addrinfo
-}
-
#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
}
}
-// XXX Event loops ignore SIGPIPE by default.
+// FIXME Event loops ignore SIGPIPE by default.
pub unsafe fn loop_new() -> *c_void {
return rust_uv_loop_new();
}
+++ /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.
-
-//! Utilities for references
-
-#[cfg(not(test))]
-use prelude::*;
-
-/// Cast a region pointer - &T - to a uint.
-#[inline]
-pub fn to_uint<T>(thing: &T) -> uint {
- thing as *T as uint
-}
-
-/// Determine if two borrowed pointers point to the same thing.
-#[inline]
-pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
- (thing as *T) == (other as *T)
-}
-
-// Equality for region pointers
-#[cfg(not(test))]
-impl<'a, T: Eq> Eq for &'a T {
- #[inline]
- fn eq(&self, other: & &'a T) -> bool {
- *(*self) == *(*other)
- }
- #[inline]
- fn ne(&self, other: & &'a T) -> bool {
- *(*self) != *(*other)
- }
-}
-
-// Comparison for region pointers
-#[cfg(not(test))]
-impl<'a, T: Ord> Ord for &'a T {
- #[inline]
- fn lt(&self, other: & &'a T) -> bool {
- *(*self) < *(*other)
- }
- #[inline]
- fn le(&self, other: & &'a T) -> bool {
- *(*self) <= *(*other)
- }
- #[inline]
- fn ge(&self, other: & &'a T) -> bool {
- *(*self) >= *(*other)
- }
- #[inline]
- fn gt(&self, other: & &'a T) -> bool {
- *(*self) > *(*other)
- }
-}
-
-#[cfg(not(test))]
-impl<'a, T: TotalOrd> TotalOrd for &'a T {
- #[inline]
- fn cmp(&self, other: & &'a T) -> Ordering { (**self).cmp(*other) }
-}
-
-#[cfg(not(test))]
-impl<'a, T: TotalEq> TotalEq for &'a T {
- #[inline]
- fn equals(&self, other: & &'a T) -> bool { (**self).equals(*other) }
-}
-
-#[cfg(test)]
-mod tests {
- use super::ref_eq;
-
- #[test]
- fn test_ref_eq() {
- let x = 1;
- let y = 1;
-
- assert!(ref_eq(&x, &x));
- assert!(!ref_eq(&x, &y));
- }
-}
use ptr;
use str::StrSlice;
use str;
-use vec::{CopyableVector, ImmutableVector, MutableVector};
+use vec::{CloneableVector, ImmutableVector, MutableVector};
use vec;
use unstable::intrinsics;
#[cfg(unix)]
fn debug_mem() -> bool {
- // XXX: Need to port the environment struct to newsched
+ // FIXME: Need to port the environment struct to newsched
false
}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
//! ```rust,should_fail
//! // Create a simple streaming channel
//! let (port, chan) = Chan::new();
-//! do spawn {
+//! spawn(proc() {
//! chan.send(10);
-//! }
+//! })
//! assert_eq!(port.recv(), 10);
//!
//! // Create a shared channel which can be sent along from many tasks
//! let (port, chan) = SharedChan::new();
//! for i in range(0, 10) {
//! let chan = chan.clone();
-//! do spawn {
+//! spawn(proc() {
//! chan.send(i);
-//! }
+//! })
//! }
//!
//! for _ in range(0, 10) {
use spsc = sync::spsc_queue;
use mpsc = sync::mpsc_queue;
-pub use self::select::Select;
+pub use self::select::{Select, Handle};
macro_rules! test (
{ fn $name:ident() $b:block $($a:attr)*} => (
$($a)* #[test] fn native() {
use native;
let (p, c) = Chan::new();
- do native::task::spawn { c.send(f()) }
+ native::task::spawn(proc() { c.send(f()) });
p.recv();
}
}
// All implementations -- the fun part
///////////////////////////////////////////////////////////////////////////////
-static DISCONNECTED: int = int::min_value;
+static DISCONNECTED: int = int::MIN;
static RESCHED_FREQ: int = 200;
impl Packet {
test!(fn smoke_threads() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
c.send(1);
- }
+ });
assert_eq!(p.recv(), 1);
})
test!(fn port_gone_concurrent() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
p.recv();
- }
+ });
loop { c.send(1) }
} #[should_fail])
test!(fn port_gone_concurrent_shared() {
let (p, c) = SharedChan::new();
let c1 = c.clone();
- do spawn {
+ spawn(proc() {
p.recv();
- }
+ });
loop {
c.send(1);
c1.send(1);
test!(fn chan_gone_concurrent() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
c.send(1);
c.send(1);
- }
+ });
loop { p.recv(); }
} #[should_fail])
test!(fn stress() {
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
for _ in range(0, 10000) { c.send(1); }
- }
+ });
for _ in range(0, 10000) {
assert_eq!(p.recv(), 1);
}
let (p, c) = SharedChan::<int>::new();
let (p1, c1) = Chan::new();
- do spawn {
+ spawn(proc() {
for _ in range(0, AMT * NTHREADS) {
assert_eq!(p.recv(), 1);
}
_ => {}
}
c1.send(());
- }
+ });
for _ in range(0, NTHREADS) {
let c = c.clone();
- do spawn {
+ spawn(proc() {
for _ in range(0, AMT) { c.send(1); }
- }
+ });
}
p1.recv();
})
let (p1, c1) = Chan::new();
let (port, chan) = SharedChan::new();
let chan2 = chan.clone();
- do spawn {
+ spawn(proc() {
c1.send(());
for _ in range(0, 40) {
assert_eq!(p.recv(), 1);
}
chan2.send(());
- }
+ });
p1.recv();
- do native::task::spawn {
+ native::task::spawn(proc() {
for _ in range(0, 40) {
c.send(1);
}
chan.send(());
- }
+ });
port.recv();
port.recv();
}
fn recv_from_outside_runtime() {
let (p, c) = Chan::<int>::new();
let (dp, dc) = Chan::new();
- do native::task::spawn {
+ native::task::spawn(proc() {
for _ in range(0, 40) {
assert_eq!(p.recv(), 1);
}
dc.send(());
- };
+ });
for _ in range(0, 40) {
c.send(1);
}
let (p2, c2) = Chan::<int>::new();
let (port, chan) = SharedChan::new();
let chan2 = chan.clone();
- do native::task::spawn {
+ native::task::spawn(proc() {
assert_eq!(p1.recv(), 1);
c2.send(2);
chan2.send(());
- }
- do native::task::spawn {
+ });
+ native::task::spawn(proc() {
c1.send(1);
assert_eq!(p2.recv(), 2);
chan.send(());
- }
+ });
port.recv();
port.recv();
}
test!(fn oneshot_single_thread_recv_chan_close() {
// Receiving on a closed chan will fail
- let res = do task::try {
+ let res = task::try(proc() {
let (port, chan) = Chan::<~int>::new();
{ let _c = chan; }
port.recv();
- };
+ });
// What is our res?
assert!(res.is_err());
})
test!(fn oneshot_multi_task_recv_then_send() {
let (port, chan) = Chan::<~int>::new();
- do spawn {
+ spawn(proc() {
assert!(port.recv() == ~10);
- }
+ });
chan.send(~10);
})
test!(fn oneshot_multi_task_recv_then_close() {
let (port, chan) = Chan::<~int>::new();
- do spawn {
+ spawn(proc() {
let _chan = chan;
- }
- let res = do task::try {
+ });
+ let res = task::try(proc() {
assert!(port.recv() == ~10);
- };
+ });
assert!(res.is_err());
})
test!(fn oneshot_multi_thread_close_stress() {
- stress_factor().times(|| {
+ for _ in range(0, stress_factor()) {
let (port, chan) = Chan::<int>::new();
- do spawn {
+ spawn(proc() {
let _p = port;
- }
+ });
let _chan = chan;
- })
+ }
})
test!(fn oneshot_multi_thread_send_close_stress() {
- stress_factor().times(|| {
+ for _ in range(0, stress_factor()) {
let (port, chan) = Chan::<int>::new();
- do spawn {
+ spawn(proc() {
let _p = port;
- }
- do task::try {
+ });
+ task::try(proc() {
chan.send(1);
- };
- })
+ });
+ }
})
test!(fn oneshot_multi_thread_recv_close_stress() {
- stress_factor().times(|| {
+ for _ in range(0, stress_factor()) {
let (port, chan) = Chan::<int>::new();
- do spawn {
+ spawn(proc() {
let port = port;
- let res = do task::try {
+ let res = task::try(proc() {
port.recv();
- };
+ });
assert!(res.is_err());
- };
- do spawn {
+ });
+ spawn(proc() {
let chan = chan;
- do spawn {
+ spawn(proc() {
let _chan = chan;
- }
- };
- })
+ });
+ });
+ }
})
test!(fn oneshot_multi_thread_send_recv_stress() {
- stress_factor().times(|| {
+ for _ in range(0, stress_factor()) {
let (port, chan) = Chan::<~int>::new();
- do spawn {
+ spawn(proc() {
chan.send(~10);
- }
- do spawn {
+ });
+ spawn(proc() {
assert!(port.recv() == ~10);
- }
- })
+ });
+ }
})
test!(fn stream_send_recv_stress() {
- stress_factor().times(|| {
+ for _ in range(0, stress_factor()) {
let (port, chan) = Chan::<~int>::new();
send(chan, 0);
fn send(chan: Chan<~int>, i: int) {
if i == 10 { return }
- do spawn {
+ spawn(proc() {
chan.send(~i);
send(chan, i + 1);
- }
+ });
}
fn recv(port: Port<~int>, i: int) {
if i == 10 { return }
- do spawn {
+ spawn(proc() {
assert!(port.recv() == ~i);
recv(port, i + 1);
- };
+ });
}
- })
+ }
})
test!(fn recv_a_lot() {
// Regression test that we don't run out of stack in scheduler context
let (port, chan) = Chan::new();
- 10000.times(|| { chan.send(()) });
- 10000.times(|| { port.recv() });
+ for _ in range(0, 10000) { chan.send(()); }
+ for _ in range(0, 10000) { port.recv(); }
})
test!(fn shared_chan_stress() {
let (port, chan) = SharedChan::new();
let total = stress_factor() + 100;
- total.times(|| {
+ for _ in range(0, total) {
let chan_clone = chan.clone();
- do spawn {
+ spawn(proc() {
chan_clone.send(());
- }
- });
+ });
+ }
- total.times(|| {
+ for _ in range(0, total) {
port.recv();
- });
+ }
})
test!(fn test_nested_recv_iter() {
let (port, chan) = Chan::<int>::new();
let (total_port, total_chan) = Chan::<int>::new();
- do spawn {
+ spawn(proc() {
let mut acc = 0;
for x in port.iter() {
acc += x;
}
total_chan.send(acc);
- }
+ });
chan.send(3);
chan.send(1);
let (port, chan) = Chan::<int>::new();
let (count_port, count_chan) = Chan::<int>::new();
- do spawn {
+ spawn(proc() {
let mut count = 0;
for x in port.iter() {
if count >= 3 {
}
}
count_chan.send(count);
- }
+ });
chan.send(2);
chan.send(2);
let (p, c) = Chan::<int>::new();
let (p1, c1) = Chan::<()>::new();
let (p2, c2) = Chan::<()>::new();
- do spawn {
+ spawn(proc() {
p1.recv();
c.send(1);
c2.send(());
p1.recv();
drop(c);
c2.send(());
- }
+ });
assert_eq!(p.try_recv(), Empty);
c1.send(());
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/// This handle is used to keep the port in the set as well as interact with the
/// underlying port.
pub struct Handle<'port, T> {
+ /// A unique ID for this Handle.
id: uint,
priv selector: &'port Select,
priv port: &'port mut Port<T>,
}
-struct Packets { priv cur: *mut Packet }
+struct Packets { cur: *mut Packet }
impl Select {
/// Creates a new selection structure. This set is initially empty and
assert!(amt > 0);
let mut ready_index = amt;
- let mut ready_id = uint::max_value;
+ let mut ready_id = uint::MAX;
let mut iter = self.iter().enumerate();
// Acquire a number of blocking contexts, and block on each one
if (*packet).decrement() {
Ok(())
} else {
+ // Empty to_wake first to avoid tripping an assertion in
+ // abort_selection in the disconnected case.
+ let task = (*packet).to_wake.take_unwrap();
(*packet).abort_selection(false);
(*packet).selecting.store(false, SeqCst);
ready_index = i;
ready_id = (*packet).selection_id;
- Err((*packet).to_wake.take_unwrap())
+ Err(task)
}
});
assert!(!(*packet).selecting.load(Relaxed));
}
- assert!(ready_id != uint::max_value);
+ assert!(ready_id != uint::MAX);
return ready_id;
}
}
let (mut p2, _c2) = Chan::<int>::new();
let (p3, c3) = Chan::<int>::new();
- do spawn {
- 20.times(task::deschedule);
+ spawn(proc() {
+ for _ in range(0, 20) { task::deschedule(); }
c1.send(1);
p3.recv();
- 20.times(task::deschedule);
- }
+ for _ in range(0, 20) { task::deschedule(); }
+ });
select! (
a = p1.recv() => { assert_eq!(a, 1); },
let (mut p2, c2) = Chan::<int>::new();
let (p3, c3) = Chan::<()>::new();
- do spawn {
- 20.times(task::deschedule);
+ spawn(proc() {
+ for _ in range(0, 20) { task::deschedule(); }
c1.send(1);
c2.send(2);
p3.recv();
- }
+ });
select! (
a = p1.recv() => { assert_eq!(a, 1); },
let (mut p2, c2) = Chan::<int>::new();
let (p3, c3) = Chan::<()>::new();
- do spawn {
+ spawn(proc() {
for i in range(0, AMT) {
if i % 2 == 0 {
c1.send(i);
}
p3.recv();
}
- }
+ });
for i in range(0, AMT) {
select! (
rt::Keyword(parse::One) => value == 1,
rt::Keyword(parse::Two) => value == 2,
- // XXX: Few/Many should have a user-specified boundary
+ // FIXME: Few/Many should have a user-specified boundary
// One possible option would be in the function
// pointer of the 'arg: Argument' struct.
rt::Keyword(parse::Few) => value < 8,
macro_rules! floating(($ty:ident) => {
impl Float for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
- // XXX: this shouldn't perform an allocation
+ // FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exact(f.abs(), i),
None => ::$ty::to_str_digits(f.abs(), 6)
impl LowerExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
- // XXX: this shouldn't perform an allocation
+ // FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false),
None => ::$ty::to_str_exp_digits(f.abs(), 6, false)
impl UpperExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
- // XXX: this shouldn't perform an allocation
+ // FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true),
None => ::$ty::to_str_exp_digits(f.abs(), 6, true)
/// Unwraps this buffer, returning the underlying writer.
///
/// The internal buffer is flushed before returning the writer.
- pub fn unwrap(mut self) -> W { self.inner.unwrap() }
+ pub fn unwrap(self) -> W { self.inner.unwrap() }
}
impl<W: Writer> Writer for LineBufferedWriter<W> {
use io;
use option::{None, Option, Some};
use super::{Reader, Writer};
-use vec::{bytes, CopyableVector, MutableVector, ImmutableVector};
+use vec::{bytes, CloneableVector, MutableVector, ImmutableVector};
/// Allows reading from a port.
///
#[test]
fn test_port_reader() {
let (port, chan) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
chan.send(~[1u8, 2u8]);
chan.send(~[]);
chan.send(~[3u8, 4u8]);
chan.send(~[5u8, 6u8]);
chan.send(~[7u8, 8u8]);
- }
+ });
let mut reader = PortReader::new(port);
let mut buf = ~[0u8, ..3];
writer.write_be_u32(42);
let wanted = ~[0u8, 0u8, 0u8, 42u8];
- let got = do task::try { port.recv() }.unwrap();
+ let got = task::try(proc() { port.recv() }).unwrap();
assert_eq!(wanted, got);
let mut err = None;
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
//! Utility mixins that apply to all Readers and Writers
-// XXX: Not sure how this should be structured
-// XXX: Iteration should probably be considered separately
+// FIXME: Not sure how this should be structured
+// FIXME: Iteration should probably be considered separately
use container::Container;
use iter::Iterator;
#[test]
fn test_read_write_le_mem() {
- let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value];
+ let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX];
let mut writer = MemWriter::new();
for i in uints.iter() {
#[test]
fn test_read_write_be() {
- let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value];
+ let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX];
let mut writer = MemWriter::new();
for i in uints.iter() {
#[test]
fn test_read_be_int_n() {
- let ints = [::i32::min_value, -123456, -42, -5, 0, 1, ::i32::max_value];
+ let ints = [::i32::MIN, -123456, -42, -5, 0, 1, ::i32::MAX];
let mut writer = MemWriter::new();
for i in ints.iter() {
///
/// This function will raise on the `io_error` condition on failure.
pub fn fsync(&mut self) {
- self.fd.fsync().map_err(|e| io_error::cond.raise(e));
+ let _ = self.fd.fsync().map_err(|e| io_error::cond.raise(e));
}
/// This function is similar to `fsync`, except that it may not synchronize
///
/// This function will raise on the `io_error` condition on failure.
pub fn datasync(&mut self) {
- self.fd.datasync().map_err(|e| io_error::cond.raise(e));
+ let _ = self.fd.datasync().map_err(|e| io_error::cond.raise(e));
}
/// Either truncates or extends the underlying file, updating the size of
///
/// On error, this function will raise on the `io_error` condition.
pub fn truncate(&mut self, size: i64) {
- self.fd.truncate(size).map_err(|e| io_error::cond.raise(e));
+ let _ = self.fd.truncate(size).map_err(|e| io_error::cond.raise(e));
}
/// Tests whether this stream has reached EOF.
use super::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, io_error,
OtherIoError};
use vec;
-use vec::{Vector, ImmutableVector, MutableVector, OwnedCopyableVector};
+use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector};
/// Writes to an owned, growable byte vector
///
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
```
* Make an simple HTTP request
- XXX This needs more improvement: TcpStream constructor taking &str,
+ FIXME This needs more improvement: TcpStream constructor taking &str,
`write_str` and `write_line` methods.
```rust,should_fail
* Connect based on URL? Requires thinking about where the URL type lives
and how to make protocol handlers extensible, e.g. the "tcp" protocol
yields a `TcpStream`.
- XXX this is not implemented now.
+ FIXME this is not implemented now.
```rust
// connect("tcp://localhost:8080");
# ::std::io::fs::unlink(&Path::new("diary.txt"));
```
-XXX: Need better condition handling syntax
+FIXME: Need better condition handling syntax
In this case the condition handler will have the opportunity to
inspect the IoError raised by either the call to `new` or the call to
In particular code written to ignore errors and expect conditions to be unhandled
will start passing around null or zero objects when wrapped in a condition handler.
-* XXX: How should we use condition handlers that return values?
-* XXX: Should EOF raise default conditions when EOF is not an error?
+* FIXME: How should we use condition handlers that return values?
+* FIXME: Should EOF raise default conditions when EOF is not an error?
# Issues with i/o scheduler affinity, work stealing, task pinning
* Async I/O. We'll probably want it eventually
-# XXX Questions and issues
+# FIXME Questions and issues
* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
Overloading would be nice.
use to_str::ToStr;
use uint;
use unstable::finally::Finally;
-use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCopyableVector};
+use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCloneableVector};
use vec;
// Reexports
/// The type passed to I/O condition handlers to indicate error
///
-/// # XXX
+/// # FIXME
///
/// Is something like this sufficient? It's kind of archaic
pub struct IoError {
}
}
-// XXX: Can't put doc comments on macros
+// FIXME: Can't put doc comments on macros
// Raised by `I/O` operations on error.
condition! {
pub io_error: IoError -> ();
/// Raises the `io_error` condition on error. If the condition
/// is handled then no guarantee is made about the number of bytes
/// read and the contents of `buf`. If the condition is handled
- /// returns `None` (XXX see below).
+ /// returns `None` (FIXME see below).
///
- /// # XXX
+ /// # FIXME
///
/// * Should raise_default error on eof?
/// * If the condition is handled it should still return the bytes read,
///
/// The number of bytes returned is system-dependant.
fn read_le_uint(&mut self) -> uint {
- self.read_le_uint_n(uint::bytes) as uint
+ self.read_le_uint_n(uint::BYTES) as uint
}
/// Reads a little-endian integer.
///
/// The number of bytes returned is system-dependant.
fn read_le_int(&mut self) -> int {
- self.read_le_int_n(int::bytes) as int
+ self.read_le_int_n(int::BYTES) as int
}
/// Reads a big-endian unsigned integer.
///
/// The number of bytes returned is system-dependant.
fn read_be_uint(&mut self) -> uint {
- self.read_be_uint_n(uint::bytes) as uint
+ self.read_be_uint_n(uint::BYTES) as uint
}
/// Reads a big-endian integer.
///
/// The number of bytes returned is system-dependant.
fn read_be_int(&mut self) -> int {
- self.read_be_int_n(int::bytes) as int
+ self.read_be_int_n(int::BYTES) as int
}
/// Reads a big-endian `u64`.
/// Write a little-endian uint (number of bytes depends on system).
fn write_le_uint(&mut self, n: uint) {
- extensions::u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
+ extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write(v))
}
/// Write a little-endian int (number of bytes depends on system).
fn write_le_int(&mut self, n: int) {
- extensions::u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
+ extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write(v))
}
/// Write a big-endian uint (number of bytes depends on system).
fn write_be_uint(&mut self, n: uint) {
- extensions::u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
+ extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write(v))
}
/// Write a big-endian int (number of bytes depends on system).
fn write_be_int(&mut self, n: int) {
- extensions::u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
+ extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write(v))
}
/// Write a big-endian u64 (8 bytes).
SeekCur,
}
-/// # XXX
+/// # FIXME
/// * Are `u64` and `i64` the right choices?
pub trait Seek {
/// Return position of file cursor in the stream
///
/// A successful seek clears the EOF indicator.
///
- /// # XXX
+ /// # FIXME
///
/// * What is the behavior when seeking past the end of a stream?
fn seek(&mut self, pos: i64, style: SeekStyle);
/// The Some contains another Option representing whether the connection attempt was succesful.
/// A successful connection will be wrapped in Some.
/// A failed connection is represented as a None and raises a condition.
-struct IncomingConnections<'a, A> {
+pub struct IncomingConnections<'a, A> {
priv inc: &'a mut A,
}
///
/// On failure, this will raise on the `io_error` condition.
///
-/// XXX: this is not public because the `Hint` structure is not ready for public
+/// FIXME: this is not public because the `Hint` structure is not ready for public
/// consumption just yet.
fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
-> Option<~[Info]> {
LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint))
}
-#[cfg(test)]
+// Ignored on android since we cannot give tcp/ip
+// permission without help of apk
+#[cfg(test, not(target_os = "android"))]
mod test {
use io::net::ip::Ipv4Addr;
use prelude::*;
use super::*;
- #[test]
- #[ignore(cfg(target_os="android"))] // cannot give tcp/ip permission without help of apk
- fn dns_smoke_test() {
+ iotest!(fn dns_smoke_test() {
let ipaddrs = get_host_addresses("localhost").unwrap();
let mut found_local = false;
let local_addr = &Ipv4Addr(127, 0, 0, 1);
found_local = found_local || addr == local_addr;
}
assert!(found_local);
- }
+ })
+
+ iotest!(fn issue_10663() {
+ // Something should happen here, but this certainly shouldn't cause
+ // everything to die. The actual outcome we don't care too much about.
+ get_host_addresses("example.com");
+ } #[ignore])
}
let addr = next_test_ip4();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip6();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip4();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip6();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip4();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip6();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip4();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let addr = next_test_ip6();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
// Close
- }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
iotest!(fn multiple_connect_serial_ip4() {
let addr = next_test_ip4();
- let max = 10;
+ let max = 10u;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
- max.times(|| {
+ for _ in range(0, max) {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
- });
- }
+ }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
iotest!(fn multiple_connect_serial_ip6() {
let addr = next_test_ip6();
- let max = 10;
+ let max = 10u;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
- max.times(|| {
+ for _ in range(0, max) {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
- });
- }
+ }
+ });
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
static MAX: int = 10;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
// Start another task to handle the connection
- do spawn {
+ spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
assert!(buf[0] == i as u8);
debug!("read");
- }
+ });
}
- }
+ });
port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
if i == MAX { return }
- do spawn {
+ spawn(proc() {
debug!("connecting");
let mut stream = TcpStream::connect(addr);
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([i as u8]);
- }
+ });
}
})
static MAX: int = 10;
let (port, chan) = Chan::<()>::new();
- do spawn {
+ spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
// Start another task to handle the connection
- do spawn {
+ spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
assert!(buf[0] == i as u8);
debug!("read");
- }
+ });
}
- }
+ });
port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
if i == MAX { return }
- do spawn {
+ spawn(proc() {
debug!("connecting");
let mut stream = TcpStream::connect(addr);
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([i as u8]);
- }
+ });
}
})
static MAX: int = 10;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
for stream in acceptor.incoming().take(MAX as uint) {
// Start another task to handle the connection
- do spawn {
+ spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
assert!(buf[0] == 99);
debug!("read");
- }
+ });
}
- }
+ });
port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
if i == MAX { return }
- do spawn {
+ spawn(proc() {
debug!("connecting");
let mut stream = TcpStream::connect(addr);
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([99]);
- }
+ });
}
})
static MAX: int = 10;
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
for stream in acceptor.incoming().take(MAX as uint) {
// Start another task to handle the connection
- do spawn {
+ spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
assert!(buf[0] == 99);
debug!("read");
- }
+ });
}
- }
+ });
port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
if i == MAX { return }
- do spawn {
+ spawn(proc() {
debug!("connecting");
let mut stream = TcpStream::connect(addr);
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([99]);
- }
+ });
}
})
pub fn peer_name(addr: SocketAddr) {
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
acceptor.accept();
- }
+ });
port.recv();
let stream = TcpStream::connect(addr);
})
iotest!(fn socket_and_peer_name_ip6() {
- // XXX: peer name is not consistent
+ // FIXME: peer name is not consistent
//peer_name(next_test_ip6());
socket_name(next_test_ip6());
})
iotest!(fn partial_read() {
let addr = next_test_ip4();
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut srv = TcpListener::bind(addr).listen();
c.send(());
let mut cl = srv.accept().unwrap();
let mut b = [0];
cl.read(b);
c.send(());
- }
+ });
p.recv();
let mut c = TcpStream::connect(addr).unwrap();
c.write([1]);
p.recv();
})
+
+ iotest!(fn double_bind() {
+ let mut called = false;
+ io_error::cond.trap(|e| {
+ assert!(e.kind == ConnectionRefused || e.kind == OtherIoError);
+ called = true;
+ }).inside(|| {
+ let addr = next_test_ip4();
+ let listener = TcpListener::bind(addr).unwrap().listen();
+ assert!(listener.is_some());
+ let listener2 = TcpListener::bind(addr).and_then(|l|
+ l.listen());
+ assert!(listener2.is_none());
+ });
+ assert!(called);
+ })
+
+ iotest!(fn fast_rebind() {
+ let addr = next_test_ip4();
+ let (port, chan) = Chan::new();
+
+ spawn(proc() {
+ port.recv();
+ let stream = TcpStream::connect(addr);
+ // Close
+ port.recv();
+ });
+
+ {
+ let mut acceptor = TcpListener::bind(addr).listen();
+ chan.send(());
+ {
+ let stream = acceptor.accept();
+ // Close client
+ chan.send(());
+ }
+ // Close listener
+ }
+ let listener = TcpListener::bind(addr);
+ })
}
let (port, chan) = Chan::new();
let (port2, chan2) = Chan::new();
- do spawn {
+ spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(ref mut client) => {
port.recv();
None => fail!()
}
chan2.send(());
- }
+ });
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
let client_ip = next_test_ip6();
let (port, chan) = Chan::<()>::new();
- do spawn {
+ spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(ref mut client) => {
port.recv();
}
None => fail!()
}
- }
+ });
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
let (port, chan) = Chan::new();
let (port2, chan2) = Chan::new();
- do spawn {
+ spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(client) => {
let client = ~client;
None => fail!()
}
chan2.send(());
- }
+ });
match UdpSocket::bind(server_ip) {
Some(server) => {
let (port, chan) = Chan::new();
let (port2, chan2) = Chan::new();
- do spawn {
+ spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(client) => {
let client = ~client;
None => fail!()
}
chan2.send(());
- }
+ });
match UdpSocket::bind(server_ip) {
Some(server) => {
let path2 = path1.clone();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
client(UnixStream::connect(&path2).unwrap());
- }
+ });
let mut acceptor = UnixListener::bind(&path1).listen();
chan.send(());
let path2 = path1.clone();
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
port.recv();
- times.times(|| {
+ for _ in range(0, times) {
let mut stream = UnixStream::connect(&path2);
stream.write([100]);
- })
- }
+ }
+ });
let mut acceptor = UnixListener::bind(&path1).listen();
chan.send(());
- times.times(|| {
+ for _ in range(0, times) {
let mut client = acceptor.accept();
let mut buf = [0];
client.read(buf);
assert_eq!(buf[0], 100);
- })
+ }
}
#[test]
let out = PipeStream::open(out);
let mut input = PipeStream::open(input);
let (p, c) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut out = out;
out.write([10]);
p.recv(); // don't close the pipe until the other read has finished
- }
+ });
let mut buf = [0, ..10];
input.read(buf);
/// let mut listener = Listener::new();
/// listener.register(Interrupt);
///
-/// do spawn {
+/// spawn({
/// loop {
/// match listener.port.recv() {
/// Interrupt => println!("Got Interrupt'ed"),
/// _ => (),
/// }
/// }
-/// }
+/// });
///
/// ```
pub struct Listener {
let (p, c) = Chan::new();
let (mut r, w) = (PortReader::new(p), ChanWriter::new(c));
- do spawn {
+ spawn(proc() {
set_stdout(~w as ~Writer);
println!("hello!");
- }
+ });
assert_eq!(r.read_to_str(), ~"hello!\n");
})
let (p, c) = Chan::new();
let (mut r, w) = (PortReader::new(p), ChanWriter::new(c));
- do spawn {
+ spawn(proc() {
set_stderr(~w as ~Writer);
fail!("my special message");
- }
+ });
let s = r.read_to_str();
assert!(s.contains("my special message"));
})
$($a)* #[test] fn native() {
use native;
let (p, c) = Chan::new();
- do native::task::spawn { c.send(f()) }
+ native::task::spawn(proc() { c.send(f()) });
p.recv();
}
}
let mut timer = Timer::new().unwrap();
let timer_port = timer.periodic(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
// when we drop the TimerWatcher we're going to destroy the channel,
// which must wake up the task on the other end
let mut timer = Timer::new().unwrap();
let timer_port = timer.periodic(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
timer.oneshot(1);
})
let mut timer = Timer::new().unwrap();
let timer_port = timer.periodic(1000);
- do spawn {
+ spawn(proc() {
timer_port.recv_opt();
- }
+ });
timer.sleep(1);
})
/// of the original iterator.
///
/// Note: Random access with flipped indices still only applies to the first
- /// `uint::max_value` elements of the original iterator.
+ /// `uint::MAX` elements of the original iterator.
#[inline]
fn rev(self) -> Rev<Self> {
Rev{iter: self}
///
/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
pub trait RandomAccessIterator<A>: Iterator<A> {
- /// Return the number of indexable elements. At most `std::uint::max_value`
+ /// Return the number of indexable elements. At most `std::uint::MAX`
/// elements are indexable, even if the iterator represents a longer range.
fn indexable(&self) -> uint;
match self.orig.size_hint() {
sz @ (0, Some(0)) => sz,
(0, _) => (0, None),
- _ => (uint::max_value, None)
+ _ => (uint::MAX, None)
}
}
}
#[inline]
fn indexable(&self) -> uint {
if self.orig.indexable() > 0 {
- uint::max_value
+ uint::MAX
} else {
0
}
/// Check whether peekable iterator is empty or not.
#[inline]
pub fn is_empty(&mut self) -> bool {
- self.peek().is_some()
+ self.peek().is_none()
}
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
- (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+ (uint::MAX, None) // Too bad we can't specify an infinite lower bound
}
}
#[inline]
fn next(&mut self) -> Option<A> { self.idx(0) }
#[inline]
- fn size_hint(&self) -> (uint, Option<uint>) { (uint::max_value, None) }
+ fn size_hint(&self) -> (uint, Option<uint>) { (uint::MAX, None) }
}
impl<A: Clone> DoubleEndedIterator<A> for Repeat<A> {
impl<A: Clone> RandomAccessIterator<A> for Repeat<A> {
#[inline]
- fn indexable(&self) -> uint { uint::max_value }
+ fn indexable(&self) -> uint { uint::MAX }
#[inline]
fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) }
}
fn test_cycle() {
let cycle_len = 3;
let it = count(0u, 1).take(cycle_len).cycle();
- assert_eq!(it.size_hint(), (uint::max_value, None));
+ assert_eq!(it.size_hint(), (uint::MAX, None));
for (i, x) in it.take(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
let v2 = &[10, 11, 12];
let vi = v.iter();
- assert_eq!(c.size_hint(), (uint::max_value, None));
+ assert_eq!(c.size_hint(), (uint::MAX, None));
assert_eq!(vi.size_hint(), (10, Some(10)));
assert_eq!(c.take(5).size_hint(), (5, Some(5)));
assert_eq!(c.skip(5).size_hint().second(), None);
assert_eq!(c.take_while(|_| false).size_hint(), (0, None));
assert_eq!(c.skip_while(|_| false).size_hint(), (0, None));
- assert_eq!(c.enumerate().size_hint(), (uint::max_value, None));
- assert_eq!(c.chain(vi.map(|&i| i)).size_hint(), (uint::max_value, None));
+ assert_eq!(c.enumerate().size_hint(), (uint::MAX, None));
+ assert_eq!(c.chain(vi.map(|&i| i)).size_hint(), (uint::MAX, None));
assert_eq!(c.zip(vi).size_hint(), (10, Some(10)));
assert_eq!(c.scan(0, |_,_| Some(0)).size_hint(), (0, None));
assert_eq!(c.filter(|_| false).size_hint(), (0, None));
- assert_eq!(c.map(|_| 0).size_hint(), (uint::max_value, None));
+ assert_eq!(c.map(|_| 0).size_hint(), (uint::MAX, None));
assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None));
assert_eq!(vi.take(5).size_hint(), (5, Some(5)));
assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
// this test is only meaningful when sizeof uint < sizeof u64
- assert_eq!(range(uint::max_value - 1, uint::max_value).size_hint(), (1, Some(1)));
+ assert_eq!(range(uint::MAX - 1, uint::MAX).size_hint(), (1, Some(1)));
assert_eq!(range(-10i, -1).size_hint(), (9, Some(9)));
assert_eq!(range(Foo, Foo).size_hint(), (0, None));
}
assert_eq!(ys, [5, 4, 3, 2, 1]);
}
+ #[test]
fn test_peekable_is_empty() {
let a = [1];
let mut it = a.iter().peekable();
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://static.rust-lang.org/doc/master")];
-#[feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args)];
+#[feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args, simd)];
// Don't link to std. We are std.
#[no_std];
#[deny(non_camel_case_types)];
#[deny(missing_doc)];
+#[allow(unknown_features)];
// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
+mod macros;
+
mod rtdeps;
/* The Prelude. */
pub mod ptr;
pub mod owned;
pub mod managed;
-pub mod borrow;
+mod reference;
pub mod rc;
pub mod gc;
pub use kinds;
pub use local_data;
pub use logging;
- pub use logging;
pub use option;
pub use os;
pub use rt;
pub enum timezone {}
}
pub mod bsd44 {
- use libc::types::os::arch::c95::c_uint;
+ use libc::types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type sa_family_t = u16;
ipv6mr_multiaddr: in6_addr,
ipv6mr_interface: c_uint,
}
+ pub struct addrinfo {
+ ai_flags: c_int,
+ ai_family: c_int,
+ ai_socktype: c_int,
+ ai_protocol: c_int,
+ ai_addrlen: socklen_t,
+ ai_addr: *sockaddr,
+ ai_canonname: *c_char,
+ ai_next: *addrinfo
+ }
}
}
pub enum timezone {}
}
pub mod bsd44 {
- use libc::types::os::arch::c95::c_uint;
+ use libc::types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type sa_family_t = u8;
ipv6mr_multiaddr: in6_addr,
ipv6mr_interface: c_uint,
}
+ pub struct addrinfo {
+ ai_flags: c_int,
+ ai_family: c_int,
+ ai_socktype: c_int,
+ ai_protocol: c_int,
+ ai_addrlen: socklen_t,
+ ai_canonname: *c_char,
+ ai_addr: *sockaddr,
+ ai_next: *addrinfo
+ }
}
}
}
pub mod bsd44 {
- use libc::types::os::arch::c95::{c_int, c_uint};
+ use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t};
pub type SOCKET = c_uint;
pub type socklen_t = c_int;
ipv6mr_multiaddr: in6_addr,
ipv6mr_interface: c_uint,
}
+ pub struct addrinfo {
+ ai_flags: c_int,
+ ai_family: c_int,
+ ai_socktype: c_int,
+ ai_protocol: c_int,
+ ai_addrlen: size_t,
+ ai_canonname: *c_char,
+ ai_addr: *sockaddr,
+ ai_next: *addrinfo
+ }
}
}
}
pub mod bsd44 {
- use libc::types::os::arch::c95::{c_int, c_uint};
+ use libc::types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = c_int;
pub type sa_family_t = u8;
ipv6mr_multiaddr: in6_addr,
ipv6mr_interface: c_uint,
}
+ pub struct addrinfo {
+ ai_flags: c_int,
+ ai_family: c_int,
+ ai_socktype: c_int,
+ ai_protocol: c_int,
+ ai_addrlen: socklen_t,
+ ai_canonname: *c_char,
+ ai_addr: *sockaddr,
+ ai_next: *addrinfo
+ }
}
}
pub static SOL_SOCKET: c_int = 0xffff;
pub static SO_KEEPALIVE: c_int = 8;
pub static SO_BROADCAST: c_int = 32;
+ pub static SO_REUSEADDR: c_int = 4;
}
pub mod extra {
use libc::types::os::arch::c95::c_int;
pub static SOL_SOCKET: c_int = 1;
pub static SO_KEEPALIVE: c_int = 9;
pub static SO_BROADCAST: c_int = 6;
+ pub static SO_REUSEADDR: c_int = 2;
}
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
pub static SOL_SOCKET: c_int = 0xffff;
pub static SO_KEEPALIVE: c_int = 0x0008;
pub static SO_BROADCAST: c_int = 0x0020;
+ pub static SO_REUSEADDR: c_int = 0x0004;
}
pub mod extra {
use libc::types::os::arch::c95::c_int;
pub static MAP_PRIVATE : c_int = 0x0002;
pub static MAP_FIXED : c_int = 0x0010;
pub static MAP_ANON : c_int = 0x1000;
+ pub static MAP_STACK : c_int = 0;
pub static MAP_FAILED : *c_void = -1 as *c_void;
pub static SOL_SOCKET: c_int = 0xffff;
pub static SO_KEEPALIVE: c_int = 0x0008;
pub static SO_BROADCAST: c_int = 0x0020;
+ pub static SO_REUSEADDR: c_int = 0x0004;
}
pub mod extra {
use libc::types::os::arch::c95::c_int;
fn test_tls_multitask() {
static my_key: Key<~str> = &Key;
set(my_key, ~"parent data");
- do task::spawn {
+ task::spawn(proc() {
// TLS shouldn't carry over.
assert!(get(my_key, |k| k.map(|k| (*k).clone())).is_none());
set(my_key, ~"child data");
assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() ==
~"child data");
// should be cleaned up for us
- }
+ });
// Must work multiple times
assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == ~"parent data");
assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == ~"parent data");
// subsequent upcall (esp. for logging, think vsnprintf) would run on
// a stack smaller than 1 MB.
static my_key: Key<~str> = &Key;
- do task::spawn {
+ task::spawn(proc() {
set(my_key, ~"hax");
- }
+ });
}
#[test]
static str_key: Key<~str> = &Key;
static box_key: Key<@()> = &Key;
static int_key: Key<int> = &Key;
- do task::spawn {
+ task::spawn(proc() {
set(str_key, ~"string data");
set(box_key, @());
set(int_key, 42);
- }
+ });
}
#[test]
static str_key: Key<~str> = &Key;
static box_key: Key<@()> = &Key;
static int_key: Key<int> = &Key;
- do task::spawn {
+ task::spawn(proc() {
set(str_key, ~"string data");
set(str_key, ~"string data 2");
set(box_key, @());
// with the crazy polymorphic transmute rather than the provided
// finaliser.
set(int_key, 31337);
- }
+ });
}
#[test]
static int_key: Key<int> = &Key;
set(str_key, ~"parent data");
set(box_key, @());
- do task::spawn {
+ task::spawn(proc() {
// spawn_linked
set(str_key, ~"string data");
set(box_key, @());
set(int_key, 42);
fail!();
- }
+ });
// Not quite nondeterministic.
set(int_key, 31337);
fail!();
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+#[macro_escape];
+
+#[macro_export]
+macro_rules! log(
+ ($lvl:expr, $($arg:tt)+) => ({
+ let lvl = $lvl;
+ if lvl <= __log_level() {
+ format_args!(|args| {
+ ::std::logging::log(lvl, args)
+ }, $($arg)+)
+ }
+ })
+)
+#[macro_export]
+macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
+#[macro_export]
+macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
+#[macro_export]
+macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
+#[macro_export]
+macro_rules! debug( ($($arg:tt)*) => (
+ if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
+))
+
+#[macro_export]
+macro_rules! log_enabled(
+ ($lvl:expr) => ( {
+ let lvl = $lvl;
+ lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
+ } )
+)
+
+#[macro_export]
+macro_rules! fail(
+ () => (
+ fail!("explicit failure")
+ );
+ ($msg:expr) => (
+ ::std::rt::begin_unwind($msg, file!(), line!())
+ );
+ ($fmt:expr, $($arg:tt)*) => (
+ {
+ // a closure can't have return type !, so we need a full
+ // function to pass to format_args!, *and* we need the
+ // file and line numbers right here; so an inner bare fn
+ // is our only choice.
+ #[inline]
+ fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
+ ::std::rt::begin_unwind_fmt(fmt, file!(), line!())
+ }
+ format_args!(run_fmt, $fmt, $($arg)*)
+ }
+ )
+)
+
+#[macro_export]
+macro_rules! assert(
+ ($cond:expr) => {
+ if !$cond {
+ fail!("assertion failed: {:s}", stringify!($cond))
+ }
+ };
+ ($cond:expr, $msg:expr) => {
+ if !$cond {
+ fail!($msg)
+ }
+ };
+ ($cond:expr, $( $arg:expr ),+) => {
+ if !$cond {
+ fail!( $($arg),+ )
+ }
+ }
+)
+
+#[macro_export]
+macro_rules! assert_eq (
+ ($given:expr , $expected:expr) => (
+ {
+ let given_val = &($given);
+ let expected_val = &($expected);
+ // check both directions of equality....
+ if !((*given_val == *expected_val) &&
+ (*expected_val == *given_val)) {
+ fail!("assertion failed: `(left == right) && (right == left)` \
+ (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
+ }
+ }
+ )
+)
+
+/// A utility macro for indicating unreachable code. It will fail if
+/// executed. This is occasionally useful to put after loops that never
+/// terminate normally, but instead directly return from a function.
+///
+/// # Example
+///
+/// ```rust
+/// fn choose_weighted_item(v: &[Item]) -> Item {
+/// assert!(!v.is_empty());
+/// let mut so_far = 0u;
+/// for item in v.iter() {
+/// so_far += item.weight;
+/// if so_far > 100 {
+/// return item;
+/// }
+/// }
+/// // The above loop always returns, so we must hint to the
+/// // type checker that it isn't possible to get down here
+/// unreachable!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! unreachable (() => (
+ fail!("internal error: entered unreachable code");
+))
+
+#[macro_export]
+macro_rules! condition (
+
+ { pub $c:ident: $input:ty -> $out:ty; } => {
+
+ pub mod $c {
+ #[allow(unused_imports)];
+ #[allow(non_uppercase_statics)];
+ #[allow(missing_doc)];
+
+ use super::*;
+
+ local_data_key!(key: @::std::condition::Handler<$input, $out>)
+
+ pub static cond :
+ ::std::condition::Condition<$input,$out> =
+ ::std::condition::Condition {
+ name: stringify!($c),
+ key: key
+ };
+ }
+ };
+
+ { $c:ident: $input:ty -> $out:ty; } => {
+
+ mod $c {
+ #[allow(unused_imports)];
+ #[allow(non_uppercase_statics)];
+ #[allow(dead_code)];
+
+ use super::*;
+
+ local_data_key!(key: @::std::condition::Handler<$input, $out>)
+
+ pub static cond :
+ ::std::condition::Condition<$input,$out> =
+ ::std::condition::Condition {
+ name: stringify!($c),
+ key: key
+ };
+ }
+ }
+)
+
+#[macro_export]
+macro_rules! format(($($arg:tt)*) => (
+ format_args!(::std::fmt::format, $($arg)*)
+))
+#[macro_export]
+macro_rules! write(($dst:expr, $($arg:tt)*) => (
+ format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
+))
+#[macro_export]
+macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
+ format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
+))
+#[macro_export]
+macro_rules! print (
+ ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
+)
+#[macro_export]
+macro_rules! println (
+ ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
+)
+
+#[macro_export]
+macro_rules! local_data_key (
+ ($name:ident: $ty:ty) => (
+ static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ );
+ (pub $name:ident: $ty:ty) => (
+ pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+ )
+)
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#[test]
fn test_overflows() {
- assert!((::int::max_value > 0));
- assert!((::int::min_value <= 0));
- assert!((::int::min_value + ::int::max_value + 1 == 0));
+ assert!((::int::MAX > 0));
+ assert!((::int::MIN <= 0));
+ assert!((::int::MIN + ::int::MAX + 1 == 0));
}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
-pub static bits : uint = $bits;
+pub static BITS : uint = $bits;
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
-pub static bytes : uint = ($bits / 8);
+pub static BYTES : uint = ($bits / 8);
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `Bounded::min_value` function.
-pub static min_value: $T = (-1 as $T) << (bits - 1);
-// FIXME(#9837): Compute min_value like this so the high bits that shouldn't exist are 0.
+pub static MIN: $T = (-1 as $T) << (BITS - 1);
+// FIXME(#9837): Compute MIN like this so the high bits that shouldn't exist are 0.
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `Bounded::max_value` function.
-pub static max_value: $T = !min_value;
+pub static MAX: $T = !MIN;
impl CheckedDiv for $T {
#[inline]
fn checked_div(&self, v: &$T) -> Option<$T> {
- if *v == 0 || (*self == min_value && *v == -1) {
+ if *v == 0 || (*self == MIN && *v == -1) {
None
} else {
Some(self / *v)
impl Bounded for $T {
#[inline]
- fn min_value() -> $T { min_value }
+ fn min_value() -> $T { MIN }
#[inline]
- fn max_value() -> $T { max_value }
+ fn max_value() -> $T { MAX }
}
impl Int for $T {}
fn test_signed_checked_div() {
assert_eq!(10i.checked_div(&2), Some(5));
assert_eq!(5i.checked_div(&0), None);
- assert_eq!(int::min_value.checked_div(&-1), None);
+ assert_eq!(int::MIN.checked_div(&-1), None);
}
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
pub trait Unsigned: Num {}
-/// Times trait
-///
-/// ```rust
-/// let ten = 10u;
-/// let mut accum = 0;
-/// ten.times(|| { accum += 1; })
-/// ```
-///
-pub trait Times {
- fn times(&self, it: ||);
-}
-
pub trait Integer: Num
+ Orderable
+ Div<Self,Self>
#[test]
fn test_cast_range_int_min() {
- assert_eq!(int::min_value.to_int(), Some(int::min_value as int));
- assert_eq!(int::min_value.to_i8(), None);
- assert_eq!(int::min_value.to_i16(), None);
- // int::min_value.to_i32() is word-size specific
- assert_eq!(int::min_value.to_i64(), Some(int::min_value as i64));
- assert_eq!(int::min_value.to_uint(), None);
- assert_eq!(int::min_value.to_u8(), None);
- assert_eq!(int::min_value.to_u16(), None);
- assert_eq!(int::min_value.to_u32(), None);
- assert_eq!(int::min_value.to_u64(), None);
+ assert_eq!(int::MIN.to_int(), Some(int::MIN as int));
+ assert_eq!(int::MIN.to_i8(), None);
+ assert_eq!(int::MIN.to_i16(), None);
+ // int::MIN.to_i32() is word-size specific
+ assert_eq!(int::MIN.to_i64(), Some(int::MIN as i64));
+ assert_eq!(int::MIN.to_uint(), None);
+ assert_eq!(int::MIN.to_u8(), None);
+ assert_eq!(int::MIN.to_u16(), None);
+ assert_eq!(int::MIN.to_u32(), None);
+ assert_eq!(int::MIN.to_u64(), None);
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(int::min_value.to_i32(), Some(int::min_value as i32));
+ assert_eq!(int::MIN.to_i32(), Some(int::MIN as i32));
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(int::min_value.to_i32(), None);
+ assert_eq!(int::MIN.to_i32(), None);
}
check_word_size();
#[test]
fn test_cast_range_i8_min() {
- assert_eq!(i8::min_value.to_int(), Some(i8::min_value as int));
- assert_eq!(i8::min_value.to_i8(), Some(i8::min_value as i8));
- assert_eq!(i8::min_value.to_i16(), Some(i8::min_value as i16));
- assert_eq!(i8::min_value.to_i32(), Some(i8::min_value as i32));
- assert_eq!(i8::min_value.to_i64(), Some(i8::min_value as i64));
- assert_eq!(i8::min_value.to_uint(), None);
- assert_eq!(i8::min_value.to_u8(), None);
- assert_eq!(i8::min_value.to_u16(), None);
- assert_eq!(i8::min_value.to_u32(), None);
- assert_eq!(i8::min_value.to_u64(), None);
+ assert_eq!(i8::MIN.to_int(), Some(i8::MIN as int));
+ assert_eq!(i8::MIN.to_i8(), Some(i8::MIN as i8));
+ assert_eq!(i8::MIN.to_i16(), Some(i8::MIN as i16));
+ assert_eq!(i8::MIN.to_i32(), Some(i8::MIN as i32));
+ assert_eq!(i8::MIN.to_i64(), Some(i8::MIN as i64));
+ assert_eq!(i8::MIN.to_uint(), None);
+ assert_eq!(i8::MIN.to_u8(), None);
+ assert_eq!(i8::MIN.to_u16(), None);
+ assert_eq!(i8::MIN.to_u32(), None);
+ assert_eq!(i8::MIN.to_u64(), None);
}
#[test]
fn test_cast_range_i16_min() {
- assert_eq!(i16::min_value.to_int(), Some(i16::min_value as int));
- assert_eq!(i16::min_value.to_i8(), None);
- assert_eq!(i16::min_value.to_i16(), Some(i16::min_value as i16));
- assert_eq!(i16::min_value.to_i32(), Some(i16::min_value as i32));
- assert_eq!(i16::min_value.to_i64(), Some(i16::min_value as i64));
- assert_eq!(i16::min_value.to_uint(), None);
- assert_eq!(i16::min_value.to_u8(), None);
- assert_eq!(i16::min_value.to_u16(), None);
- assert_eq!(i16::min_value.to_u32(), None);
- assert_eq!(i16::min_value.to_u64(), None);
+ assert_eq!(i16::MIN.to_int(), Some(i16::MIN as int));
+ assert_eq!(i16::MIN.to_i8(), None);
+ assert_eq!(i16::MIN.to_i16(), Some(i16::MIN as i16));
+ assert_eq!(i16::MIN.to_i32(), Some(i16::MIN as i32));
+ assert_eq!(i16::MIN.to_i64(), Some(i16::MIN as i64));
+ assert_eq!(i16::MIN.to_uint(), None);
+ assert_eq!(i16::MIN.to_u8(), None);
+ assert_eq!(i16::MIN.to_u16(), None);
+ assert_eq!(i16::MIN.to_u32(), None);
+ assert_eq!(i16::MIN.to_u64(), None);
}
#[test]
fn test_cast_range_i32_min() {
- assert_eq!(i32::min_value.to_int(), Some(i32::min_value as int));
- assert_eq!(i32::min_value.to_i8(), None);
- assert_eq!(i32::min_value.to_i16(), None);
- assert_eq!(i32::min_value.to_i32(), Some(i32::min_value as i32));
- assert_eq!(i32::min_value.to_i64(), Some(i32::min_value as i64));
- assert_eq!(i32::min_value.to_uint(), None);
- assert_eq!(i32::min_value.to_u8(), None);
- assert_eq!(i32::min_value.to_u16(), None);
- assert_eq!(i32::min_value.to_u32(), None);
- assert_eq!(i32::min_value.to_u64(), None);
+ assert_eq!(i32::MIN.to_int(), Some(i32::MIN as int));
+ assert_eq!(i32::MIN.to_i8(), None);
+ assert_eq!(i32::MIN.to_i16(), None);
+ assert_eq!(i32::MIN.to_i32(), Some(i32::MIN as i32));
+ assert_eq!(i32::MIN.to_i64(), Some(i32::MIN as i64));
+ assert_eq!(i32::MIN.to_uint(), None);
+ assert_eq!(i32::MIN.to_u8(), None);
+ assert_eq!(i32::MIN.to_u16(), None);
+ assert_eq!(i32::MIN.to_u32(), None);
+ assert_eq!(i32::MIN.to_u64(), None);
}
#[test]
fn test_cast_range_i64_min() {
- // i64::min_value.to_int() is word-size specific
- assert_eq!(i64::min_value.to_i8(), None);
- assert_eq!(i64::min_value.to_i16(), None);
- assert_eq!(i64::min_value.to_i32(), None);
- assert_eq!(i64::min_value.to_i64(), Some(i64::min_value as i64));
- assert_eq!(i64::min_value.to_uint(), None);
- assert_eq!(i64::min_value.to_u8(), None);
- assert_eq!(i64::min_value.to_u16(), None);
- assert_eq!(i64::min_value.to_u32(), None);
- assert_eq!(i64::min_value.to_u64(), None);
+ // i64::MIN.to_int() is word-size specific
+ assert_eq!(i64::MIN.to_i8(), None);
+ assert_eq!(i64::MIN.to_i16(), None);
+ assert_eq!(i64::MIN.to_i32(), None);
+ assert_eq!(i64::MIN.to_i64(), Some(i64::MIN as i64));
+ assert_eq!(i64::MIN.to_uint(), None);
+ assert_eq!(i64::MIN.to_u8(), None);
+ assert_eq!(i64::MIN.to_u16(), None);
+ assert_eq!(i64::MIN.to_u32(), None);
+ assert_eq!(i64::MIN.to_u64(), None);
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(i64::min_value.to_int(), None);
+ assert_eq!(i64::MIN.to_int(), None);
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(i64::min_value.to_int(), Some(i64::min_value as int));
+ assert_eq!(i64::MIN.to_int(), Some(i64::MIN as int));
}
check_word_size();
#[test]
fn test_cast_range_int_max() {
- assert_eq!(int::max_value.to_int(), Some(int::max_value as int));
- assert_eq!(int::max_value.to_i8(), None);
- assert_eq!(int::max_value.to_i16(), None);
- // int::max_value.to_i32() is word-size specific
- assert_eq!(int::max_value.to_i64(), Some(int::max_value as i64));
- assert_eq!(int::max_value.to_u8(), None);
- assert_eq!(int::max_value.to_u16(), None);
- // int::max_value.to_u32() is word-size specific
- assert_eq!(int::max_value.to_u64(), Some(int::max_value as u64));
+ assert_eq!(int::MAX.to_int(), Some(int::MAX as int));
+ assert_eq!(int::MAX.to_i8(), None);
+ assert_eq!(int::MAX.to_i16(), None);
+ // int::MAX.to_i32() is word-size specific
+ assert_eq!(int::MAX.to_i64(), Some(int::MAX as i64));
+ assert_eq!(int::MAX.to_u8(), None);
+ assert_eq!(int::MAX.to_u16(), None);
+ // int::MAX.to_u32() is word-size specific
+ assert_eq!(int::MAX.to_u64(), Some(int::MAX as u64));
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(int::max_value.to_i32(), Some(int::max_value as i32));
- assert_eq!(int::max_value.to_u32(), Some(int::max_value as u32));
+ assert_eq!(int::MAX.to_i32(), Some(int::MAX as i32));
+ assert_eq!(int::MAX.to_u32(), Some(int::MAX as u32));
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(int::max_value.to_i32(), None);
- assert_eq!(int::max_value.to_u32(), None);
+ assert_eq!(int::MAX.to_i32(), None);
+ assert_eq!(int::MAX.to_u32(), None);
}
check_word_size();
#[test]
fn test_cast_range_i8_max() {
- assert_eq!(i8::max_value.to_int(), Some(i8::max_value as int));
- assert_eq!(i8::max_value.to_i8(), Some(i8::max_value as i8));
- assert_eq!(i8::max_value.to_i16(), Some(i8::max_value as i16));
- assert_eq!(i8::max_value.to_i32(), Some(i8::max_value as i32));
- assert_eq!(i8::max_value.to_i64(), Some(i8::max_value as i64));
- assert_eq!(i8::max_value.to_uint(), Some(i8::max_value as uint));
- assert_eq!(i8::max_value.to_u8(), Some(i8::max_value as u8));
- assert_eq!(i8::max_value.to_u16(), Some(i8::max_value as u16));
- assert_eq!(i8::max_value.to_u32(), Some(i8::max_value as u32));
- assert_eq!(i8::max_value.to_u64(), Some(i8::max_value as u64));
+ assert_eq!(i8::MAX.to_int(), Some(i8::MAX as int));
+ assert_eq!(i8::MAX.to_i8(), Some(i8::MAX as i8));
+ assert_eq!(i8::MAX.to_i16(), Some(i8::MAX as i16));
+ assert_eq!(i8::MAX.to_i32(), Some(i8::MAX as i32));
+ assert_eq!(i8::MAX.to_i64(), Some(i8::MAX as i64));
+ assert_eq!(i8::MAX.to_uint(), Some(i8::MAX as uint));
+ assert_eq!(i8::MAX.to_u8(), Some(i8::MAX as u8));
+ assert_eq!(i8::MAX.to_u16(), Some(i8::MAX as u16));
+ assert_eq!(i8::MAX.to_u32(), Some(i8::MAX as u32));
+ assert_eq!(i8::MAX.to_u64(), Some(i8::MAX as u64));
}
#[test]
fn test_cast_range_i16_max() {
- assert_eq!(i16::max_value.to_int(), Some(i16::max_value as int));
- assert_eq!(i16::max_value.to_i8(), None);
- assert_eq!(i16::max_value.to_i16(), Some(i16::max_value as i16));
- assert_eq!(i16::max_value.to_i32(), Some(i16::max_value as i32));
- assert_eq!(i16::max_value.to_i64(), Some(i16::max_value as i64));
- assert_eq!(i16::max_value.to_uint(), Some(i16::max_value as uint));
- assert_eq!(i16::max_value.to_u8(), None);
- assert_eq!(i16::max_value.to_u16(), Some(i16::max_value as u16));
- assert_eq!(i16::max_value.to_u32(), Some(i16::max_value as u32));
- assert_eq!(i16::max_value.to_u64(), Some(i16::max_value as u64));
+ assert_eq!(i16::MAX.to_int(), Some(i16::MAX as int));
+ assert_eq!(i16::MAX.to_i8(), None);
+ assert_eq!(i16::MAX.to_i16(), Some(i16::MAX as i16));
+ assert_eq!(i16::MAX.to_i32(), Some(i16::MAX as i32));
+ assert_eq!(i16::MAX.to_i64(), Some(i16::MAX as i64));
+ assert_eq!(i16::MAX.to_uint(), Some(i16::MAX as uint));
+ assert_eq!(i16::MAX.to_u8(), None);
+ assert_eq!(i16::MAX.to_u16(), Some(i16::MAX as u16));
+ assert_eq!(i16::MAX.to_u32(), Some(i16::MAX as u32));
+ assert_eq!(i16::MAX.to_u64(), Some(i16::MAX as u64));
}
#[test]
fn test_cast_range_i32_max() {
- assert_eq!(i32::max_value.to_int(), Some(i32::max_value as int));
- assert_eq!(i32::max_value.to_i8(), None);
- assert_eq!(i32::max_value.to_i16(), None);
- assert_eq!(i32::max_value.to_i32(), Some(i32::max_value as i32));
- assert_eq!(i32::max_value.to_i64(), Some(i32::max_value as i64));
- assert_eq!(i32::max_value.to_uint(), Some(i32::max_value as uint));
- assert_eq!(i32::max_value.to_u8(), None);
- assert_eq!(i32::max_value.to_u16(), None);
- assert_eq!(i32::max_value.to_u32(), Some(i32::max_value as u32));
- assert_eq!(i32::max_value.to_u64(), Some(i32::max_value as u64));
+ assert_eq!(i32::MAX.to_int(), Some(i32::MAX as int));
+ assert_eq!(i32::MAX.to_i8(), None);
+ assert_eq!(i32::MAX.to_i16(), None);
+ assert_eq!(i32::MAX.to_i32(), Some(i32::MAX as i32));
+ assert_eq!(i32::MAX.to_i64(), Some(i32::MAX as i64));
+ assert_eq!(i32::MAX.to_uint(), Some(i32::MAX as uint));
+ assert_eq!(i32::MAX.to_u8(), None);
+ assert_eq!(i32::MAX.to_u16(), None);
+ assert_eq!(i32::MAX.to_u32(), Some(i32::MAX as u32));
+ assert_eq!(i32::MAX.to_u64(), Some(i32::MAX as u64));
}
#[test]
fn test_cast_range_i64_max() {
- // i64::max_value.to_int() is word-size specific
- assert_eq!(i64::max_value.to_i8(), None);
- assert_eq!(i64::max_value.to_i16(), None);
- assert_eq!(i64::max_value.to_i32(), None);
- assert_eq!(i64::max_value.to_i64(), Some(i64::max_value as i64));
- // i64::max_value.to_uint() is word-size specific
- assert_eq!(i64::max_value.to_u8(), None);
- assert_eq!(i64::max_value.to_u16(), None);
- assert_eq!(i64::max_value.to_u32(), None);
- assert_eq!(i64::max_value.to_u64(), Some(i64::max_value as u64));
+ // i64::MAX.to_int() is word-size specific
+ assert_eq!(i64::MAX.to_i8(), None);
+ assert_eq!(i64::MAX.to_i16(), None);
+ assert_eq!(i64::MAX.to_i32(), None);
+ assert_eq!(i64::MAX.to_i64(), Some(i64::MAX as i64));
+ // i64::MAX.to_uint() is word-size specific
+ assert_eq!(i64::MAX.to_u8(), None);
+ assert_eq!(i64::MAX.to_u16(), None);
+ assert_eq!(i64::MAX.to_u32(), None);
+ assert_eq!(i64::MAX.to_u64(), Some(i64::MAX as u64));
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(i64::max_value.to_int(), None);
- assert_eq!(i64::max_value.to_uint(), None);
+ assert_eq!(i64::MAX.to_int(), None);
+ assert_eq!(i64::MAX.to_uint(), None);
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(i64::max_value.to_int(), Some(i64::max_value as int));
- assert_eq!(i64::max_value.to_uint(), Some(i64::max_value as uint));
+ assert_eq!(i64::MAX.to_int(), Some(i64::MAX as int));
+ assert_eq!(i64::MAX.to_uint(), Some(i64::MAX as uint));
}
check_word_size();
#[test]
fn test_cast_range_uint_min() {
- assert_eq!(uint::min_value.to_int(), Some(uint::min_value as int));
- assert_eq!(uint::min_value.to_i8(), Some(uint::min_value as i8));
- assert_eq!(uint::min_value.to_i16(), Some(uint::min_value as i16));
- assert_eq!(uint::min_value.to_i32(), Some(uint::min_value as i32));
- assert_eq!(uint::min_value.to_i64(), Some(uint::min_value as i64));
- assert_eq!(uint::min_value.to_uint(), Some(uint::min_value as uint));
- assert_eq!(uint::min_value.to_u8(), Some(uint::min_value as u8));
- assert_eq!(uint::min_value.to_u16(), Some(uint::min_value as u16));
- assert_eq!(uint::min_value.to_u32(), Some(uint::min_value as u32));
- assert_eq!(uint::min_value.to_u64(), Some(uint::min_value as u64));
+ assert_eq!(uint::MIN.to_int(), Some(uint::MIN as int));
+ assert_eq!(uint::MIN.to_i8(), Some(uint::MIN as i8));
+ assert_eq!(uint::MIN.to_i16(), Some(uint::MIN as i16));
+ assert_eq!(uint::MIN.to_i32(), Some(uint::MIN as i32));
+ assert_eq!(uint::MIN.to_i64(), Some(uint::MIN as i64));
+ assert_eq!(uint::MIN.to_uint(), Some(uint::MIN as uint));
+ assert_eq!(uint::MIN.to_u8(), Some(uint::MIN as u8));
+ assert_eq!(uint::MIN.to_u16(), Some(uint::MIN as u16));
+ assert_eq!(uint::MIN.to_u32(), Some(uint::MIN as u32));
+ assert_eq!(uint::MIN.to_u64(), Some(uint::MIN as u64));
}
#[test]
fn test_cast_range_u8_min() {
- assert_eq!(u8::min_value.to_int(), Some(u8::min_value as int));
- assert_eq!(u8::min_value.to_i8(), Some(u8::min_value as i8));
- assert_eq!(u8::min_value.to_i16(), Some(u8::min_value as i16));
- assert_eq!(u8::min_value.to_i32(), Some(u8::min_value as i32));
- assert_eq!(u8::min_value.to_i64(), Some(u8::min_value as i64));
- assert_eq!(u8::min_value.to_uint(), Some(u8::min_value as uint));
- assert_eq!(u8::min_value.to_u8(), Some(u8::min_value as u8));
- assert_eq!(u8::min_value.to_u16(), Some(u8::min_value as u16));
- assert_eq!(u8::min_value.to_u32(), Some(u8::min_value as u32));
- assert_eq!(u8::min_value.to_u64(), Some(u8::min_value as u64));
+ assert_eq!(u8::MIN.to_int(), Some(u8::MIN as int));
+ assert_eq!(u8::MIN.to_i8(), Some(u8::MIN as i8));
+ assert_eq!(u8::MIN.to_i16(), Some(u8::MIN as i16));
+ assert_eq!(u8::MIN.to_i32(), Some(u8::MIN as i32));
+ assert_eq!(u8::MIN.to_i64(), Some(u8::MIN as i64));
+ assert_eq!(u8::MIN.to_uint(), Some(u8::MIN as uint));
+ assert_eq!(u8::MIN.to_u8(), Some(u8::MIN as u8));
+ assert_eq!(u8::MIN.to_u16(), Some(u8::MIN as u16));
+ assert_eq!(u8::MIN.to_u32(), Some(u8::MIN as u32));
+ assert_eq!(u8::MIN.to_u64(), Some(u8::MIN as u64));
}
#[test]
fn test_cast_range_u16_min() {
- assert_eq!(u16::min_value.to_int(), Some(u16::min_value as int));
- assert_eq!(u16::min_value.to_i8(), Some(u16::min_value as i8));
- assert_eq!(u16::min_value.to_i16(), Some(u16::min_value as i16));
- assert_eq!(u16::min_value.to_i32(), Some(u16::min_value as i32));
- assert_eq!(u16::min_value.to_i64(), Some(u16::min_value as i64));
- assert_eq!(u16::min_value.to_uint(), Some(u16::min_value as uint));
- assert_eq!(u16::min_value.to_u8(), Some(u16::min_value as u8));
- assert_eq!(u16::min_value.to_u16(), Some(u16::min_value as u16));
- assert_eq!(u16::min_value.to_u32(), Some(u16::min_value as u32));
- assert_eq!(u16::min_value.to_u64(), Some(u16::min_value as u64));
+ assert_eq!(u16::MIN.to_int(), Some(u16::MIN as int));
+ assert_eq!(u16::MIN.to_i8(), Some(u16::MIN as i8));
+ assert_eq!(u16::MIN.to_i16(), Some(u16::MIN as i16));
+ assert_eq!(u16::MIN.to_i32(), Some(u16::MIN as i32));
+ assert_eq!(u16::MIN.to_i64(), Some(u16::MIN as i64));
+ assert_eq!(u16::MIN.to_uint(), Some(u16::MIN as uint));
+ assert_eq!(u16::MIN.to_u8(), Some(u16::MIN as u8));
+ assert_eq!(u16::MIN.to_u16(), Some(u16::MIN as u16));
+ assert_eq!(u16::MIN.to_u32(), Some(u16::MIN as u32));
+ assert_eq!(u16::MIN.to_u64(), Some(u16::MIN as u64));
}
#[test]
fn test_cast_range_u32_min() {
- assert_eq!(u32::min_value.to_int(), Some(u32::min_value as int));
- assert_eq!(u32::min_value.to_i8(), Some(u32::min_value as i8));
- assert_eq!(u32::min_value.to_i16(), Some(u32::min_value as i16));
- assert_eq!(u32::min_value.to_i32(), Some(u32::min_value as i32));
- assert_eq!(u32::min_value.to_i64(), Some(u32::min_value as i64));
- assert_eq!(u32::min_value.to_uint(), Some(u32::min_value as uint));
- assert_eq!(u32::min_value.to_u8(), Some(u32::min_value as u8));
- assert_eq!(u32::min_value.to_u16(), Some(u32::min_value as u16));
- assert_eq!(u32::min_value.to_u32(), Some(u32::min_value as u32));
- assert_eq!(u32::min_value.to_u64(), Some(u32::min_value as u64));
+ assert_eq!(u32::MIN.to_int(), Some(u32::MIN as int));
+ assert_eq!(u32::MIN.to_i8(), Some(u32::MIN as i8));
+ assert_eq!(u32::MIN.to_i16(), Some(u32::MIN as i16));
+ assert_eq!(u32::MIN.to_i32(), Some(u32::MIN as i32));
+ assert_eq!(u32::MIN.to_i64(), Some(u32::MIN as i64));
+ assert_eq!(u32::MIN.to_uint(), Some(u32::MIN as uint));
+ assert_eq!(u32::MIN.to_u8(), Some(u32::MIN as u8));
+ assert_eq!(u32::MIN.to_u16(), Some(u32::MIN as u16));
+ assert_eq!(u32::MIN.to_u32(), Some(u32::MIN as u32));
+ assert_eq!(u32::MIN.to_u64(), Some(u32::MIN as u64));
}
#[test]
fn test_cast_range_u64_min() {
- assert_eq!(u64::min_value.to_int(), Some(u64::min_value as int));
- assert_eq!(u64::min_value.to_i8(), Some(u64::min_value as i8));
- assert_eq!(u64::min_value.to_i16(), Some(u64::min_value as i16));
- assert_eq!(u64::min_value.to_i32(), Some(u64::min_value as i32));
- assert_eq!(u64::min_value.to_i64(), Some(u64::min_value as i64));
- assert_eq!(u64::min_value.to_uint(), Some(u64::min_value as uint));
- assert_eq!(u64::min_value.to_u8(), Some(u64::min_value as u8));
- assert_eq!(u64::min_value.to_u16(), Some(u64::min_value as u16));
- assert_eq!(u64::min_value.to_u32(), Some(u64::min_value as u32));
- assert_eq!(u64::min_value.to_u64(), Some(u64::min_value as u64));
+ assert_eq!(u64::MIN.to_int(), Some(u64::MIN as int));
+ assert_eq!(u64::MIN.to_i8(), Some(u64::MIN as i8));
+ assert_eq!(u64::MIN.to_i16(), Some(u64::MIN as i16));
+ assert_eq!(u64::MIN.to_i32(), Some(u64::MIN as i32));
+ assert_eq!(u64::MIN.to_i64(), Some(u64::MIN as i64));
+ assert_eq!(u64::MIN.to_uint(), Some(u64::MIN as uint));
+ assert_eq!(u64::MIN.to_u8(), Some(u64::MIN as u8));
+ assert_eq!(u64::MIN.to_u16(), Some(u64::MIN as u16));
+ assert_eq!(u64::MIN.to_u32(), Some(u64::MIN as u32));
+ assert_eq!(u64::MIN.to_u64(), Some(u64::MIN as u64));
}
#[test]
fn test_cast_range_uint_max() {
- assert_eq!(uint::max_value.to_int(), None);
- assert_eq!(uint::max_value.to_i8(), None);
- assert_eq!(uint::max_value.to_i16(), None);
- assert_eq!(uint::max_value.to_i32(), None);
- // uint::max_value.to_i64() is word-size specific
- assert_eq!(uint::max_value.to_u8(), None);
- assert_eq!(uint::max_value.to_u16(), None);
- // uint::max_value.to_u32() is word-size specific
- assert_eq!(uint::max_value.to_u64(), Some(uint::max_value as u64));
+ assert_eq!(uint::MAX.to_int(), None);
+ assert_eq!(uint::MAX.to_i8(), None);
+ assert_eq!(uint::MAX.to_i16(), None);
+ assert_eq!(uint::MAX.to_i32(), None);
+ // uint::MAX.to_i64() is word-size specific
+ assert_eq!(uint::MAX.to_u8(), None);
+ assert_eq!(uint::MAX.to_u16(), None);
+ // uint::MAX.to_u32() is word-size specific
+ assert_eq!(uint::MAX.to_u64(), Some(uint::MAX as u64));
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(uint::max_value.to_u32(), Some(uint::max_value as u32));
- assert_eq!(uint::max_value.to_i64(), Some(uint::max_value as i64));
+ assert_eq!(uint::MAX.to_u32(), Some(uint::MAX as u32));
+ assert_eq!(uint::MAX.to_i64(), Some(uint::MAX as i64));
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(uint::max_value.to_u32(), None);
- assert_eq!(uint::max_value.to_i64(), None);
+ assert_eq!(uint::MAX.to_u32(), None);
+ assert_eq!(uint::MAX.to_i64(), None);
}
check_word_size();
#[test]
fn test_cast_range_u8_max() {
- assert_eq!(u8::max_value.to_int(), Some(u8::max_value as int));
- assert_eq!(u8::max_value.to_i8(), None);
- assert_eq!(u8::max_value.to_i16(), Some(u8::max_value as i16));
- assert_eq!(u8::max_value.to_i32(), Some(u8::max_value as i32));
- assert_eq!(u8::max_value.to_i64(), Some(u8::max_value as i64));
- assert_eq!(u8::max_value.to_uint(), Some(u8::max_value as uint));
- assert_eq!(u8::max_value.to_u8(), Some(u8::max_value as u8));
- assert_eq!(u8::max_value.to_u16(), Some(u8::max_value as u16));
- assert_eq!(u8::max_value.to_u32(), Some(u8::max_value as u32));
- assert_eq!(u8::max_value.to_u64(), Some(u8::max_value as u64));
+ assert_eq!(u8::MAX.to_int(), Some(u8::MAX as int));
+ assert_eq!(u8::MAX.to_i8(), None);
+ assert_eq!(u8::MAX.to_i16(), Some(u8::MAX as i16));
+ assert_eq!(u8::MAX.to_i32(), Some(u8::MAX as i32));
+ assert_eq!(u8::MAX.to_i64(), Some(u8::MAX as i64));
+ assert_eq!(u8::MAX.to_uint(), Some(u8::MAX as uint));
+ assert_eq!(u8::MAX.to_u8(), Some(u8::MAX as u8));
+ assert_eq!(u8::MAX.to_u16(), Some(u8::MAX as u16));
+ assert_eq!(u8::MAX.to_u32(), Some(u8::MAX as u32));
+ assert_eq!(u8::MAX.to_u64(), Some(u8::MAX as u64));
}
#[test]
fn test_cast_range_u16_max() {
- assert_eq!(u16::max_value.to_int(), Some(u16::max_value as int));
- assert_eq!(u16::max_value.to_i8(), None);
- assert_eq!(u16::max_value.to_i16(), None);
- assert_eq!(u16::max_value.to_i32(), Some(u16::max_value as i32));
- assert_eq!(u16::max_value.to_i64(), Some(u16::max_value as i64));
- assert_eq!(u16::max_value.to_uint(), Some(u16::max_value as uint));
- assert_eq!(u16::max_value.to_u8(), None);
- assert_eq!(u16::max_value.to_u16(), Some(u16::max_value as u16));
- assert_eq!(u16::max_value.to_u32(), Some(u16::max_value as u32));
- assert_eq!(u16::max_value.to_u64(), Some(u16::max_value as u64));
+ assert_eq!(u16::MAX.to_int(), Some(u16::MAX as int));
+ assert_eq!(u16::MAX.to_i8(), None);
+ assert_eq!(u16::MAX.to_i16(), None);
+ assert_eq!(u16::MAX.to_i32(), Some(u16::MAX as i32));
+ assert_eq!(u16::MAX.to_i64(), Some(u16::MAX as i64));
+ assert_eq!(u16::MAX.to_uint(), Some(u16::MAX as uint));
+ assert_eq!(u16::MAX.to_u8(), None);
+ assert_eq!(u16::MAX.to_u16(), Some(u16::MAX as u16));
+ assert_eq!(u16::MAX.to_u32(), Some(u16::MAX as u32));
+ assert_eq!(u16::MAX.to_u64(), Some(u16::MAX as u64));
}
#[test]
fn test_cast_range_u32_max() {
- // u32::max_value.to_int() is word-size specific
- assert_eq!(u32::max_value.to_i8(), None);
- assert_eq!(u32::max_value.to_i16(), None);
- assert_eq!(u32::max_value.to_i32(), None);
- assert_eq!(u32::max_value.to_i64(), Some(u32::max_value as i64));
- assert_eq!(u32::max_value.to_uint(), Some(u32::max_value as uint));
- assert_eq!(u32::max_value.to_u8(), None);
- assert_eq!(u32::max_value.to_u16(), None);
- assert_eq!(u32::max_value.to_u32(), Some(u32::max_value as u32));
- assert_eq!(u32::max_value.to_u64(), Some(u32::max_value as u64));
+ // u32::MAX.to_int() is word-size specific
+ assert_eq!(u32::MAX.to_i8(), None);
+ assert_eq!(u32::MAX.to_i16(), None);
+ assert_eq!(u32::MAX.to_i32(), None);
+ assert_eq!(u32::MAX.to_i64(), Some(u32::MAX as i64));
+ assert_eq!(u32::MAX.to_uint(), Some(u32::MAX as uint));
+ assert_eq!(u32::MAX.to_u8(), None);
+ assert_eq!(u32::MAX.to_u16(), None);
+ assert_eq!(u32::MAX.to_u32(), Some(u32::MAX as u32));
+ assert_eq!(u32::MAX.to_u64(), Some(u32::MAX as u64));
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(u32::max_value.to_int(), None);
+ assert_eq!(u32::MAX.to_int(), None);
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(u32::max_value.to_int(), Some(u32::max_value as int));
+ assert_eq!(u32::MAX.to_int(), Some(u32::MAX as int));
}
check_word_size();
#[test]
fn test_cast_range_u64_max() {
- assert_eq!(u64::max_value.to_int(), None);
- assert_eq!(u64::max_value.to_i8(), None);
- assert_eq!(u64::max_value.to_i16(), None);
- assert_eq!(u64::max_value.to_i32(), None);
- assert_eq!(u64::max_value.to_i64(), None);
- // u64::max_value.to_uint() is word-size specific
- assert_eq!(u64::max_value.to_u8(), None);
- assert_eq!(u64::max_value.to_u16(), None);
- assert_eq!(u64::max_value.to_u32(), None);
- assert_eq!(u64::max_value.to_u64(), Some(u64::max_value as u64));
+ assert_eq!(u64::MAX.to_int(), None);
+ assert_eq!(u64::MAX.to_i8(), None);
+ assert_eq!(u64::MAX.to_i16(), None);
+ assert_eq!(u64::MAX.to_i32(), None);
+ assert_eq!(u64::MAX.to_i64(), None);
+ // u64::MAX.to_uint() is word-size specific
+ assert_eq!(u64::MAX.to_u8(), None);
+ assert_eq!(u64::MAX.to_u16(), None);
+ assert_eq!(u64::MAX.to_u32(), None);
+ assert_eq!(u64::MAX.to_u64(), Some(u64::MAX as u64));
#[cfg(target_word_size = "32")]
fn check_word_size() {
- assert_eq!(u64::max_value.to_uint(), None);
+ assert_eq!(u64::MAX.to_uint(), None);
}
#[cfg(target_word_size = "64")]
fn check_word_size() {
- assert_eq!(u64::max_value.to_uint(), Some(u64::max_value as uint));
+ assert_eq!(u64::MAX.to_uint(), Some(u64::MAX as uint));
}
check_word_size();
#[test]
fn test_saturating_add_uint() {
- use uint::max_value;
+ use uint::MAX;
assert_eq!(3u.saturating_add(5u), 8u);
- assert_eq!(3u.saturating_add(max_value-1), max_value);
- assert_eq!(max_value.saturating_add(max_value), max_value);
- assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ assert_eq!(3u.saturating_add(MAX-1), MAX);
+ assert_eq!(MAX.saturating_add(MAX), MAX);
+ assert_eq!((MAX-2).saturating_add(1), MAX-1);
}
#[test]
fn test_saturating_sub_uint() {
- use uint::max_value;
+ use uint::MAX;
assert_eq!(5u.saturating_sub(3u), 2u);
assert_eq!(3u.saturating_sub(5u), 0u);
assert_eq!(0u.saturating_sub(1u), 0u);
- assert_eq!((max_value-1).saturating_sub(max_value), 0);
+ assert_eq!((MAX-1).saturating_sub(MAX), 0);
}
#[test]
fn test_saturating_add_int() {
- use int::{min_value,max_value};
+ use int::{MIN,MAX};
assert_eq!(3i.saturating_add(5i), 8i);
- assert_eq!(3i.saturating_add(max_value-1), max_value);
- assert_eq!(max_value.saturating_add(max_value), max_value);
- assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ assert_eq!(3i.saturating_add(MAX-1), MAX);
+ assert_eq!(MAX.saturating_add(MAX), MAX);
+ assert_eq!((MAX-2).saturating_add(1), MAX-1);
assert_eq!(3i.saturating_add(-5i), -2i);
- assert_eq!(min_value.saturating_add(-1i), min_value);
- assert_eq!((-2i).saturating_add(-max_value), min_value);
+ assert_eq!(MIN.saturating_add(-1i), MIN);
+ assert_eq!((-2i).saturating_add(-MAX), MIN);
}
#[test]
fn test_saturating_sub_int() {
- use int::{min_value,max_value};
+ use int::{MIN,MAX};
assert_eq!(3i.saturating_sub(5i), -2i);
- assert_eq!(min_value.saturating_sub(1i), min_value);
- assert_eq!((-2i).saturating_sub(max_value), min_value);
+ assert_eq!(MIN.saturating_sub(1i), MIN);
+ assert_eq!((-2i).saturating_sub(MAX), MIN);
assert_eq!(3i.saturating_sub(-5i), 8i);
- assert_eq!(3i.saturating_sub(-(max_value-1)), max_value);
- assert_eq!(max_value.saturating_sub(-max_value), max_value);
- assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
+ assert_eq!(3i.saturating_sub(-(MAX-1)), MAX);
+ assert_eq!(MAX.saturating_sub(-MAX), MAX);
+ assert_eq!((MAX-2).saturating_sub(-1), MAX-1);
}
#[test]
fn test_checked_add() {
- let five_less = uint::max_value - 5;
- assert_eq!(five_less.checked_add(&0), Some(uint::max_value - 5));
- assert_eq!(five_less.checked_add(&1), Some(uint::max_value - 4));
- assert_eq!(five_less.checked_add(&2), Some(uint::max_value - 3));
- assert_eq!(five_less.checked_add(&3), Some(uint::max_value - 2));
- assert_eq!(five_less.checked_add(&4), Some(uint::max_value - 1));
- assert_eq!(five_less.checked_add(&5), Some(uint::max_value));
+ let five_less = uint::MAX - 5;
+ assert_eq!(five_less.checked_add(&0), Some(uint::MAX - 5));
+ assert_eq!(five_less.checked_add(&1), Some(uint::MAX - 4));
+ assert_eq!(five_less.checked_add(&2), Some(uint::MAX - 3));
+ assert_eq!(five_less.checked_add(&3), Some(uint::MAX - 2));
+ assert_eq!(five_less.checked_add(&4), Some(uint::MAX - 1));
+ assert_eq!(five_less.checked_add(&5), Some(uint::MAX));
assert_eq!(five_less.checked_add(&6), None);
assert_eq!(five_less.checked_add(&7), None);
}
#[test]
fn test_checked_mul() {
- let third = uint::max_value / 3;
+ let third = uint::MAX / 3;
assert_eq!(third.checked_mul(&0), Some(0));
assert_eq!(third.checked_mul(&1), Some(third));
assert_eq!(third.checked_mul(&2), Some(third * 2));
use char;
use str::{StrSlice};
use str;
-use vec::{CopyableVector, ImmutableVector, MutableVector};
+use vec::{CloneableVector, ImmutableVector, MutableVector};
use vec::OwnedVector;
use num;
use num::{NumCast, Zero, One, cast, Integer};
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use num::{CheckedAdd, CheckedSub, CheckedMul};
use num::{CheckedDiv, Zero, One, strconv};
use num::{ToStrRadix, FromStrRadix};
-use num;
use option::{Option, Some, None};
use str;
use unstable::intrinsics;
-uint_module!(uint, int, ::int::bits)
+uint_module!(uint, int, ::int::BITS)
///
/// Divide two numbers, return the result, rounded up.
///
pub fn div_floor(x: uint, y: uint) -> uint { return x / y; }
-impl num::Times for uint {
- #[inline]
- ///
- /// A convenience form for basic repetition. Given a uint `x`,
- /// `x.times(|| { ... })` executes the given block x times.
- ///
- /// Equivalent to `for uint::range(0, x) |_| { ... }`.
- ///
- /// Not defined on all integer types to permit unambiguous
- /// use with integer literals of inferred integer-type as
- /// the self-value (eg. `100.times(|| { ... })`).
- ///
- fn times(&self, it: ||) {
- let mut i = *self;
- while i > 0 {
- it();
- i -= 1;
- }
- }
-}
-
/// Returns the smallest power of 2 greater than or equal to `n`
#[inline]
pub fn next_power_of_two(n: uint) -> uint {
#[test]
fn test_overflows() {
use uint;
- assert!((uint::max_value > 0u));
- assert!((uint::min_value <= 0u));
- assert!((uint::min_value + uint::max_value + 1u == 0u));
+ assert!((uint::MAX > 0u));
+ assert!((uint::MIN <= 0u));
+ assert!((uint::MIN + uint::MAX + 1u == 0u));
}
#[test]
assert!((div_ceil(3u, 4u) == 1u));
assert!((div_round(3u, 4u) == 1u));
}
-
-#[test]
-pub fn test_times() {
- use num::Times;
- let ten = 10 as uint;
- let mut accum = 0;
- ten.times(|| { accum += 1; });
- assert!((accum == 10));
-}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
macro_rules! uint_module (($T:ty, $T_SIGNED:ty, $bits:expr) => (
-pub static bits : uint = $bits;
-pub static bytes : uint = ($bits / 8);
+pub static BITS : uint = $bits;
+pub static BYTES : uint = ($bits / 8);
-pub static min_value: $T = 0 as $T;
-pub static max_value: $T = 0 as $T - 1 as $T;
+pub static MIN: $T = 0 as $T;
+pub static MAX: $T = 0 as $T - 1 as $T;
impl CheckedDiv for $T {
#[inline]
impl Bounded for $T {
#[inline]
- fn min_value() -> $T { min_value }
+ fn min_value() -> $T { MIN }
#[inline]
- fn max_value() -> $T { max_value }
+ fn max_value() -> $T { MAX }
}
impl Int for $T {}
assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(&(0b1010 as $T)));
assert_eq!(0b1110 as $T, (0b0111 as $T).shl(&(1 as $T)));
assert_eq!(0b0111 as $T, (0b1110 as $T).shr(&(1 as $T)));
- assert_eq!(max_value - (0b1011 as $T), (0b1011 as $T).not());
+ assert_eq!(MAX - (0b1011 as $T), (0b1011 as $T).not());
}
#[test]
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/// checking for overflow:
///
/// fn inc_conditionally(x: uint) -> Option<uint> {
-/// if x == uint::max_value { return None; }
+/// if x == uint::MAX { return None; }
/// else { return Some(x+1u); }
/// }
/// let v = [1u, 2, 3];
#[cfg(target_os = "macos")]
use iter::range;
use libc;
-use libc::{c_char, c_void, c_int, size_t};
+use libc::{c_char, c_void, c_int};
use option::{Some, None};
use os;
use prelude::*;
use ptr;
use str;
-use to_str;
+use fmt;
use unstable::finally::Finally;
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
let mut buf = [0 as c_char, ..BUF_BYTES];
unsafe {
- if libc::getcwd(buf.as_mut_ptr(), buf.len() as size_t).is_null() {
+ if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
fail!()
}
Path::new(CString::new(buf.as_ptr(), false))
format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
}
-/// Optionally returns the filesystem path to the current executable which is
+/// Optionally returns the filesystem path of the current executable which is
/// running. If any failure occurs, None is returned.
-pub fn self_exe_path() -> Option<Path> {
+pub fn self_exe_name() -> Option<Path> {
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~[u8]> {
let mib = ~[CTL_KERN as c_int,
KERN_PROC as c_int,
KERN_PROC_PATHNAME as c_int, -1 as c_int];
- let mut sz: size_t = 0;
+ let mut sz: libc::size_t = 0;
let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
- ptr::mut_null(), &mut sz, ptr::null(), 0u as size_t);
+ ptr::mut_null(), &mut sz, ptr::null(),
+ 0u as libc::size_t);
if err != 0 { return None; }
if sz == 0 { return None; }
let mut v: ~[u8] = vec::with_capacity(sz as uint);
let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
- v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(), 0u as size_t);
+ v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
+ 0u as libc::size_t);
if err != 0 { return None; }
if sz == 0 { return None; }
v.set_len(sz as uint - 1); // chop off trailing NUL
}
}
- load_self().and_then(|path| Path::new_opt(path).map(|mut p| { p.pop(); p }))
+ load_self().and_then(Path::new_opt)
+}
+
+/// Optionally returns the filesystem path to the current executable which is
+/// running. Like self_exe_name() but without the binary's name.
+/// If any failure occurs, None is returned.
+pub fn self_exe_path() -> Option<Path> {
+ self_exe_name().map(|mut p| { p.pop(); p })
}
/**
#[cfg(target_os = "macos")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
- fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
+ fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
-> c_int {
#[nolink]
extern {
- fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
- -> c_int;
+ fn strerror_r(errnum: c_int, buf: *mut c_char,
+ buflen: libc::size_t) -> c_int;
}
unsafe {
strerror_r(errnum, buf, buflen)
// and requires macros to instead use the POSIX compliant variant.
// So we just use __xpg_strerror_r which is always POSIX compliant
#[cfg(target_os = "linux")]
- fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+ fn strerror_r(errnum: c_int, buf: *mut c_char,
+ buflen: libc::size_t) -> c_int {
#[nolink]
extern {
fn __xpg_strerror_r(errnum: c_int,
buf: *mut c_char,
- buflen: size_t)
+ buflen: libc::size_t)
-> c_int;
}
unsafe {
let p = buf.as_mut_ptr();
unsafe {
- if strerror_r(errno() as c_int, p, buf.len() as size_t) < 0 {
+ if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
fail!("strerror_r failure");
}
}
}
-/// A memory mapped file or chunk of memory. This is a very system-specific interface to the OS's
-/// memory mapping facilities (`mmap` on POSIX, `VirtualAlloc`/`CreateFileMapping` on win32). It
-/// makes no attempt at abstracting platform differences, besides in error values returned. Consider
+/// A memory mapped file or chunk of memory. This is a very system-specific
+/// interface to the OS's memory mapping facilities (`mmap` on POSIX,
+/// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
+/// abstracting platform differences, besides in error values returned. Consider
/// yourself warned.
///
-/// The memory map is released (unmapped) when the destructor is run, so don't let it leave scope by
-/// accident if you want it to stick around.
+/// The memory map is released (unmapped) when the destructor is run, so don't
+/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
/// Pointer to the memory created or modified by this map.
data: *mut u8,
/// Type of memory map
pub enum MemoryMapKind {
- /// Memory-mapped file. On Windows, the inner pointer is a handle to the mapping, and
- /// corresponds to `CreateFileMapping`. Elsewhere, it is null.
+ /// Virtual memory map. Usually used to change the permissions of a given
+ /// chunk of memory. Corresponds to `VirtualAlloc` on Windows.
MapFile(*u8),
- /// Virtual memory map. Usually used to change the permissions of a given chunk of memory.
- /// Corresponds to `VirtualAlloc` on Windows.
+ /// Virtual memory map. Usually used to change the permissions of a given
+ /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
+ /// Windows.
MapVirtual
}
MapWritable,
/// The memory should be executable
MapExecutable,
- /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on POSIX.
+ /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
+ /// POSIX.
MapAddr(*u8),
/// Create a memory mapping for a file with a given fd.
MapFd(c_int),
- /// When using `MapFd`, the start of the map is `uint` bytes from the start of the file.
- MapOffset(uint)
+ /// When using `MapFd`, the start of the map is `uint` bytes from the start
+ /// of the file.
+ MapOffset(uint),
+ /// On POSIX, this can be used to specify the default flags passed to
+ /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
+ /// `MAP_ANON`. This will override both of those. This is platform-specific
+ /// (the exact values used) and ignored on Windows.
+ MapNonStandardFlags(c_int),
}
/// Possible errors when creating a map.
pub enum MapError {
/// ## The following are POSIX-specific
///
- /// fd was not open for reading or, if using `MapWritable`, was not open for writing.
+ /// fd was not open for reading or, if using `MapWritable`, was not open for
+ /// writing.
ErrFdNotAvail,
/// fd was not valid
ErrInvalidFd,
- /// Either the address given by `MapAddr` or offset given by `MapOffset` was not a multiple of
- /// `MemoryMap::granularity` (unaligned to page size).
+ /// Either the address given by `MapAddr` or offset given by `MapOffset` was
+ /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
ErrUnaligned,
/// With `MapFd`, the fd does not support mapping.
ErrNoMapSupport,
- /// If using `MapAddr`, the address + `min_len` was outside of the process's address space. If
- /// using `MapFd`, the target of the fd didn't have enough resources to fulfill the request.
+ /// If using `MapAddr`, the address + `min_len` was outside of the process's
+ /// address space. If using `MapFd`, the target of the fd didn't have enough
+ /// resources to fulfill the request.
ErrNoMem,
+ /// A zero-length map was requested. This is invalid according to
+ /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
+ /// Not all platforms obey this, but this wrapper does.
+ ErrZeroLength,
/// Unrecognized error. The inner value is the unrecognized errno.
ErrUnknown(int),
/// ## The following are win32-specific
///
- /// Unsupported combination of protection flags (`MapReadable`/`MapWritable`/`MapExecutable`).
+ /// Unsupported combination of protection flags
+ /// (`MapReadable`/`MapWritable`/`MapExecutable`).
ErrUnsupProt,
- /// When using `MapFd`, `MapOffset` was given (Windows does not support this at all)
+ /// When using `MapFd`, `MapOffset` was given (Windows does not support this
+ /// at all)
ErrUnsupOffset,
/// When using `MapFd`, there was already a mapping to the file.
ErrAlreadyExists,
- /// Unrecognized error from `VirtualAlloc`. The inner value is the return value of GetLastError.
+ /// Unrecognized error from `VirtualAlloc`. The inner value is the return
+ /// value of GetLastError.
ErrVirtualAlloc(uint),
- /// Unrecognized error from `CreateFileMapping`. The inner value is the return value of
- /// `GetLastError`.
+ /// Unrecognized error from `CreateFileMapping`. The inner value is the
+ /// return value of `GetLastError`.
ErrCreateFileMappingW(uint),
- /// Unrecognized error from `MapViewOfFile`. The inner value is the return value of
- /// `GetLastError`.
+ /// Unrecognized error from `MapViewOfFile`. The inner value is the return
+ /// value of `GetLastError`.
ErrMapViewOfFile(uint)
}
-impl to_str::ToStr for MapError {
- fn to_str(&self) -> ~str {
- match *self {
- ErrFdNotAvail => ~"fd not available for reading or writing",
- ErrInvalidFd => ~"Invalid fd",
- ErrUnaligned => ~"Unaligned address, invalid flags, \
- negative length or unaligned offset",
- ErrNoMapSupport=> ~"File doesn't support mapping",
- ErrNoMem => ~"Invalid address, or not enough available memory",
- ErrUnknown(code) => format!("Unknown error={}", code),
- ErrUnsupProt => ~"Protection mode unsupported",
- ErrUnsupOffset => ~"Offset in virtual memory mode is unsupported",
- ErrAlreadyExists => ~"File mapping for specified file already exists",
- ErrVirtualAlloc(code) => format!("VirtualAlloc failure={}", code),
- ErrCreateFileMappingW(code) => format!("CreateFileMappingW failure={}", code),
- ErrMapViewOfFile(code) => format!("MapViewOfFile failure={}", code)
- }
+impl fmt::Default for MapError {
+ fn fmt(val: &MapError, out: &mut fmt::Formatter) {
+ let str = match *val {
+ ErrFdNotAvail => "fd not available for reading or writing",
+ ErrInvalidFd => "Invalid fd",
+ ErrUnaligned => {
+ "Unaligned address, invalid flags, negative length or \
+ unaligned offset"
+ }
+ ErrNoMapSupport=> "File doesn't support mapping",
+ ErrNoMem => "Invalid address, or not enough available memory",
+ ErrUnsupProt => "Protection mode unsupported",
+ ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
+ ErrAlreadyExists => "File mapping for specified file already exists",
+ ErrZeroLength => "Zero-length mapping not allowed",
+ ErrUnknown(code) => {
+ write!(out.buf, "Unknown error = {}", code);
+ return
+ },
+ ErrVirtualAlloc(code) => {
+ write!(out.buf, "VirtualAlloc failure = {}", code);
+ return
+ },
+ ErrCreateFileMappingW(code) => {
+ format!("CreateFileMappingW failure = {}", code);
+ return
+ },
+ ErrMapViewOfFile(code) => {
+ write!(out.buf, "MapViewOfFile failure = {}", code);
+ return
+ }
+ };
+ write!(out.buf, "{}", str);
}
}
#[cfg(unix)]
impl MemoryMap {
- /// Create a new mapping with the given `options`, at least `min_len` bytes long.
+ /// Create a new mapping with the given `options`, at least `min_len` bytes
+ /// long. `min_len` must be greater than zero; see the note on
+ /// `ErrZeroLength`.
pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
use libc::off_t;
+ if min_len == 0 {
+ return Err(ErrZeroLength)
+ }
let mut addr: *u8 = ptr::null();
let mut prot = 0;
let mut flags = libc::MAP_PRIVATE;
let mut fd = -1;
let mut offset = 0;
+ let mut custom_flags = false;
let len = round_up(min_len, page_size());
for &o in options.iter() {
flags |= libc::MAP_FILE;
fd = fd_;
},
- MapOffset(offset_) => { offset = offset_ as off_t; }
+ MapOffset(offset_) => { offset = offset_ as off_t; },
+ MapNonStandardFlags(f) => { custom_flags = true; flags = f },
}
}
- if fd == -1 { flags |= libc::MAP_ANON; }
+ if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
let r = unsafe {
- libc::mmap(addr as *c_void, len as size_t, prot, flags, fd, offset)
+ libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
+ offset)
};
if r.equiv(&libc::MAP_FAILED) {
Err(match errno() as c_int {
}
}
- /// Granularity that the offset or address must be for `MapOffset` and `MapAddr` respectively.
+ /// Granularity that the offset or address must be for `MapOffset` and
+ /// `MapAddr` respectively.
pub fn granularity() -> uint {
page_size()
}
impl Drop for MemoryMap {
/// Unmap the mapping. Fails the task if `munmap` fails.
fn drop(&mut self) {
+ if self.len == 0 { /* workaround for dummy_stack */ return; }
+
unsafe {
match libc::munmap(self.data as *c_void, self.len as libc::size_t) {
0 => (),
MapExecutable => { executable = true; }
MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
MapFd(fd_) => { fd = fd_; },
- MapOffset(offset_) => { offset = offset_; }
+ MapOffset(offset_) => { offset = offset_; },
+ MapNonStandardFlags(f) => {
+ info!("MemoryMap::new: MapNonStandardFlags used on \
+ Windows: {}", f)
+ }
}
}
#[cfg(windows)]
impl Drop for MemoryMap {
- /// Unmap the mapping. Fails the task if any of `VirtualFree`, `UnmapViewOfFile`, or
- /// `CloseHandle` fail.
+ /// Unmap the mapping. Fails the task if any of `VirtualFree`,
+ /// `UnmapViewOfFile`, or `CloseHandle` fail.
fn drop(&mut self) {
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
use libc::consts::os::extra::FALSE;
+ if self.len == 0 { return }
unsafe {
match self.kind {
MapVirtual => {
- if libc::VirtualFree(self.data as *mut c_void,
- self.len as size_t,
- libc::MEM_RELEASE) == FALSE {
+ if libc::VirtualFree(self.data as *mut c_void, 0,
+ libc::MEM_RELEASE) == 0 {
error!("VirtualFree failed: {}", errno());
}
},
assert_eq!(getenv(n), option::Some(s));
}
+ #[test]
+ fn test_self_exe_name() {
+ let path = os::self_exe_name();
+ assert!(path.is_some());
+ let path = path.unwrap();
+ debug!("{:?}", path.clone());
+
+ // Hard to test this function
+ assert!(path.is_absolute());
+ }
+
#[test]
fn test_self_exe_path() {
let path = os::self_exe_path();
os::MapWritable
]) {
Ok(chunk) => chunk,
- Err(msg) => fail!(msg.to_str())
+ Err(msg) => fail!("{}", msg)
};
assert!(chunk.len >= 16);
MapOffset(size / 2)
]) {
Ok(chunk) => chunk,
- Err(msg) => fail!(msg.to_str())
+ Err(msg) => fail!("{}", msg)
};
assert!(chunk.len > 0);
use str::{OwnedStr, Str, StrSlice};
use to_str::ToStr;
use vec;
-use vec::{CopyableVector, OwnedCopyableVector, OwnedVector, Vector};
+use vec::{CloneableVector, OwnedCloneableVector, OwnedVector, Vector};
use vec::{ImmutableEqVector, ImmutableVector};
/// Typedef for POSIX file paths.
use str::Str;
use to_bytes::IterBytes;
use vec;
-use vec::{CopyableVector, RevSplits, Splits, Vector, VectorVector,
- ImmutableEqVector, OwnedVector, ImmutableVector, OwnedCopyableVector};
+use vec::{CloneableVector, RevSplits, Splits, Vector, VectorVector,
+ ImmutableEqVector, OwnedVector, ImmutableVector, OwnedCloneableVector};
use super::{BytesContainer, GenericPath, GenericPathUnsafe};
/// Iterator that yields successive components of a Path as &[u8]
/// Returns a normalized byte vector representation of a path, by removing all empty
/// components, and unnecessary . and .. components.
- fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
+ fn normalize<V: Vector<u8>+CloneableVector<u8>>(v: V) -> ~[u8] {
// borrowck is being very picky
let val = {
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
use task;
macro_rules! t(
- ($name:expr => $code:block) => (
+ ($name:expr => $code:expr) => (
{
let mut t = task::task();
t.name($name);
- let res = do t.try $code;
+ let res = t.try(proc() $code);
assert!(res.is_err());
}
)
use task;
macro_rules! t(
- ($name:expr => $code:block) => (
+ ($name:expr => $code:expr) => (
{
let mut t = task::task();
t.name($name);
- let res = do t.try $code;
+ let res = t.try(proc() $code);
assert!(res.is_err());
}
)
pub use iter::{FromIterator, Extendable};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
-pub use num::Times;
pub use num::{Integer, Real, Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Orderable, Signed, Unsigned, Round};
pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
pub use str::{Str, StrVector, StrSlice, OwnedStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, IntoStr};
-pub use tuple::{CopyableTuple, ImmutableTuple};
+pub use tuple::{CloneableTuple, ImmutableTuple};
pub use tuple::{ImmutableTuple1, ImmutableTuple2, ImmutableTuple3, ImmutableTuple4};
pub use tuple::{ImmutableTuple5, ImmutableTuple6, ImmutableTuple7, ImmutableTuple8};
pub use tuple::{ImmutableTuple9, ImmutableTuple10, ImmutableTuple11, ImmutableTuple12};
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
-pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCopyableVector};
-pub use vec::{OwnedVector, OwnedCopyableVector,OwnedEqVector};
+pub use vec::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCloneableVector};
+pub use vec::{OwnedVector, OwnedCloneableVector,OwnedEqVector};
pub use vec::{MutableVector, MutableTotalOrdVector};
-pub use vec::{Vector, VectorVector, CopyableVector, ImmutableVector};
+pub use vec::{Vector, VectorVector, CloneableVector, ImmutableVector};
// Reexported runtime types
pub use comm::{Port, Chan, SharedChan};
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
-// XXX maybe having this separate is overkill (the only reason is to
+// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
use rand::{Rng, SeedableRng, OSRng};
use iter::{Iterator, range, range_step, Repeat};
-use num::Times;
use option::{None, Some};
use vec::{raw, MutableVector, ImmutableVector};
use mem;
}}
);
- 4.times(|| mix!());
+ for _ in range(0, 4) { mix!(); }
if use_rsl {
macro_rules! memloop (
for _ in range(0, 20) {
let (p, c) = Chan::new();
chans.push(c);
- do task::spawn {
+ task::spawn(proc() {
// wait until all the tasks are ready to go.
p.recv();
r.fill_bytes(v);
task::deschedule();
}
- }
+ })
}
// start all the tasks
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
impl Rand for int {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> int {
- if int::bits == 32 {
+ if int::BITS == 32 {
rng.gen::<i32>() as int
} else {
rng.gen::<i64>() as int
impl Rand for uint {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> uint {
- if uint::bits == 32 {
+ if uint::BITS == 32 {
rng.gen::<u32>() as uint
} else {
rng.gen::<u64>() as uint
--- /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.
+
+//! Utilities for references
+
+#[cfg(not(test))]
+use prelude::*;
+
+// Equality for region pointers
+#[cfg(not(test))]
+impl<'a, T: Eq> Eq for &'a T {
+ #[inline]
+ fn eq(&self, other: & &'a T) -> bool {
+ *(*self) == *(*other)
+ }
+ #[inline]
+ fn ne(&self, other: & &'a T) -> bool {
+ *(*self) != *(*other)
+ }
+}
+
+// Comparison for region pointers
+#[cfg(not(test))]
+impl<'a, T: Ord> Ord for &'a T {
+ #[inline]
+ fn lt(&self, other: & &'a T) -> bool {
+ *(*self) < *(*other)
+ }
+ #[inline]
+ fn le(&self, other: & &'a T) -> bool {
+ *(*self) <= *(*other)
+ }
+ #[inline]
+ fn ge(&self, other: & &'a T) -> bool {
+ *(*self) >= *(*other)
+ }
+ #[inline]
+ fn gt(&self, other: & &'a T) -> bool {
+ *(*self) > *(*other)
+ }
+}
+
+#[cfg(not(test))]
+impl<'a, T: TotalOrd> TotalOrd for &'a T {
+ #[inline]
+ fn cmp(&self, other: & &'a T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<'a, T: TotalEq> TotalEq for &'a T {
+ #[inline]
+ fn equals(&self, other: & &'a T) -> bool { (**self).equals(*other) }
+}
+
true
}
- fn visit_opaque_box(&mut self) -> bool {
- self.align_to::<@u8>();
- if ! self.inner.visit_opaque_box() { return false; }
- self.bump_past::<@u8>();
- true
- }
-
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, ck: uint) -> bool {
self.align_to::<proc()>();
if ! self.inner.visit_closure_ptr(ck) {
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool {
- self.writer.write(['@' as u8]);
- self.get::<&raw::Box<()>>(|this, b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *u8;
- this.visit_ptr_inner(p, b.type_desc);
- })
- }
-
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
#[deriving(Clone, DeepClone, Eq, Ord, TotalEq, TotalOrd, ToStr)]
+#[must_use]
pub enum Result<T, E> {
/// Contains the success value
Ok(T),
/// checking for overflow:
///
/// fn inc_conditionally(x: uint) -> Result<uint, &'static str> {
-/// if x == uint::max_value { return Err("overflow"); }
+/// if x == uint::MAX { return Err("overflow"); }
/// else { return Ok(x+1u); }
/// }
/// let v = [1u, 2, 3];
/// Iterates recursively over `crate_map` and all child crate maps
pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: |&ModEntry|) {
- // XXX: use random numbers as keys from the OS-level RNG when there is a nice
+ // FIXME: use random numbers as keys from the OS-level RNG when there is a nice
// way to do this
let mut v: HashSet<*CrateMap<'a>> = HashSet::with_capacity_and_keys(0, 0, 32);
do_iter_crate_map(crate_map, f, &mut v);
//! Runtime environment settings
-use from_str::FromStr;
+use from_str::from_str;
use option::{Some, None};
use os;
// They are expected to be initialized once then left alone.
static mut MIN_STACK: uint = 2 * 1024 * 1024;
+/// This default corresponds to 20M of cache per scheduler (at the default size).
+static mut MAX_CACHED_STACKS: uint = 10;
static mut DEBUG_BORROW: bool = false;
static mut POISON_ON_FREE: bool = false;
pub fn init() {
unsafe {
match os::getenv("RUST_MIN_STACK") {
- Some(s) => match FromStr::from_str(s) {
+ Some(s) => match from_str(s) {
Some(i) => MIN_STACK = i,
None => ()
},
None => ()
}
+ match os::getenv("RUST_MAX_CACHED_STACKS") {
+ Some(max) => MAX_CACHED_STACKS = from_str(max).expect("expected positive integer in \
+ RUST_MAX_CACHED_STACKS"),
+ None => ()
+ }
match os::getenv("RUST_DEBUG_BORROW") {
Some(_) => DEBUG_BORROW = true,
None => ()
unsafe { MIN_STACK }
}
+pub fn max_cached_stacks() -> uint {
+ unsafe { MAX_CACHED_STACKS }
+}
+
pub fn debug_borrow() -> bool {
unsafe { DEBUG_BORROW }
}
#[test]
fn thread_local_task_smoke_test() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let task = ~Task::new();
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
- }
+ });
}
#[test]
fn thread_local_task_two_instances() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let task = ~Task::new();
Local::put(task);
let task: ~Task = Local::take();
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
- }
-
+ });
}
#[test]
fn borrow_smoke_test() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let task = ~Task::new();
Local::put(task);
}
let task: ~Task = Local::take();
cleanup_task(task);
- }
+ });
}
#[test]
fn borrow_with_return() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let task = ~Task::new();
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
- }
+ });
}
#[test]
fn try_take() {
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
let task = ~Task::new();
Local::put(task);
assert!(u.is_none());
cleanup_task(t);
- }
+ });
}
fn cleanup_task(mut t: ~Task) {
#[inline]
pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
- // XXX: Unsafe borrow for speed. Lame.
+ // FIXME: Unsafe borrow for speed. Lame.
let task: Option<*mut Task> = Local::try_unsafe_borrow();
match task {
Some(task) => {
// A little compatibility function
#[inline]
pub unsafe fn local_free(ptr: *u8) {
- // XXX: Unsafe borrow for speed. Lame.
+ // FIXME: Unsafe borrow for speed. Lame.
let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
match task_ptr {
Some(task) => {
Several modules in `core` are clients of `rt`:
* `std::task` - The user-facing interface to the Rust task model.
-* `std::task::local_data` - The interface to local data.
+* `std::local_data` - The interface to local data.
* `std::gc` - The garbage collector.
* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
* `std::condition` - Uses local data.
* `std::cleanup` - Local heap destruction.
* `std::io` - In the future `std::io` will use an `rt` implementation.
* `std::logging`
-* `std::pipes`
* `std::comm`
-* `std::stackwalk`
*/
-// XXX: this should not be here.
+// FIXME: this should not be here.
#[allow(missing_doc)];
use any::Any;
pub use self::util::default_sched_threads;
// Export unwinding facilities used by the failure macros
-pub use self::unwind::{begin_unwind, begin_unwind_raw};
+pub use self::unwind::{begin_unwind, begin_unwind_raw, begin_unwind_fmt};
-// XXX: these probably shouldn't be public...
+// FIXME: these probably shouldn't be public...
#[doc(hidden)]
pub mod shouldnt_be_public {
pub use super::local_ptr::native::maybe_tls_key;
/// The (low, high) edges of the current stack.
fn stack_bounds(&self) -> (uint, uint); // (lo, hi)
- // XXX: This is a serious code smell and this should not exist at all.
+ // FIXME: This is a serious code smell and this should not exist at all.
fn wrap(~self) -> ~Any;
}
/// the crate's logging flags, registering GC
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: **u8) {
- // XXX: Derefing these pointers is not safe.
+ // FIXME: Derefing these pointers is not safe.
// Need to propagate the unsafety to `start`.
unsafe {
args::init(argc, argv);
#[unsafe_destructor]
impl<'a> Drop for LocalIo<'a> {
fn drop(&mut self) {
- // XXX(pcwalton): Do nothing here for now, but eventually we may want
+ // FIXME(pcwalton): Do nothing here for now, but eventually we may want
// something. For now this serves to make `LocalIo` noncopyable.
}
}
/// Returns the underlying I/O factory as a trait reference.
#[inline]
pub fn get<'a>(&'a mut self) -> &'a mut IoFactory {
- // XXX(pcwalton): I think this is actually sound? Could borrow check
+ // FIXME(pcwalton): I think this is actually sound? Could borrow check
// allow this safely?
unsafe {
cast::transmute_copy(&self.factory)
//! to implement this.
use any::AnyOwnExt;
-use borrow;
use cast;
use cleanup;
use clone::Clone;
// pretty sketchy and involves shuffling vtables of trait objects
// around, but it gets the job done.
//
- // XXX: This function is a serious code smell and should be avoided at
+ // FIXME: This function is a serious code smell and should be avoided at
// all costs. I have yet to think of a method to avoid this
// function, and I would be saddened if more usage of the function
// crops up.
impl Drop for Task {
fn drop(&mut self) {
- rtdebug!("called drop for a task: {}", borrow::to_uint(self));
+ rtdebug!("called drop for a task: {}", self as *mut Task as uint);
rtassert!(self.destroyed);
}
}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
extern fn thread_start(main: *libc::c_void) -> imp::rust_thread_return {
use unstable::stack;
unsafe {
- stack::record_stack_bounds(0, uint::max_value);
+ stack::record_stack_bounds(0, uint::MAX);
let f: ~proc() = cast::transmute(main);
(*f)();
cast::transmute(0 as imp::rust_thread_return)
use super::Thread;
#[test]
- fn smoke() { do Thread::start {}.join(); }
+ fn smoke() { Thread::start(proc (){}).join(); }
#[test]
- fn data() { assert_eq!(do Thread::start { 1 }.join(), 1); }
+ fn data() { assert_eq!(Thread::start(proc () { 1 }).join(), 1); }
#[test]
- fn detached() { do Thread::spawn {} }
+ fn detached() { Thread::spawn(proc () {}) }
}
use any::{Any, AnyRefExt};
use c_str::CString;
use cast;
+use fmt;
use kinds::Send;
use option::{Some, None, Option};
use prelude::drop;
begin_unwind(msg, file, line as uint)
}
+/// The entry point for unwinding with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `fail!()` has as low an implact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[inline(never)] #[cold]
+pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! {
+ // We do two allocations here, unfortunately. But (a) they're
+ // required with the current scheme, and (b) we don't handle
+ // failure + OOM properly anyway (see comment in begin_unwind
+ // below).
+ begin_unwind_inner(~fmt::format(msg), file, line)
+}
+
/// This is the entry point of unwinding for fail!() and assert!().
-#[inline(never)] #[cold] // this is the slow path, please never inline this
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
- // Note that this should be the only allocation performed in this block.
+ // Note that this should be the only allocation performed in this code path.
// Currently this means that fail!() on OOM will invoke this code path,
// but then again we're not really ready for failing on OOM anyway. If
// we do start doing this, then we should propagate this allocation to
// be performed in the parent of this task instead of the task that's
// failing.
- let msg = ~msg as ~Any;
+ // see below for why we do the `Any` coercion here.
+ begin_unwind_inner(~msg, file, line)
+}
+
+
+/// The core of the unwinding.
+///
+/// This is non-generic to avoid instantiation bloat in other crates
+/// (which makes compilation of small crates noticably slower). (Note:
+/// we need the `Any` object anyway, we're not just creating it to
+/// avoid being generic.)
+///
+/// Do this split took the LLVM IR line counts of `fn main() { fail!()
+/// }` from ~1900/3700 (-O/no opts) to 180/590.
+#[inline(never)] #[cold] // this is the slow path, please never inline this
+fn begin_unwind_inner(msg: ~Any, file: &'static str, line: uint) -> ! {
let mut task;
{
let msg_s = match msg.as_ref::<&'static str>() {
use vec::ImmutableVector;
// Indicates whether we should perform expensive sanity checks, including rtassert!
-// XXX: Once the runtime matures remove the `true` below to turn off rtassert, etc.
+// FIXME: Once the runtime matures remove the `true` below to turn off rtassert, etc.
pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert);
/// Get the number of cores available
let (p, ch) = SharedChan::new();
let ch_clone = ch.clone();
- do spawn {
+ spawn(proc() {
let _guard = io::ignore_io_error();
let mut error = error;
match error {
Some(ref mut e) => ch.send((2, e.read_to_end())),
None => ch.send((2, ~[]))
}
- }
- do spawn {
+ });
+ spawn(proc() {
let _guard = io::ignore_io_error();
let mut output = output;
match output {
Some(ref mut e) => ch_clone.send((1, e.read_to_end())),
None => ch_clone.send((1, ~[]))
}
- }
+ });
let status = self.finish();
os::close(pipe_out.out as int);
os::close(pipe_err.out as int);
- do spawn {
+ spawn(proc() {
writeclose(pipe_in.out, "test");
- }
+ });
let actual = readclose(pipe_out.input);
readclose(pipe_err.input);
process.finish();
fn as_slice<'r>(&'r self) -> &'r str {
match *self {
SendStrOwned(ref s) => s.as_slice(),
- // XXX: Borrowchecker doesn't recognize lifetime as static unless prompted
+ // FIXME: Borrowchecker doesn't recognize lifetime as static unless prompted
// SendStrStatic(s) => s.as_slice()
SendStrStatic(s) => {let tmp: &'static str = s; tmp}
}
use from_str::FromStr;
use uint;
use vec;
-use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
+use vec::{OwnedVector, OwnedCloneableVector, ImmutableVector, MutableVector};
use default::Default;
use send_str::{SendStr, SendStrOwned};
use unstable::raw::Repr;
// Helper functions used for Unicode normalization
fn canonical_sort(comb: &mut [(char, u8)]) {
use iter::range;
- use tuple::CopyableTuple;
+ use tuple::CloneableTuple;
let len = comb.len();
for i in range(0, len) {
/// External iterator for a string's normalization's characters.
/// Use with the `std::iter` module.
#[deriving(Clone)]
-struct Normalizations<'a> {
+pub struct Normalizations<'a> {
priv kind: NormalizationForm,
priv iter: Chars<'a>,
priv buffer: ~[(char, u8)],
// NB: the "buffer pool" strategy is not done for speed, but rather for
// correctness. For more info, see the comment on `swap_buffer`
-// XXX: all atomic operations in this module use a SeqCst ordering. That is
+// FIXME: all atomic operations in this module use a SeqCst ordering. That is
// probably overkill
use cast;
static AMT: int = 100000;
let mut pool = BufferPool::<int>::new();
let (mut w, s) = pool.deque();
- let t = do Thread::start {
+ let t = Thread::start(proc() {
let mut s = s;
let mut left = AMT;
while left > 0 {
Abort | Empty => {}
}
}
- };
+ });
for _ in range(0, AMT) {
w.push(1);
static AMT: int = 100000;
let mut pool = BufferPool::<(int, int)>::new();
let (mut w, s) = pool.deque();
- let t = do Thread::start {
+ let t = Thread::start(proc() {
let mut s = s;
let mut left = AMT;
while left > 0 {
Abort | Empty => {}
}
}
- };
+ });
for _ in range(0, AMT) {
w.push((1, 10));
let threads = range(0, nthreads).map(|_| {
let s = s.clone();
- do Thread::start {
+ Thread::start(proc() {
unsafe {
let mut s = s;
while (*unsafe_remaining).load(SeqCst) > 0 {
}
}
}
- }
+ })
}).to_owned_vec();
while remaining.load(SeqCst) > 0 {
let mut pool = BufferPool::<~int>::new();
let threads = range(0, AMT).map(|_| {
let (w, s) = pool.deque();
- do Thread::start {
+ Thread::start(proc() {
stampede(w, s, 4, 10000);
- }
+ })
}).to_owned_vec();
for thread in threads.move_iter() {
let threads = range(0, NTHREADS).map(|_| {
let s = s.clone();
- do Thread::start {
+ Thread::start(proc() {
unsafe {
let mut s = s;
loop {
}
}
}
- }
+ })
}).to_owned_vec();
let mut rng = rand::task_rng();
let thread_box = unsafe {
*cast::transmute::<&~AtomicUint,**mut AtomicUint>(&unique_box)
};
- (do Thread::start {
+ (Thread::start(proc() {
unsafe {
let mut s = s;
loop {
}
}
}
- }, unique_box)
+ }), unique_box)
}));
let mut rng = rand::task_rng();
for _ in range(0, nthreads) {
let q = q.clone();
let chan = chan.clone();
- do native::task::spawn {
+ native::task::spawn(proc() {
let mut q = q;
for i in range(0, nmsgs) {
assert!(q.push(i));
}
chan.send(());
- }
+ });
}
let mut completion_ports = ~[];
let (completion_port, completion_chan) = Chan::new();
completion_ports.push(completion_port);
let q = q.clone();
- do native::task::spawn {
+ native::task::spawn(proc() {
let mut q = q;
let mut i = 0u;
loop {
}
}
completion_chan.send(i);
- }
+ });
}
for completion_port in completion_ports.mut_iter() {
for _ in range(0, nthreads) {
let q = p.clone();
let chan = chan.clone();
- do native::task::spawn {
+ native::task::spawn(proc() {
let mut q = q;
for i in range(0, nmsgs) {
q.push(i);
}
chan.send(());
- }
+ });
}
let mut i = 0u;
// Node within the linked list queue of messages to send
struct Node<T> {
- // XXX: this could be an uninitialized T if we're careful enough, and
+ // FIXME: this could be an uninitialized T if we're careful enough, and
// that would reduce memory usage (and be a bit faster).
// is it worth it?
value: Option<T>, // nullable for re-use of nodes
if self.cache_bound == 0 {
self.tail_prev.store(tail, Release);
} else {
- // XXX: this is dubious with overflow.
+ // FIXME: this is dubious with overflow.
let additions = self.cache_additions.load(Relaxed);
let subtractions = self.cache_subtractions.load(Relaxed);
let size = additions - subtractions;
fn stress_bound(bound: uint) {
let (c, mut p) = queue(bound, ());
let (port, chan) = Chan::new();
- do native::task::spawn {
+ native::task::spawn(proc() {
let mut c = c;
for _ in range(0, 100000) {
loop {
}
}
chan.send(());
- }
+ });
for _ in range(0, 100000) {
p.push(1);
}
* # Example
*
* ```
- * do spawn {
+ * spawn(proc() {
* log(error, "Hello, World!");
- * }
+ * })
* ```
*/
let result = self.future_result();
- do self.spawn {
+ self.spawn(proc() {
ch.send(f());
- }
+ });
match result.recv() {
Ok(()) => Ok(po.recv()),
#[test]
fn test_unnamed_task() {
- do spawn {
+ spawn(proc() {
with_task_name(|name| {
assert!(name.is_none());
})
- }
+ })
}
#[test]
fn test_owned_named_task() {
let mut t = task();
t.name(~"ada lovelace");
- do t.spawn {
+ t.spawn(proc() {
with_task_name(|name| {
assert!(name.unwrap() == "ada lovelace");
})
- }
+ })
}
#[test]
fn test_static_named_task() {
let mut t = task();
t.name("ada lovelace");
- do t.spawn {
+ t.spawn(proc() {
with_task_name(|name| {
assert!(name.unwrap() == "ada lovelace");
})
- }
+ })
}
#[test]
fn test_send_named_task() {
let mut t = task();
t.name("ada lovelace".into_send_str());
- do t.spawn {
+ t.spawn(proc() {
with_task_name(|name| {
assert!(name.unwrap() == "ada lovelace");
})
- }
+ })
}
#[test]
fn test_run_basic() {
let (po, ch) = Chan::new();
- do task().spawn {
+ task().spawn(proc() {
ch.send(());
- }
+ });
po.recv();
}
fn test_add_wrapper() {
let (po, ch) = Chan::new();
let mut b0 = task();
- do b0.add_wrapper |body| {
+ b0.add_wrapper(proc(body) {
let ch = ch;
let result: proc() = proc() {
body();
ch.send(());
};
result
- };
- do b0.spawn { }
+ });
+ b0.spawn(proc() { });
po.recv();
}
fn test_future_result() {
let mut builder = task();
let result = builder.future_result();
- do builder.spawn {}
+ builder.spawn(proc() {});
assert!(result.recv().is_ok());
let mut builder = task();
let result = builder.future_result();
- do builder.spawn {
+ builder.spawn(proc() {
fail!();
- }
+ });
assert!(result.recv().is_err());
}
#[test]
fn test_try_success() {
- match do try {
+ match try(proc() {
~"Success!"
- } {
+ }) {
result::Ok(~"Success!") => (),
_ => fail!()
}
#[test]
fn test_try_fail() {
- match do try {
+ match try(proc() {
fail!()
- } {
+ }) {
result::Err(_) => (),
result::Ok(()) => fail!()
}
fn f(i: int, ch: SharedChan<()>) {
let ch = ch.clone();
- do spawn {
+ spawn(proc() {
if i == 0 {
ch.send(());
} else {
f(i - 1, ch);
}
- };
+ });
}
f(10, ch);
fn test_spawn_sched_childs_on_default_sched() {
let (po, ch) = Chan::new();
- do spawn {
+ spawn(proc() {
let ch = ch;
- do spawn {
+ spawn(proc() {
ch.send(());
- };
- };
+ });
+ });
po.recv();
}
let x = ~1;
let x_in_parent = ptr::to_unsafe_ptr(&*x) as uint;
- do spawnfn {
+ spawnfn(proc() {
let x_in_child = ptr::to_unsafe_ptr(&*x) as uint;
ch.send(x_in_child);
- }
+ });
let x_in_child = p.recv();
assert_eq!(x_in_parent, x_in_child);
fn test_avoid_copying_the_body_task_spawn() {
avoid_copying_the_body(|f| {
let builder = task();
- do builder.spawn || {
+ builder.spawn(proc() {
f();
- }
+ });
})
}
#[test]
fn test_avoid_copying_the_body_try() {
avoid_copying_the_body(|f| {
- do try || {
+ try(proc() {
f()
- };
+ });
})
}
#[test]
fn test_try_fail_message_static_str() {
- match do try {
+ match try(proc() {
fail!("static string");
- } {
+ }) {
Err(e) => {
type T = &'static str;
assert!(e.is::<T>());
#[test]
fn test_try_fail_message_owned_str() {
- match do try {
+ match try(proc() {
fail!(~"owned string");
- } {
+ }) {
Err(e) => {
type T = ~str;
assert!(e.is::<T>());
#[test]
fn test_try_fail_message_any() {
- match do try {
+ match try(proc() {
fail!(~413u16 as ~Any);
- } {
+ }) {
Err(e) => {
type T = ~Any;
assert!(e.is::<T>());
fn test_try_fail_message_unit_struct() {
struct Juju;
- match do try {
+ match try(proc() {
fail!(Juju)
- } {
+ }) {
Err(ref e) if e.is::<Juju>() => {}
Err(_) | Ok(()) => fail!()
}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
static SHIFT: uint = 4;
static SIZE: uint = 1 << SHIFT;
static MASK: uint = SIZE - 1;
-static NUM_CHUNKS: uint = uint::bits / SHIFT;
+static NUM_CHUNKS: uint = uint::BITS / SHIFT;
enum Child<T> {
Internal(~TrieNode<T>),
// if this was done via a trait, the key could be generic
#[inline]
fn chunk(n: uint, idx: uint) -> uint {
- let sh = uint::bits - (SHIFT * (idx + 1));
+ let sh = uint::BITS - (SHIFT * (idx + 1));
(n >> sh) & MASK
}
fn test_each_reverse_break() {
let mut m = TrieMap::new();
- for x in range(uint::max_value - 10000, uint::max_value).rev() {
+ for x in range(uint::MAX - 10000, uint::MAX).rev() {
m.insert(x, x / 2);
}
- let mut n = uint::max_value - 1;
+ let mut n = uint::MAX - 1;
m.each_reverse(|k, v| {
- if n == uint::max_value - 5000 { false } else {
- assert!(n > uint::max_value - 5000);
+ if n == uint::MAX - 5000 { false } else {
+ assert!(n > uint::MAX - 5000);
assert_eq!(*k, n);
assert_eq!(*v, n / 2);
let empty_map : TrieMap<uint> = TrieMap::new();
assert_eq!(empty_map.iter().next(), None);
- let first = uint::max_value - 10000;
- let last = uint::max_value;
+ let first = uint::MAX - 10000;
+ let last = uint::MAX;
let mut map = TrieMap::new();
for x in range(first, last).rev() {
let mut empty_map : TrieMap<uint> = TrieMap::new();
assert!(empty_map.mut_iter().next().is_none());
- let first = uint::max_value - 10000;
- let last = uint::max_value;
+ let first = uint::MAX - 10000;
+ let last = uint::MAX;
let mut map = TrieMap::new();
for x in range(first, last).rev() {
#[test]
fn test_sane_chunk() {
let x = 1;
- let y = 1 << (uint::bits - 1);
+ let y = 1 << (uint::BITS - 1);
let mut trie = TrieSet::new();
#[cfg(not(test))] use default::Default;
/// Method extensions to pairs where both types satisfy the `Clone` bound
-pub trait CopyableTuple<T, U> {
+pub trait CloneableTuple<T, U> {
/// Return the first element of self
fn first(&self) -> T;
/// Return the second element of self
fn swap(&self) -> (U, T);
}
-impl<T:Clone,U:Clone> CopyableTuple<T, U> for (T, U) {
+impl<T:Clone,U:Clone> CloneableTuple<T, U> for (T, U) {
/// Return the first element of self
#[inline]
fn first(&self) -> T {
align: uint,
// Called on a copy of a value of type `T` *after* memcpy
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
take_glue: GlueFn,
// Called when a value of type `T` is no longer needed
fn visit_param(&mut self, i: uint) -> bool;
fn visit_self(&mut self) -> bool;
fn visit_type(&mut self) -> bool;
- fn visit_opaque_box(&mut self) -> bool;
+
+ // NOTE remove after next snapshot
+ #[cfg(stage0)]
fn visit_closure_ptr(&mut self, ck: uint) -> bool;
}
#[test]
fn test_run_in_bare_thread() {
let i = 100;
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
assert_eq!(i, 100);
- }
+ });
}
#[test]
fn test_run_in_bare_thread_exchange() {
// Does the exchange heap work without the runtime?
let i = ~100;
- do run_in_bare_thread {
+ run_in_bare_thread(proc() {
assert!(i == ~100);
- }
+ });
}
/// Dynamically inquire about whether we're running under V.
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
let prev = self.cnt.fetch_add(1, atomics::SeqCst);
if prev < 0 {
- // Make sure we never overflow, we'll never have int::min_value
+ // Make sure we never overflow, we'll never have int::MIN
// simultaneous calls to `doit` to make this value go back to 0
- self.cnt.store(int::min_value, atomics::SeqCst);
+ self.cnt.store(int::MIN, atomics::SeqCst);
return
}
unsafe { self.mutex.lock() }
if self.cnt.load(atomics::SeqCst) > 0 {
f();
- let prev = self.cnt.swap(int::min_value, atomics::SeqCst);
+ let prev = self.cnt.swap(int::MIN, atomics::SeqCst);
self.lock_cnt.store(prev, atomics::SeqCst);
}
unsafe { self.mutex.unlock() }
let (p, c) = SharedChan::new();
for _ in range(0, 10) {
let c = c.clone();
- do spawn {
+ spawn(proc() {
for _ in range(0, 4) { task::deschedule() }
unsafe {
o.doit(|| {
assert!(run);
}
c.send(());
- }
+ });
}
unsafe {
static mut lock: Mutex = MUTEX_INIT;
unsafe {
lock.lock();
- let t = do Thread::start {
+ let t = Thread::start(proc() {
lock.lock();
lock.signal();
lock.unlock();
- };
+ });
lock.wait();
lock.unlock();
t.join();
#[allow(non_camel_case_types)];
+#[experimental]
#[simd]
pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
+#[experimental]
#[simd]
pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
+#[experimental]
#[simd]
pub struct i32x4(i32, i32, i32, i32);
+#[experimental]
#[simd]
pub struct i64x2(i64, i64);
+#[experimental]
#[simd]
pub struct u8x16(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
+#[experimental]
#[simd]
pub struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16);
+#[experimental]
#[simd]
pub struct u32x4(u32, u32, u32, u32);
+#[experimental]
#[simd]
pub struct u64x2(u64, u64);
+#[experimental]
#[simd]
pub struct f32x4(f32, f32, f32, f32);
+#[experimental]
#[simd]
pub struct f64x2(f64, f64);
let (port, chan) = Chan::new();
futures.push(port);
- do task::spawn {
+ task::spawn(proc() {
for _ in range(0u, count) {
total.with(|count| **count += 1);
}
chan.send(());
- }
+ });
};
for f in futures.mut_iter() { f.recv() }
// accesses will also fail.
let x = Exclusive::new(1);
let x2 = x.clone();
- do task::try || {
+ task::try(proc() {
x2.with(|one| assert_eq!(*one, 2))
- };
+ });
x.with(|one| assert_eq!(*one, 1));
}
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
}
}
-/// Extension methods for vector slices with copyable elements
-pub trait CopyableVector<T> {
+/// Extension methods for vector slices with cloneable elements
+pub trait CloneableVector<T> {
/// Copy `self` into a new owned vector
fn to_owned(&self) -> ~[T];
}
/// Extension methods for vector slices
-impl<'a, T: Clone> CopyableVector<T> for &'a [T] {
+impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
/// Returns a copy of `v`.
#[inline]
fn to_owned(&self) -> ~[T] {
}
/// Extension methods for owned vectors
-impl<T: Clone> CopyableVector<T> for ~[T] {
+impl<T: Clone> CloneableVector<T> for ~[T] {
#[inline]
fn to_owned(&self) -> ~[T] { self.clone() }
}
/// Extension methods for managed vectors
-impl<T: Clone> CopyableVector<T> for @[T] {
+impl<T: Clone> CloneableVector<T> for @[T] {
#[inline]
fn to_owned(&self) -> ~[T] { self.as_slice().to_owned() }
#[inline]
fn split(self, pred: 'a |&T| -> bool) -> Splits<'a, T> {
- self.splitn(uint::max_value, pred)
+ self.splitn(uint::MAX, pred)
}
#[inline]
#[inline]
fn rsplit(self, pred: 'a |&T| -> bool) -> RevSplits<'a, T> {
- self.rsplitn(uint::max_value, pred)
+ self.rsplitn(uint::MAX, pred)
}
#[inline]
}
/// Extension methods for vectors containing `Clone` elements.
-pub trait ImmutableCopyableVector<T> {
+pub trait ImmutableCloneableVector<T> {
/**
* Partitions the vector into those that satisfies the predicate, and
* those that do not.
fn permutations(self) -> Permutations<T>;
}
-impl<'a,T:Clone> ImmutableCopyableVector<T> for &'a [T] {
+impl<'a,T:Clone> ImmutableCloneableVector<T> for &'a [T] {
#[inline]
fn partitioned(&self, f: |&T| -> bool) -> (~[T], ~[T]) {
let mut lefts = ~[];
}
/// Extension methods for owned vectors containing `Clone` elements.
-pub trait OwnedCopyableVector<T:Clone> {
+pub trait OwnedCloneableVector<T:Clone> {
/// Iterates over the slice `rhs`, copies each element, and then appends it to
/// the vector provided `v`. The `rhs` vector is traversed in-order.
///
fn grow_set(&mut self, index: uint, initval: &T, val: T);
}
-impl<T:Clone> OwnedCopyableVector<T> for ~[T] {
+impl<T:Clone> OwnedCloneableVector<T> for ~[T] {
#[inline]
fn push_all(&mut self, rhs: &[T]) {
let new_len = self.len() + rhs.len();
// The Rust abstract syntax tree.
-use codemap::{Span, Spanned};
+use codemap::{Span, Spanned, DUMMY_SP};
use abi::AbiSet;
+use ast_util;
use opt_vec::OptVec;
-use parse::token::{interner_get, str_to_ident};
+use parse::token::{interner_get, str_to_ident, special_idents};
use std::cell::RefCell;
use std::hashmap::HashMap;
pub struct TyParam {
ident: Ident,
id: NodeId,
- bounds: OptVec<TyParamBound>
+ bounds: OptVec<TyParamBound>,
+ default: Option<P<Ty>>
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum Def {
DefFn(DefId, Purity),
DefStaticMethod(/* method */ DefId, MethodProvenance, Purity),
- DefSelf(NodeId, bool /* is_mutbl */),
DefSelfTy(/* trait id */ NodeId),
DefMod(DefId),
DefForeignMod(DefId),
pub enum Pat_ {
PatWild,
PatWildMulti,
- // A pat_ident may either be a new bound variable,
+ // A PatIdent may either be a new bound variable,
// or a nullary enum (in which case the second field
// is None).
// In the nullary enum case, the parser can't determine
// set (of "pat_idents that refer to nullary enums")
PatIdent(BindingMode, Path, Option<@Pat>),
PatEnum(Path, Option<~[@Pat]>), /* "none" means a * pattern where
- * we don't bind the fields to names */
+ * we don't bind the fields to names */
PatStruct(Path, ~[FieldPat], bool),
PatTup(~[@Pat]),
PatUniq(@Pat),
PatLit(@Expr),
PatRange(@Expr, @Expr),
// [a, b, ..i, y, z] is represented as
- // pat_vec(~[a, b], Some(i), ~[y, z])
+ // PatVec(~[a, b], Some(i), ~[y, z])
PatVec(~[@Pat], Option<@Pat>, ~[@Pat])
}
impl Expr {
pub fn get_callee_id(&self) -> Option<NodeId> {
match self.node {
- ExprMethodCall(callee_id, _, _, _, _, _) |
+ ExprMethodCall(callee_id, _, _, _, _) |
ExprIndex(callee_id, _, _) |
ExprBinary(callee_id, _, _, _) |
ExprAssignOp(callee_id, _, _, _) |
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum CallSugar {
NoSugar,
- DoSugar,
ForSugar
}
ExprBox(@Expr, @Expr),
ExprVec(~[@Expr], Mutability),
ExprCall(@Expr, ~[@Expr], CallSugar),
- ExprMethodCall(NodeId, @Expr, Ident, ~[P<Ty>], ~[@Expr], CallSugar),
+ ExprMethodCall(NodeId, Ident, ~[P<Ty>], ~[@Expr], CallSugar),
ExprTup(~[@Expr]),
ExprBinary(NodeId, BinOp, @Expr, @Expr),
ExprUnary(NodeId, UnOp, @Expr),
ExprMatch(@Expr, ~[Arm]),
ExprFnBlock(P<FnDecl>, P<Block>),
ExprProc(P<FnDecl>, P<Block>),
- ExprDoBody(@Expr),
ExprBlock(P<Block>),
ExprAssign(@Expr, @Expr),
/// of a function call.
ExprPath(Path),
- /// The special identifier `self`.
- ExprSelf,
ExprAddrOf(Mutability, @Expr),
ExprBreak(Option<Name>),
ExprAgain(Option<Name>),
impl ToStr for IntTy {
fn to_str(&self) -> ~str {
- ::ast_util::int_ty_to_str(*self)
+ ast_util::int_ty_to_str(*self)
}
}
impl ToStr for UintTy {
fn to_str(&self) -> ~str {
- ::ast_util::uint_ty_to_str(*self)
+ ast_util::uint_ty_to_str(*self)
}
}
impl ToStr for FloatTy {
fn to_str(&self) -> ~str {
- ::ast_util::float_ty_to_str(*self)
+ ast_util::float_ty_to_str(*self)
}
}
TyTup(~[P<Ty>]),
TyPath(Path, Option<OptVec<TyParamBound>>, NodeId), // for #7264; see above
TyTypeof(@Expr),
- // ty_infer means the type should be inferred instead of it having been
+ // TyInfer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not
// nested in one.
TyInfer,
id: NodeId,
}
+impl Arg {
+ pub fn new_self(span: Span, mutability: Mutability) -> Arg {
+ let path = ast_util::ident_to_path(span, special_idents::self_);
+ Arg {
+ // HACK(eddyb) fake type for the self argument.
+ ty: P(Ty {
+ id: DUMMY_NODE_ID,
+ node: TyInfer,
+ span: DUMMY_SP,
+ }),
+ pat: @Pat {
+ id: DUMMY_NODE_ID,
+ node: PatIdent(BindByValue(mutability), path, None),
+ span: span
+ },
+ id: DUMMY_NODE_ID
+ }
+ }
+}
+
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct FnDecl {
inputs: ~[Arg],
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum ExplicitSelf_ {
SelfStatic, // no self
- SelfValue(Mutability), // `self`, `mut self`
+ SelfValue, // `self`
SelfRegion(Option<Lifetime>, Mutability), // `&'lt self`, `&'lt mut self`
SelfBox, // `@self`
- SelfUniq(Mutability) // `~self`, `mut ~self`
+ SelfUniq // `~self`
}
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
body: P<Block>,
id: NodeId,
span: Span,
- self_id: NodeId,
vis: Visibility,
}
use fold::Folder;
use fold;
use parse::token::{get_ident_interner, IdentInterner};
-use parse::token::special_idents;
use print::pprust;
use util::small_vector::SmallVector;
/// from, even if it's hard to read (previously they would all just be
/// listed as `__extensions__::method_name::hash`, with no indication
/// of the type).
-// XXX: these dollar signs and the names in general are actually a
+// FIXME: these dollar signs and the names in general are actually a
// relic of $ being one of the very few valid symbol names on
// unix. These kinds of details shouldn't be exposed way up here
// in the ast.
NodeExpr(@Expr),
NodeStmt(@Stmt),
NodeArg(@Pat),
- // HACK(eddyb) should always be a pattern, but `self` is not, and thus it
- // is identified only by an ident and no span is available. In all other
- // cases, node_span will return the proper span (required by borrowck).
- NodeLocal(Ident, Option<@Pat>),
+ NodeLocal(@Pat),
NodeBlock(P<Block>),
/// NodeStructCtor represents a tuple struct.
let mut map = self.map.map.borrow_mut();
map.get().insert(id as uint, node);
}
-
- fn map_self(&self, m: @Method) {
- self.insert(m.self_id, NodeLocal(special_idents::self_, None));
- }
}
impl<F: FoldOps> Folder for Ctx<F> {
let impl_did = ast_util::local_def(i.id);
for &m in ms.iter() {
self.insert(m.id, NodeMethod(m, impl_did, p));
- self.map_self(m);
}
}
}
Provided(m) => {
self.insert(m.id, NodeTraitMethod(@Provided(m), d_id, p));
- self.map_self(m);
}
}
}
fn fold_pat(&mut self, pat: @Pat) -> @Pat {
let pat = fold::noop_fold_pat(pat, self);
match pat.node {
- PatIdent(_, ref path, _) => {
+ PatIdent(..) => {
// Note: this is at least *potentially* a pattern...
- self.insert(pat.id, NodeLocal(ast_util::path_to_ident(path), Some(pat)));
+ self.insert(pat.id, NodeLocal(pat));
}
_ => {}
}
NodeMethod(m, impl_did, @path)
};
cx.insert(m.id, entry);
- cx.map_self(m);
}
}
Some(NodeArg(pat)) => {
format!("arg {} (id={})", pprust::pat_to_str(pat, itr), id)
}
- Some(NodeLocal(ident, _)) => {
- format!("local (id={}, name={})", id, itr.get(ident.name))
+ Some(NodeLocal(pat)) => {
+ format!("local {} (id={})", pprust::pat_to_str(pat, itr), id)
}
Some(NodeBlock(block)) => {
format!("block {} (id={})", pprust::block_to_str(block, itr), id)
Some(NodeVariant(variant, _, _)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
- Some(NodeArg(pat)) => pat.span,
- Some(NodeLocal(_, pat)) => match pat {
- Some(pat) => pat.span,
- None => fail!("node_span: cannot get span from NodeLocal (likely `self`)")
- },
+ Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_, item, _)) => item.span,
Some(NodeCalleeScope(expr)) => expr.span,
pub fn def_id_of_def(d: Def) -> DefId {
match d {
- DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
- DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
- DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
- id
- }
- DefArg(id, _) | DefLocal(id, _) | DefSelf(id, _) | DefSelfTy(id)
- | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
- | DefTyParamBinder(id) | DefLabel(id) => {
- local_def(id)
- }
+ DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
+ DefForeignMod(id) | DefStatic(id, _) |
+ DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
+ DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
+ id
+ }
+ DefArg(id, _) | DefLocal(id, _) | DefSelfTy(id)
+ | DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
+ | DefTyParamBinder(id) | DefLabel(id) => {
+ local_def(id)
+ }
- DefPrimTy(_) => fail!()
+ DefPrimTy(_) => fail!()
}
}
}
}
-/* True if d is either a def_self, or a chain of def_upvars
- referring to a def_self */
-pub fn is_self(d: ast::Def) -> bool {
- match d {
- DefSelf(..) => true,
- DefUpvar(_, d, _, _) => is_self(*d),
- _ => false
- }
-}
-
/// Maps a binary operator to its precedence
pub fn operator_prec(op: ast::BinOp) -> uint {
match op {
impl IdRange {
pub fn max() -> IdRange {
IdRange {
- min: u32::max_value,
- max: u32::min_value,
+ min: u32::MAX,
+ max: u32::MIN,
}
}
self.operation.visit_id(node_id);
match *function_kind {
- visit::FkItemFn(_, generics, _, _) => {
- self.visit_generics_helper(generics)
- }
- visit::FkMethod(_, generics, method) => {
- self.operation.visit_id(method.self_id);
+ visit::FkItemFn(_, generics, _, _) |
+ visit::FkMethod(_, generics, _) => {
self.visit_generics_helper(generics)
}
visit::FkFnBlock => {}
#[deriving(Eq,IterBytes, Ord)]
pub struct CharPos(uint);
-// XXX: Lots of boilerplate in these impls, but so far my attempts to fix
+// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
// have been unsuccessful
impl Pos for BytePos {
use std::cell::Cell;
use std::io;
use std::io::stdio::StdWriter;
+use std::iter::range;
use std::local_data;
use extra::term;
// Skip is the number of characters we need to skip because they are
// part of the 'filename:line ' part of the previous line.
let skip = fm.name.len() + digits + 3u;
- skip.times(|| s.push_char(' '));
+ for _ in range(0, skip) { s.push_char(' '); }
let orig = fm.get_line(lines.lines[0] as int);
for pos in range(0u, left-skip) {
let curChar = (orig[pos] as char);
if hi.col != lo.col {
// the ^ already takes up one space
let num_squigglies = hi.col.to_uint()-lo.col.to_uint()-1u;
- num_squigglies.times(|| s.push_char('~'));
+ for _ in range(0, num_squigglies) { s.push_char('~'); }
}
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()));
}
// Span seems to use half-opened interval, so subtract 1
let skip = last_line_start.len() + hi.col.to_uint() - 1;
let mut s = ~"";
- skip.times(|| s.push_char(' '));
+ for _ in range(0, skip) { s.push_char(' '); }
s.push_char('^');
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()));
}
pub type ItemDecorator =
fn(&ExtCtxt, Span, @ast::MetaItem, ~[@ast::Item]) -> ~[@ast::Item];
-pub struct SyntaxExpanderTT {
- expander: SyntaxExpanderTTExpander,
+pub struct BasicMacroExpander {
+ expander: MacroExpanderFn,
span: Option<Span>
}
-pub trait SyntaxExpanderTTTrait {
+pub trait MacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
- token_tree: &[ast::TokenTree],
- context: ast::SyntaxContext)
+ token_tree: &[ast::TokenTree])
-> MacResult;
}
-pub type SyntaxExpanderTTFunNoCtxt =
+pub type MacroExpanderFn =
fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
-> MacResult;
-enum SyntaxExpanderTTExpander {
- SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt),
-}
-
-impl SyntaxExpanderTTTrait for SyntaxExpanderTT {
+impl MacroExpander for BasicMacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
- token_tree: &[ast::TokenTree],
- _: ast::SyntaxContext)
+ token_tree: &[ast::TokenTree])
-> MacResult {
- match self.expander {
- SyntaxExpanderTTExpanderWithoutContext(f) => {
- f(ecx, span, token_tree)
- }
- }
+ (self.expander)(ecx, span, token_tree)
}
}
-enum SyntaxExpanderTTItemExpander {
- SyntaxExpanderTTItemExpanderWithContext(SyntaxExpanderTTItemFun),
- SyntaxExpanderTTItemExpanderWithoutContext(SyntaxExpanderTTItemFunNoCtxt),
-}
-
-pub struct SyntaxExpanderTTItem {
- expander: SyntaxExpanderTTItemExpander,
+pub struct BasicIdentMacroExpander {
+ expander: IdentMacroExpanderFn,
span: Option<Span>
}
-pub trait SyntaxExpanderTTItemTrait {
+pub trait IdentMacroExpander {
fn expand(&self,
cx: &mut ExtCtxt,
sp: Span,
ident: ast::Ident,
- token_tree: ~[ast::TokenTree],
- context: ast::SyntaxContext)
+ token_tree: ~[ast::TokenTree])
-> MacResult;
}
-impl SyntaxExpanderTTItemTrait for SyntaxExpanderTTItem {
+impl IdentMacroExpander for BasicIdentMacroExpander {
fn expand(&self,
cx: &mut ExtCtxt,
sp: Span,
ident: ast::Ident,
- token_tree: ~[ast::TokenTree],
- context: ast::SyntaxContext)
+ token_tree: ~[ast::TokenTree])
-> MacResult {
- match self.expander {
- SyntaxExpanderTTItemExpanderWithContext(fun) => {
- fun(cx, sp, ident, token_tree, context)
- }
- SyntaxExpanderTTItemExpanderWithoutContext(fun) => {
- fun(cx, sp, ident, token_tree)
- }
- }
+ (self.expander)(cx, sp, ident, token_tree)
}
}
-pub type SyntaxExpanderTTItemFun =
- fn(&mut ExtCtxt, Span, ast::Ident, ~[ast::TokenTree], ast::SyntaxContext)
- -> MacResult;
-
-pub type SyntaxExpanderTTItemFunNoCtxt =
+pub type IdentMacroExpanderFn =
fn(&mut ExtCtxt, Span, ast::Ident, ~[ast::TokenTree]) -> MacResult;
pub type MacroCrateRegistrationFun =
- extern "Rust" fn(|ast::Name, SyntaxExtension|);
+ fn(|ast::Name, SyntaxExtension|);
pub trait AnyMacro {
fn make_expr(&self) -> @ast::Expr;
ItemDecorator(ItemDecorator),
// Token-tree expanders
- NormalTT(~SyntaxExpanderTTTrait:'static, Option<Span>),
+ NormalTT(~MacroExpander:'static, Option<Span>),
// An IdentTT is a macro that has an
// identifier in between the name of the
// perhaps macro_rules! will lose its odd special identifier argument,
// and this can go away also
- IdentTT(~SyntaxExpanderTTItemTrait:'static, Option<Span>),
+ IdentTT(~IdentMacroExpander:'static, Option<Span>),
}
pub struct BlockInfo {
// AST nodes into full ASTs
pub fn syntax_expander_table() -> SyntaxEnv {
// utility function to simplify creating NormalTT syntax extensions
- fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt)
- -> SyntaxExtension {
- NormalTT(~SyntaxExpanderTT{
- expander: SyntaxExpanderTTExpanderWithoutContext(f),
- span: None,
- },
- None)
+ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
+ NormalTT(~BasicMacroExpander {
+ expander: f,
+ span: None,
+ },
+ None)
}
let mut syntax_expanders = SyntaxEnv::new();
syntax_expanders.insert(intern(&"macro_rules"),
- IdentTT(~SyntaxExpanderTTItem {
- expander: SyntaxExpanderTTItemExpanderWithContext(
- ext::tt::macro_rules::add_new_extension),
+ IdentTT(~BasicIdentMacroExpander {
+ expander: ext::tt::macro_rules::add_new_extension,
span: None,
},
None));
syntax_expanders.insert(intern(&"fmt"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::fmt::expand_syntax_ext));
syntax_expanders.insert(intern(&"format_args"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::format::expand_args));
syntax_expanders.insert(intern(&"env"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::env::expand_env));
syntax_expanders.insert(intern(&"option_env"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::env::expand_option_env));
syntax_expanders.insert(intern("bytes"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::bytes::expand_syntax_ext));
syntax_expanders.insert(intern("concat_idents"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::concat_idents::expand_syntax_ext));
syntax_expanders.insert(intern("concat"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::concat::expand_syntax_ext));
syntax_expanders.insert(intern(&"log_syntax"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::log_syntax::expand_syntax_ext));
syntax_expanders.insert(intern(&"deriving"),
ItemDecorator(ext::deriving::expand_meta_deriving));
// Quasi-quoting expanders
syntax_expanders.insert(intern(&"quote_tokens"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_tokens));
syntax_expanders.insert(intern(&"quote_expr"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_expr));
syntax_expanders.insert(intern(&"quote_ty"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_ty));
syntax_expanders.insert(intern(&"quote_item"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_item));
syntax_expanders.insert(intern(&"quote_pat"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_pat));
syntax_expanders.insert(intern(&"quote_stmt"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::quote::expand_quote_stmt));
syntax_expanders.insert(intern(&"line"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_line));
syntax_expanders.insert(intern(&"col"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_col));
syntax_expanders.insert(intern(&"file"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_file));
syntax_expanders.insert(intern(&"stringify"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_stringify));
syntax_expanders.insert(intern(&"include"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_include));
syntax_expanders.insert(intern(&"include_str"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_include_str));
syntax_expanders.insert(intern(&"include_bin"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_include_bin));
syntax_expanders.insert(intern(&"module_path"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::source_util::expand_mod));
syntax_expanders.insert(intern(&"asm"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::asm::expand_asm));
syntax_expanders.insert(intern(&"cfg"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::cfg::expand_cfg));
syntax_expanders.insert(intern(&"trace_macros"),
- builtin_normal_tt_no_ctxt(
+ builtin_normal_expander(
ext::trace_macros::expand_trace_macros));
syntax_expanders
}
use fold::Folder;
use opt_vec;
use opt_vec::OptVec;
+use parse::token::special_idents;
pub struct Field {
ident: ast::Ident,
fn ty_field_imm(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::TypeField;
fn strip_bounds(&self, bounds: &Generics) -> Generics;
- fn typaram(&self, id: ast::Ident, bounds: OptVec<ast::TyParamBound>) -> ast::TyParam;
+ fn typaram(&self,
+ id: ast::Ident,
+ bounds: OptVec<ast::TyParamBound>,
+ default: Option<P<ast::Ty>>) -> ast::TyParam;
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
name: Ident, attrs: ~[ast::Attribute], node: ast::Item_) -> @ast::Item;
fn arg(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::Arg;
- // XXX unused self
+ // FIXME unused self
fn fn_decl(&self, inputs: ~[ast::Arg], output: P<ast::Ty>) -> P<ast::FnDecl>;
fn item_fn_poly(&self,
})
}
- fn typaram(&self, id: ast::Ident, bounds: OptVec<ast::TyParamBound>) -> ast::TyParam {
- ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, bounds: bounds }
+ fn typaram(&self,
+ id: ast::Ident,
+ bounds: OptVec<ast::TyParamBound>,
+ default: Option<P<ast::Ty>>) -> ast::TyParam {
+ ast::TyParam {
+ ident: id,
+ id: ast::DUMMY_NODE_ID,
+ bounds: bounds,
+ default: default
+ }
}
// these are strange, and probably shouldn't be used outside of
self.expr_path(self.path_ident(span, id))
}
fn expr_self(&self, span: Span) -> @ast::Expr {
- self.expr(span, ast::ExprSelf)
+ self.expr_ident(span, special_idents::self_)
}
fn expr_binary(&self, sp: Span, op: ast::BinOp,
fn expr_method_call(&self, span: Span,
expr: @ast::Expr,
ident: ast::Ident,
- args: ~[@ast::Expr]) -> @ast::Expr {
- self.expr(span,
- ast::ExprMethodCall(ast::DUMMY_NODE_ID, expr, ident, ~[], args, ast::NoSugar))
+ mut args: ~[@ast::Expr]) -> @ast::Expr {
+ args.unshift(expr);
+ self.expr(span, ast::ExprMethodCall(ast::DUMMY_NODE_ID, ident, ~[], args, ast::NoSugar))
}
fn expr_block(&self, b: P<ast::Block>) -> @ast::Expr {
self.expr(b.span, ast::ExprBlock(b))
}
}
- // XXX unused self
+ // FIXME unused self
fn fn_decl(&self, inputs: ~[ast::Arg], output: P<ast::Ty>) -> P<ast::FnDecl> {
P(ast::FnDecl {
inputs: inputs,
fn item(&self, span: Span,
name: Ident, attrs: ~[ast::Attribute], node: ast::Item_) -> @ast::Item {
- // XXX: Would be nice if our generated code didn't violate
+ // FIXME: Would be nice if our generated code didn't violate
// Rust coding conventions
@ast::Item { ident: name,
attrs: attrs,
fn cs_clone(
name: &str,
- cx: &ExtCtxt, span: Span,
+ cx: &ExtCtxt, trait_span: Span,
substr: &Substructure) -> @Expr {
let clone_ident = substr.method_ident;
let ctor_ident;
let all_fields;
- let subcall = |field|
- cx.expr_method_call(span, field, clone_ident, ~[]);
+ let subcall = |field: &FieldInfo|
+ cx.expr_method_call(field.span, field.self_, clone_ident, ~[]);
match *substr.fields {
Struct(ref af) => {
ctor_ident = variant.node.name;
all_fields = af;
},
- EnumNonMatching(..) => cx.span_bug(span,
- format!("Non-matching enum variants in `deriving({})`",
- name)),
- StaticEnum(..) | StaticStruct(..) => cx.span_bug(span,
- format!("Static method in `deriving({})`",
- name))
+ EnumNonMatching(..) => cx.span_bug(trait_span,
+ format!("Non-matching enum variants in `deriving({})`",
+ name)),
+ StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span,
+ format!("Static method in `deriving({})`",
+ name))
}
match *all_fields {
[FieldInfo { name: None, .. }, ..] => {
// enum-like
- let subcalls = all_fields.map(|field| subcall(field.self_));
- cx.expr_call_ident(span, ctor_ident, subcalls)
+ let subcalls = all_fields.map(subcall);
+ cx.expr_call_ident(trait_span, ctor_ident, subcalls)
},
_ => {
// struct-like
let fields = all_fields.map(|field| {
let ident = match field.name {
Some(i) => i,
- None => cx.span_bug(span,
+ None => cx.span_bug(trait_span,
format!("unnamed field in normal struct in `deriving({})`",
- name))
+ name))
};
- cx.field_imm(span, ident, subcall(field.self_))
+ cx.field_imm(field.span, ident, subcall(field))
});
if fields.is_empty() {
// no fields, so construct like `None`
- cx.expr_ident(span, ctor_ident)
+ cx.expr_ident(trait_span, ctor_ident)
} else {
- cx.expr_struct_ident(span, ctor_ident, fields)
+ cx.expr_struct_ident(trait_span, ctor_ident, fields)
}
}
}
_ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`")
};
- let cmp = cx.expr_binary(span, op,
- cx.expr_deref(span, self_f),
- cx.expr_deref(span, other_f));
+ let cmp = cx.expr_binary(span, op, self_f, other_f);
let not_cmp = cx.expr_unary(span, ast::UnNot,
- cx.expr_binary(span, op,
- cx.expr_deref(span, other_f),
- cx.expr_deref(span, self_f)));
+ cx.expr_binary(span, op, other_f, self_f));
let and = cx.expr_binary(span, ast::BiAnd, not_cmp, subexpr);
cx.expr_binary(span, ast::BiOr, cmp, and)
trait_def.expand(mitem, in_items)
}
-fn decodable_substructure(cx: &ExtCtxt, span: Span,
+fn decodable_substructure(cx: &ExtCtxt, trait_span: Span,
substr: &Substructure) -> @Expr {
let decoder = substr.nonself_args[0];
let recurse = ~[cx.ident_of("extra"),
cx.ident_of("decode")];
// throw an underscore in front to suppress unused variable warnings
let blkarg = cx.ident_of("_d");
- let blkdecoder = cx.expr_ident(span, blkarg);
- let calldecode = cx.expr_call_global(span, recurse, ~[blkdecoder]);
- let lambdadecode = cx.lambda_expr_1(span, calldecode, blkarg);
+ let blkdecoder = cx.expr_ident(trait_span, blkarg);
+ let calldecode = cx.expr_call_global(trait_span, recurse, ~[blkdecoder]);
+ let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg);
return match *substr.fields {
StaticStruct(_, ref summary) => {
let read_struct_field = cx.ident_of("read_struct_field");
let result = decode_static_fields(cx,
- span,
+ trait_span,
substr.type_ident,
summary,
|span, name, field| {
cx.expr_uint(span, field),
lambdadecode])
});
- cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
- ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
- cx.expr_uint(span, nfields),
- cx.lambda_expr_1(span, result, blkarg)])
+ cx.expr_method_call(trait_span, decoder, cx.ident_of("read_struct"),
+ ~[cx.expr_str(trait_span, cx.str_of(substr.type_ident)),
+ cx.expr_uint(trait_span, nfields),
+ cx.lambda_expr_1(trait_span, result, blkarg)])
}
StaticEnum(_, ref fields) => {
let variant = cx.ident_of("i");
let mut variants = ~[];
let rvariant_arg = cx.ident_of("read_enum_variant_arg");
- for (i, f) in fields.iter().enumerate() {
- let (name, parts) = match *f { (i, ref p) => (i, p) };
- variants.push(cx.expr_str(span, cx.str_of(name)));
+ for (i, &(name, v_span, ref parts)) in fields.iter().enumerate() {
+ variants.push(cx.expr_str(v_span, cx.str_of(name)));
let decoded = decode_static_fields(cx,
- span,
+ v_span,
name,
parts,
|span, _, field| {
lambdadecode])
});
- arms.push(cx.arm(span,
- ~[cx.pat_lit(span, cx.expr_uint(span, i))],
+ arms.push(cx.arm(v_span,
+ ~[cx.pat_lit(v_span, cx.expr_uint(v_span, i))],
decoded));
}
- arms.push(cx.arm_unreachable(span));
+ arms.push(cx.arm_unreachable(trait_span));
- let result = cx.expr_match(span, cx.expr_ident(span, variant), arms);
- let lambda = cx.lambda_expr(span, ~[blkarg, variant], result);
- let variant_vec = cx.expr_vec(span, variants);
- let result = cx.expr_method_call(span, blkdecoder,
+ let result = cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms);
+ let lambda = cx.lambda_expr(trait_span, ~[blkarg, variant], result);
+ let variant_vec = cx.expr_vec(trait_span, variants);
+ let result = cx.expr_method_call(trait_span, blkdecoder,
cx.ident_of("read_enum_variant"),
~[variant_vec, lambda]);
- cx.expr_method_call(span, decoder, cx.ident_of("read_enum"),
- ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
- cx.lambda_expr_1(span, result, blkarg)])
+ cx.expr_method_call(trait_span, decoder, cx.ident_of("read_enum"),
+ ~[cx.expr_str(trait_span, cx.str_of(substr.type_ident)),
+ cx.lambda_expr_1(trait_span, result, blkarg)])
}
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
};
/// - `outer_pat_ident` is the name of this enum variant/struct
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
fn decode_static_fields(cx: &ExtCtxt,
- outer_span: Span,
+ trait_span: Span,
outer_pat_ident: Ident,
fields: &StaticFields,
getarg: |Span, @str, uint| -> @Expr)
match *fields {
Unnamed(ref fields) => {
if fields.is_empty() {
- cx.expr_ident(outer_span, outer_pat_ident)
+ cx.expr_ident(trait_span, outer_pat_ident)
} else {
let fields = fields.iter().enumerate().map(|(i, &span)| {
getarg(span, format!("_field{}", i).to_managed(), i)
}).collect();
- cx.expr_call_ident(outer_span, outer_pat_ident, fields)
+ cx.expr_call_ident(trait_span, outer_pat_ident, fields)
}
}
Named(ref fields) => {
let fields = fields.iter().enumerate().map(|(i, &(name, span))| {
cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
}).collect();
- cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
+ cx.expr_struct_ident(trait_span, outer_pat_ident, fields)
}
}
}
trait_def.expand(mitem, in_items)
}
-fn default_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+fn default_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let default_ident = ~[
cx.ident_of("std"),
cx.ident_of("default"),
match *summary {
Unnamed(ref fields) => {
if fields.is_empty() {
- cx.expr_ident(span, substr.type_ident)
+ cx.expr_ident(trait_span, substr.type_ident)
} else {
let exprs = fields.map(|sp| default_call(*sp));
- cx.expr_call_ident(span, substr.type_ident, exprs)
+ cx.expr_call_ident(trait_span, substr.type_ident, exprs)
}
}
Named(ref fields) => {
let default_fields = fields.map(|&(ident, span)| {
cx.field_imm(span, ident, default_call(span))
});
- cx.expr_struct_ident(span, substr.type_ident, default_fields)
+ cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
}
}
}
StaticEnum(..) => {
- cx.span_err(span, "`Default` cannot be derived for enums, only structs");
+ cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs");
// let compilation continue
- cx.expr_uint(span, 0)
+ cx.expr_uint(trait_span, 0)
}
- _ => cx.bug("Non-static method in `deriving(Default)`")
+ _ => cx.span_bug(trait_span, "Non-static method in `deriving(Default)`")
};
}
trait_def.expand(mitem, in_items)
}
-fn encodable_substructure(cx: &ExtCtxt, span: Span,
+fn encodable_substructure(cx: &ExtCtxt, trait_span: Span,
substr: &Substructure) -> @Expr {
let encoder = substr.nonself_args[0];
// throw an underscore in front to suppress unused variable warnings
let blkarg = cx.ident_of("_e");
- let blkencoder = cx.expr_ident(span, blkarg);
+ let blkencoder = cx.expr_ident(trait_span, blkarg);
let encode = cx.ident_of("encode");
return match *substr.fields {
Struct(ref fields) => {
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = ~[];
- for (i, f) in fields.iter().enumerate() {
- let name = match f.name {
+ for (i, &FieldInfo { name, self_, span, .. }) in fields.iter().enumerate() {
+ let name = match name {
Some(id) => cx.str_of(id),
None => format!("_field{}", i).to_managed()
};
- let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
+ let enc = cx.expr_method_call(span, self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_struct_field,
stmts.push(cx.stmt_expr(call));
}
- let blk = cx.lambda_stmts_1(span, stmts, blkarg);
- cx.expr_method_call(span, encoder, cx.ident_of("emit_struct"),
- ~[cx.expr_str(span, cx.str_of(substr.type_ident)),
- cx.expr_uint(span, fields.len()),
+ let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
+ cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_struct"),
+ ~[cx.expr_str(trait_span, cx.str_of(substr.type_ident)),
+ cx.expr_uint(trait_span, fields.len()),
blk])
}
// so we need to generate a unique local variable to take the
// mutable loan out on, otherwise we get conflicts which don't
// actually exist.
- let me = cx.stmt_let(span, false, blkarg, encoder);
- let encoder = cx.expr_ident(span, blkarg);
+ let me = cx.stmt_let(trait_span, false, blkarg, encoder);
+ let encoder = cx.expr_ident(trait_span, blkarg);
let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
let mut stmts = ~[];
- for (i, f) in fields.iter().enumerate() {
- let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
+ for (i, &FieldInfo { self_, span, .. }) in fields.iter().enumerate() {
+ let enc = cx.expr_method_call(span, self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_variant_arg,
stmts.push(cx.stmt_expr(call));
}
- let blk = cx.lambda_stmts_1(span, stmts, blkarg);
- let name = cx.expr_str(span, cx.str_of(variant.node.name));
- let call = cx.expr_method_call(span, blkencoder,
+ let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
+ let name = cx.expr_str(trait_span, cx.str_of(variant.node.name));
+ let call = cx.expr_method_call(trait_span, blkencoder,
cx.ident_of("emit_enum_variant"),
~[name,
- cx.expr_uint(span, idx),
- cx.expr_uint(span, fields.len()),
+ cx.expr_uint(trait_span, idx),
+ cx.expr_uint(trait_span, fields.len()),
blk]);
- let blk = cx.lambda_expr_1(span, call, blkarg);
- let ret = cx.expr_method_call(span, encoder,
+ let blk = cx.lambda_expr_1(trait_span, call, blkarg);
+ let ret = cx.expr_method_call(trait_span, encoder,
cx.ident_of("emit_enum"),
- ~[cx.expr_str(span,
+ ~[cx.expr_str(trait_span,
cx.str_of(substr.type_ident)),
blk]);
- cx.expr_block(cx.block(span, ~[me], Some(ret)))
+ cx.expr_block(cx.block(trait_span, ~[me], Some(ret)))
}
_ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)")
C0(int),
C1 { x: int }
}
+~~~
The `int`s in `B` and `C0` don't have an identifier, so the
`Option<ident>`s would be `None` for them.
StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
-StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, Unnamed(~[<span of int>])),
- (<ident of C1>, Named(~[(<ident of x>, <span of x>)]))])
+StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
+ (<ident of C1>, <span of C1>,
+ Named(~[(<ident of x>, <span of x>)]))])
~~~
*/
/// A static method where Self is a struct.
StaticStruct(&'a ast::StructDef, StaticFields),
/// A static method where Self is an enum.
- StaticEnum(&'a ast::EnumDef, ~[(Ident, StaticFields)])
+ StaticEnum(&'a ast::EnumDef, ~[(Ident, Span, StaticFields)])
}
// require the current trait
bounds.push(cx.typarambound(trait_path.clone()));
- trait_generics.ty_params.push(cx.typaram(ty_param.ident, bounds));
+ trait_generics.ty_params.push(cx.typaram(ty_param.ident, bounds, None));
}
// Create the reference to the trait.
// create the generics that aren't for Self
let fn_generics = self.generics.to_generics(trait_.cx, trait_.span, type_ident, generics);
+ let self_arg = match explicit_self.node {
+ ast::SelfStatic => None,
+ _ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
+ };
let args = arg_types.move_iter().map(|(name, ty)| {
trait_.cx.arg(trait_.span, name, ty)
- }).collect();
+ });
+ let args = self_arg.move_iter().chain(args).collect();
let ret_type = self.get_ret_ty(trait_, generics, type_ident);
body: body_block,
id: ast::DUMMY_NODE_ID,
span: trait_.span,
- self_id: ast::DUMMY_NODE_ID,
vis: ast::Inherited,
}
}
trait_.summarise_struct(struct_def)
}
};
- (ident, summary)
+ (ident, v.span, summary)
});
self.call_substructure_method(trait_, type_ident,
self_args, nonself_args,
};
let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
paths.push(path.clone());
- ident_expr.push((sp, opt_id, cx.expr_path(path)));
+ let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
+ ident_expr.push((sp, opt_id, val));
}
let subpats = self.create_subpatterns(paths, mutbl);
let path = cx.path_ident(sp, cx.ident_of(format!("{}_{}", prefix, i)));
paths.push(path.clone());
- ident_expr.push((sp, None, cx.expr_path(path)));
+ let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
+ ident_expr.push((sp, None, val));
}
let subpats = self.create_subpatterns(paths, mutbl);
cx.expr_method_call(field.span,
field.self_,
substructure.method_ident,
- field.other.clone())
+ field.other.map(|e| cx.expr_addr_of(field.span, *e)))
});
f(cx, trait_span, called)
trait_def.expand(mitem, in_items)
}
-fn iter_bytes_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+fn iter_bytes_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let (lsb0, f)= match substr.nonself_args {
[l, f] => (l, f),
- _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(IterBytes)`")
+ _ => cx.span_bug(trait_span, "Incorrect number of arguments in `deriving(IterBytes)`")
};
// Build the "explicitly borrowed" stack closure, "|_buf| f(_buf)".
let blk_arg = cx.ident_of("_buf");
let borrowed_f =
- cx.lambda_expr_1(span, cx.expr_call(span, f, ~[cx.expr_ident(span, blk_arg)]),
+ cx.lambda_expr_1(trait_span,
+ cx.expr_call(trait_span, f, ~[cx.expr_ident(trait_span, blk_arg)]),
blk_arg);
let iter_bytes_ident = substr.method_ident;
- let call_iterbytes = |thing_expr| {
+ let call_iterbytes = |span, thing_expr| {
cx.expr_method_call(span,
thing_expr,
iter_bytes_ident,
// iteration function.
let discriminant = match variant.node.disr_expr {
Some(d)=> d,
- None => cx.expr_uint(span, index)
+ None => cx.expr_uint(trait_span, index)
};
- exprs.push(call_iterbytes(discriminant));
+ exprs.push(call_iterbytes(trait_span, discriminant));
fields = fs;
}
- _ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
+ _ => cx.span_bug(trait_span, "Impossible substructure in `deriving(IterBytes)`")
}
- for &FieldInfo { self_, .. } in fields.iter() {
- exprs.push(call_iterbytes(self_));
+ for &FieldInfo { self_, span, .. } in fields.iter() {
+ exprs.push(call_iterbytes(span, self_));
}
if exprs.len() == 0 {
- cx.span_bug(span, "#[deriving(IterBytes)] needs at least one field");
+ cx.span_bug(trait_span, "#[deriving(IterBytes)] needs at least one field");
}
exprs.slice(1, exprs.len()).iter().fold(exprs[0], |prev, me| {
- cx.expr_binary(span, BiAnd, prev, *me)
+ cx.expr_binary(trait_span, BiAnd, prev, *me)
})
}
trait_def.expand(mitem, in_items)
}
-fn cs_from(name: &str, cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+fn cs_from(name: &str, cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let n = match substr.nonself_args {
[n] => n,
- _ => cx.span_bug(span, "Incorrect number of arguments in `deriving(FromPrimitive)`")
+ _ => cx.span_bug(trait_span, "Incorrect number of arguments in `deriving(FromPrimitive)`")
};
match *substr.fields {
StaticStruct(..) => {
- cx.span_err(span, "`FromPrimitive` cannot be derived for structs");
- return cx.expr_fail(span, @"");
+ cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
+ return cx.expr_fail(trait_span, @"");
}
StaticEnum(enum_def, _) => {
if enum_def.variants.is_empty() {
- cx.span_err(span, "`FromPrimitive` cannot be derived for enums with no variants");
- return cx.expr_fail(span, @"");
+ cx.span_err(trait_span,
+ "`FromPrimitive` cannot be derived for enums with no variants");
+ return cx.expr_fail(trait_span, @"");
}
let mut arms = ~[];
match variant.node.kind {
ast::TupleVariantKind(ref args) => {
if !args.is_empty() {
- cx.span_err(span, "`FromPrimitive` cannot be derived for \
- enum variants with arguments");
- return cx.expr_fail(span, @"");
+ cx.span_err(trait_span,
+ "`FromPrimitive` cannot be derived for \
+ enum variants with arguments");
+ return cx.expr_fail(trait_span, @"");
}
+ let span = variant.span;
// expr for `$n == $variant as $name`
let variant = cx.expr_ident(span, variant.node.name);
arms.push(arm);
}
ast::StructVariantKind(_) => {
- cx.span_err(span, "`FromPrimitive` cannot be derived for enums \
- with struct variants");
- return cx.expr_fail(span, @"");
+ cx.span_err(trait_span,
+ "`FromPrimitive` cannot be derived for enums \
+ with struct variants");
+ return cx.expr_fail(trait_span, @"");
}
}
}
// arm for `_ => None`
let arm = ast::Arm {
- pats: ~[cx.pat_wild(span)],
+ pats: ~[cx.pat_wild(trait_span)],
guard: None,
- body: cx.block_expr(cx.expr_none(span)),
+ body: cx.block_expr(cx.expr_none(trait_span)),
};
arms.push(arm);
- cx.expr_match(span, n, arms)
+ cx.expr_match(trait_span, n, arms)
}
- _ => cx.bug("expected StaticEnum in deriving(FromPrimitive)")
+ _ => cx.span_bug(trait_span, "expected StaticEnum in deriving(FromPrimitive)")
}
}
trait_def.expand(mitem, in_items)
}
-fn rand_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+fn rand_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let rng = match substr.nonself_args {
[rng] => ~[ rng ],
_ => cx.bug("Incorrect number of arguments to `rand` in `deriving(Rand)`")
return match *substr.fields {
StaticStruct(_, ref summary) => {
- rand_thing(cx, span, substr.type_ident, summary, rand_call)
+ rand_thing(cx, trait_span, substr.type_ident, summary, rand_call)
}
StaticEnum(_, ref variants) => {
if variants.is_empty() {
- cx.span_err(span, "`Rand` cannot be derived for enums with no variants");
+ cx.span_err(trait_span, "`Rand` cannot be derived for enums with no variants");
// let compilation continue
- return cx.expr_uint(span, 0);
+ return cx.expr_uint(trait_span, 0);
}
- let variant_count = cx.expr_uint(span, variants.len());
+ let variant_count = cx.expr_uint(trait_span, variants.len());
- let rand_name = cx.path_all(span,
+ let rand_name = cx.path_all(trait_span,
true,
rand_ident.clone(),
opt_vec::Empty,
let rand_name = cx.expr_path(rand_name);
// ::std::rand::Rand::rand(rng)
- let rv_call = cx.expr_call(span,
+ let rv_call = cx.expr_call(trait_span,
rand_name,
~[ rng[0] ]);
// need to specify the uint-ness of the random number
- let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
+ let uint_ty = cx.ty_ident(trait_span, cx.ident_of("uint"));
let value_ident = cx.ident_of("__value");
- let let_statement = cx.stmt_let_typed(span,
+ let let_statement = cx.stmt_let_typed(trait_span,
false,
value_ident,
uint_ty,
rv_call);
// rand() % variants.len()
- let value_ref = cx.expr_ident(span, value_ident);
- let rand_variant = cx.expr_binary(span,
+ let value_ref = cx.expr_ident(trait_span, value_ident);
+ let rand_variant = cx.expr_binary(trait_span,
ast::BiRem,
value_ref,
variant_count);
- let mut arms = variants.iter().enumerate().map(|(i, id_sum)| {
- let i_expr = cx.expr_uint(span, i);
- let pat = cx.pat_lit(span, i_expr);
+ let mut arms = variants.iter().enumerate().map(|(i, &(ident, v_span, ref summary))| {
+ let i_expr = cx.expr_uint(v_span, i);
+ let pat = cx.pat_lit(v_span, i_expr);
- match *id_sum {
- (ident, ref summary) => {
- cx.arm(span,
- ~[ pat ],
- rand_thing(cx, span, ident, summary, |sp| rand_call(sp)))
- }
- }
+ cx.arm(v_span,
+ ~[ pat ],
+ rand_thing(cx, v_span, ident, summary, |sp| rand_call(sp)))
}).collect::<~[ast::Arm]>();
// _ => {} at the end. Should never occur
- arms.push(cx.arm_unreachable(span));
+ arms.push(cx.arm_unreachable(trait_span));
- let match_expr = cx.expr_match(span, rand_variant, arms);
+ let match_expr = cx.expr_match(trait_span, rand_variant, arms);
- let block = cx.block(span, ~[ let_statement ], Some(match_expr));
+ let block = cx.block(trait_span, ~[ let_statement ], Some(match_expr));
cx.expr_block(block)
}
_ => cx.bug("Non-static method in `deriving(Rand)`")
};
fn rand_thing(cx: &ExtCtxt,
- span: Span,
+ trait_span: Span,
ctor_ident: Ident,
summary: &StaticFields,
rand_call: |Span| -> @Expr)
match *summary {
Unnamed(ref fields) => {
if fields.is_empty() {
- cx.expr_ident(span, ctor_ident)
+ cx.expr_ident(trait_span, ctor_ident)
} else {
let exprs = fields.map(|span| rand_call(*span));
- cx.expr_call_ident(span, ctor_ident, exprs)
+ cx.expr_call_ident(trait_span, ctor_ident, exprs)
}
}
Named(ref fields) => {
let rand_fields = fields.map(|&(ident, span)| {
cx.field_imm(span, ident, rand_call(span))
});
- cx.expr_struct_ident(span, ctor_ident, rand_fields)
+ cx.expr_struct_ident(trait_span, ctor_ident, rand_fields)
}
}
}
let path = b.to_path(cx, span, self_ident, self_generics);
cx.typarambound(path)
}));
- cx.typaram(cx.ident_of(name), bounds)
+ cx.typaram(cx.ident_of(name), bounds, None)
}
fn mk_generics(lifetimes: ~[ast::Lifetime], ty_params: ~[ast::TyParam]) -> Generics {
let self_path = cx.expr_self(span);
match *self_ptr {
None => {
- (self_path, respan(span, ast::SelfValue(ast::MutImmutable)))
+ (self_path, respan(span, ast::SelfValue))
}
Some(ref ptr) => {
let self_ty = respan(
span,
match *ptr {
- Send => ast::SelfUniq(ast::MutImmutable),
+ Send => ast::SelfUniq,
Managed => ast::SelfBox,
Borrowed(ref lt, mutbl) => {
let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));
trait_def.expand(mitem, in_items)
}
-fn zero_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+fn zero_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let zero_ident = ~[
cx.ident_of("std"),
cx.ident_of("num"),
match *summary {
Unnamed(ref fields) => {
if fields.is_empty() {
- cx.expr_ident(span, substr.type_ident)
+ cx.expr_ident(trait_span, substr.type_ident)
} else {
let exprs = fields.map(|sp| zero_call(*sp));
- cx.expr_call_ident(span, substr.type_ident, exprs)
+ cx.expr_call_ident(trait_span, substr.type_ident, exprs)
}
}
Named(ref fields) => {
let zero_fields = fields.map(|&(ident, span)| {
cx.field_imm(span, ident, zero_call(span))
});
- cx.expr_struct_ident(span, substr.type_ident, zero_fields)
+ cx.expr_struct_ident(trait_span, substr.type_ident, zero_fields)
}
}
}
StaticEnum(..) => {
- cx.span_err(span, "`Zero` cannot be derived for enums, only structs");
+ cx.span_err(trait_span, "`Zero` cannot be derived for enums, only structs");
// let compilation continue
- cx.expr_uint(span, 0)
+ cx.expr_uint(trait_span, 0)
}
_ => cx.bug("Non-static method in `deriving(Zero)`")
};
use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{TokenTree};
use ast;
-use ast_util::{mtwt_outer_mark, new_rename, new_mark};
+use ast_util::{new_rename, new_mark};
use ext::build::AstBuilder;
use attr;
use attr::AttrMetaMethods;
use ext::base::*;
use fold::*;
use parse;
-use parse::{parse_item_from_source_str};
use parse::token;
use parse::token::{fresh_mark, fresh_name, ident_to_str, intern};
use visit;
// for the other three macro invocation chunks of code
// in this file.
// Token-tree macros:
- MacInvocTT(ref pth, ref tts, ctxt) => {
+ MacInvocTT(ref pth, ref tts, _) => {
if pth.segments.len() > 1u {
fld.cx.span_err(
pth.span,
let fm = fresh_mark();
// mark before:
let marked_before = mark_tts(*tts,fm);
- let marked_ctxt = new_mark(fm, ctxt);
// The span that we pass to the expanders we want to
// be the root of the call stack. That's the most
let expanded = match expandfun.expand(fld.cx,
mac_span.call_site,
- marked_before,
- marked_ctxt) {
+ marked_before) {
MRExpr(e) => e,
MRAny(any_macro) => any_macro.make_expr(),
_ => {
// Keep going, outside-in.
//
- // XXX(pcwalton): Is it necessary to clone the
+ // FIXME(pcwalton): Is it necessary to clone the
// node here?
let fully_expanded =
fld.fold_expr(marked_after).node.clone();
// logic as for expression-position macro invocations.
pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander)
-> SmallVector<@ast::Item> {
- let (pth, tts, ctxt) = match it.node {
+ let (pth, tts) = match it.node {
ItemMac(codemap::Spanned {
- node: MacInvocTT(ref pth, ref tts, ctxt),
+ node: MacInvocTT(ref pth, ref tts, _),
..
}) => {
- (pth, (*tts).clone(), ctxt)
+ (pth, (*tts).clone())
}
_ => fld.cx.span_bug(it.span, "invalid item macro invocation")
};
});
// mark before expansion:
let marked_before = mark_tts(tts,fm);
- let marked_ctxt = new_mark(fm,ctxt);
- expander.expand(fld.cx, it.span, marked_before, marked_ctxt)
+ expander.expand(fld.cx, it.span, marked_before)
}
Some(&IdentTT(ref expander, span)) => {
if it.ident.name == parse::token::special_idents::invalid.name {
});
// mark before expansion:
let marked_tts = mark_tts(tts,fm);
- let marked_ctxt = new_mark(fm,ctxt);
- expander.expand(fld.cx, it.span, it.ident, marked_tts, marked_ctxt)
+ expander.expand(fld.cx, it.span, it.ident, marked_tts)
}
_ => {
fld.cx.span_err(it.span, format!("{}! is not legal in item position", extnamestr));
pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> {
// why the copying here and not in expand_expr?
// looks like classic changed-in-only-one-place
- let (pth, tts, semi, ctxt) = match s.node {
+ let (pth, tts, semi) = match s.node {
StmtMac(ref mac, semi) => {
match mac.node {
- MacInvocTT(ref pth, ref tts, ctxt) => {
- (pth, (*tts).clone(), semi, ctxt)
+ MacInvocTT(ref pth, ref tts, _) => {
+ (pth, (*tts).clone(), semi)
}
}
}
let fm = fresh_mark();
// mark before expansion:
let marked_tts = mark_tts(tts,fm);
- let marked_ctxt = new_mark(fm,ctxt);
// See the comment in expand_expr for why we want the original span,
// not the current mac.span.
let expanded = match expandfun.expand(fld.cx,
mac_span.call_site,
- marked_tts,
- marked_ctxt) {
+ marked_tts) {
MRExpr(e) => {
@codemap::Spanned {
node: StmtExpr(e, ast::DUMMY_NODE_ID),
}
}
-// FIXME (#2247): this is a moderately bad kludge to inject some macros into
-// the default compilation environment in that it injects strings, rather than
-// syntax elements.
-
-pub fn std_macros() -> @str {
-@r#"mod __std_macros {
- #[macro_escape];
- #[doc(hidden)];
- #[allow(dead_code)];
-
- macro_rules! ignore (($($x:tt)*) => (()))
-
- macro_rules! log(
- ($lvl:expr, $($arg:tt)+) => ({
- let lvl = $lvl;
- if lvl <= __log_level() {
- format_args!(|args| {
- ::std::logging::log(lvl, args)
- }, $($arg)+)
- }
- })
- )
- macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
- macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
- macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
- macro_rules! debug( ($($arg:tt)*) => (
- if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
- ))
-
- macro_rules! log_enabled(
- ($lvl:expr) => ( {
- let lvl = $lvl;
- lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
- } )
- )
-
- macro_rules! fail(
- () => (
- fail!("explicit failure")
- );
- ($msg:expr) => (
- ::std::rt::begin_unwind($msg, file!(), line!())
- );
- ($fmt:expr, $($arg:tt)*) => (
- ::std::rt::begin_unwind(format!($fmt, $($arg)*), file!(), line!())
- )
- )
-
- macro_rules! assert(
- ($cond:expr) => {
- if !$cond {
- fail!("assertion failed: {:s}", stringify!($cond))
- }
- };
- ($cond:expr, $msg:expr) => {
- if !$cond {
- fail!($msg)
- }
- };
- ($cond:expr, $( $arg:expr ),+) => {
- if !$cond {
- fail!( $($arg),+ )
- }
- }
- )
-
- macro_rules! assert_eq (
- ($given:expr , $expected:expr) => (
- {
- let given_val = &($given);
- let expected_val = &($expected);
- // check both directions of equality....
- if !((*given_val == *expected_val) &&
- (*expected_val == *given_val)) {
- fail!("assertion failed: `(left == right) && (right == left)` \
- (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
- }
- }
- )
- )
-
- /// A utility macro for indicating unreachable code. It will fail if
- /// executed. This is occasionally useful to put after loops that never
- /// terminate normally, but instead directly return from a function.
- ///
- /// # Example
- ///
- /// ```rust
- /// fn choose_weighted_item(v: &[Item]) -> Item {
- /// assert!(!v.is_empty());
- /// let mut so_far = 0u;
- /// for item in v.iter() {
- /// so_far += item.weight;
- /// if so_far > 100 {
- /// return item;
- /// }
- /// }
- /// // The above loop always returns, so we must hint to the
- /// // type checker that it isn't possible to get down here
- /// unreachable!();
- /// }
- /// ```
- macro_rules! unreachable (() => (
- fail!("internal error: entered unreachable code");
- ))
-
- macro_rules! condition (
-
- { pub $c:ident: $input:ty -> $out:ty; } => {
-
- pub mod $c {
- #[allow(unused_imports)];
- #[allow(non_uppercase_statics)];
- #[allow(missing_doc)];
-
- use super::*;
-
- local_data_key!(key: @::std::condition::Handler<$input, $out>)
-
- pub static cond :
- ::std::condition::Condition<$input,$out> =
- ::std::condition::Condition {
- name: stringify!($c),
- key: key
- };
- }
- };
-
- { $c:ident: $input:ty -> $out:ty; } => {
-
- mod $c {
- #[allow(unused_imports)];
- #[allow(non_uppercase_statics)];
- #[allow(dead_code)];
-
- use super::*;
-
- local_data_key!(key: @::std::condition::Handler<$input, $out>)
-
- pub static cond :
- ::std::condition::Condition<$input,$out> =
- ::std::condition::Condition {
- name: stringify!($c),
- key: key
- };
- }
- }
- )
-
- macro_rules! format(($($arg:tt)*) => (
- format_args!(::std::fmt::format, $($arg)*)
- ))
- macro_rules! write(($dst:expr, $($arg:tt)*) => (
- format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
- ))
- macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
- format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
- ))
- macro_rules! print (
- ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
- )
- macro_rules! println (
- ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
- )
-
- macro_rules! local_data_key (
- ($name:ident: $ty:ty) => (
- static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
- );
- (pub $name:ident: $ty:ty) => (
- pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
- )
- )
-}"#
-}
-
-struct Injector {
- sm: @ast::Item,
-}
-
-impl Folder for Injector {
- fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
- // Just inject the standard macros at the start of the first module
- // in the crate: that is, at the start of the crate file itself.
- let items = vec::append(~[ self.sm ], module.items);
- ast::Mod {
- items: items,
- ..(*module).clone() // FIXME #2543: Bad copy.
- }
- }
-}
-
-// 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: @parse::ParseSess,
- cfg: ast::CrateConfig,
- c: Crate)
- -> Crate {
- let sm = match parse_item_from_source_str(@"<std-macros>",
- std_macros(),
- cfg.clone(),
- parse_sess) {
- Some(item) => item,
- None => fail!("expected core macros to parse correctly")
- };
-
- let mut injector = Injector {
- sm: sm,
- };
- injector.fold_crate(c)
-}
-
pub struct MacroExpander<'a> {
extsbox: SyntaxEnv,
cx: &'a mut ExtCtxt<'a>,
fun_to_ctxt_folder(@Repainter{ctxt:ctxt}).fold_expr(expr)
}
-// take the mark from the given ctxt (that has a mark at the outside),
-// and apply it to everything in the token trees, thereby cancelling
-// that mark.
-pub fn mtwt_cancel_outer_mark(tts: &[ast::TokenTree], ctxt: ast::SyntaxContext)
- -> ~[ast::TokenTree] {
- let outer_mark = mtwt_outer_mark(ctxt);
- mark_tts(tts,outer_mark)
-}
-
fn original_span(cx: &ExtCtxt) -> @codemap::ExpnInfo {
let mut relevant_info = cx.backtrace();
let mut einfo = relevant_info.unwrap();
}
}
- // make sure that fail! is present
- #[test] fn fail_exists_test () {
- let src = @"fn main() { fail!(\"something appropriately gloomy\");}";
- let sess = parse::new_parse_sess(None);
- let crate_ast = parse::parse_crate_from_source_str(
- @"<test>",
- src,
- ~[],sess);
- let crate_ast = inject_std_macros(sess, ~[], crate_ast);
- // don't bother with striping, doesn't affect fail!.
- let mut loader = ErrLoader;
- expand_crate(sess,&mut loader,~[],crate_ast);
- }
-
// these following tests are quite fragile, in that they don't test what
// *kind* of failure occurs.
expand_crate(sess,&mut loader,~[],crate_ast);
}
- #[test] fn std_macros_must_parse () {
- let src = super::std_macros();
- let sess = parse::new_parse_sess(None);
- let cfg = ~[];
- let item_ast = parse::parse_item_from_source_str(
- @"<test>",
- src,
- cfg,sess);
- match item_ast {
- Some(_) => (), // success
- None => fail!("expected this to parse")
- }
- }
-
#[test] fn test_contains_flatten (){
let attr1 = make_dummy_attr (@"foo");
let attr2 = make_dummy_attr (@"bar");
}
}
- #[test] fn cancel_outer_mark_test(){
- let invalid_name = token::special_idents::invalid.name;
- let ident_str = @"x";
- let tts = string_to_tts(ident_str);
- let fm = fresh_mark();
- let marked_once = fold::fold_tts(tts,&mut new_mark_folder(fm));
- assert_eq!(marked_once.len(),1);
- let marked_once_ctxt =
- match marked_once[0] {
- ast::TTTok(_,token::IDENT(id,_)) => id.ctxt,
- _ => fail!(format!("unexpected shape for marked tts: {:?}",marked_once[0]))
- };
- assert_eq!(mtwt_marksof(marked_once_ctxt,invalid_name),~[fm]);
- let remarked = mtwt_cancel_outer_mark(marked_once,marked_once_ctxt);
- assert_eq!(remarked.len(),1);
- match remarked[0] {
- ast::TTTok(_,token::IDENT(id,_)) =>
- assert_eq!(mtwt_marksof(id.ctxt,invalid_name),~[]),
- _ => fail!(format!("unexpected shape for marked tts: {:?}",remarked[0]))
- }
- }
-
#[test]
fn renaming () {
let item_ast = string_to_crate(@"fn f() -> int { a }");
}
cur_eis.push(ei);
- rust_parser.tokens_consumed.times(|| {
+ for _ in range(0, rust_parser.tokens_consumed) {
let _ = rdr.next_token();
- });
+ }
}
}
use ast;
use codemap::{Span, Spanned, DUMMY_SP};
use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef};
-use ext::base::{NormalTT, SyntaxExpanderTTTrait};
+use ext::base::{NormalTT, MacroExpander};
use ext::base;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
}
}
-struct MacroRulesSyntaxExpanderTTFun {
+struct MacroRulesMacroExpander {
name: Ident,
lhses: @~[@NamedMatch],
rhses: @~[@NamedMatch],
}
-impl SyntaxExpanderTTTrait for MacroRulesSyntaxExpanderTTFun {
+impl MacroExpander for MacroRulesMacroExpander {
fn expand(&self,
cx: &mut ExtCtxt,
sp: Span,
- arg: &[ast::TokenTree],
- _: ast::SyntaxContext)
+ arg: &[ast::TokenTree])
-> MacResult {
generic_extension(cx, sp, self.name, arg, *self.lhses, *self.rhses)
}
pub fn add_new_extension(cx: &mut ExtCtxt,
sp: Span,
name: Ident,
- arg: ~[ast::TokenTree],
- _: ast::SyntaxContext)
+ arg: ~[ast::TokenTree])
-> base::MacResult {
// these spans won't matter, anyways
fn ms(m: Matcher_) -> Matcher {
_ => cx.span_bug(sp, "wrong-structured rhs")
};
- let exp = ~MacroRulesSyntaxExpanderTTFun {
+ let exp = ~MacroRulesMacroExpander {
name: name,
lhses: lhses,
rhses: rhses,
// return the next token from the TtReader.
// EFFECT: advances the reader's token field
pub fn tt_next_token(r: &TtReader) -> TokenAndSpan {
- // XXX(pcwalton): Bad copy?
+ // FIXME(pcwalton): Bad copy?
let ret_val = TokenAndSpan {
tok: r.cur_tok.get(),
sp: r.cur_span.get(),
}
loop { /* because it's easiest, this handles `TTDelim` not starting
with a `TTTok`, even though it won't happen */
- // XXX(pcwalton): Bad copy.
+ // FIXME(pcwalton): Bad copy.
match r.stack.get().forest[r.stack.get().idx.get()].clone() {
TTDelim(tts) => {
r.stack.set(@TtFrame {
return ret_val;
}
TTSeq(sp, tts, sep, zerok) => {
- // XXX(pcwalton): Bad copy.
+ // FIXME(pcwalton): Bad copy.
let t = TTSeq(sp, tts, sep.clone(), zerok);
match lockstep_iter_size(&t, r) {
LisUnconstrained => {
return ret_val;
}
MatchedNonterminal(ref other_whole_nt) => {
- // XXX(pcwalton): Bad copy.
+ // FIXME(pcwalton): Bad copy.
r.cur_span.set(sp);
r.cur_tok.set(INTERPOLATED((*other_whole_nt).clone()));
r.stack.get().idx.set(r.stack.get().idx.get() + 1u);
fn fold_explicit_self_(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ {
match *es {
- SelfStatic | SelfValue(_) | SelfUniq(_) | SelfBox => {
- *es
- }
+ SelfStatic | SelfValue | SelfUniq | SelfBox => *es,
SelfRegion(ref lifetime, m) => {
SelfRegion(fold_opt_lifetime(lifetime, self), m)
}
ident: tp.ident,
id: fld.new_id(tp.id),
bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
+ default: tp.default.map(|x| fld.fold_ty(x))
}
}
body: folder.fold_block(m.body),
id: folder.new_id(m.id),
span: folder.new_span(m.span),
- self_id: folder.new_id(m.self_id),
vis: m.vis
}
}
args.map(|&x| folder.fold_expr(x)),
blk)
}
- ExprMethodCall(callee_id, f, i, ref tps, ref args, blk) => {
+ ExprMethodCall(callee_id, i, ref tps, ref args, blk) => {
ExprMethodCall(
folder.new_id(callee_id),
- folder.fold_expr(f),
folder.fold_ident(i),
tps.map(|&x| folder.fold_ty(x)),
args.map(|&x| folder.fold_expr(x)),
ExprUnary(callee_id, binop, ohs) => {
ExprUnary(folder.new_id(callee_id), binop, folder.fold_expr(ohs))
}
- ExprDoBody(f) => ExprDoBody(folder.fold_expr(f)),
ExprLit(_) => e.node.clone(),
ExprCast(expr, ty) => {
ExprCast(folder.fold_expr(expr), folder.fold_ty(ty))
folder.fold_expr(er))
}
ExprPath(ref pth) => ExprPath(folder.fold_path(pth)),
- ExprSelf => ExprSelf,
ExprLogLevel => ExprLogLevel,
ExprBreak(opt_ident) => ExprBreak(opt_ident),
ExprAgain(opt_ident) => ExprAgain(opt_ident),
| ast::ExprWhile(..)
| ast::ExprLoop(..)
| ast::ExprForLoop(..)
- | ast::ExprCall(_, _, ast::DoSugar)
| ast::ExprCall(_, _, ast::ForSugar)
- | ast::ExprMethodCall(_, _, _, _, _, ast::DoSugar)
- | ast::ExprMethodCall(_, _, _, _, _, ast::ForSugar) => false,
+ | ast::ExprMethodCall(_, _, _, _, ast::ForSugar) => false,
_ => true
}
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/// remove a "[ \t]*\*" block from each line, if possible
fn horizontal_trim(lines: ~[~str]) -> ~[~str] {
- let mut i = uint::max_value;
+ let mut i = uint::MAX;
let mut can_trim = true;
let mut first = true;
for line in lines.iter() {
}
fn span_diag(@self) -> @SpanHandler { self.span_diagnostic }
fn peek(@self) -> TokenAndSpan {
- // XXX(pcwalton): Bad copy!
+ // FIXME(pcwalton): Bad copy!
TokenAndSpan {
tok: self.peek_tok.get(),
sp: self.peek_span.get(),
use abi;
use abi::AbiSet;
use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil};
-use ast::{CallSugar, NoSugar, DoSugar};
+use ast::{CallSugar, NoSugar};
use ast::{BareFnTy, ClosureTy};
use ast::{RegionTyParamBound, TraitTyParamBound};
use ast::{Provided, Public, Purity};
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
-use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
+use ast::{ExprBreak, ExprCall, ExprCast};
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
-use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc, ExprRepeat};
-use ast::{ExprRet, ExprSelf, ExprStruct, ExprTup, ExprUnary};
+use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
+use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprVec, ExprVstore, ExprVstoreSlice, ExprVstoreBox};
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, ExternFn, Field, FnDecl};
use ast::{ExprVstoreUniq, Onceness, Once, Many};
}
/// A path paired with optional type bounds.
-struct PathAndBounds {
+pub struct PathAndBounds {
path: ast::Path,
bounds: Option<OptVec<TyParamBound>>,
}
body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- self_id: ast::DUMMY_NODE_ID,
vis: vis,
})
}
Parser::token_is_lifetime(&self.token) {
// CLOSURE
//
- // XXX(pcwalton): Eventually `token::LT` will not unambiguously
+ // FIXME(pcwalton): Eventually `token::LT` will not unambiguously
// introduce a closure, once procs can have lifetime bounds. We
// will need to refactor the grammar a little bit at that point.
ExprCall(f, args, sugar)
}
- pub fn mk_method_call(&mut self,
- rcvr: @Expr,
- ident: Ident,
- tps: ~[P<Ty>],
- args: ~[@Expr],
+ fn mk_method_call(&mut self, ident: Ident, tps: ~[P<Ty>], args: ~[@Expr],
sugar: CallSugar) -> ast::Expr_ {
- ExprMethodCall(ast::DUMMY_NODE_ID, rcvr, ident, tps, args, sugar)
+ ExprMethodCall(ast::DUMMY_NODE_ID, ident, tps, args, sugar)
}
pub fn mk_index(&mut self, expr: @Expr, idx: @Expr) -> ast::Expr_ {
return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock));
} else if self.eat_keyword(keywords::Self) {
- ex = ExprSelf;
+ let path = ast_util::ident_to_path(mk_sp(lo, hi), special_idents::self_);
+ ex = ExprPath(path);
hi = self.span.hi;
} else if self.eat_keyword(keywords::If) {
return self.parse_if_expr();
} else if self.eat_keyword(keywords::For) {
return self.parse_for_expr(None);
- } else if self.eat_keyword(keywords::Do) {
- return self.parse_sugary_call_expr(lo, ~"do", DoSugar,
- ExprDoBody);
} else if self.eat_keyword(keywords::While) {
return self.parse_while_expr();
} else if Parser::token_is_lifetime(&self.token) {
let mut fields = ~[];
let mut base = None;
- fields.push(self.parse_field());
while self.token != token::RBRACE {
- self.commit_expr(fields.last().unwrap().expr,
- &[token::COMMA], &[token::RBRACE]);
-
if self.eat(&token::DOTDOT) {
base = Some(self.parse_expr());
break;
}
- if self.token == token::RBRACE {
- // Accept an optional trailing comma.
- break;
- }
fields.push(self.parse_field());
+ self.commit_expr(fields.last().unwrap().expr,
+ &[token::COMMA], &[token::RBRACE]);
}
hi = pth.span.hi;
- self.commit_expr_expecting(fields.last().unwrap().expr, token::RBRACE);
+ self.expect(&token::RBRACE);
ex = ExprStruct(pth, fields, base);
return self.mk_expr(lo, hi, ex);
}
// expr.f() method call
match self.token {
token::LPAREN => {
- let es = self.parse_unspanned_seq(
+ let mut es = self.parse_unspanned_seq(
&token::LPAREN,
&token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA),
);
hi = self.span.hi;
- let nd = self.mk_method_call(e, i, tys, es, NoSugar);
+ es.unshift(e);
+ let nd = self.mk_method_call(i, tys, es, NoSugar);
e = self.mk_expr(lo, hi, nd);
}
_ => {
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
}
-
- // parse a 'do'.
- // the 'do' expression parses as a call, but looks like
- // a function call followed by a closure expression.
- pub fn parse_sugary_call_expr(&mut self,
- lo: BytePos,
- keyword: ~str,
- sugar: CallSugar,
- ctor: |v: @Expr| -> Expr_)
- -> @Expr {
- // Parse the callee `foo` in
- // do foo || {
- // do foo.bar || {
- // etc, or the portion of the call expression before the lambda in
- // do foo() || {
- // or
- // do foo.bar(a) || {
- // Turn on the restriction to stop at | or || so we can parse
- // them as the lambda arguments
- let e = self.parse_expr_res(RESTRICT_NO_BAR_OR_DOUBLEBAR_OP);
- match e.node {
- ExprCall(f, ref args, NoSugar) => {
- let block = self.parse_lambda_block_expr();
- let last_arg = self.mk_expr(block.span.lo, block.span.hi,
- ctor(block));
- let args = vec::append((*args).clone(), [last_arg]);
- self.mk_expr(lo, block.span.hi, ExprCall(f, args, sugar))
- }
- ExprMethodCall(_, f, i, ref tps, ref args, NoSugar) => {
- let block = self.parse_lambda_block_expr();
- let last_arg = self.mk_expr(block.span.lo, block.span.hi,
- ctor(block));
- let args = vec::append((*args).clone(), [last_arg]);
- let method_call = self.mk_method_call(f,
- i,
- (*tps).clone(),
- args,
- sugar);
- self.mk_expr(lo, block.span.hi, method_call)
- }
- ExprField(f, i, ref tps) => {
- let block = self.parse_lambda_block_expr();
- let last_arg = self.mk_expr(block.span.lo, block.span.hi,
- ctor(block));
- let method_call = self.mk_method_call(f,
- i,
- (*tps).clone(),
- ~[last_arg],
- sugar);
- self.mk_expr(lo, block.span.hi, method_call)
- }
- ExprPath(..) | ExprCall(..) | ExprMethodCall(..) |
- ExprParen(..) => {
- let block = self.parse_lambda_block_expr();
- let last_arg = self.mk_expr(block.span.lo, block.span.hi,
- ctor(block));
- let call = self.mk_call(e, ~[last_arg], sugar);
- self.mk_expr(lo, last_arg.span.hi, call)
- }
- _ => {
- // There may be other types of expressions that can
- // represent the callee in `do` expressions
- // but they aren't represented by tests
- debug!("sugary call on {:?}", e.node);
- self.span_fatal(
- e.span,
- format!("`{}` must be followed by a block call", keyword));
- }
- }
- }
-
pub fn parse_while_expr(&mut self) -> @Expr {
let lo = self.last_span.lo;
let cond = self.parse_expr();
// For distingishing between struct literals and blocks
fn looking_at_struct_literal(&mut self) -> bool {
self.token == token::LBRACE &&
- (self.look_ahead(1, |t| token::is_plain_ident(t)) &&
- self.look_ahead(2, |t| *t == token::COLON))
+ ((self.look_ahead(1, |t| token::is_plain_ident(t)) &&
+ self.look_ahead(2, |t| *t == token::COLON))
+ || self.look_ahead(1, |t| *t == token::DOTDOT))
}
fn parse_match_expr(&mut self) -> @Expr {
return Some(result);
}
- // matches typaram = IDENT optbounds
+ // matches typaram = IDENT optbounds ( EQ ty )?
fn parse_ty_param(&mut self) -> TyParam {
let ident = self.parse_ident();
let opt_bounds = self.parse_optional_ty_param_bounds();
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
let bounds = opt_bounds.unwrap_or_default();
- ast::TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds }
+
+ let default = if self.token == token::EQ {
+ self.bump();
+ Some(self.parse_ty(false))
+ }
+ else { None };
+
+ TyParam {
+ ident: ident,
+ id: ast::DUMMY_NODE_ID,
+ bounds: bounds,
+ default: default
+ }
}
// parse a set of optional generic type parameter declarations
pub fn parse_generics(&mut self) -> ast::Generics {
if self.eat(&token::LT) {
let lifetimes = self.parse_lifetimes();
- let ty_params = self.parse_seq_to_gt(
- Some(token::COMMA),
- |p| p.parse_ty_param());
+ let mut seen_default = false;
+ let ty_params = self.parse_seq_to_gt(Some(token::COMMA), |p| {
+ let ty_param = p.parse_ty_param();
+ if ty_param.default.is_some() {
+ seen_default = true;
+ } else if seen_default {
+ p.span_err(p.last_span,
+ "type parameters with a default must be trailing");
+ }
+ ty_param
+ });
ast::Generics { lifetimes: lifetimes, ty_params: ty_params }
} else {
ast_util::empty_generics()
// A bit of complexity and lookahead is needed here in order to be
// backwards compatible.
let lo = self.span.lo;
+ let mut mutbl_self = MutImmutable;
let explicit_self = match self.token {
token::BINOP(token::AND) => {
maybe_parse_borrowed_explicit_self(self)
maybe_parse_explicit_self(SelfBox, self)
}
token::TILDE => {
- maybe_parse_explicit_self(SelfUniq(MutImmutable), self)
+ maybe_parse_explicit_self(SelfUniq, self)
}
token::IDENT(..) if self.is_self_ident() => {
self.bump();
- SelfValue(MutImmutable)
+ SelfValue
}
token::BINOP(token::STAR) => {
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
// emitting cryptic "unexpected token" errors.
self.bump();
- let mutability = if Parser::token_is_mutability(&self.token) {
+ let _mutability = if Parser::token_is_mutability(&self.token) {
self.parse_mutability()
} else { MutImmutable };
if self.is_self_ident() {
self.span_err(self.span, "cannot pass self by unsafe pointer");
self.bump();
}
- SelfValue(mutability)
+ SelfValue
}
_ if Parser::token_is_mutability(&self.token) &&
self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => {
- let mutability = self.parse_mutability();
+ mutbl_self = self.parse_mutability();
self.expect_self_ident();
- SelfValue(mutability)
+ SelfValue
}
_ if Parser::token_is_mutability(&self.token) &&
self.look_ahead(1, |t| *t == token::TILDE) &&
self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => {
- let mutability = self.parse_mutability();
+ mutbl_self = self.parse_mutability();
self.bump();
self.expect_self_ident();
- SelfUniq(mutability)
+ SelfUniq
}
_ => SelfStatic
};
+ let explicit_self_sp = mk_sp(lo, self.span.hi);
+
// If we parsed a self type, expect a comma before the argument list.
- let fn_inputs;
- if explicit_self != SelfStatic {
+ let fn_inputs = if explicit_self != SelfStatic {
match self.token {
token::COMMA => {
self.bump();
let sep = seq_sep_trailing_disallowed(token::COMMA);
- fn_inputs = self.parse_seq_to_before_end(
+ let mut fn_inputs = self.parse_seq_to_before_end(
&token::RPAREN,
sep,
parse_arg_fn
);
+ fn_inputs.unshift(Arg::new_self(explicit_self_sp, mutbl_self));
+ fn_inputs
}
token::RPAREN => {
- fn_inputs = ~[];
+ ~[Arg::new_self(explicit_self_sp, mutbl_self)]
}
_ => {
let token_str = self.this_token_to_str();
}
} else {
let sep = seq_sep_trailing_disallowed(token::COMMA);
- fn_inputs = self.parse_seq_to_before_end(&token::RPAREN,
- sep,
- parse_arg_fn);
- }
+ self.parse_seq_to_before_end(&token::RPAREN, sep, parse_arg_fn)
+ };
self.expect(&token::RPAREN);
body: body,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
- self_id: ast::DUMMY_NODE_ID,
vis: visa,
}
}
let generics = self.parse_generics();
// This is a new-style impl declaration.
- // XXX: clownshoes
+ // FIXME: clownshoes
let ident = special_idents::clownshoes_extensions;
// Special case: if the next identifier that follows is '(', don't
token_str))
}
- let _ = ast::DUMMY_NODE_ID; // XXX: Workaround for crazy bug.
+ let _ = ast::DUMMY_NODE_ID; // FIXME: Workaround for crazy bug.
let new_id = ast::DUMMY_NODE_ID;
(class_name,
ItemStruct(@ast::StructDef {
(14, As, "as");
(15, Break, "break");
(16, Const, "const");
- (17, Do, "do");
- (18, Else, "else");
- (19, Enum, "enum");
- (20, Extern, "extern");
- (21, False, "false");
- (22, Fn, "fn");
- (23, For, "for");
- (24, If, "if");
- (25, Impl, "impl");
- (26, In, "in");
- (27, Let, "let");
- (28, __LogLevel, "__log_level");
- (29, Loop, "loop");
- (30, Match, "match");
- (31, Mod, "mod");
- (32, Mut, "mut");
- (33, Once, "once");
- (34, Priv, "priv");
- (35, Pub, "pub");
- (36, Ref, "ref");
- (37, Return, "return");
+ (17, Else, "else");
+ (18, Enum, "enum");
+ (19, Extern, "extern");
+ (20, False, "false");
+ (21, Fn, "fn");
+ (22, For, "for");
+ (23, If, "if");
+ (24, Impl, "impl");
+ (25, In, "in");
+ (26, Let, "let");
+ (27, __LogLevel, "__log_level");
+ (28, Loop, "loop");
+ (29, Match, "match");
+ (30, Mod, "mod");
+ (31, Mut, "mut");
+ (32, Once, "once");
+ (33, Priv, "priv");
+ (34, Pub, "pub");
+ (35, Ref, "ref");
+ (36, Return, "return");
// Static and Self are also special idents (prefill de-dupes)
(super::STATIC_KEYWORD_NAME, Static, "static");
(super::SELF_KEYWORD_NAME, Self, "self");
- (38, Struct, "struct");
- (39, Super, "super");
- (40, True, "true");
- (41, Trait, "trait");
- (42, Type, "type");
- (43, Unsafe, "unsafe");
- (44, Use, "use");
- (45, While, "while");
- (46, Continue, "continue");
- (47, Proc, "proc");
- (48, Box, "box");
+ (37, Struct, "struct");
+ (38, Super, "super");
+ (39, True, "true");
+ (40, Trait, "trait");
+ (41, Type, "type");
+ (42, Unsafe, "unsafe");
+ (43, Use, "use");
+ (44, While, "while");
+ (45, Continue, "continue");
+ (46, Proc, "proc");
+ (47, Box, "box");
'reserved:
- (49, Alignof, "alignof");
- (50, Be, "be");
- (51, Offsetof, "offsetof");
- (52, Pure, "pure");
- (53, Sizeof, "sizeof");
- (54, Typeof, "typeof");
- (55, Unsized, "unsized");
- (56, Yield, "yield");
+ (48, Alignof, "alignof");
+ (49, Be, "be");
+ (50, Offsetof, "offsetof");
+ (51, Pure, "pure");
+ (52, Sizeof, "sizeof");
+ (53, Typeof, "typeof");
+ (54, Unsized, "unsized");
+ (55, Yield, "yield");
}
}
base_args: &mut ~[@ast::Expr])
-> Option<@ast::Expr> {
match sugar {
- ast::DoSugar => {
- head(s, "do");
- Some(base_args.pop().unwrap())
- }
ast::ForSugar => {
head(s, "for");
Some(base_args.pop().unwrap())
}
if sugar != ast::NoSugar {
nbsp(s);
- match blk.unwrap().node {
- // need to handle closures specifically
- ast::ExprDoBody(e) => {
- end(s); // we close our head box; closure
- // will create it's own.
- print_expr(s, e);
- end(s); // close outer box, as closures don't
- }
- _ => {
- // not sure if this can happen.
- print_expr(s, blk.unwrap());
- }
- }
+ // not sure if this can happen
+ print_expr(s, blk.unwrap());
}
}
match wth {
Some(expr) => {
ibox(s, indent_unit);
- word(&mut s.s, ",");
- space(&mut s.s);
+ if !fields.is_empty() {
+ word(&mut s.s, ",");
+ space(&mut s.s);
+ }
word(&mut s.s, "..");
print_expr(s, expr);
end(s);
print_expr(s, func);
print_call_post(s, sugar, &blk, &mut base_args);
}
- ast::ExprMethodCall(_, func, ident, ref tys, ref args, sugar) => {
- let mut base_args = (*args).clone();
+ ast::ExprMethodCall(_, ident, ref tys, ref args, sugar) => {
+ let mut base_args = args.slice_from(1).to_owned();
let blk = print_call_pre(s, sugar, &mut base_args);
- print_expr(s, func);
+ print_expr(s, args[0]);
word(&mut s.s, ".");
print_ident(s, ident);
if tys.len() > 0u {
// empty box to satisfy the close.
ibox(s, 0);
}
- ast::ExprDoBody(body) => {
- print_expr(s, body);
- }
ast::ExprBlock(blk) => {
// containing cbox, will be closed by print-block at }
cbox(s, indent_unit);
word(&mut s.s, "]");
}
ast::ExprPath(ref path) => print_path(s, path, true),
- ast::ExprSelf => word(&mut s.s, "self"),
ast::ExprBreak(opt_ident) => {
word(&mut s.s, "break");
space(&mut s.s);
}
pub fn explicit_self_to_str(explicit_self: &ast::ExplicitSelf_, intr: @IdentInterner) -> ~str {
- to_str(explicit_self, |a, &b| { print_explicit_self(a, b); () }, intr)
+ to_str(explicit_self, |a, &b| { print_explicit_self(a, b, ast::MutImmutable); () }, intr)
}
// Returns whether it printed anything
-pub fn print_explicit_self(s: &mut State, explicit_self: ast::ExplicitSelf_) -> bool {
+fn print_explicit_self(s: &mut State,
+ explicit_self: ast::ExplicitSelf_,
+ mutbl: ast::Mutability) -> bool {
+ print_mutability(s, mutbl);
match explicit_self {
ast::SelfStatic => { return false; }
- ast::SelfValue(m) => {
- print_mutability(s, m);
+ ast::SelfValue => {
word(&mut s.s, "self");
}
- ast::SelfUniq(m) => {
- print_mutability(s, m);
+ ast::SelfUniq => {
word(&mut s.s, "~self");
}
ast::SelfRegion(ref lt, m) => {
// self type and the args all in the same box.
rbox(s, 0u, Inconsistent);
let mut first = true;
- for explicit_self in opt_explicit_self.iter() {
- first = !print_explicit_self(s, *explicit_self);
+ for &explicit_self in opt_explicit_self.iter() {
+ let m = match explicit_self {
+ ast::SelfStatic => ast::MutImmutable,
+ _ => match decl.inputs[0].pat.node {
+ ast::PatIdent(ast::BindByValue(m), _, _) => m,
+ _ => ast::MutImmutable
+ }
+ };
+ first = !print_explicit_self(s, explicit_self, m);
}
- for arg in decl.inputs.iter() {
+ // HACK(eddyb) ignore the separately printed self argument.
+ let args = if first {
+ decl.inputs.as_slice()
+ } else {
+ decl.inputs.slice_from(1)
+ };
+
+ for arg in args.iter() {
if first { first = false; } else { word_space(s, ","); }
print_arg(s, arg);
}
let param = generics.ty_params.get(idx);
print_ident(s, param.ident);
print_bounds(s, ¶m.bounds, false);
+ match param.default {
+ Some(default) => {
+ space(&mut s.s);
+ word_space(s, "=");
+ print_type(s, default);
+ }
+ _ => {}
+ }
}
}
popen(s);
}
- // It is unfortunate to duplicate the commasep logic, but we want the
- // self type and the args all in the same box.
- rbox(s, 0u, Inconsistent);
- let mut first = true;
- for explicit_self in opt_explicit_self.iter() {
- first = !print_explicit_self(s, *explicit_self);
- }
- for arg in decl.inputs.iter() {
- if first { first = false; } else { word_space(s, ","); }
- print_arg(s, arg);
- }
- end(s);
+ print_fn_args(s, decl, opt_explicit_self);
if opt_sigil == Some(ast::BorrowedSigil) {
word(&mut s.s, "|");
word(&mut s.s, st);
}
-// XXX(pcwalton): A nasty function to extract the string from an `io::Writer`
+// FIXME(pcwalton): A nasty function to extract the string from an `io::Writer`
// that we "know" to be a `MemWriter` that works around the lack of checked
// downcasts.
unsafe fn get_mem_writer(writer: &mut ~io::Writer) -> ~str {
explicit_self: &ExplicitSelf,
env: E) {
match explicit_self.node {
- SelfStatic | SelfValue(_) | SelfBox | SelfUniq(_) => {}
+ SelfStatic | SelfValue | SelfBox | SelfUniq => {}
SelfRegion(ref lifetime, _) => {
visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env)
}
generics: &Generics,
env: E) {
for type_parameter in generics.ty_params.iter() {
- walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
+ walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone());
+ match type_parameter.default {
+ Some(ty) => visitor.visit_ty(ty, env.clone()),
+ None => {}
+ }
}
walk_lifetime_decls(visitor, &generics.lifetimes, env);
}
}
visitor.visit_expr(callee_expression, env.clone())
}
- ExprMethodCall(_, callee, _, ref types, ref arguments, _) => {
+ ExprMethodCall(_, _, ref types, ref arguments, _) => {
walk_exprs(visitor, *arguments, env.clone());
for &typ in types.iter() {
visitor.visit_ty(typ, env.clone())
}
- visitor.visit_expr(callee, env.clone())
}
ExprBinary(_, _, left_expression, right_expression) => {
visitor.visit_expr(left_expression, env.clone());
visitor.visit_expr(right_expression, env.clone())
}
ExprAddrOf(_, subexpression) |
- ExprUnary(_, _, subexpression) |
- ExprDoBody(subexpression) => {
+ ExprUnary(_, _, subexpression) => {
visitor.visit_expr(subexpression, env.clone())
}
ExprLit(_) => {}
ExprPath(ref path) => {
visitor.visit_path(path, expression.id, env.clone())
}
- ExprSelf | ExprBreak(_) | ExprAgain(_) => {}
+ ExprBreak(_) | ExprAgain(_) => {}
ExprRet(optional_expression) => {
walk_expr_opt(visitor, optional_expression, env.clone())
}
-Subproject commit 535989a92ce1f6f6488c94a2c8f4ed438349f162
+Subproject commit e1dabb48f0f898d1a808b3de3a26f5ee3735c7dd
void*
rust_uv_loop_new() {
-// XXX libuv doesn't always ignore SIGPIPE even though we don't need it.
+// FIXME libuv doesn't always ignore SIGPIPE even though we don't need it.
#ifndef __WIN32__
signal(SIGPIPE, SIG_IGN);
#endif
Reloc::Model RM,
CodeGenOpt::Level OptLevel,
bool EnableSegmentedStacks,
- bool UseSoftFloat) {
+ bool UseSoftFloat,
+ bool NoFramePointerElim) {
std::string Error;
Triple Trip(Triple::normalize(triple));
const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(),
}
TargetOptions Options;
- Options.NoFramePointerElim = true;
+ Options.NoFramePointerElim = NoFramePointerElim;
Options.EnableSegmentedStacks = EnableSegmentedStacks;
Options.FloatABIType = FloatABI::Default;
Options.UseSoftFloat = UseSoftFloat;
std::string ErrorInfo;
raw_fd_ostream OS(path, ErrorInfo, sys::fs::F_Binary);
formatted_raw_ostream FOS(OS);
- PM->add(createPrintModulePass(&FOS));
+ PM->add(createPrintModulePass(FOS));
PM->run(*unwrap(M));
}
return DIT(ref ? unwrap<MDNode>(ref) : NULL);
}
+extern "C" const uint32_t LLVMRustDebugMetadataVersion = DEBUG_METADATA_VERSION;
+
+extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M,
+ const char *name,
+ uint32_t value) {
+ unwrap(M)->addModuleFlag(Module::Warning, name, value);
+}
+
extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) {
return new DIBuilder(*unwrap(M));
}
LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) {
Module *Dst = unwrap(dst);
MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
- std::string Err;
- Module *Src = llvm::getLazyBitcodeModule(buf, Dst->getContext(), &Err);
- if (Src == NULL) {
- LLVMRustError = Err.c_str();
+ ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(buf, Dst->getContext());
+ if (!Src) {
+ LLVMRustError = Src.getError().message().c_str();
delete buf;
return false;
}
- if (Linker::LinkModules(Dst, Src, Linker::DestroySource, &Err)) {
+ std::string Err;
+ if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) {
LLVMRustError = Err.c_str();
return false;
}
extern "C" const char*
LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) {
- for (Archive::child_iterator child = ar->begin_children(),
- end = ar->end_children();
+ for (Archive::child_iterator child = ar->child_begin(),
+ end = ar->child_end();
child != end; ++child) {
StringRef sect_name;
error_code err = child->getName(sect_name);
LLVMRustDestroyArchive(Archive *ar) {
delete ar;
}
+
+extern "C" void
+LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) {
+ GlobalValue *V = unwrap<GlobalValue>(Value);
+ V->setDLLStorageClass(GlobalValue::DLLExportStorageClass);
+}
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2014-01-22
+2014-01-27
#include "llvm/PassManager.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/Analysis/Verifier.h"
+#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/Lint.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/Assembly/Parser.h"
-#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Timer.h"
pub fn foo<T:Send + Clone>(x: T) -> Port<T> {
let (p, c) = Chan::new();
- do task::spawn() {
+ task::spawn(proc() {
c.send(x.clone());
- }
+ });
p
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+pub struct Heap;
+
+pub struct FakeHeap;
+
+pub struct FakeVec<T, A = FakeHeap>;
// part of issue-6919.rs
struct C<'a> {
- k: 'a ||,
+ pub k: 'a ||,
}
fn no_op() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Wrap<A>(A);
#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
register(token::intern("make_a_1"),
- NormalTT(~SyntaxExpanderTT {
- expander: SyntaxExpanderTTExpanderWithoutContext(expand_make_a_1),
+ NormalTT(~BasicMacroExpander {
+ expander: expand_make_a_1,
span: None,
},
None));
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 A {
+ a: int,
+ pub b: int,
+}
+
+pub struct B {
+ a: int,
+ priv b: int,
+}
let to_child = to_child.clone();
let mut builder = task::task();
worker_results.push(builder.future_result());
- do builder.spawn {
+ builder.spawn(proc() {
for _ in range(0u, size / workers) {
//error!("worker {:?}: sending {:?} bytes", i, num_bytes);
to_child.send(bytes(num_bytes));
}
//error!("worker {:?} exiting", i);
- }
+ });
}
- do task::spawn || {
+ task::spawn(proc() {
server(&from_parent, &to_parent);
- }
+ });
for r in worker_results.iter() {
r.recv();
let (from_parent, to_child) = Chan::new();
let mut builder = task::task();
worker_results.push(builder.future_result());
- do builder.spawn {
+ builder.spawn(proc() {
for _ in range(0u, size / workers) {
//error!("worker {:?}: sending {:?} bytes", i, num_bytes);
to_child.send(bytes(num_bytes));
}
//error!("worker {:?} exiting", i);
- };
+ });
from_parent
} else {
let (from_parent, to_child) = SharedChan::new();
let to_child = to_child.clone();
let mut builder = task::task();
worker_results.push(builder.future_result());
- do builder.spawn {
+ builder.spawn(proc() {
for _ in range(0u, size / workers) {
//error!("worker {:?}: sending {:?} bytes", i, num_bytes);
to_child.send(bytes(num_bytes));
}
//error!("worker {:?} exiting", i);
- };
+ });
}
from_parent
};
- do task::spawn || {
+ task::spawn(proc() {
server(&from_parent, &to_parent);
- }
+ });
for r in worker_results.iter() {
r.recv();
//error!("spawning %?", i);
let (new_chan, num_port) = init();
let num_chan_2 = num_chan.clone();
- let new_future = do Future::spawn() {
+ let new_future = Future::spawn(proc() {
thread_ring(i, msg_per_task, num_chan_2, num_port)
- };
+ });
futures.push(new_future);
num_chan = new_chan;
};
//error!("spawning %?", i);
let (new_chan, num_port) = init();
let num_chan_2 = num_chan.clone();
- let new_future = do Future::spawn {
+ let new_future = Future::spawn(proc() {
thread_ring(i, msg_per_task, num_chan_2, num_port)
- };
+ });
futures.push(new_future);
num_chan = new_chan;
};
// Create a stream B->A
let (pb,cb) = Chan::<()>::new();
- do spawn() || {
+ spawn(proc() {
let chan = ca;
let port = pb;
- n.times(|| {
+ for _ in range(0, n) {
chan.send(());
port.recv();
- })
- }
+ }
+ });
- do spawn() || {
+ spawn(proc() {
let chan = cb;
let port = pa;
- n.times(|| {
+ for _ in range(0, n) {
port.recv();
chan.send(());
- })
- }
+ }
+ });
}
- m.times(|| {
+ for _ in range(0, m) {
run_pair(n)
- })
+ }
}
}
let (port,chan) = Chan::new();
- do spawn {
+ spawn(proc() {
chan.send(parfib(n-1));
- };
+ });
let m2 = parfib(n-2);
return (port.recv() + m2);
}
100000
};
- n.times(|| {
- do spawn || {};
- })
+ for _ in range(0, n) {
+ spawn(proc() {});
+ }
}
// except according to those terms.
extern mod extra;
+extern mod arena;
use std::iter::range_step;
use extra::future::Future;
-use extra::arena::TypedArena;
+use arena::TypedArena;
enum Tree<'a> {
Nil,
let mut messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
use std::num::pow;
let iterations = pow(2, (max_depth - depth + min_depth) as uint);
- do Future::spawn {
+ Future::spawn(proc() {
let mut chk = 0;
for i in range(1, iterations + 1) {
let arena = TypedArena::new();
}
format!("{}\t trees of depth {}\t check: {}",
iterations * 2, depth, chk)
- }
+ })
}).to_owned_vec();
for message in messages.mut_iter() {
let to_rendezvous = to_rendezvous.clone();
let to_rendezvous_log = to_rendezvous_log.clone();
let (from_rendezvous, to_creature) = Chan::new();
- do task::spawn {
+ task::spawn(proc() {
creature(ii,
col,
from_rendezvous,
to_rendezvous.clone(),
to_rendezvous_log.clone());
- }
+ });
to_creature
}).collect();
AminoAcid { c: 't' as u8, p: 0.3015094502008 },
];
-// XXX: Use map().
+// FIXME: Use map().
fn sum_and_scale(a: &'static [AminoAcid]) -> ~[AminoAcid] {
let mut result = ~[];
let mut p = 0f32;
let (from_parent, to_child) = Chan::new();
- do spawn {
+ spawn(proc() {
make_sequence_processor(sz, &from_parent, &to_parent_);
- }
+ });
to_child
}).collect::<~[Chan<~[u8]>]>();
code
}
- // XXX: Inefficient.
+ // FIXME: Inefficient.
fn unpack(&self, frame: i32) -> ~str {
let mut key = **self;
let mut result = ~[];
Iterate {f: f, next: x}
}
struct Iterate<'a, T> {
- priv f: 'a |&T| -> T,
- priv next: T
+ f: 'a |&T| -> T,
+ next: T
}
impl<'a, T> Iterator<T> for Iterate<'a, T> {
fn next(&mut self) -> Option<T> {
Cons(T, &'a List<'a, T>)
}
struct ListIterator<'a, T> {
- priv cur: &'a List<'a, T>
+ cur: &'a List<'a, T>
}
impl<'a, T> List<'a, T> {
fn iter(&'a self) -> ListIterator<'a, T> {
for i in range(0, num_tasks) {
let mut builder = task::task();
results.push(builder.future_result());
- do builder.spawn {
+ builder.spawn(proc() {
stress_task(i);
- }
+ });
}
for r in results.iter() {
r.recv();
let w = wait.clone();
let v = v.clone();
let out = out.clone();
- do spawn {
+ spawn(proc() {
for i in range(chk, min(len, chk + chunk)) {
let val = v.read(|v| f(v, i));
out.write(|out| out[i] = val);
}
let _ = w;
- }
+ });
}
let _ = wait.unwrap();
}
let (next_p, ch) = Chan::new();
let imm_i = i;
let imm_p = p;
- do spawn {
+ spawn(proc() {
roundtrip(imm_i, n_tasks, &imm_p, &ch);
- };
+ });
p = next_p;
i += 1;
}
let imm_p = p;
let imm_ch = ch1;
- do spawn {
+ spawn(proc() {
roundtrip(1, n_tasks, &imm_p, &imm_ch);
- }
+ });
}
fn roundtrip(id: int, n_tasks: int, p: &Port<int>, ch: &Chan<int>) {
--- /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.
+
+// Useful smoketest for scheduler performance.
+fn main() {
+ for _ in range(1, 100_000) {
+ spawn(proc() {})
+ }
+}
--- /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.
+
+// Useful for checking syscall usage of baseline scheduler usage
+fn main() {
+ spawn(proc() {});
+}
fn run(repeat: int, depth: int) {
for _ in range(0, repeat) {
info!("starting {:.4f}", precise_time_s());
- do task::try {
+ task::try(proc() {
recurse_or_fail(depth, None)
- };
+ });
info!("stopping {:.4f}", precise_time_s());
}
}
// This used to be O(n^2) in the number of generations that ever existed.
// With this code, only as many generations are alive at a time as tasks
// alive at a time,
- do spawn {
+ spawn(proc() {
if gens_left & 1 == 1 {
task::deschedule(); // shake things up a bit
}
} else {
c.send(())
}
- }
+ });
}
fn main() {
for _ in range(0, num_tasks) {
let ch = ch.clone();
let mut t = task::task();
- do t.spawn { // linked
+ t.spawn(proc() { // linked
ch.send(());
let (p, _c) = stream::<()>();
p.recv(); // block forever
- }
+ });
}
error!("Grandchild group getting started");
for _ in range(0, num_tasks) {
// Main group #0 waits for unsupervised group #1.
// Grandparent group #1 waits for middle group #2, then fails, killing #3.
// Middle group #2 creates grandchild_group #3, waits for it to be ready, exits.
- let x: result::Result<(), ~Any> = do task::try { // unlinked
- do spawn_supervised_blocking("grandparent") {
- do spawn_supervised_blocking("middle") {
+ let x: result::Result<(), ~Any> = task::try(proc() { // unlinked
+ spawn_supervised_blocking("grandparent", proc() {
+ spawn_supervised_blocking("middle", proc() {
grandchild_group(num_tasks);
- }
+ });
// When grandchild group is ready to go, make the middle group exit.
error!("Middle group wakes up and exits");
- }
+ });
// Grandparent group waits for middle group to be gone, then fails
error!("Grandparent group wakes up and fails");
fail!();
- };
+ });
assert!(x.is_err());
}
let wait_ports: ~[Port<Chan<Chan<int>>>] = vec::from_fn(children, |_| {
let (wait_port, wait_chan) = stream::<Chan<Chan<int>>>();
- do task::spawn {
+ task::spawn(proc() {
calc(children / 2, &wait_chan);
- }
+ });
wait_port
});
args
};
- let children = from_str::<uint>(args[1]).get();
+ let children = from_str::<uint>(args[1]).unwrap();
let (wait_port, wait_chan) = stream();
- do task::spawn {
+ task::spawn(proc() {
calc(children, &wait_chan);
- };
+ });
let start_chan = wait_port.recv();
let (sum_port, sum_chan) = stream::<int>();
start_chan.send(sum_chan);
let sum = sum_port.recv();
- error!("How many tasks? %d tasks.", sum);
+ error!("How many tasks? {} tasks.", sum);
}
});
y.unwrap();
// Adding this line causes a method unification failure instead
- // do (&option::unwrap(y)).read |state| { assert!(*state == 1); }
+ // (&option::unwrap(y)).read(|state| { assert!(*state == 1); })
}
x.write_downgrade(|write_mode| y = Some(write_mode));
y.unwrap();
// Adding this line causes a method unification failure instead
- // do (&option::unwrap(y)).write |state| { assert!(*state == 1); }
+ // (&option::unwrap(y)).write(|state| { assert!(*state == 1); })
}
}
fn foo<'a>() {
- let _ = S::new::<int,f64>(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _ = S::new::<int,f64>(1, 1.0); //~ ERROR the impl referenced by this path needs 1 type parameter, but 0 type parameters were supplied
let _ = S::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
- let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path needs 1 type parameter, but 0 type parameters were supplied
let _: S2 = Trait::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
}
let mut v = ~3;
let mut x = &mut v;
- 3.times(|| {
+ for _ in range(0, 3) {
borrow(v); //~ ERROR cannot borrow
- });
+ }
*x = ~5;
}
fn box_imm() {
let v = ~3;
let _w = &v;
- do task::spawn {
+ task::spawn(proc() {
info!("v={}", *v);
//~^ ERROR cannot move `v` into closure
- }
+ });
let v = ~3;
let _w = &v;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 foo() {}
+
+fn main() {
+ let f = foo;
+ let f_closure: || = f;
+ //~^ ERROR: cannot coerce non-statically resolved bare fn
+ let f_proc: proc() = f;
+ //~^ ERROR: cannot coerce non-statically resolved bare fn
+}
+++ /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.
-
-#[feature(struct_variant)];
-
-struct NotEq;
-
-#[deriving(Eq)]
-enum Foo {
- Bar {
- x: NotEq //~ ERROR mismatched types
- //~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
- }
-}
-
-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.
-
-#[feature(struct_variant)];
-
-struct NotEq;
-
-#[deriving(Eq)]
-enum Foo {
- Bar(NotEq), //~ ERROR mismatched types
- //~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
- Baz { x: NotEq }
-}
-
-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.
-
-struct NotEq;
-
-#[deriving(Eq)]
-struct Foo {
- x: NotEq //~ ERROR mismatched types
- //~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
-}
-
-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.
-
-struct NotEq;
-
-#[deriving(Eq)]
-struct Foo (
- NotEq //~ ERROR mismatched types
- //~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
- );
-
-pub fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 NoCloneOrEq;
+
+#[deriving(Eq)]
+struct E {
+ x: NoCloneOrEq //~ ERROR does not implement any method in scope named `eq`
+ //~^ ERROR does not implement any method in scope named `ne`
+}
+#[deriving(Clone)]
+struct C {
+ x: NoCloneOrEq //~ ERROR does not implement any method in scope named `clone`
+}
+
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Clone)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Clone)]
+enum Enum {
+ A(
+ Error //~ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Clone)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Clone)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(Clone)]
+struct Error;
+
+#[deriving(DeepClone,Clone)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(Clone)]
+struct Error;
+
+#[deriving(DeepClone,Clone)]
+enum Enum {
+ A(
+ Error //~ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(Clone)]
+struct Error;
+
+#[deriving(DeepClone,Clone)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(Clone)]
+struct Error;
+
+#[deriving(DeepClone,Clone)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Default)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Default)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Eq)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+//~^ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Eq)]
+enum Enum {
+ A(
+ Error //~ ERROR
+//~^ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Eq)]
+struct Struct {
+ x: Error //~ ERROR
+//~^ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Eq)]
+struct Struct(
+ Error //~ ERROR
+//~^ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Ord)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Ord)]
+enum Enum {
+ A(
+ Error //~ ERROR
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Ord)]
+struct Struct {
+ x: Error //~ ERROR
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Ord)]
+struct Struct(
+ Error //~ ERROR
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Rand)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Rand)]
+enum Enum {
+ A(
+ Error //~ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Rand)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Rand)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(TotalEq)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(TotalEq)]
+enum Enum {
+ A(
+ Error //~ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(TotalEq)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(TotalEq)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(TotalEq)]
+struct Error;
+
+#[deriving(TotalOrd,TotalEq)]
+enum Enum {
+ A {
+ x: Error //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(TotalEq)]
+struct Error;
+
+#[deriving(TotalOrd,TotalEq)]
+enum Enum {
+ A(
+ Error //~ ERROR
+ )
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(TotalEq)]
+struct Error;
+
+#[deriving(TotalOrd,TotalEq)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+#[deriving(TotalEq)]
+struct Error;
+
+#[deriving(TotalOrd,TotalEq)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Zero)]
+struct Struct {
+ x: Error //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
+
+#[feature(struct_variant)];
+extern mod extra;
+
+
+struct Error;
+
+#[deriving(Zero)]
+struct Struct(
+ Error //~ ERROR
+);
+
+fn main() {}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- do something
- |x| do somethingelse //~ ERROR: expected `{` but found `do`
- |y| say(x, y)
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- let x = do y; //~ ERROR: expected `{` but found
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f(f: proc(int) -> bool) -> bool { f(10i) }
-
-fn main() {
- assert!(do f() |i| { i == 10i } == 10i);
- //~^ ERROR: expected `bool` but found `int`
-}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 Heap;
+
+struct Vec<T, A = Heap>; //~ ERROR: default type parameters are experimental
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[simd]
+pub struct i64x2(i64, i64); //~ ERROR: SIMD types are experimental
+
+fn main() {}
\ No newline at end of file
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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-fast feature doesn't work.
+
+fn main() {
+ trace_macros!(true); //~ ERROR: `trace_macros` is not stable
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct Foo<A, B, C = (A, B)>;
+
+impl<A, B, C = (A, B)> Foo<A, B, C> {
+ fn new() -> Foo<A, B, C> {Foo}
+}
+
+fn main() {
+ Foo::<int>::new(); //~ ERROR the impl referenced by this path needs at least 2 type parameters, but 1 type parameter were supplied
+ //~^ ERROR not enough type parameters provided: expected at least 2, found 1
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+impl<T, A = Heap> Vec<T, A> {
+ fn new() -> Vec<T, A> {Vec}
+}
+
+fn main() {
+ Vec::<int, Heap, bool>::new(); //~ ERROR the impl referenced by this path needs at most 2 type parameters, but 3 type parameters were supplied
+ //~^ ERROR too many type parameters provided: expected at most 2, found 3
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<A = Heap, T>; //~ ERROR type parameters with a default must be trailing
+
+struct Foo<A, B = Vec<C>, C>; //~ ERROR type parameters with a default must be trailing
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+fn main() {
+ let _: Vec; //~ ERROR wrong number of type arguments: expected at least 1 but found 0
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+fn main() {
+ let _: Vec<int, Heap, bool>; //~ ERROR wrong number of type arguments: expected at most 2 but found 3
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+struct A;
+struct B;
+struct C;
+struct Foo<T = A, U = B, V = C>;
+
+fn main() {
+ // Ensure that the printed type doesn't include the default type params...
+ let _: Foo<int> = ();
+ //~^ ERROR mismatched types: expected `Foo<int>` but found `()`
+
+ // ...even when they're present, but the same types as the defaults.
+ let _: Foo<int, B, C> = ();
+ //~^ ERROR mismatched types: expected `Foo<int>` but found `()`
+
+ // But not when there's a different type in between.
+ let _: Foo<A, int, C> = ();
+ //~^ ERROR mismatched types: expected `Foo<A,int>` but found `()`
+
+ // And don't print <> at all when there's just defaults.
+ let _: Foo<A, B, C> = ();
+ //~^ ERROR mismatched types: expected `Foo` but found `()`
+}
// except according to those terms.
fn main() {
- let _f = 10.times; //~ ERROR attempted to take value of method
+ let _f = 10i.abs; //~ ERROR attempted to take value of method
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+enum foo { foo(bar) }
+enum bar { bar_none, bar_some(bar) } //~ ERROR illegal recursive enum type; wrap the inner value in a box to make it representable
+
+fn main() {
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+enum foo { foo(bar) }
+struct bar { x: bar } //~ ERROR illegal recursive struct type; wrap the inner value in a box to make it representable
+//~^ ERROR this type cannot be instantiated without an instance of itself
+
+fn main() {
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+enum E1 { V1(E2<E1>), }
+enum E2<T> { V2(E2<E1>), } //~ ERROR illegal recursive enum type; wrap the inner value in a box to make it representable
+
+fn main() {
+}
fn main() {
let needlesArr: ~[char] = ~['a', 'f'];
- do needlesArr.iter().fold() |x, y| {
- }
- //~^^ ERROR 1 parameter was supplied (including the closure passed by the `do` keyword)
+ needlesArr.iter().fold(|x, y| {
+ });
+ //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied
//
// the first error is, um, non-ideal.
}
+++ /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
-fn function() -> &mut [int] {
- let mut x: &'static mut [int] = &[1,2,3];
- x[0] = 12345;
- x //~ ERROR bad
-}
-
-fn main() {
- let x = function();
- error!("%?", x);
-}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 S { //~ ERROR illegal recursive struct type; wrap the inner value in a box to make it representable
+ element: Option<S>
+}
+
+fn main() {
+ let x = S { element: None };
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-extern mod extra;
-use std::cmp::Eq;
-
-fn f<T:Eq>(o: &mut Option<T>) {
- assert!(*o == None);
-}
-
-fn main() {
- f::<int>(&mut None);
- //~^ ERROR cannot borrow
-}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
struct A;
impl A {
fn m(&self) {
- fn x() {
- self.m()
- //~^ ERROR can't capture dynamic environment in a fn item
- //~^^ ERROR `self` is not allowed in this context
- }
+ fn x() {
+ self.m() //~ ERROR can't capture dynamic environment in a fn item
+ //~^ ERROR unresolved name `self`
+ }
}
}
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.
-
-// This file was auto-generated using 'src/etc/generate-keyword-tests.py do'
-
-fn main() {
- let do = "foo"; //~ error: ident
-}
+++ /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.
-
-use std::task;
-
-fn user(_i: int) {}
-
-fn foo() {
- // Here, i is *moved* into the closure: Not actually OK
- let mut i = 0;
- do task::spawn {
- user(i); //~ ERROR mutable variables cannot be implicitly captured
- }
-}
-
-fn bar() {
- // Here, i would be implicitly *copied* but it
- // is mutable: bad
- let mut i = 0;
- while i < 10 {
- do task::spawn {
- user(i); //~ ERROR mutable variables cannot be implicitly captured
- }
- i += 1;
- }
-}
-
-fn car() {
- // Here, i is mutable, but *explicitly* shadowed copied:
- let mut i = 0;
- while i < 10 {
- {
- let i = i;
- do task::spawn {
- user(i);
- }
- }
- i += 1;
- }
-}
-
-fn main() {
-}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[feature(default_type_params)];
+
+#[deny(default_type_param_usage)];
+
+pub struct Heap;
+
+pub struct Vec<T, A = Heap>;
+
+pub struct FooAlloc;
+
+pub type VecFoo<T> = Vec<T, FooAlloc>; //~ ERROR provided type arguments with defaults
+
+fn main() {}
struct Foo {
a: int,
- priv b: int,
+ b: int,
}
pub struct PubFoo { //~ ERROR: missing documentation
enum Baz {
BazA {
a: int,
- priv b: int
+ b: int
},
BarB
}
use self::lint_stability::*;
fn test() {
- // XXX: attributes on methods are not encoded cross crate.
+ // FIXME: attributes on methods are not encoded cross crate.
let foo = MethodTester;
deprecated(); //~ ERROR use of deprecated item
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(dead_assignment)];
+#[allow(unused_variable)];
+#[allow(dead_code)];
+#[deny(unused_mut)];
+
+struct Foo;
+impl Foo {
+ fn foo(mut self) {} //~ ERROR: variable does not need to be mutable
+ fn bar(mut ~self) {} //~ ERROR: variable does not need to be mutable
+}
+
+fn main() {}
// immediately, so that we get more errors listed at a time.
#[feature(asm)];
+#[feature(trace_macros)];
#[deriving(Default, //~ ERROR
Rand, //~ ERROR
fn main() {
let x = ~"Hello world!";
- do task::spawn {
+ task::spawn(proc() {
println!("{}", x);
- }
+ });
println!("{}", x); //~ ERROR use of moved value
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
let arc = ~MutexArc::new(1);
let arc2 = ~MutexArc::new(*arc);
- do task::spawn || {
+ task::spawn(proc() {
(*arc2).access(|mutex| { //~ ERROR instantiating a type parameter with an incompatible type
})
- };
+ });
}
fn main() {}
let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = arc::Arc::new(v);
- do task::spawn() {
+ task::spawn(proc() {
let v = arc_v.get();
assert_eq!(v[3], 4);
- };
+ });
assert_eq!((arc_v.get())[2], 3);
let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = arc::Arc::new(v);
- do task::spawn() {
+ task::spawn(proc() {
let v = arc_v.get();
assert_eq!(v[3], 4);
- };
+ });
assert_eq!((arc_v.get())[2], 3); //~ ERROR use of moved value: `arc_v`
let x = foo(Port(@()));
- do task::spawn {
+ task::spawn(proc() {
let y = x; //~ ERROR does not fulfill `Send`
error!("{:?}", y);
- }
+ });
}
fn main() {
let x = arc::Arc::new(true);
- do foo {
+ foo(proc() {
assert!(*x.get());
drop(x);
- }
+ });
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This tests verifies that unary structs and enum variants
+// are treated as rvalues and their lifetime is not bounded to
+// the static scope.
+
+struct Test;
+
+enum MyEnum {
+ Variant1
+}
+
+fn structLifetime() -> &Test {
+ let testValue = &Test; //~ ERROR borrowed value does not live long enough
+ testValue
+}
+
+fn variantLifetime() -> &MyEnum {
+ let testValue = &Variant1; //~ ERROR borrowed value does not live long enough
+ testValue
+}
+
+
+fn main() {}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we cannot return a stack allocated slice
+
+fn function(x: int) -> &'static [int] {
+ &[x] //~ ERROR mismatched types
+}
+
+fn main() {
+ let x = function(1);
+ let y = x[0];
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 FIXME #11741 tuple structs ignore stability attributes
+
+#[deny(experimental)];
+
+use std::unstable::simd;
+
+fn main() {
+ let _ = simd::i64x2(0, 0); //~ ERROR: experimental
+}
+#[feature(simd)];
+
#[simd]
struct vec4<T>(T, T, T, T); //~ ERROR SIMD vector cannot be generic
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:struct-field-privacy.rs
+
+extern mod xc = "struct-field-privacy";
+
+struct A {
+ a: int,
+}
+
+mod inner {
+ struct A {
+ a: int,
+ pub b: int,
+ priv c: int, //~ ERROR: unnecessary `priv` visibility
+ }
+ pub struct B {
+ a: int,
+ priv b: int,
+ pub c: int, //~ ERROR: unnecessary `pub` visibility
+ }
+}
+
+fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B) {
+ //~^ ERROR: type `A` is private
+ //~^^ ERROR: struct `A` is private
+
+ a.a;
+ b.a; //~ ERROR: field `a` is private
+ b.b;
+ b.c; //~ ERROR: field `c` is private
+ c.a;
+ c.b; //~ ERROR: field `b` is private
+ c.c;
+
+ d.a; //~ ERROR: field `a` is private
+ d.b;
+
+ e.a;
+ e.b; //~ ERROR: field `b` is private
+}
+
+fn main() {}
y = Some(x.downgrade(write_mode));
})
// Adding this line causes a method unification failure instead
- // do (&option::unwrap(y)).read { }
+ // (&option::unwrap(y)).read(proc() { });
}
y = Some(write_mode);
});
// Adding this line causes a method unification failure instead
- // do (&option::unwrap(y)).write { }
+ // (&option::unwrap(y)).write(proc() { })
}
// error-pattern:mismatched types: expected `char` but found
// Issue #876
-#[no_std];
-
-extern mod std;
+#[no_implicit_prelude];
fn last<T>(v: ~[&T]) -> std::option::Option<T> {
fail!();
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
}
impl foo for int {
fn bar(&self) -> int {
- //~^ ERROR method `bar` has 0 parameters but the declaration in trait `foo::bar` has 1
+ //~^ ERROR method `bar` has 1 parameter but the declaration in trait `foo::bar` has 2
*self
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[deny(unused_result, unused_must_use)];
+#[allow(dead_code)];
+
+#[must_use]
+enum MustUse { Test }
+
+fn foo<T>() -> T { fail!() }
+
+fn bar() -> int { return foo::<int>(); }
+fn baz() -> MustUse { return foo::<MustUse>(); }
+
+#[allow(unused_result)]
+fn test() {
+ foo::<int>();
+ foo::<MustUse>(); //~ ERROR: unused result which must be used
+}
+
+#[allow(unused_result, unused_must_use)]
+fn test2() {
+ foo::<int>();
+ foo::<MustUse>();
+}
+
+fn main() {
+ foo::<int>(); //~ ERROR: unused result
+ foo::<MustUse>(); //~ ERROR: unused result which must be used
+
+ let _ = foo::<int>();
+ let _ = foo::<MustUse>();
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct A { pub i: int } //~ ERROR: unnecessary `pub`
-struct B { priv i: int } // don't warn b/c B can still be returned
+struct A { pub i: int }
+struct B { priv i: int } //~ ERROR: unnecessary `priv`
pub enum C { pub Variant } //~ ERROR: unnecessary `pub`
enum D { priv Variant2 } //~ ERROR: unnecessary `priv`
while_expr(40, 41, 42);
loop_expr(43, 44, 45);
}
-
-
-
--- /dev/null
+fn main() {
+ let args : ~[~str] = ::std::os::args();
+ ::std::io::println(args[0]);
+}
+
+
+// xfail-android: FIXME(#10381)
+
+// This test case checks whether compile unit names are set correctly, so that the correct default
+// source file can be found.
+
+// compile-flags:-Z extra-debug-info
+// debugger:list
+// check:1[...]fn main() {
+// check:2[...]let args : ~[~str] = ::std::os::args();
+// check:3[...]::std::io::println(args[0]);
+// check:4[...]}
+
+// 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.
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// error-pattern:index out of bounds: the len is 3 but the index is
-use std::uint::max_value;
+use std::uint;
use std::mem::size_of;
fn main() {
let xs = [1, 2, 3];
- xs[max_value / size_of::<int>() + 1];
+ xs[uint::MAX / size_of::<int>() + 1];
}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// length (in bytes), because the scaling of the index will cause it to
// wrap around to a small number.
- let idx = uint::max_value & !(uint::max_value >> 1u);
+ let idx = uint::MAX & !(uint::MAX >> 1u);
error!("ov2 idx = 0x%x", idx);
// This should fail.
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// This test is only meaningful on 32-bit hosts.
- let idx = u64::max_value & !(u64::max_value >> 1u);
+ let idx = u64::MAX & !(u64::MAX >> 1u);
error!("ov3 idx = 0x%8.8x%8.8x",
(idx >> 32) as uint,
idx as uint);
}
fn main() {
- do 10u.times {
- do task::spawn {
+ for _ in range(0, 10u) {
+ task::spawn(proc() {
let result = count(5u);
info!("result = %?", result);
fail!();
- };
+ });
}
}
use std::task;
fn main() {
- do task::try {
+ task::try(proc() {
fail!("test");
1
- }.unwrap()
+ }).unwrap()
}
fn main() {
let mut t = task::task();
t.name(~"owned name");
- do t.try {
+ t.try(proc() {
fail!("test");
1
- }.unwrap()
+ }).unwrap()
}
fn main() {
let mut t = ::std::task::task();
t.name("send name".to_send_str());
- do t.try {
+ t.try(proc() {
fail!("test");
3
- }.unwrap()
+ }).unwrap()
}
fn main() {
let mut t = ::std::task::task();
t.name("static name");
- do t.try {
+ t.try(proc() {
fail!("test");
- }.unwrap()
+ }).unwrap()
}
}
fn main() {
- do task::spawn {
+ task::spawn(proc() {
let r = and_then_get_big_again(4);
getbig_call_c_and_fail(10000);
- };
+ });
}
}
fn main() {
- do task::spawn {
+ task::spawn(proc() {
getbig_and_fail(400);
- };
+ });
}
}
fn main() {
- do task::spawn {
+ task::spawn(proc() {
getbig_and_fail(1);
- };
+ });
}
#[start]
fn start(argc: int, argv: **u8) -> int {
- do native::start(argc, argv) {
+ native::start(argc, argv, proc() {
fail!();
- }
+ })
}
fn main() {
error!("whatever");
- do task::spawn {
+ task::spawn(proc() {
let _i = r(5);
- };
+ });
fail!();
}
// except according to those terms.
#[crate_id="boot#0.1"];
-#[crate_type="lib"];
+#[crate_type="dylib"];
#[no_uv];
extern mod rustuv;
#[no_mangle] // this needs to get called from C
pub extern "C" fn foo(argc: int, argv: **u8) -> int {
- do green::start(argc, argv) {
- do spawn {
+ green::start(argc, argv, proc() {
+ spawn(proc() {
println!("hello");
- }
- }
+ });
+ })
}
// except according to those terms.
#[crate_id="boot#0.1"];
-#[crate_type="lib"];
+#[crate_type="dylib"];
#[no_uv];
extern mod native;
#[no_mangle] // this needs to get called from C
pub extern "C" fn foo(argc: int, argv: **u8) -> int {
- do native::start(argc, argv) {
- do spawn {
+ native::start(argc, argv, proc() {
+ spawn(proc() {
println!("hello");
- }
- }
+ });
+ })
}
}
fn main() {
- do task::try {
+ task::try(proc() {
let _a = A;
lib::callback(|| fail!());
1
- };
+ });
unsafe {
assert!(lib::statik == 1);
fn check_pp<T>(cx: fake_ext_ctxt,
expr: T, f: |pprust::ps, T|, expect: ~str) {
- let s = do io::with_str_writer |wr| {
+ let s = io::with_str_writer(|wr| {
let pp = pprust::rust_printer(wr, cx.parse_sess().interner);
f(pp, expr);
pp::eof(pp.s);
- };
+ });
stdout().write_line(s);
if expect != ~"" {
error!("expect: '%s', got: '%s'", expect, s);
(@"test").test_imm();
(&"test").test_imm();
- // XXX: Other types of mutable vecs don't currently exist
+ // FIXME: Other types of mutable vecs don't currently exist
// NB: We don't do this double autoreffing for &mut self because that would
// allow creating a mutable pointer to a temporary, which would be a source
}
pub fn main() {
- 10000.times(|| bitv_test());
+ for _ in range(0, 10000) { bitv_test(); }
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn add(x: proc(f64) -> f64) -> f64 {
- x(10.0)
-}
-
-pub fn main() {
- // Trailing expressions don't require parentheses:
- let y = do add |x| { x + 10.0 } + 10.0;
-
- assert_eq!(y, 30.0);
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f(_: proc()) -> proc(proc() -> uint) {
- proc(_: proc() -> uint) {}
-}
-
-pub fn main() {
- do do f {} { 20 };
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f(_: proc()) -> proc(uint) -> uint {
- proc(x: uint) { x }
-}
-
-pub fn main() {
- let z = do f {} (22u);
- assert_eq!(z, 22u);
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f(_: proc(int, int) -> int) -> int {
- 10
-}
-
-fn w_semi() {
- // the semicolon causes compiler not to
- // complain about the ignored return value:
- do f |x, y| { x+y };
-}
-
-fn w_paren1() -> int {
- (do f |x, y| { x+y }) - 10
-}
-
-fn w_paren2() -> int {
- (do f |x, y| { x+y } - 10)
-}
-
-fn w_ret() -> int {
- return do f |x, y| { x+y } - 10;
-}
-
-pub fn main() {
- w_semi();
- w_paren1();
- w_paren2();
- w_ret();
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn call_any(f: proc() -> uint) -> uint {
- return f();
-}
-
-pub fn main() {
- let x_r = do call_any { 22u };
- assert_eq!(x_r, 22u);
-}
info!("{:?}", *i);
}
- // Usable at all:
- do inty |x| { x };
-
- // Higher precedence than assignments:
- let result = do inty |e| { e };
- assert_eq!(result, 100);
-
- // Higher precedence than unary operations:
- let stringy = do inty |e| { e }.to_str();
- assert!(do booly |_| { true });
- assert!(!do booly |_| { false });
-
- // Usable in funny statement-like forms:
- if !do booly |_| { true } {
- assert!(false);
- }
- match do booly |_| { false } {
- true => { fail!("incorrect answer."); }
- false => { }
- }
- match 3 {
- _ if do booly |_| { true } => {
- }
- _ => {
- fail!("wrong answer.");
- }
- }
-
-
- // Lower precedence than binary operations:
- let w = do inty |_| { 10 } + 10;
- let y = do inty |_| { 10 } + 10;
- let z = 10 + do inty |_| { 10 };
- assert_eq!(w, y);
- assert_eq!(y, z);
-
- // In the tail of a block
- let w = if true {
- do booly |_| {
- true
- }
- } else {
- false
- };
- assert!(w);
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#[feature(managed_boxes)];
-use std::borrow;
use std::ptr;
fn borrow(x: &int, f: |x: &int|) {
fn test1(x: @~int) {
borrow(&*(*x).clone(), |p| {
let x_a = ptr::to_unsafe_ptr(&**x);
- assert!((x_a as uint) != borrow::to_uint(p));
+ assert!((x_a as uint) != (p as *int as uint));
assert_eq!(unsafe{*x_a}, *p);
})
}
fn foo(x: ()) -> Port<()> {
let (p, c) = Chan::<()>::new();
- do task::spawn() {
+ task::spawn(proc() {
c.send(x);
- }
+ });
p
}
#[start]
fn start(argc: int, argv: **u8) -> int {
- do native::start(argc, argv) {
+ native::start(argc, argv, proc() {
main();
- }
+ })
}
fn main() {
let (p, c) = Chan::new();
let (mut r, w) = (PortReader::new(p), ChanWriter::new(c));
- do spawn {
+ spawn(proc() {
set_logger(~MyWriter(w) as ~Logger);
debug!("debug");
info!("info");
- }
+ });
assert_eq!(r.read_to_str(), ~"info\n");
}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::borrow;
-
pub fn main() {
let x = 3;
- info!("&x={:x}", borrow::to_uint(&x));
+ info!("&x={:x}", (&x as *int as uint));
}
}
struct dog {
- priv barks: uint,
+ barks: uint,
volume: int,
}
#[deriving(Clone)]
struct cat {
- priv meows: uint,
+ meows: uint,
how_hungry: int,
name: ~str,
}
struct cat {
- priv meows: uint,
+ meows: uint,
how_hungry: int,
name: ~str,
}
// ok: T should be in scope when resolving the trait ref for map
struct cat<T> {
// Yes, you can have negative meows
- priv meows : int,
+ meows : int,
how_hungry : int,
name : T,
use cci_class_trait::animals::noisy;
struct cat {
- priv meows: uint,
+ meows: uint,
how_hungry : int,
name : ~str,
#[deriving(Clone)]
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
name : ~str,
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat<U> {
- priv info : ~[U],
- priv meows : uint,
+ info : ~[U],
+ meows : uint,
how_hungry : int,
}
// xfail-fast
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
name : ~str,
// except according to those terms.
struct cat<U> {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
name : ~str,
pub fn main() {
let (p,c) = Chan::new();
- do foo {
+ foo(proc() {
c.send(());
- }
+ });
p.recv();
}
pub fn main() {
// Procs
- let greeting = ~"Hi ";
- do call_it |s| {
- greeting + s
- }
-
let greeting = ~"Hello ";
call_it(proc(s) {
greeting + s
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 id<T>(x: T) -> T {
+ x
+}
+
+#[deriving(Eq)]
+struct Foo<T>(T);
+
+#[deriving(Eq)]
+enum Bar<T> {
+ Bar(T)
+}
+
+pub fn main() {
+ let f: |int| -> int = id;
+ assert_eq!(f(5), 5);
+
+ let f: proc(int) -> int = id;
+ assert_eq!(f(5), 5);
+
+ let f: |int| -> Foo<int> = Foo;
+ assert_eq!(f(5), Foo(5));
+
+ let f: proc(int) -> Foo<int> = Foo;
+ assert_eq!(f(5), Foo(5));
+
+ let f: |int| -> Bar<int> = Bar;
+ assert_eq!(f(5), Bar(5));
+
+ let f: proc(int) -> Bar<int> = Bar;
+ assert_eq!(f(5), Bar(5));
+
+ let f: |int| -> Option<int> = Some;
+ assert_eq!(f(5), Some(5));
+
+ let f: proc(int) -> Option<int> = Some;
+ assert_eq!(f(5), Some(5));
+}
roundtrip::<C>();
roundtrip::<D>();
- 20.times(|| {
+ for _ in range(0, 20) {
roundtrip::<E>();
roundtrip::<F>();
roundtrip::<G<int>>();
- })
+ }
}
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#[deriving(Eq, FromPrimitive)]
enum A {
- Foo = int::max_value,
+ Foo = int::MAX,
Bar = 1,
Baz = 3,
Qux,
}
pub fn main() {
- let x: Option<A> = FromPrimitive::from_int(int::max_value);
+ let x: Option<A> = FromPrimitive::from_int(int::MAX);
assert_eq!(x, Some(Foo));
let x: Option<A> = FromPrimitive::from_int(1);
pub fn main() {
// check there's no segfaults
- 20.times(|| {
+ for _ in range(0, 20) {
rand::random::<A>();
rand::random::<B>();
rand::random::<C>();
rand::random::<D>();
- })
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+
+// xfail-test FIXME #11820: & is unreliable in deriving
+
use std::cmp::{Less,Equal,Greater};
#[deriving(TotalEq,TotalOrd)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test FIXME #11820: & is unreliable in deriving
+
#[deriving(Eq,Ord)]
struct A<'a> {
x: &'a int
+++ /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.
-
-// no-reformat
-// Testing various forms of `do` with empty arg lists
-
-fn f(_f: proc() -> bool) -> bool {
- true
-}
-
-pub fn main() {
- do f() || { true };
- do f() { true };
- do f || { true };
- do f { 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.
-
-// Testing that we can drop the || in do exprs
-
-fn f(_f: proc() -> bool) -> bool { true }
-
-fn d(_f: proc()) { }
-
-pub fn main() {
- do d { }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn f(f: proc(int)) { f(10) }
-
-pub fn main() {
- do f() |i| { assert!(i == 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.
-
-fn f(f: proc(int) -> int) -> int { f(10) }
-
-pub fn main() {
- assert_eq!(do f() |i| { i }, 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.
-
-fn f(f: proc(int) -> int) -> int { f(10) }
-
-pub fn main() {
- assert_eq!(do f |i| { i }, 10);
-}
fn test_fn() {
type t = 'static || -> int;
fn ten() -> int { return 10; }
- let rs: t = { ten };
+ let rs: t = ten;
assert!((rs() == 10));
}
pub fn main() {
// Make sure we're on a task with small Rust stacks (main currently
// has a large stack)
- do task::spawn {
+ task::spawn(proc() {
let result = count(1000u);
info!("result = {}", result);
assert_eq!(result, 1000u);
- };
+ });
}
pub fn main() {
// Make sure we're on a task with small Rust stacks (main currently
// has a large stack)
- do task::spawn {
+ task::spawn(proc() {
let result = count(12u);
info!("result = {}", result);
assert_eq!(result, 2048u);
- };
+ });
}
}
pub fn main() {
- 100u.times(|| {
- do task::spawn {
+ for _ in range(0, 100u) {
+ task::spawn(proc() {
assert_eq!(count(5u), 16u);
- };
- })
+ });
+ }
}
}
pub fn main() {
- 10u.times(|| {
- do task::spawn {
+ for _ in range(0, 10u) {
+ task::spawn(proc() {
let result = count(5u);
info!("result = {}", result);
assert_eq!(result, 16u);
- };
- })
+ });
+ }
}
}
pub fn main() {
- let ret = do task::try {
+ let ret = task::try(proc() {
let _a = A { b: B { foo: 3 } };
- };
+ });
assert!(ret.is_err());
unsafe { assert!(dropped); }
}
pub fn main() {
unsafe {
- do run_in_bare_thread() {
+ run_in_bare_thread(proc() {
let i = &100;
rust_dbg_call(callback, cast::transmute(i));
- }
+ });
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:default_type_params_xc.rs
+
+// xfail-fast #[feature] doesn't work with check-fast
+#[feature(default_type_params)];
+
+#[allow(default_type_param_usage)];
+
+extern mod default_type_params_xc;
+
+struct Vec<T, A = default_type_params_xc::Heap>;
+
+struct Foo;
+
+fn main() {
+ let _a = Vec::<int>;
+ let _b = Vec::<int, default_type_params_xc::FakeHeap>;
+ let _c = default_type_params_xc::FakeVec::<int>;
+ let _d = default_type_params_xc::FakeVec::<int, Foo>;
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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-fast #[feature] doesn't work with check-fast
+#[feature(default_type_params)];
+
+#[allow(default_type_param_usage)];
+
+struct Foo<A = (int, char)> {
+ a: A
+}
+
+impl Foo<int> {
+ fn bar_int(&self) -> int {
+ self.a
+ }
+}
+
+impl Foo<char> {
+ fn bar_char(&self) -> char {
+ self.a
+ }
+}
+
+impl Foo {
+ fn bar(&self) {
+ let (i, c): (int, char) = self.a;
+ assert_eq!(Foo { a: i }.bar_int(), i);
+ assert_eq!(Foo { a: c }.bar_char(), c);
+ }
+}
+
+impl<A: Clone> Foo<A> {
+ fn baz(&self) -> A {
+ self.a.clone()
+ }
+}
+
+fn default_foo(x: Foo) {
+ let (i, c): (int, char) = x.a;
+ assert_eq!(i, 1);
+ assert_eq!(c, 'a');
+
+ x.bar();
+ assert_eq!(x.baz(), (1, 'a'));
+}
+
+fn main() {
+ default_foo(Foo { a: (1, 'a') });
+}
// xfail-win32 TempDir may cause IoError on windows: #10462
extern mod extra;
+extern mod glob;
-use extra::glob::glob;
+use glob::glob;
use extra::tempfile::TempDir;
use std::unstable::finally::Finally;
use std::{os, unstable};
extern mod extra;
fn loopy(n: int) {
- if n > 0 { do spawn { loopy(n - 1) }; do spawn { loopy(n - 1) }; }
+ if n > 0 { spawn(proc() { loopy(n - 1) }); spawn(proc() { loopy(n - 1) }); }
loop { }
}
// Commenting this out, as this will hang forever otherwise.
// Even after seeing the comment above, I'm not sure what the
// intention of this test is.
- // do spawn { loopy(5) };
+ // spawn(proc() { loopy(5) });
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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-fast - check-fast doesn't understand aux-build
+// aux-build:issue_10031_aux.rs
+extern mod issue_10031_aux;
+
+pub fn main() {
+ let _ = issue_10031_aux::Wrap(());
+}
}
fn filter<A,IA:iterable<A>>(self: IA, prd: 'static |A| -> bool, blk: |A|) {
- do self.iter |a| {
+ self.iter(|a| {
if prd(a) { blk(a) }
- }
+ });
}
fn foldl<A,B,IA:iterable<A>>(self: IA, b0: B, blk: |B, A| -> B) -> B {
let mut b = b0;
- do self.iter |a| {
+ self.iter(|a| {
b = blk(b, a);
- }
+ });
b
}
pub fn main() {
let (p,c) = comm::stream();
- do task::try || {
+ task::try(|| {
let (p2,c2) = comm::stream();
- do task::spawn || {
+ task::spawn(|| {
p2.recv();
error!("sibling fails");
fail!();
- }
+ });
let (p3,c3) = comm::stream();
c.send(c3);
c2.send(());
error!("child blocks");
p3.recv();
- };
+ });
error!("parent tries");
assert!(!p.recv().try_send(()));
error!("all done!");
pub fn main() {
let mut x = 0;
- 4096.times(|| x += 1);
+ for _ in range(0, 4096) { x += 1; }
assert_eq!(x, 4096);
println!("x = {}", x);
}
struct AsciiArt {
width: uint,
height: uint,
- priv fill: char,
- priv lines: ~[~[char]],
+ fill: char,
+ lines: ~[~[char]],
// This struct can be quite large so we'll disable copying: developers need
// to either pass these structs around via references or move them.
// Use an anonymous function to build a vector of vectors containing
// blank characters for each position in our canvas.
let lines = vec::build(Some(height), |push| {
- height.times(|| push(vec::from_elem(width, '.')))
+ for _ in range(0, height) { push(vec::from_elem(width, '.')); }
});
// Rust code often returns values by omitting the trailing semi-colon
}
fn foo(name: ~str, samples_chan: Chan<Msg>) {
- do task::spawn
- {
+ task::spawn(proc() {
let mut samples_chan = samples_chan;
let callback: SamplesFn = proc(buffer) {
for i in range(0u, buffer.len()) {
}
};
samples_chan.send(GetSamples(name.clone(), callback));
- };
+ });
}
pub fn main() {}
}
priv fn parse_list(len: uint, io: @io::Reader) -> Result {
- let mut list: ~[Result] = ~[];
- do len.times {
- let v =
- match io.read_char() {
- '$' => parse_bulk(io),
- ':' => parse_int(io),
- _ => fail!()
- };
- list.push(v);
+ let mut list: ~[Result] = ~[];
+ for _ in range(0, len) {
+ let v = match io.read_char() {
+ '$' => parse_bulk(io),
+ ':' => parse_int(io),
+ _ => fail!()
+ };
+ list.push(v);
}
- return List(list);
+ return List(list);
}
priv fn chop(s: ~str) -> ~str {
fn query2(cmd: ~[~str]) -> Result {
let _cmd = cmd_to_str(cmd);
- do io::with_str_reader(~"$3\r\nXXX\r\n") |sb| {
+ io::with_str_reader(~"$3\r\nXXX\r\n")(|sb| {
let res = parse_response(@sb as @io::Reader);
println!("{:?}", res);
res
- }
+ });
}
pub fn main() {
let mut count = 0;
- 999_999.times(|| count += 1);
+ for _ in range(0, 999_999) { count += 1; }
assert_eq!(count, 999_999);
println!("{}", count);
}
pub fn main() {
let (port, chan) = Chan::new();
- do spawn {
+ spawn(proc() {
println(port.recv());
- }
+ });
chan.send("hello, world");
}
pub fn main() {
let (port, chan) = Chan::<&'static str>::new();
- do task::spawn {
+ task::spawn(proc() {
assert_eq!(port.recv(), "hello, world");
- }
+ });
chan.send("hello, world");
}
impl Fooable for uint {
fn yes(self) {
- self.times(|| println!("yes"));
+ for _ in range(0, self) { println!("yes"); }
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait OpInt<'a> { fn call<'a>(&'a self, int, int) -> int; }
+
+impl<'a> OpInt<'a> for 'a |int, int| -> int {
+ fn call(&self, a:int, b:int) -> int {
+ (*self)(a, b)
+ }
+}
+
+fn squarei<'a>(x: int, op: &'a OpInt) -> int { op.call(x, x) }
+
+fn muli(x:int, y:int) -> int { x * y }
+
+pub fn main() {
+ let f = |x,y| muli(x,y);
+ {
+ let g = &f;
+ let h = g as &OpInt;
+ squarei(3, h);
+ }
+}
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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::task;
+
+fn user(_i: int) {}
+
+fn foo() {
+ // Here, i is *copied* into the proc (heap closure).
+ // Requires allocation. The proc's copy is not mutable.
+ let mut i = 0;
+ task::spawn(proc() {
+ user(i);
+ println!("spawned {}", i)
+ });
+ i += 1;
+ println!("original {}", i)
+}
+
+fn bar() {
+ // Here, the original i has not been moved, only copied, so is still
+ // mutable outside of the proc.
+ let mut i = 0;
+ while i < 10 {
+ task::spawn(proc() {
+ user(i);
+ });
+ i += 1;
+ }
+}
+
+fn car() {
+ // Here, i must be shadowed in the proc to be mutable.
+ let mut i = 0;
+ while i < 10 {
+ task::spawn(proc() {
+ let mut i = i;
+ i += 1;
+ user(i);
+ });
+ i += 1;
+ }
+}
+
+pub fn main() {}
+
pub fn main() {
let (p,c) = Chan::new();
- do spawn {
+ spawn(proc() {
let mut f = Foo(Cell::new(0));
debug!("{}", f);
let Foo(ref mut f) = f;
assert!(f.get() == 1);
c.send(());
- }
+ });
p.recv();
}
pub fn main() {
let x = ~"Hello world!";
- do task::spawn {
+ task::spawn(proc() {
println!("{}", x);
- }
+ });
}
#[start]
fn start(argc: int, argv: **u8) -> int {
// make sure that native::start always waits for all children to finish
- do native::start(argc, argv) {
- do spawn {
+ native::start(argc, argv, proc() {
+ spawn(proc() {
unsafe { set = true; }
- }
- };
+ });
+ });
// if we didn't set the global, then return a nonzero code
if unsafe {set} {0} else {1}
}
fn main() {
- do task::try::<()> {
+ task::try::<()>(proc() {
let _a = A;
fail!();
- };
+ });
assert!(unsafe { !HIT });
}
assert_eq!(15u32.add(&6u32), 21u32);
assert_eq!(15u64.add(&6u64), 21u64);
- // times
- 15u.times(|| {});
-
// floats
// num
assert_eq!(10f32.to_int().unwrap(), 10);
pub fn main() {
let x = arc::Arc::new(true);
- do foo {
+ foo(proc() {
assert!(*x.get());
drop(x);
- }
+ });
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern mod extra;
-use extra::arena::Arena;
+extern mod arena;
+use arena::Arena;
pub fn main() {
let mut arena = Arena::new();
let (port, chan) = stream();
info!("main started");
- do spawn {
+ spawn(proc() {
starve_main(port);
- };
+ });
let mut i: int = 0;
info!("main waiting for alive signal");
chan.send(i);
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
// except according to those terms.
struct cat {
- priv meows : uint,
+ meows : uint,
how_hungry : int,
}
if ! self.inner().visit_type() { return false; }
true
}
-
- fn visit_opaque_box(&mut self) -> bool {
- self.align_to::<@u8>();
- if ! self.inner().visit_opaque_box() { return false; }
- self.bump_past::<@u8>();
- true
- }
-
- fn visit_closure_ptr(&mut self, ck: uint) -> bool {
- self.align_to::<(uint,uint)>();
- if ! self.inner().visit_closure_ptr(ck) { return false; }
- self.bump_past::<(uint,uint)>();
- true
- }
}
struct my_visitor(@RefCell<Stuff>);
fn visit_param(&mut self, _i: uint) -> bool { true }
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool { true }
- fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn get_tydesc_for<T>(_t: T) -> *TyDesc {
fn visit_param(&mut self, _i: uint) -> bool { true }
fn visit_self(&mut self) -> bool { true }
fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&mut self) -> bool { true }
- fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn visit_ty<T>(v: &mut MyVisitor) {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test verifies that temporary lifetime is correctly computed
+// for static objects in enclosing scopes.
+
+extern mod extra;
+use std::cmp::Eq;
+
+fn f<T:Eq>(o: &mut Option<T>) {
+ assert!(*o == None);
+}
+
+pub fn main() {
+ mod t {
+ enum E {V=1, A=0}
+ static C: E = V;
+ }
+
+ f::<int>(&mut None);
+}
// - Multiple lifetime parameters
// - Arenas
-extern mod extra;
+extern mod arena;
-use extra::arena;
-use extra::arena::Arena;
+use arena::Arena;
use std::hashmap::HashMap;
use std::cast;
use std::libc;
type Type<'tcx> = &'tcx TypeStructure<'tcx>;
-#[deriving(Eq)]
enum TypeStructure<'tcx> {
TypeInt,
TypeFunction(Type<'tcx>, Type<'tcx>),
}
+impl<'tcx> Eq for TypeStructure<'tcx> {
+ fn eq(&self, other: &TypeStructure<'tcx>) -> bool {
+ match (*self, *other) {
+ (TypeInt, TypeInt) => true,
+ (TypeFunction(s_a, s_b), TypeFunction(o_a, o_b)) => *s_a == *o_a && *s_b == *o_b,
+ _ => false
+ }
+ }
+}
struct TypeContext<'tcx, 'ast> {
ty_arena: &'tcx Arena,
pub fn main() {
let (p, c) = Chan::new();
- do task::spawn() {
+ task::spawn(proc() {
let (pp, cc) = Chan::new();
c.send(cc);
let _r = pp.recv();
- }
+ });
p.recv().send(test(42));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::unstable::simd::{i32x4, f32x4};
+#[allow(experimental)];
+
+use std::unstable::simd::{i32x4, f32x4, u32x4};
fn test_int(e: i32) -> i32 {
let v = i32x4(e, 0i32, 0i32, 0i32);
e2
}
+pub fn test_shift(e: u32) -> u32 {
+ let v = u32x4(e, 0u32, 0u32, 0u32);
+ let one = u32x4(1u32, 0u32, 0u32, 0u32);
+ let u32x4(e2, _, _, _) = v << one >> one;
+ e2
+}
+
pub fn main() {
assert_eq!(test_int(3i32), 9i32);
assert_eq!(test_float(3f32), 9f32);
+ assert_eq!(test_shift(3u32), 3u32);
}
+// xfail-fast feature doesn't work
+
+#[feature(simd)];
+
#[simd]
struct RGBA {
r: f32,
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#[deriving(Eq,Clone)]
+struct Foo<T> {
+ bar: T,
+ baz: T
+}
+
+pub fn main() {
+ let foo = Foo {
+ bar: 0,
+ baz: 1
+ };
+
+ let foo_ = foo.clone();
+ let foo = Foo { ..foo };
+ assert_eq!(foo, foo_);
+
+ let foo = Foo {
+ bar: ~"one",
+ baz: ~"two"
+ };
+
+ let foo_ = foo.clone();
+ let foo = Foo { ..foo };
+ assert_eq!(foo, foo_);
+}
let i: int = 0;
let mut builder = task::task();
let mut result = builder.future_result();
- do builder.spawn {
+ builder.spawn(proc() {
start(i)
- }
+ });
// Sleep long enough for the task to finish.
let mut i = 0;
let number_of_messages: int = 10;
let c = ch.clone();
- do task::spawn || {
+ task::spawn(proc() {
test00_start(&c, number_of_messages * 0, number_of_messages);
- }
+ });
let c = ch.clone();
- do task::spawn || {
+ task::spawn(proc() {
test00_start(&c, number_of_messages * 1, number_of_messages);
- }
+ });
let c = ch.clone();
- do task::spawn || {
+ task::spawn(proc() {
test00_start(&c, number_of_messages * 2, number_of_messages);
- }
+ });
let c = ch.clone();
- do task::spawn || {
+ task::spawn(proc() {
test00_start(&c, number_of_messages * 3, number_of_messages);
- }
+ });
let mut i: int = 0;
while i < number_of_messages {
let mut builder = task::task();
let result = builder.future_result();
- do builder.spawn {
+ builder.spawn(proc() {
let mut ch = ch;
test00_start(&mut ch, number_of_messages);
- }
+ });
let mut i: int = 0;
while i < number_of_messages {
*b = true;
}
let (p, c) = stream();
- do task::spawn_unlinked {
+ task::spawn_unlinked(proc() {
let ccc = c;
wrapper(ccc, f)
- }
+ });
p
}
~dogge2 as ~Pet:Freeze+Send]);
let (p1,c1) = Chan::new();
let arc1 = arc.clone();
- do task::spawn { check_legs(arc1); c1.send(()); }
+ task::spawn(proc() { check_legs(arc1); c1.send(()); });
let (p2,c2) = Chan::new();
let arc2 = arc.clone();
- do task::spawn { check_names(arc2); c2.send(()); }
+ task::spawn(proc() { check_names(arc2); c2.send(()); });
let (p3,c3) = Chan::new();
let arc3 = arc.clone();
- do task::spawn { check_pedigree(arc3); c3.send(()); }
+ task::spawn(proc() { check_pedigree(arc3); c3.send(()); });
p1.recv();
p2.recv();
p3.recv();
}
pub fn main() {
- let x = do task::try {
+ let x = task::try(proc() {
let _b = Foo;
- };
+ });
let s = x.unwrap_err().move::<&'static str>().unwrap();
assert_eq!(s.as_slice(), "This failure should happen.");