auto merge of #14187 : alexcrichton/rust/rollup, r=alexcrichton

Closes #14184 (std: Move the owned module from core to std)
Closes #14183 (Allow blocks in const expressions)
Closes #14176 (Add tests for from_bits.)
Closes #14175 (Replaced ~T by Box<T> in manual)
Closes #14173 (Implements Default trait for BigInt and BigUint)
Closes #14171 (Fix #8391)
Closes #14159 (Clean up unicode code in libstd)
Closes #14126 (docs: Add a not found page)
Closes #14123 (add a line to the example to clarify semantics)
Closes #14106 (Pretty printer improvements)
Closes #14083 (rustllvm: Add LLVMRustArrayType)
Closes #13957 (io: Implement process wait timeouts)
This commit is contained in:
bors 2014-05-13 18:31:51 -07:00
commit b2b383cab5
118 changed files with 2195 additions and 934 deletions

View File

@ -30,7 +30,7 @@ DOCS := index intro tutorial guide-ffi guide-macros guide-lifetimes \
guide-tasks guide-container guide-pointers guide-testing \
guide-runtime complement-bugreport complement-cheatsheet \
complement-lang-faq complement-project-faq rust rustdoc \
guide-unsafe
guide-unsafe not_found
PDF_DOCS := tutorial rust

View File

@ -8,19 +8,52 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::from_str::FromStr;
use std::fmt;
#[deriving(Clone, Eq)]
pub enum mode {
mode_compile_fail,
mode_run_fail,
mode_run_pass,
mode_pretty,
mode_debug_info_gdb,
mode_debug_info_lldb,
mode_codegen
pub enum Mode {
CompileFail,
RunFail,
RunPass,
Pretty,
DebugInfoGdb,
DebugInfoLldb,
Codegen
}
impl FromStr for Mode {
fn from_str(s: &str) -> Option<Mode> {
match s {
"compile-fail" => Some(CompileFail),
"run-fail" => Some(RunFail),
"run-pass" => Some(RunPass),
"pretty" => Some(Pretty),
"debuginfo-lldb" => Some(DebugInfoLldb),
"debuginfo-gdb" => Some(DebugInfoGdb),
"codegen" => Some(Codegen),
_ => None,
}
}
}
impl fmt::Show for Mode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
CompileFail => "compile-fail",
RunFail => "run-fail",
RunPass => "run-pass",
Pretty => "pretty",
DebugInfoGdb => "debuginfo-gdb",
DebugInfoLldb => "debuginfo-lldb",
Codegen => "codegen",
};
write!(f.buf, "{}", msg)
}
}
#[deriving(Clone)]
pub struct config {
pub struct Config {
// The library paths required for running the compiler
pub compile_lib_path: ~str,
@ -49,7 +82,7 @@ pub struct config {
pub stage_id: ~str,
// The test mode, compile-fail, run-fail, run-pass
pub mode: mode,
pub mode: Mode,
// Run ignored tests
pub run_ignored: bool,

View File

@ -14,7 +14,6 @@
// we use our own (green) start below; do not link in libnative; issue #13247.
#![no_start]
#![allow(non_camel_case_types)]
#![deny(warnings)]
extern crate test;
@ -27,9 +26,10 @@ extern crate rustuv;
use std::os;
use std::io;
use std::io::fs;
use std::from_str::FromStr;
use getopts::{optopt, optflag, reqopt};
use common::{config, mode_run_pass, mode_run_fail, mode_compile_fail, mode_pretty,
mode_debug_info_gdb, mode_debug_info_lldb, mode_codegen, mode};
use common::Config;
use common::{Pretty, DebugInfoGdb, Codegen};
use util::logv;
pub mod procsrv;
@ -51,7 +51,7 @@ pub fn main() {
run_tests(&config);
}
pub fn parse_config(args: Vec<~str> ) -> config {
pub fn parse_config(args: Vec<~str> ) -> Config {
let groups : Vec<getopts::OptGroup> =
vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
@ -112,7 +112,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
Path::new(m.opt_str(nm).unwrap())
}
config {
Config {
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
rustc_path: opt_path(matches, "rustc-path"),
@ -122,7 +122,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
build_base: opt_path(matches, "build-base"),
aux_base: opt_path(matches, "aux-base"),
stage_id: matches.opt_str("stage-id").unwrap(),
mode: str_mode(matches.opt_str("mode").unwrap()),
mode: FromStr::from_str(matches.opt_str("mode").unwrap()).expect("invalid mode"),
run_ignored: matches.opt_present("ignored"),
filter:
if !matches.free.is_empty() {
@ -155,7 +155,7 @@ pub fn parse_config(args: Vec<~str> ) -> config {
}
}
pub fn log_config(config: &config) {
pub fn log_config(config: &Config) {
let c = config;
logv(c, format!("configuration:"));
logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
@ -164,7 +164,7 @@ pub fn log_config(config: &config) {
logv(c, format!("src_base: {}", config.src_base.display()));
logv(c, format!("build_base: {}", config.build_base.display()));
logv(c, format!("stage_id: {}", config.stage_id));
logv(c, format!("mode: {}", mode_str(config.mode)));
logv(c, format!("mode: {}", config.mode));
logv(c, format!("run_ignored: {}", config.run_ignored));
logv(c, format!("filter: {}", opt_str(&config.filter)));
logv(c, format!("runtool: {}", opt_str(&config.runtool)));
@ -198,35 +198,10 @@ pub fn opt_str2(maybestr: Option<~str>) -> ~str {
match maybestr { None => "(none)".to_owned(), Some(s) => { s } }
}
pub fn str_mode(s: ~str) -> mode {
match s.as_slice() {
"compile-fail" => mode_compile_fail,
"run-fail" => mode_run_fail,
"run-pass" => mode_run_pass,
"pretty" => mode_pretty,
"debuginfo-gdb" => mode_debug_info_gdb,
"debuginfo-lldb" => mode_debug_info_lldb,
"codegen" => mode_codegen,
s => fail!("invalid mode: " + s)
}
}
pub fn mode_str(mode: mode) -> ~str {
match mode {
mode_compile_fail => "compile-fail".to_owned(),
mode_run_fail => "run-fail".to_owned(),
mode_run_pass => "run-pass".to_owned(),
mode_pretty => "pretty".to_owned(),
mode_debug_info_gdb => "debuginfo-gdb".to_owned(),
mode_debug_info_lldb => "debuginfo-lldb".to_owned(),
mode_codegen => "codegen".to_owned(),
}
}
pub fn run_tests(config: &config) {
pub fn run_tests(config: &Config) {
if config.target == "arm-linux-androideabi".to_owned() {
match config.mode{
mode_debug_info_gdb => {
match config.mode {
DebugInfoGdb => {
println!("arm-linux-androideabi debug-info \
test uses tcp 5039 port. please reserve it");
}
@ -255,7 +230,7 @@ pub fn run_tests(config: &config) {
}
}
pub fn test_opts(config: &config) -> test::TestOpts {
pub fn test_opts(config: &Config) -> test::TestOpts {
test::TestOpts {
filter: config.filter.clone(),
run_ignored: config.run_ignored,
@ -270,7 +245,7 @@ pub fn test_opts(config: &config) -> test::TestOpts {
}
}
pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
pub fn make_tests(config: &Config) -> Vec<test::TestDescAndFn> {
debug!("making tests from {}",
config.src_base.display());
let mut tests = Vec::new();
@ -281,7 +256,7 @@ pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
if is_test(config, &file) {
let t = make_test(config, &file, || {
match config.mode {
mode_codegen => make_metrics_test_closure(config, &file),
Codegen => make_metrics_test_closure(config, &file),
_ => make_test_closure(config, &file)
}
});
@ -291,11 +266,11 @@ pub fn make_tests(config: &config) -> Vec<test::TestDescAndFn> {
tests
}
pub fn is_test(config: &config, testfile: &Path) -> bool {
pub fn is_test(config: &Config, testfile: &Path) -> bool {
// Pretty-printer does not work with .rc files yet
let valid_extensions =
match config.mode {
mode_pretty => vec!(".rs".to_owned()),
Pretty => vec!(".rs".to_owned()),
_ => vec!(".rc".to_owned(), ".rs".to_owned())
};
let invalid_prefixes = vec!(".".to_owned(), "#".to_owned(), "~".to_owned());
@ -314,7 +289,7 @@ pub fn is_test(config: &config, testfile: &Path) -> bool {
return valid;
}
pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
-> test::TestDescAndFn {
test::TestDescAndFn {
desc: test::TestDesc {
@ -326,7 +301,7 @@ pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
}
}
pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
// Try to elide redundant long paths
fn shorten(path: &Path) -> ~str {
@ -336,19 +311,17 @@ pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {
format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
}
test::DynTestName(format!("[{}] {}",
mode_str(config.mode),
shorten(testfile)))
test::DynTestName(format!("[{}] {}", config.mode, shorten(testfile)))
}
pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = testfile.as_str().unwrap().to_owned();
test::DynTestFn(proc() { runtest::run(config, testfile) })
}
pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
let config = (*config).clone();
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = testfile.as_str().unwrap().to_owned();

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use common::config;
use common::Config;
use common;
use util;
@ -34,6 +34,8 @@ pub struct TestProps {
pub check_stdout: bool,
// Don't force a --crate-type=dylib flag on the command line
pub no_prefer_dynamic: bool,
// Don't run --pretty expanded when running pretty printing tests
pub no_pretty_expanded: bool,
}
// Load any test directives embedded in the file
@ -48,6 +50,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
let mut force_host = false;
let mut check_stdout = false;
let mut no_prefer_dynamic = false;
let mut no_pretty_expanded = false;
iter_header(testfile, |ln| {
match parse_error_pattern(ln) {
Some(ep) => error_patterns.push(ep),
@ -78,6 +81,10 @@ pub fn load_props(testfile: &Path) -> TestProps {
no_prefer_dynamic = parse_no_prefer_dynamic(ln);
}
if !no_pretty_expanded {
no_pretty_expanded = parse_no_pretty_expanded(ln);
}
match parse_aux_build(ln) {
Some(ab) => { aux_builds.push(ab); }
None => {}
@ -107,14 +114,15 @@ pub fn load_props(testfile: &Path) -> TestProps {
force_host: force_host,
check_stdout: check_stdout,
no_prefer_dynamic: no_prefer_dynamic,
no_pretty_expanded: no_pretty_expanded,
}
}
pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
fn ignore_target(config: &config) -> ~str {
pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
fn ignore_target(config: &Config) -> ~str {
"ignore-".to_owned() + util::get_os(config.target)
}
fn ignore_stage(config: &config) -> ~str {
fn ignore_stage(config: &Config) -> ~str {
"ignore-".to_owned() + config.stage_id.split('-').next().unwrap()
}
@ -122,7 +130,7 @@ pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
if parse_name_directive(ln, "ignore-test") { false }
else if parse_name_directive(ln, ignore_target(config)) { false }
else if parse_name_directive(ln, ignore_stage(config)) { false }
else if config.mode == common::mode_pretty &&
else if config.mode == common::Pretty &&
parse_name_directive(ln, "ignore-pretty") { false }
else if config.target != config.host &&
parse_name_directive(ln, "ignore-cross-compile") { false }
@ -180,6 +188,10 @@ fn parse_no_prefer_dynamic(line: &str) -> bool {
parse_name_directive(line, "no-prefer-dynamic")
}
fn parse_no_pretty_expanded(line: &str) -> bool {
parse_name_directive(line, "no-pretty-expanded")
}
fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
parse_name_value_directive(line, "exec-env".to_owned()).map(|nv| {
// nv is either FOO or FOO=BAR

View File

@ -68,7 +68,7 @@ pub fn run(lib_path: &str,
input: Option<~str>) -> Option<Result> {
let env = env.clone().append(target_env(lib_path, prog).as_slice());
let mut opt_process = Process::configure(ProcessConfig {
let opt_process = Process::configure(ProcessConfig {
program: prog,
args: args,
env: Some(env.as_slice()),
@ -76,11 +76,12 @@ pub fn run(lib_path: &str,
});
match opt_process {
Ok(ref mut process) => {
Ok(mut process) => {
for input in input.iter() {
process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
}
let ProcessOutput { status, output, error } = process.wait_with_output();
let ProcessOutput { status, output, error } =
process.wait_with_output().unwrap();
Some(Result {
status: status,

View File

@ -8,7 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use common::{config, mode_compile_fail, mode_pretty, mode_run_fail, mode_run_pass};
use common::Config;
use common::{CompileFail, Pretty, RunFail, RunPass, DebugInfoGdb, DebugInfoLldb};
use errors;
use header::TestProps;
use header;
@ -30,7 +31,7 @@ use std::strbuf::StrBuf;
use std::task;
use test::MetricMap;
pub fn run(config: config, testfile: ~str) {
pub fn run(config: Config, testfile: ~str) {
match config.target.as_slice() {
@ -47,7 +48,7 @@ pub fn run(config: config, testfile: ~str) {
run_metrics(config, testfile, &mut _mm);
}
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
pub fn run_metrics(config: Config, testfile: ~str, mm: &mut MetricMap) {
if config.verbose {
// We're going to be dumping a lot of info. Start on a new line.
print!("\n\n");
@ -57,17 +58,17 @@ pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
let props = header::load_props(&testfile);
debug!("loaded props");
match config.mode {
mode_compile_fail => run_cfail_test(&config, &props, &testfile),
mode_run_fail => run_rfail_test(&config, &props, &testfile),
mode_run_pass => run_rpass_test(&config, &props, &testfile),
mode_pretty => run_pretty_test(&config, &props, &testfile),
mode_debug_info_gdb => run_debuginfo_gdb_test(&config, &props, &testfile),
mode_debug_info_lldb => run_debuginfo_lldb_test(&config, &props, &testfile),
mode_codegen => run_codegen_test(&config, &props, &testfile, mm)
CompileFail => run_cfail_test(&config, &props, &testfile),
RunFail => run_rfail_test(&config, &props, &testfile),
RunPass => run_rpass_test(&config, &props, &testfile),
Pretty => run_pretty_test(&config, &props, &testfile),
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
Codegen => run_codegen_test(&config, &props, &testfile, mm),
}
}
fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = compile_test(config, props, testfile);
if proc_res.status.success() {
@ -88,7 +89,7 @@ fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
check_no_compiler_crash(&proc_res);
}
fn run_rfail_test(config: &config, props: &TestProps, testfile: &Path) {
fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
let proc_res = if !config.jit {
let proc_res = compile_test(config, props, testfile);
@ -121,7 +122,7 @@ fn check_correct_failure_status(proc_res: &ProcRes) {
}
}
fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
if !config.jit {
let mut proc_res = compile_test(config, props, testfile);
@ -141,7 +142,7 @@ fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
}
}
fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
if props.pp_exact.is_some() {
logv(config, "testing for exact pretty-printing".to_owned());
} else { logv(config, "testing for converging pretty-printing".to_owned()); }
@ -156,9 +157,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
let mut round = 0;
while round < rounds {
logv(config, format!("pretty-printing round {}", round));
let proc_res = print_source(config,
testfile,
(*srcs.get(round)).clone());
let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "normal");
if !proc_res.status.success() {
fatal_ProcRes(format!("pretty-printing failed in round {}", round),
@ -195,18 +194,43 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
if !proc_res.status.success() {
fatal_ProcRes("pretty-printed source does not typecheck".to_owned(), &proc_res);
}
if props.no_pretty_expanded { return }
// additionally, run `--pretty expanded` and try to build it.
let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "expanded");
if !proc_res.status.success() {
fatal_ProcRes(format!("pretty-printing (expanded) failed"), &proc_res);
}
let ProcRes{ stdout: expanded_src, .. } = proc_res;
let proc_res = typecheck_source(config, props, testfile, expanded_src);
if !proc_res.status.success() {
fatal_ProcRes(format!("pretty-printed source (expanded) does not typecheck"), &proc_res);
}
return;
fn print_source(config: &config, testfile: &Path, src: ~str) -> ProcRes {
compose_and_run(config, testfile, make_pp_args(config, testfile),
Vec::new(), config.compile_lib_path, Some(src))
fn print_source(config: &Config,
props: &TestProps,
testfile: &Path,
src: ~str,
pretty_type: &str) -> ProcRes {
compose_and_run(config, testfile,
make_pp_args(config, props, testfile, pretty_type.to_owned()),
props.exec_env.clone(), config.compile_lib_path, Some(src))
}
fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
let args = vec!("-".to_owned(), "--pretty".to_owned(), "normal".to_owned(),
"--target=".to_owned() + config.target);
fn make_pp_args(config: &Config,
props: &TestProps,
testfile: &Path,
pretty_type: ~str) -> ProcArgs {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let mut args = vec!("-".to_owned(), "--pretty".to_owned(), pretty_type,
"--target=".to_owned() + config.target,
"-L".to_owned(), aux_dir.as_str().unwrap().to_owned());
args.push_all_move(split_maybe_args(&config.target_rustcflags));
args.push_all_move(split_maybe_args(&props.compile_flags));
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
}
@ -228,13 +252,13 @@ actual:\n\
}
}
fn typecheck_source(config: &config, props: &TestProps,
fn typecheck_source(config: &Config, props: &TestProps,
testfile: &Path, src: ~str) -> ProcRes {
let args = make_typecheck_args(config, props, testfile);
compose_and_run_compiler(config, props, testfile, args, Some(src))
}
fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> ProcArgs {
let aux_dir = aux_output_dir_name(config, testfile);
let target = if props.force_host {
config.host.as_slice()
@ -255,8 +279,8 @@ actual:\n\
}
}
fn run_debuginfo_gdb_test(config: &config, props: &TestProps, testfile: &Path) {
let mut config = config {
fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
let mut config = Config {
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
.. config.clone()
@ -403,14 +427,14 @@ fn run_debuginfo_gdb_test(config: &config, props: &TestProps, testfile: &Path) {
check_debugger_output(&debugger_run_result, check_lines.as_slice());
}
fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path) {
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
use std::io::process::{Process, ProcessConfig, ProcessOutput};
if config.lldb_python_dir.is_none() {
fatal("Can't run LLDB test because LLDB's python path is not set.".to_owned());
}
let mut config = config {
let mut config = Config {
target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
.. config.clone()
@ -465,7 +489,7 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
check_debugger_output(&debugger_run_result, check_lines.as_slice());
fn run_lldb(config: &config, test_executable: &Path, debugger_script: &Path) -> ProcRes {
fn run_lldb(config: &Config, test_executable: &Path, debugger_script: &Path) -> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_batchmode_script = "./src/etc/lldb_batchmode.py".to_owned();
let test_executable_str = test_executable.as_str().unwrap().to_owned();
@ -478,7 +502,7 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
let args = &[lldb_batchmode_script, test_executable_str, debugger_script_str];
let env = &[("PYTHONPATH".to_owned(), config.lldb_python_dir.clone().unwrap())];
let mut opt_process = Process::configure(ProcessConfig {
let opt_process = Process::configure(ProcessConfig {
program: "python",
args: args,
env: Some(env),
@ -486,8 +510,9 @@ fn run_debuginfo_lldb_test(config: &config, props: &TestProps, testfile: &Path)
});
let (status, out, err) = match opt_process {
Ok(ref mut process) => {
let ProcessOutput { status, output, error } = process.wait_with_output();
Ok(process) => {
let ProcessOutput { status, output, error } =
process.wait_with_output().unwrap();
(status,
str::from_utf8(output.as_slice()).unwrap().to_owned(),
@ -834,16 +859,16 @@ struct ProcArgs {prog: ~str, args: Vec<~str> }
struct ProcRes {status: ProcessExit, stdout: ~str, stderr: ~str, cmdline: ~str}
fn compile_test(config: &config, props: &TestProps,
fn compile_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
compile_test_(config, props, testfile, [])
}
fn jit_test(config: &config, props: &TestProps, testfile: &Path) -> ProcRes {
fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
compile_test_(config, props, testfile, ["--jit".to_owned()])
}
fn compile_test_(config: &config, props: &TestProps,
fn compile_test_(config: &Config, props: &TestProps,
testfile: &Path, extra_args: &[~str]) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
@ -855,7 +880,7 @@ fn compile_test_(config: &config, props: &TestProps,
compose_and_run_compiler(config, props, testfile, args, None)
}
fn exec_compiled_test(config: &config, props: &TestProps,
fn exec_compiled_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
let env = props.exec_env.clone();
@ -876,7 +901,7 @@ fn exec_compiled_test(config: &config, props: &TestProps,
}
fn compose_and_run_compiler(
config: &config,
config: &Config,
props: &TestProps,
testfile: &Path,
args: ProcArgs,
@ -934,7 +959,7 @@ fn ensure_dir(path: &Path) {
fs::mkdir(path, io::UserRWX).unwrap();
}
fn compose_and_run(config: &config, testfile: &Path,
fn compose_and_run(config: &Config, testfile: &Path,
ProcArgs{ args, prog }: ProcArgs,
procenv: Vec<(~str, ~str)> ,
lib_path: &str,
@ -948,10 +973,10 @@ enum TargetLocation {
ThisDirectory(Path),
}
fn make_compile_args(config: &config,
fn make_compile_args(config: &Config,
props: &TestProps,
extras: Vec<~str> ,
xform: |&config, &Path| -> TargetLocation,
xform: |&Config, &Path| -> TargetLocation,
testfile: &Path)
-> ProcArgs {
let xform_file = xform(config, testfile);
@ -983,14 +1008,14 @@ fn make_compile_args(config: &config,
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
}
fn make_lib_name(config: &config, auxfile: &Path, testfile: &Path) -> Path {
fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> Path {
// what we return here is not particularly important, as it
// happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile);
aux_output_dir_name(config, testfile).join(&auxname)
}
fn make_exe_name(config: &config, testfile: &Path) -> Path {
fn make_exe_name(config: &Config, testfile: &Path) -> Path {
let mut f = output_base_name(config, testfile);
if !os::consts::EXE_SUFFIX.is_empty() {
match f.filename().map(|s| Vec::from_slice(s).append(os::consts::EXE_SUFFIX.as_bytes())) {
@ -1001,7 +1026,7 @@ fn make_exe_name(config: &config, testfile: &Path) -> Path {
f
}
fn make_run_args(config: &config, props: &TestProps, testfile: &Path) ->
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
ProcArgs {
// If we've got another tool to run under (valgrind),
// then split apart its command
@ -1029,7 +1054,7 @@ fn split_maybe_args(argstr: &Option<~str>) -> Vec<~str> {
}
}
fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str,
fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: ~str,
args: Vec<~str> , env: Vec<(~str, ~str)> ,
input: Option<~str>) -> ProcRes {
let cmdline =
@ -1069,23 +1094,23 @@ fn lib_path_cmd_prefix(path: &str) -> ~str {
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
}
fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) {
fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
dump_output_file(config, testfile, out, "out");
dump_output_file(config, testfile, err, "err");
maybe_dump_to_stdout(config, out, err);
}
fn dump_output_file(config: &config, testfile: &Path,
fn dump_output_file(config: &Config, testfile: &Path,
out: &str, extension: &str) {
let outfile = make_out_name(config, testfile, extension);
File::create(&outfile).write(out.as_bytes()).unwrap();
}
fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path {
fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> Path {
output_base_name(config, testfile).with_extension(extension)
}
fn aux_output_dir_name(config: &config, testfile: &Path) -> Path {
fn aux_output_dir_name(config: &Config, testfile: &Path) -> Path {
let mut f = output_base_name(config, testfile);
match f.filename().map(|s| Vec::from_slice(s).append(bytes!(".libaux"))) {
Some(v) => f.set_filename(v),
@ -1098,13 +1123,13 @@ fn output_testname(testfile: &Path) -> Path {
Path::new(testfile.filestem().unwrap())
}
fn output_base_name(config: &config, testfile: &Path) -> Path {
fn output_base_name(config: &Config, testfile: &Path) -> Path {
config.build_base
.join(&output_testname(testfile))
.with_extension(config.stage_id.as_slice())
}
fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
if config.verbose {
println!("------{}------------------------------", "stdout");
println!("{}", out);
@ -1137,7 +1162,7 @@ stderr:\n\
fail!();
}
fn _arm_exec_compiled_test(config: &config, props: &TestProps,
fn _arm_exec_compiled_test(config: &Config, props: &TestProps,
testfile: &Path, env: Vec<(~str, ~str)> ) -> ProcRes {
let args = make_run_args(config, props, testfile);
@ -1237,7 +1262,7 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
}
}
fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
let tdir = aux_output_dir_name(config, testfile);
let dirs = fs::readdir(&tdir).unwrap();
@ -1260,7 +1285,7 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
// codegen tests (vs. clang)
fn make_o_name(config: &config, testfile: &Path) -> Path {
fn make_o_name(config: &Config, testfile: &Path) -> Path {
output_base_name(config, testfile).with_extension("o")
}
@ -1273,7 +1298,7 @@ fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path {
}
}
fn compile_test_and_save_bitcode(config: &config, props: &TestProps,
fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
@ -1287,7 +1312,7 @@ fn compile_test_and_save_bitcode(config: &config, props: &TestProps,
compose_and_run_compiler(config, props, testfile, args, None)
}
fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps,
fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
testfile: &Path) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang");
@ -1303,7 +1328,7 @@ fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps,
compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
}
fn extract_function_from_bitcode(config: &config, _props: &TestProps,
fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
fname: &str, testfile: &Path,
suffix: &str) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
@ -1320,7 +1345,7 @@ fn extract_function_from_bitcode(config: &config, _props: &TestProps,
compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
}
fn disassemble_extract(config: &config, _props: &TestProps,
fn disassemble_extract(config: &Config, _props: &TestProps,
testfile: &Path, suffix: &str) -> ProcRes {
let bitcodefile = output_base_name(config, testfile).with_extension("bc");
let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
@ -1344,7 +1369,7 @@ fn count_extracted_lines(p: &Path) -> uint {
}
fn run_codegen_test(config: &config, props: &TestProps,
fn run_codegen_test(config: &Config, props: &TestProps,
testfile: &Path, mm: &mut MetricMap) {
if config.llvm_bin_path.is_none() {

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use common::config;
use common::Config;
#[cfg(target_os = "win32")]
use std::os::getenv;
@ -51,7 +51,7 @@ pub fn lib_path_env_var() -> ~str { "PATH".to_owned() }
#[cfg(target_os = "win32")]
pub fn path_div() -> ~str { ";".to_owned() }
pub fn logv(config: &config, s: ~str) {
pub fn logv(config: &Config, s: ~str) {
debug!("{}", s);
if config.verbose { println!("{}", s); }
}

20
src/doc/not_found.md Normal file
View File

@ -0,0 +1,20 @@
% Not Found
<!-- Completely hide the TOC and the section numbers -->
<style type="text/css">
#TOC { display: none; }
.header-section-number { display: none; }
li {list-style-type: none; }
</style>
Looks like you've taken a wrong turn.
Some things that might be helpful to you though:
## Reference
* [The Rust official site](http://rust-lang.org)
* [The Rust reference manual](http://static.rust-lang.org/doc/master/rust.html) (* [PDF](http://static.rust-lang.org/doc/master/rust.pdf))
## Docs
* [The standard library (stable)](http://doc.rust-lang.org/doc/0.10/std/index.html)
* [The standard library (master)](http://doc.rust-lang.org/doc/master/std/index.html)

View File

@ -2648,9 +2648,9 @@ before the expression they apply to.
: Logical negation. On the boolean type, this flips between `true` and
`false`. On integer types, this inverts the individual bits in the
two's complement representation of the value.
* `~`
* `box`
: [Boxing](#pointer-types) operators. Allocate a box to hold the value they are applied to,
and store the value in it. `~` creates an owned box.
and store the value in it. `box` creates an owned box.
* `&`
: Borrow operator. Returns a reference, pointing to its operand.
The operand of a borrow is statically proven to outlive the resulting pointer.
@ -3156,7 +3156,7 @@ fn main() {
~~~~
Patterns can also dereference pointers by using the `&`,
`~` or `@` symbols, as appropriate. For example, these two matches
`box` or `@` symbols, as appropriate. For example, these two matches
on `x: &int` are equivalent:
~~~~
@ -3438,11 +3438,11 @@ All pointers in Rust are explicit first-class values.
They can be copied, stored into data structures, and returned from functions.
There are four varieties of pointer in Rust:
* Owning pointers (`~`)
* Owning pointers (`Box`)
: These point to owned heap allocations (or "boxes") in the shared, inter-task heap.
Each owned box has a single owning pointer; pointer and pointee retain a 1:1 relationship at all times.
Owning pointers are written `~content`,
for example `~int` means an owning pointer to an owned box containing an integer.
Owning pointers are written `Box<content>`,
for example `Box<int>` means an owning pointer to an owned box containing an integer.
Copying an owned box is a "deep" operation:
it involves allocating a new owned box and copying the contents of the old box into the new box.
Releasing an owning pointer immediately releases its corresponding owned box.
@ -3562,8 +3562,8 @@ Whereas most calls to trait methods are "early bound" (statically resolved) to s
a call to a method on an object type is only resolved to a vtable entry at compile time.
The actual implementation for each vtable entry can vary on an object-by-object basis.
Given a pointer-typed expression `E` of type `&T` or `~T`, where `T` implements trait `R`,
casting `E` to the corresponding pointer type `&R` or `~R` results in a value of the _object type_ `R`.
Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T` implements trait `R`,
casting `E` to the corresponding pointer type `&R` or `Box<R>` results in a value of the _object type_ `R`.
This result is represented as a pair of pointers:
the vtable pointer for the `T` implementation of `R`, and the pointer value of `E`.
@ -3761,7 +3761,7 @@ Local variables are immutable unless declared otherwise like: `let mut x = ...`.
Function parameters are immutable unless declared with `mut`. The
`mut` keyword applies only to the following parameter (so `|mut x, y|`
and `fn f(mut x: ~int, y: ~int)` declare one mutable variable `x` and
and `fn f(mut x: Box<int>, y: Box<int>)` declare one mutable variable `x` and
one immutable variable `y`).
Methods that take either `self` or `~self` can optionally place them in a

View File

@ -455,7 +455,7 @@ against each pattern in order until one matches. The matching pattern
executes its corresponding arm.
~~~~
# let my_number = 1;
let my_number = 1;
match my_number {
0 => println!("zero"),
1 | 2 => println!("one or two"),

View File

@ -169,7 +169,7 @@ fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
else if hi < c { Less }
else { Greater }
}) != None
}\n\n
}\n
""");
def emit_property_module(f, mod, tbl):
@ -193,11 +193,11 @@ def emit_property_module(f, mod, tbl):
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
f.write(" super::bsearch_range_table(c, %s_table)\n" % cat)
f.write(" }\n\n")
f.write("}\n")
f.write("}\n\n")
def emit_conversions_module(f, lowerupper, upperlower):
f.write("pub mod conversions {\n")
f.write("pub mod conversions {")
f.write("""
use cmp::{Equal, Less, Greater};
use slice::ImmutableVector;
@ -225,13 +225,14 @@ def emit_conversions_module(f, lowerupper, upperlower):
else { Greater }
})
}
""");
emit_caseconversion_table(f, "LuLl", upperlower)
emit_caseconversion_table(f, "LlLu", lowerupper)
f.write("}\n")
def emit_caseconversion_table(f, name, table):
f.write(" static %s_table : &'static [(char, char)] = &[\n" % name)
f.write(" static %s_table : &'static [(char, char)] = &[\n" % name)
sorted_table = sorted(table.iteritems(), key=operator.itemgetter(0))
ix = 0
for key, value in sorted_table:
@ -255,13 +256,13 @@ def format_table_content(f, content, indent):
line = " "*indent + chunk
f.write(line)
def emit_decomp_module(f, canon, compat, combine):
def emit_core_norm_module(f, canon, compat):
canon_keys = canon.keys()
canon_keys.sort()
compat_keys = compat.keys()
compat_keys.sort()
f.write("pub mod decompose {\n");
f.write("pub mod normalization {\n");
f.write(" use option::Option;\n");
f.write(" use option::{Some, None};\n");
f.write(" use slice::ImmutableVector;\n");
@ -279,23 +280,6 @@ def emit_decomp_module(f, canon, compat, combine):
}
None => None
}
}\n
""")
f.write("""
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
use cmp::{Equal, Less, Greater};
match r.bsearch(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
Some(idx) => {
let (_, _, result) = r[idx];
result
}
None => 0
}
}\n\n
""")
@ -337,28 +321,24 @@ def emit_decomp_module(f, canon, compat, combine):
format_table_content(f, data, 8)
f.write("\n ];\n\n")
f.write(" static combining_class_table : &'static [(char, char, u8)] = &[\n")
ix = 0
for pair in combine:
f.write(ch_prefix(ix))
f.write("(%s, %s, %s)" % (escape_char(pair[0]), escape_char(pair[1]), pair[2]))
ix += 1
f.write("\n ];\n")
f.write(" pub fn canonical(c: char, i: |char|) "
+ "{ d(c, i, false); }\n\n")
f.write(" pub fn compatibility(c: char, i: |char|) "
+"{ d(c, i, true); }\n\n")
f.write(" pub fn canonical_combining_class(c: char) -> u8 {\n"
+ " bsearch_range_value_table(c, combining_class_table)\n"
+ " }\n\n")
f.write(" fn d(c: char, i: |char|, k: bool) {\n")
f.write(" use iter::Iterator;\n");
f.write(" if c <= '\\x7f' { i(c); return; }\n")
# First check the canonical decompositions
f.write("""
pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
fn d(c: char, i: |char|, k: bool) {
use iter::Iterator;
// 7-bit ASCII never decomposes
if c <= '\\x7f' { i(c); return; }
// Perform decomposition for Hangul
if (c as u32) >= S_BASE && (c as u32) < (S_BASE + S_COUNT) {
decompose_hangul(c, i);
return;
}
// First check the canonical decompositions
match bsearch_table(c, canonical_table) {
Some(canon) => {
for x in canon.iter() {
@ -367,13 +347,12 @@ def emit_decomp_module(f, canon, compat, combine):
return;
}
None => ()
}\n\n""")
}
# Bottom out if we're not doing compat.
f.write(" if !k { i(c); return; }\n")
// Bottom out if we're not doing compat.
if !k { i(c); return; }
# Then check the compatibility decompositions
f.write("""
// Then check the compatibility decompositions
match bsearch_table(c, compatibility_table) {
Some(compat) => {
for x in compat.iter() {
@ -382,24 +361,83 @@ def emit_decomp_module(f, canon, compat, combine):
return;
}
None => ()
}\n\n""")
}
# Finally bottom out.
f.write(" i(c);\n")
f.write(" }\n")
f.write("}\n\n")
// Finally bottom out.
i(c);
}
r = "unicode.rs"
for i in [r]:
if os.path.exists(i):
os.remove(i);
rf = open(r, "w")
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
static S_BASE: u32 = 0xAC00;
static L_BASE: u32 = 0x1100;
static V_BASE: u32 = 0x1161;
static T_BASE: u32 = 0x11A7;
static L_COUNT: u32 = 19;
static V_COUNT: u32 = 21;
static T_COUNT: u32 = 28;
static N_COUNT: u32 = (V_COUNT * T_COUNT);
static S_COUNT: u32 = (L_COUNT * N_COUNT);
(canon_decomp, compat_decomp, gencats,
combines, lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
// Decompose a precomposed Hangul syllable
fn decompose_hangul(s: char, f: |char|) {
use cast::transmute;
# Preamble
rf.write('''// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
let si = s as u32 - S_BASE;
let li = si / N_COUNT;
unsafe {
f(transmute(L_BASE + li));
let vi = (si % N_COUNT) / T_COUNT;
f(transmute(V_BASE + vi));
let ti = si % T_COUNT;
if ti > 0 {
f(transmute(T_BASE + ti));
}
}
}
}
""")
def emit_std_norm_module(f, combine):
f.write("pub mod normalization {\n");
f.write(" use option::{Some, None};\n");
f.write(" use slice::ImmutableVector;\n");
f.write("""
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
use cmp::{Equal, Less, Greater};
match r.bsearch(|&(lo, hi, _)| {
if lo <= c && c <= hi { Equal }
else if hi < c { Less }
else { Greater }
}) {
Some(idx) => {
let (_, _, result) = r[idx];
result
}
None => 0
}
}\n\n
""")
f.write(" static combining_class_table : &'static [(char, char, u8)] = &[\n")
ix = 0
for pair in combine:
f.write(ch_prefix(ix))
f.write("(%s, %s, %s)" % (escape_char(pair[0]), escape_char(pair[1]), pair[2]))
ix += 1
f.write("\n ];\n\n")
f.write(" pub fn canonical_combining_class(c: char) -> u8 {\n"
+ " bsearch_range_value_table(c, combining_class_table)\n"
+ " }\n")
f.write("}\n")
preamble = '''// 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.
//
@ -409,23 +447,45 @@ rf.write('''// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGH
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// The following code was generated by "src/etc/unicode.py"
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
#![allow(missing_doc)]
#![allow(non_uppercase_statics)]
#![allow(missing_doc, non_uppercase_statics)]
''')
'''
emit_bsearch_range_table(rf);
emit_property_module(rf, "general_category", gencats)
(canon_decomp, compat_decomp, gencats,
combines, lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
emit_decomp_module(rf, canon_decomp, compat_decomp, combines)
def gen_core_unicode():
r = "core_unicode.rs"
if os.path.exists(r):
os.remove(r);
with open(r, "w") as rf:
# Preamble
rf.write(preamble)
derived = load_properties("DerivedCoreProperties.txt",
["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"])
emit_bsearch_range_table(rf);
emit_property_module(rf, "general_category", gencats)
emit_property_module(rf, "derived_property", derived)
emit_core_norm_module(rf, canon_decomp, compat_decomp)
props = load_properties("PropList.txt", ["White_Space"])
emit_property_module(rf, "property", props)
emit_conversions_module(rf, lowerupper, upperlower)
derived = load_properties("DerivedCoreProperties.txt",
["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"])
emit_property_module(rf, "derived_property", derived)
props = load_properties("PropList.txt", ["White_Space"])
emit_property_module(rf, "property", props)
emit_conversions_module(rf, lowerupper, upperlower)
def gen_std_unicode():
r = "std_unicode.rs"
if os.path.exists(r):
os.remove(r);
with open(r, "w") as rf:
# Preamble
rf.write(preamble)
emit_std_norm_module(rf, combines)
gen_core_unicode()
gen_std_unicode()

View File

@ -22,11 +22,8 @@
use mem::{transmute, transmute_copy};
use option::{Option, Some, None};
use owned::Box;
use raw::TraitObject;
use result::{Result, Ok, Err};
use intrinsics::TypeId;
use intrinsics;
/// A type with no inhabitants
pub enum Void { }
@ -117,38 +114,11 @@ impl<'a> AnyMutRefExt<'a> for &'a mut Any {
}
}
/// Extension methods for an owning `Any` trait object
pub trait AnyOwnExt {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
}
impl AnyOwnExt for Box<Any> {
#[inline]
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
let to: TraitObject = transmute_copy(&self);
// Prevent destructor on self being run
intrinsics::forget(self);
// Extract the data pointer
Ok(transmute(to.data))
}
} else {
Err(self)
}
}
}
#[cfg(test)]
mod tests {
use prelude::*;
use super::*;
use owned::Box;
use realstd::owned::{Box, AnyOwnExt};
use realstd::str::StrAllocating;
#[deriving(Eq, Show)]
@ -253,6 +223,8 @@ mod tests {
#[test]
fn any_move() {
use realstd::any::Any;
use realstd::result::{Ok, Err};
let a = box 8u as Box<Any>;
let b = box Test as Box<Any>;

View File

@ -27,19 +27,25 @@
use mem::transmute;
use option::{None, Option, Some};
use iter::{Iterator, range_step};
use unicode::{derived_property, property, general_category, decompose, conversions};
use unicode::{derived_property, property, general_category, conversions};
/// Returns the canonical decomposition of a character.
pub use unicode::normalization::decompose_canonical;
/// Returns the compatibility decomposition of a character.
pub use unicode::normalization::decompose_compatible;
#[cfg(not(test))] use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
#[cfg(not(test))] use default::Default;
// UTF-8 ranges and tags for encoding characters
static TAG_CONT: uint = 128u;
static MAX_ONE_B: uint = 128u;
static TAG_TWO_B: uint = 192u;
static MAX_TWO_B: uint = 2048u;
static TAG_THREE_B: uint = 224u;
static MAX_THREE_B: uint = 65536u;
static TAG_FOUR_B: uint = 240u;
static TAG_CONT: u8 = 0b1000_0000u8;
static TAG_TWO_B: u8 = 0b1100_0000u8;
static TAG_THREE_B: u8 = 0b1110_0000u8;
static TAG_FOUR_B: u8 = 0b1111_0000u8;
static MAX_ONE_B: u32 = 0x80u32;
static MAX_TWO_B: u32 = 0x800u32;
static MAX_THREE_B: u32 = 0x10000u32;
static MAX_FOUR_B: u32 = 0x200000u32;
/*
Lu Uppercase_Letter an uppercase letter
@ -284,53 +290,6 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
}
}
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
static S_BASE: uint = 0xAC00;
static L_BASE: uint = 0x1100;
static V_BASE: uint = 0x1161;
static T_BASE: uint = 0x11A7;
static L_COUNT: uint = 19;
static V_COUNT: uint = 21;
static T_COUNT: uint = 28;
static N_COUNT: uint = (V_COUNT * T_COUNT);
static S_COUNT: uint = (L_COUNT * N_COUNT);
// Decompose a precomposed Hangul syllable
fn decompose_hangul(s: char, f: |char|) {
let si = s as uint - S_BASE;
let li = si / N_COUNT;
unsafe {
f(transmute((L_BASE + li) as u32));
let vi = (si % N_COUNT) / T_COUNT;
f(transmute((V_BASE + vi) as u32));
let ti = si % T_COUNT;
if ti > 0 {
f(transmute((T_BASE + ti) as u32));
}
}
}
/// Returns the canonical decomposition of a character
pub fn decompose_canonical(c: char, f: |char|) {
if (c as uint) < S_BASE || (c as uint) >= (S_BASE + S_COUNT) {
decompose::canonical(c, f);
} else {
decompose_hangul(c, f);
}
}
/// Returns the compatibility decomposition of a character
pub fn decompose_compatible(c: char, f: |char|) {
if (c as uint) < S_BASE || (c as uint) >= (S_BASE + S_COUNT) {
decompose::compatibility(c, f);
} else {
decompose_hangul(c, f);
}
}
///
/// Returns the hexadecimal Unicode escape of a `char`
///
@ -386,12 +345,7 @@ pub fn escape_default(c: char, f: |char|) {
/// Returns the amount of bytes this `char` would need if encoded in UTF-8
pub fn len_utf8_bytes(c: char) -> uint {
static MAX_ONE_B: uint = 128u;
static MAX_TWO_B: uint = 2048u;
static MAX_THREE_B: uint = 65536u;
static MAX_FOUR_B: uint = 2097152u;
let code = c as uint;
let code = c as u32;
match () {
_ if code < MAX_ONE_B => 1u,
_ if code < MAX_TWO_B => 2u,
@ -606,41 +560,40 @@ impl Char for char {
fn len_utf8_bytes(&self) -> uint { len_utf8_bytes(*self) }
fn encode_utf8(&self, dst: &mut [u8]) -> uint {
let code = *self as uint;
fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> uint {
let code = *self as u32;
if code < MAX_ONE_B {
dst[0] = code as u8;
return 1;
1
} else if code < MAX_TWO_B {
dst[0] = (code >> 6u & 31u | TAG_TWO_B) as u8;
dst[1] = (code & 63u | TAG_CONT) as u8;
return 2;
dst[0] = (code >> 6u & 0x1F_u32) as u8 | TAG_TWO_B;
dst[1] = (code & 0x3F_u32) as u8 | TAG_CONT;
2
} else if code < MAX_THREE_B {
dst[0] = (code >> 12u & 15u | TAG_THREE_B) as u8;
dst[1] = (code >> 6u & 63u | TAG_CONT) as u8;
dst[2] = (code & 63u | TAG_CONT) as u8;
return 3;
dst[0] = (code >> 12u & 0x0F_u32) as u8 | TAG_THREE_B;
dst[1] = (code >> 6u & 0x3F_u32) as u8 | TAG_CONT;
dst[2] = (code & 0x3F_u32) as u8 | TAG_CONT;
3
} else {
dst[0] = (code >> 18u & 7u | TAG_FOUR_B) as u8;
dst[1] = (code >> 12u & 63u | TAG_CONT) as u8;
dst[2] = (code >> 6u & 63u | TAG_CONT) as u8;
dst[3] = (code & 63u | TAG_CONT) as u8;
return 4;
dst[0] = (code >> 18u & 0x07_u32) as u8 | TAG_FOUR_B;
dst[1] = (code >> 12u & 0x3F_u32) as u8 | TAG_CONT;
dst[2] = (code >> 6u & 0x3F_u32) as u8 | TAG_CONT;
dst[3] = (code & 0x3F_u32) as u8 | TAG_CONT;
4
}
}
fn encode_utf16(&self, dst: &mut [u16]) -> uint {
let mut ch = *self as uint;
if (ch & 0xFFFF_u) == ch {
// The BMP falls through (assuming non-surrogate, as it
// should)
assert!(ch <= 0xD7FF_u || ch >= 0xE000_u);
let mut ch = *self as u32;
if (ch & 0xFFFF_u32) == ch {
// The BMP falls through (assuming non-surrogate, as it should)
assert!(ch <= 0xD7FF_u32 || ch >= 0xE000_u32);
dst[0] = ch as u16;
1
} else {
// Supplementary planes break into surrogates.
assert!(ch >= 0x1_0000_u && ch <= 0x10_FFFF_u);
ch -= 0x1_0000_u;
assert!(ch >= 0x1_0000_u32 && ch <= 0x10_FFFF_u32);
ch -= 0x1_0000_u32;
dst[0] = 0xD800_u16 | ((ch >> 10) as u16);
dst[1] = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16);
2

View File

@ -21,8 +21,6 @@ the `clone` method.
*/
use owned::Box;
/// A common trait for cloning an object.
pub trait Clone {
/// Returns a copy of the value. The contents of owned pointers
@ -41,18 +39,6 @@ pub trait Clone {
}
}
impl<T: Clone> Clone for Box<T> {
/// Return a copy of the owned box.
#[inline]
fn clone(&self) -> Box<T> { box {(**self).clone()} }
/// Perform copy-assignment from `source` by reusing the existing allocation.
#[inline]
fn clone_from(&mut self, source: &Box<T>) {
(**self).clone_from(&(**source));
}
}
impl<T> Clone for @T {
/// Return a shallow copy of the managed box.
#[inline]
@ -129,12 +115,22 @@ extern_fn_clone!(A, B, C, D, E, F, G, H)
#[cfg(test)]
mod test {
use prelude::*;
use owned::Box;
use realstd::owned::Box;
fn realclone<T: ::realstd::clone::Clone>(t: &T) -> T {
use realstd::clone::Clone;
t.clone()
}
fn realclone_from<T: ::realstd::clone::Clone>(t1: &mut T, t2: &T) {
use realstd::clone::Clone;
t1.clone_from(t2)
}
#[test]
fn test_owned_clone() {
let a = box 5i;
let b: Box<int> = a.clone();
let b: Box<int> = realclone(&a);
assert_eq!(a, b);
}
@ -157,7 +153,7 @@ mod test {
fn test_clone_from() {
let a = box 5;
let mut b = box 10;
b.clone_from(&a);
realclone_from(&mut b, &a);
assert_eq!(*b, 5);
}

View File

@ -193,7 +193,6 @@ pub fn max<T: TotalOrd>(v1: T, v2: T) -> T {
#[cfg(not(test))]
mod impls {
use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering};
use owned::Box;
// & pointers
impl<'a, T: Eq> Eq for &'a T {
@ -240,29 +239,6 @@ mod impls {
fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
}
impl<T: TotalEq> TotalEq for @T {}
// box pointers
impl<T:Eq> Eq for Box<T> {
#[inline]
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
}
impl<T:Ord> Ord for Box<T> {
#[inline]
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
}
impl<T: TotalOrd> TotalOrd for Box<T> {
#[inline]
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
}
impl<T: TotalEq> TotalEq for Box<T> {}
}
#[cfg(test)]

View File

@ -10,8 +10,6 @@
//! The `Default` trait for types which may have meaningful default values
use owned::Box;
/// A trait that types which have a useful default value should implement.
pub trait Default {
/// Return the "default value" for a type.
@ -21,7 +19,3 @@ pub trait Default {
impl<T: Default + 'static> Default for @T {
fn default() -> @T { @Default::default() }
}
impl<T: Default> Default for Box<T> {
fn default() -> Box<T> { box Default::default() }
}

View File

@ -2334,7 +2334,7 @@ mod tests {
use realstd::num;
use cmp;
use owned::Box;
use realstd::owned::Box;
use uint;
#[test]

View File

@ -30,7 +30,6 @@
#[cfg(test)] pub use cmp = realcore::cmp;
#[cfg(test)] pub use kinds = realcore::kinds;
#[cfg(test)] pub use ops = realcore::ops;
#[cfg(test)] pub use owned = realcore::owned;
#[cfg(test)] pub use ty = realcore::ty;
#[cfg(not(test))]
@ -73,7 +72,6 @@ pub mod ptr;
#[cfg(not(test))] pub mod ops;
#[cfg(not(test))] pub mod ty;
#[cfg(not(test))] pub mod cmp;
#[cfg(not(test))] pub mod owned;
pub mod clone;
pub mod default;
pub mod container;
@ -95,6 +93,9 @@ pub mod slice;
pub mod str;
pub mod tuple;
#[cfg(stage0, not(test))]
pub mod owned;
mod failure;
// FIXME: this module should not exist. Once owned allocations are no longer a

View File

@ -380,7 +380,7 @@ mod tests {
use mem::*;
use option::{Some,None};
use realstd::str::StrAllocating;
use owned::Box;
use realstd::owned::Box;
use raw;
#[test]

View File

@ -10,10 +10,14 @@
//! Operations on unique pointer types
// FIXME: this module should not exist in libcore. It must currently because the
// Box implementation is quite ad-hoc in the compiler. Once there is
// proper support in the compiler this type will be able to be defined in
// its own module.
use any::{Any, AnyRefExt};
use clone::Clone;
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
use default::Default;
use intrinsics;
use mem;
use raw::TraitObject;
use result::{Ok, Err, Result};
/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
@ -23,16 +27,75 @@
/// let foo = box(HEAP) Bar::new(...);
/// let foo = box Bar::new(...);
#[lang="exchange_heap"]
#[cfg(not(test))]
pub static HEAP: () = ();
#[cfg(test)]
pub static HEAP: () = ();
/// A type that represents a uniquely-owned value.
#[lang="owned_box"]
#[cfg(not(test))]
pub struct Box<T>(*T);
#[cfg(test)]
pub struct Box<T>(*T);
impl<T: Default> Default for Box<T> {
fn default() -> Box<T> { box Default::default() }
}
impl<T: Clone> Clone for Box<T> {
/// Return a copy of the owned box.
#[inline]
fn clone(&self) -> Box<T> { box {(**self).clone()} }
/// Perform copy-assignment from `source` by reusing the existing allocation.
#[inline]
fn clone_from(&mut self, source: &Box<T>) {
(**self).clone_from(&(**source));
}
}
// box pointers
impl<T:Eq> Eq for Box<T> {
#[inline]
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
}
impl<T:Ord> Ord for Box<T> {
#[inline]
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
}
impl<T: TotalOrd> TotalOrd for Box<T> {
#[inline]
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
}
impl<T: TotalEq> TotalEq for Box<T> {}
/// Extension methods for an owning `Any` trait object
pub trait AnyOwnExt {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
}
impl AnyOwnExt for Box<Any> {
#[inline]
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
let to: TraitObject =
*mem::transmute::<&Box<Any>, &TraitObject>(&self);
// Prevent destructor on self being run
intrinsics::forget(self);
// Extract the data pointer
Ok(mem::transmute(to.data))
}
} else {
Err(self)
}
}
}

View File

@ -1725,6 +1725,7 @@ impl<'a> StrSlice<'a> for &'a str {
#[inline]
fn is_char_boundary(&self, index: uint) -> bool {
if index == self.len() { return true; }
if index > self.len() { return false; }
let b = self[index];
return b < 128u8 || b >= 192u8;
}

View File

@ -1,4 +1,4 @@
// 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.
//
@ -8,10 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// The following code was generated by "src/etc/unicode.py"
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
#![allow(missing_doc, non_uppercase_statics)]
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use cmp::{Equal, Less, Greater};
use slice::ImmutableVector;
@ -102,7 +103,8 @@ pub mod general_category {
}
}
pub mod decompose {
pub mod normalization {
use option::Option;
use option::{Some, None};
use slice::ImmutableVector;
@ -123,7 +125,6 @@ pub mod decompose {
}
// Canonical decompositions
static canonical_table : &'static [(char, &'static [char])] = &[
('\xc0', &['\x41', '\u0300']), ('\xc1', &['\x41', '\u0301']), ('\xc2', &['\x41', '\u0302']),
@ -2120,14 +2121,24 @@ pub mod decompose {
&['\u53ef'])
];
pub fn canonical(c: char, i: |char|) { d(c, i, false); }
pub fn compatibility(c: char, i: |char|) { d(c, i, true); }
pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
fn d(c: char, i: |char|, k: bool) {
use iter::Iterator;
// 7-bit ASCII never decomposes
if c <= '\x7f' { i(c); return; }
// Perform decomposition for Hangul
if (c as u32) >= S_BASE && (c as u32) < (S_BASE + S_COUNT) {
decompose_hangul(c, i);
return;
}
// First check the canonical decompositions
match bsearch_table(c, canonical_table) {
Some(canon) => {
for x in canon.iter() {
@ -2138,8 +2149,10 @@ pub mod decompose {
None => ()
}
// Bottom out if we're not doing compat.
if !k { i(c); return; }
// Then check the compatibility decompositions
match bsearch_table(c, compatibility_table) {
Some(compat) => {
for x in compat.iter() {
@ -2150,8 +2163,40 @@ pub mod decompose {
None => ()
}
// Finally bottom out.
i(c);
}
// Constants from Unicode 6.2.0 Section 3.12 Conjoining Jamo Behavior
static S_BASE: u32 = 0xAC00;
static L_BASE: u32 = 0x1100;
static V_BASE: u32 = 0x1161;
static T_BASE: u32 = 0x11A7;
static L_COUNT: u32 = 19;
static V_COUNT: u32 = 21;
static T_COUNT: u32 = 28;
static N_COUNT: u32 = (V_COUNT * T_COUNT);
static S_COUNT: u32 = (L_COUNT * N_COUNT);
// Decompose a precomposed Hangul syllable
fn decompose_hangul(s: char, f: |char|) {
use mem::transmute;
let si = s as u32 - S_BASE;
let li = si / N_COUNT;
unsafe {
f(transmute(L_BASE + li));
let vi = (si % N_COUNT) / T_COUNT;
f(transmute(V_BASE + vi));
let ti = si % T_COUNT;
if ti > 0 {
f(transmute(T_BASE + ti));
}
}
}
}
pub mod derived_property {
@ -3968,6 +4013,7 @@ pub mod derived_property {
pub fn XID_Start(c: char) -> bool {
super::bsearch_range_table(c, XID_Start_table)
}
}
pub mod property {
@ -3983,6 +4029,7 @@ pub mod property {
pub fn White_Space(c: char) -> bool {
super::bsearch_range_table(c, White_Space_table)
}
}
pub mod conversions {
@ -4501,7 +4548,7 @@ pub mod conversions {
('\U00010426', '\U0001044e'), ('\U00010427', '\U0001044f')
];
static LlLu_table : &'static [(char, char)] = &[
static LlLu_table : &'static [(char, char)] = &[
('\x61', '\x41'), ('\x62', '\x42'),
('\x63', '\x43'), ('\x64', '\x44'),
('\x65', '\x45'), ('\x66', '\x46'),

View File

@ -173,7 +173,7 @@ pub use funcs::bsd43::{shutdown};
#[cfg(unix)] pub use consts::os::posix88::{EADDRINUSE, ENOENT, EISDIR, EAGAIN, EWOULDBLOCK};
#[cfg(unix)] pub use consts::os::posix88::{ECANCELED, SIGINT, EINPROGRESS};
#[cfg(unix)] pub use consts::os::posix88::{SIGTERM, SIGKILL, SIGPIPE, PROT_NONE};
#[cfg(unix)] pub use consts::os::posix01::{SIG_IGN, WNOHANG};
#[cfg(unix)] pub use consts::os::posix01::{SIG_IGN};
#[cfg(unix)] pub use consts::os::bsd44::{AF_UNIX};
#[cfg(unix)] pub use types::os::common::posix01::{pthread_t, timespec, timezone};
@ -2473,8 +2473,6 @@ pub mod consts {
pub static CLOCK_REALTIME: c_int = 0;
pub static CLOCK_MONOTONIC: c_int = 1;
pub static WNOHANG: c_int = 1;
}
pub mod posix08 {
}
@ -2924,8 +2922,6 @@ pub mod consts {
pub static CLOCK_REALTIME: c_int = 0;
pub static CLOCK_MONOTONIC: c_int = 4;
pub static WNOHANG: c_int = 1;
}
pub mod posix08 {
}
@ -3313,8 +3309,6 @@ pub mod consts {
pub static PTHREAD_CREATE_JOINABLE: c_int = 1;
pub static PTHREAD_CREATE_DETACHED: c_int = 2;
pub static PTHREAD_STACK_MIN: size_t = 8192;
pub static WNOHANG: c_int = 1;
}
pub mod posix08 {
}
@ -3980,16 +3974,6 @@ pub mod funcs {
}
}
pub mod wait {
use types::os::arch::c95::{c_int};
use types::os::arch::posix88::{pid_t};
extern {
pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int)
-> pid_t;
}
}
pub mod glob {
use types::os::arch::c95::{c_char, c_int};
use types::os::common::posix01::{glob_t};

View File

@ -10,7 +10,12 @@
//! C definitions used by libnative that don't belong in liblibc
#![allow(dead_code)]
pub use self::select::fd_set;
pub use self::signal::{sigaction, siginfo, sigset_t};
pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
use libc;
@ -34,6 +39,8 @@ pub static MSG_DONTWAIT: libc::c_int = 0x80;
#[cfg(target_os = "android")]
pub static MSG_DONTWAIT: libc::c_int = 0x40;
pub static WNOHANG: libc::c_int = 1;
extern {
pub fn gettimeofday(timeval: *mut libc::timeval,
tzp: *libc::c_void) -> libc::c_int;
@ -49,6 +56,17 @@ extern {
optlen: *mut libc::socklen_t) -> libc::c_int;
pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
options: libc::c_int) -> libc::pid_t;
pub fn sigaction(signum: libc::c_int,
act: *sigaction,
oldact: *mut sigaction) -> libc::c_int;
pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
}
#[cfg(target_os = "macos")]
@ -81,3 +99,94 @@ mod select {
set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
mod signal {
use libc;
pub static SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
pub static SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
pub static SA_NODEFER: libc::c_ulong = 0x40000000;
pub static SA_ONSTACK: libc::c_ulong = 0x08000000;
pub static SA_RESETHAND: libc::c_ulong = 0x80000000;
pub static SA_RESTART: libc::c_ulong = 0x10000000;
pub static SA_SIGINFO: libc::c_ulong = 0x00000004;
pub static SIGCHLD: libc::c_int = 17;
// This definition is not as accurate as it could be, {pid, uid, status} is
// actually a giant union. Currently we're only interested in these fields,
// however.
pub struct siginfo {
si_signo: libc::c_int,
si_errno: libc::c_int,
si_code: libc::c_int,
pub pid: libc::pid_t,
pub uid: libc::uid_t,
pub status: libc::c_int,
}
pub struct sigaction {
pub sa_handler: extern fn(libc::c_int),
pub sa_mask: sigset_t,
pub sa_flags: libc::c_ulong,
sa_restorer: *mut libc::c_void,
}
#[cfg(target_word_size = "32")]
pub struct sigset_t {
__val: [libc::c_ulong, ..32],
}
#[cfg(target_word_size = "64")]
pub struct sigset_t {
__val: [libc::c_ulong, ..16],
}
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
mod signal {
use libc;
pub static SA_ONSTACK: libc::c_int = 0x0001;
pub static SA_RESTART: libc::c_int = 0x0002;
pub static SA_RESETHAND: libc::c_int = 0x0004;
pub static SA_NOCLDSTOP: libc::c_int = 0x0008;
pub static SA_NODEFER: libc::c_int = 0x0010;
pub static SA_NOCLDWAIT: libc::c_int = 0x0020;
pub static SA_SIGINFO: libc::c_int = 0x0040;
pub static SIGCHLD: libc::c_int = 20;
#[cfg(target_os = "macos")]
pub type sigset_t = u32;
#[cfg(target_os = "freebsd")]
pub struct sigset_t {
bits: [u32, ..4],
}
// This structure has more fields, but we're not all that interested in
// them.
pub struct siginfo {
pub si_signo: libc::c_int,
pub si_errno: libc::c_int,
pub si_code: libc::c_int,
pub pid: libc::pid_t,
pub uid: libc::uid_t,
pub status: libc::c_int,
}
#[cfg(target_os = "macos")]
pub struct sigaction {
pub sa_handler: extern fn(libc::c_int),
sa_tramp: *mut libc::c_void,
pub sa_mask: sigset_t,
pub sa_flags: libc::c_int,
}
#[cfg(target_os = "freebsd")]
pub struct sigaction {
pub sa_handler: extern fn(libc::c_int),
pub sa_flags: libc::c_int,
pub sa_mask: sigset_t,
}
}

View File

@ -0,0 +1,205 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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.
//! Implementation of the helper thread for the timer module
//!
//! This module contains the management necessary for the timer worker thread.
//! This thread is responsible for performing the send()s on channels for timers
//! that are using channels instead of a blocking call.
//!
//! The timer thread is lazily initialized, and it's shut down via the
//! `shutdown` function provided. It must be maintained as an invariant that
//! `shutdown` is only called when the entire program is finished. No new timers
//! can be created in the future and there must be no active timers at that
//! time.
#![macro_escape]
use std::mem;
use std::rt::bookkeeping;
use std::rt;
use std::ty::Unsafe;
use std::unstable::mutex::StaticNativeMutex;
use task;
/// A structure for management of a helper thread.
///
/// This is generally a static structure which tracks the lifetime of a helper
/// thread.
///
/// The fields of this helper are all public, but they should not be used, this
/// is for static initialization.
pub struct Helper<M> {
/// Internal lock which protects the remaining fields
pub lock: StaticNativeMutex,
// You'll notice that the remaining fields are Unsafe<T>, and this is
// because all helper thread operations are done through &self, but we need
// these to be mutable (once `lock` is held).
/// Lazily allocated channel to send messages to the helper thread.
pub chan: Unsafe<*mut Sender<M>>,
/// OS handle used to wake up a blocked helper thread
pub signal: Unsafe<uint>,
/// Flag if this helper thread has booted and been initialized yet.
pub initialized: Unsafe<bool>,
}
macro_rules! helper_init( (static mut $name:ident: Helper<$m:ty>) => (
static mut $name: Helper<$m> = Helper {
lock: ::std::unstable::mutex::NATIVE_MUTEX_INIT,
chan: ::std::ty::Unsafe {
value: 0 as *mut Sender<$m>,
marker1: ::std::kinds::marker::InvariantType,
},
signal: ::std::ty::Unsafe {
value: 0,
marker1: ::std::kinds::marker::InvariantType,
},
initialized: ::std::ty::Unsafe {
value: false,
marker1: ::std::kinds::marker::InvariantType,
},
};
) )
impl<M: Send> Helper<M> {
/// Lazily boots a helper thread, becoming a no-op if the helper has already
/// been spawned.
///
/// This function will check to see if the thread has been initialized, and
/// if it has it returns quickly. If initialization has not happened yet,
/// the closure `f` will be run (inside of the initialization lock) and
/// passed to the helper thread in a separate task.
///
/// This function is safe to be called many times.
pub fn boot<T: Send>(&'static self,
f: || -> T,
helper: fn(imp::signal, Receiver<M>, T)) {
unsafe {
let _guard = self.lock.lock();
if !*self.initialized.get() {
let (tx, rx) = channel();
*self.chan.get() = mem::transmute(box tx);
let (receive, send) = imp::new();
*self.signal.get() = send as uint;
let t = f();
task::spawn(proc() {
bookkeeping::decrement();
helper(receive, rx, t);
self.lock.lock().signal()
});
rt::at_exit(proc() { self.shutdown() });
*self.initialized.get() = true;
}
}
}
/// Sends a message to a spawned worker thread.
///
/// This is only valid if the worker thread has previously booted
pub fn send(&'static self, msg: M) {
unsafe {
let _guard = self.lock.lock();
// Must send and *then* signal to ensure that the child receives the
// message. Otherwise it could wake up and go to sleep before we
// send the message.
assert!(!self.chan.get().is_null());
(**self.chan.get()).send(msg);
imp::signal(*self.signal.get() as imp::signal);
}
}
fn shutdown(&'static self) {
unsafe {
// Shut down, but make sure this is done inside our lock to ensure
// that we'll always receive the exit signal when the thread
// returns.
let guard = self.lock.lock();
// Close the channel by destroying it
let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
*self.chan.get() = 0 as *mut Sender<M>;
drop(chan);
imp::signal(*self.signal.get() as imp::signal);
// Wait for the child to exit
guard.wait();
drop(guard);
// Clean up after ourselves
self.lock.destroy();
imp::close(*self.signal.get() as imp::signal);
*self.signal.get() = 0;
}
}
}
#[cfg(unix)]
mod imp {
use libc;
use std::os;
use io::file::FileDesc;
pub type signal = libc::c_int;
pub fn new() -> (signal, signal) {
let pipe = os::pipe();
(pipe.input, pipe.out)
}
pub fn signal(fd: libc::c_int) {
FileDesc::new(fd, false).inner_write([0]).unwrap();
}
pub fn close(fd: libc::c_int) {
let _fd = FileDesc::new(fd, true);
}
}
#[cfg(windows)]
mod imp {
use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
use std::ptr;
use libc;
pub type signal = HANDLE;
pub fn new() -> (HANDLE, HANDLE) {
unsafe {
let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
ptr::null());
(handle, handle)
}
}
pub fn signal(handle: HANDLE) {
assert!(unsafe { SetEvent(handle) != 0 });
}
pub fn close(handle: HANDLE) {
assert!(unsafe { CloseHandle(handle) != 0 });
}
extern "system" {
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
bInitialState: BOOL,
lpName: LPCSTR) -> HANDLE;
fn SetEvent(hEvent: HANDLE) -> BOOL;
}
}

View File

@ -40,6 +40,8 @@ use ai = std::io::net::addrinfo;
pub use self::file::FileDesc;
pub use self::process::Process;
mod helper_thread;
// Native I/O implementations
pub mod addrinfo;
pub mod net;
@ -75,8 +77,6 @@ pub mod pipe;
#[cfg(unix)] #[path = "c_unix.rs"] mod c;
#[cfg(windows)] #[path = "c_win32.rs"] mod c;
mod timer_helper;
pub type IoResult<T> = Result<T, IoError>;
fn unimpl() -> IoError {

View File

@ -8,20 +8,27 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::io;
use libc::{pid_t, c_void, c_int};
use libc;
use std::io;
use std::mem;
use std::os;
use std::ptr;
use std::rt::rtio;
use p = std::io::process;
use super::IoResult;
use super::file;
use super::util;
#[cfg(windows)] use std::mem;
#[cfg(windows)] use std::strbuf::StrBuf;
#[cfg(not(windows))] use super::retry;
#[cfg(unix)] use super::c;
#[cfg(unix)] use super::retry;
#[cfg(unix)] use io::helper_thread::Helper;
#[cfg(unix)]
helper_init!(static mut HELPER: Helper<Req>)
/**
* A value representing a child process.
@ -44,6 +51,14 @@ pub struct Process {
/// Manually delivered signal
exit_signal: Option<int>,
/// Deadline after which wait() will return
deadline: u64,
}
#[cfg(unix)]
enum Req {
NewChild(libc::pid_t, Sender<p::ProcessExit>, u64),
}
impl Process {
@ -116,6 +131,7 @@ impl Process {
handle: res.handle,
exit_code: None,
exit_signal: None,
deadline: 0,
},
ret_io))
}
@ -131,11 +147,15 @@ impl Process {
impl rtio::RtioProcess for Process {
fn id(&self) -> pid_t { self.pid }
fn wait(&mut self) -> p::ProcessExit {
fn set_timeout(&mut self, timeout: Option<u64>) {
self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0);
}
fn wait(&mut self) -> IoResult<p::ProcessExit> {
match self.exit_code {
Some(code) => code,
Some(code) => Ok(code),
None => {
let code = waitpid(self.pid);
let code = try!(waitpid(self.pid, self.deadline));
// On windows, waitpid will never return a signal. If a signal
// was successfully delivered to the process, however, we can
// consider it as having died via a signal.
@ -145,7 +165,7 @@ impl rtio::RtioProcess for Process {
Some(..) => code,
};
self.exit_code = Some(code);
code
Ok(code)
}
}
}
@ -762,61 +782,301 @@ fn translate_status(status: c_int) -> p::ProcessExit {
* operate on a none-existent process or, even worse, on a newer process
* with the same id.
*/
fn waitpid(pid: pid_t) -> p::ProcessExit {
return waitpid_os(pid);
#[cfg(windows)]
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
SYNCHRONIZE,
PROCESS_QUERY_INFORMATION,
FALSE,
STILL_ACTIVE,
INFINITE,
WAIT_TIMEOUT,
WAIT_OBJECT_0,
};
use libc::funcs::extra::kernel32::{
OpenProcess,
GetExitCodeProcess,
CloseHandle,
WaitForSingleObject,
};
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> p::ProcessExit {
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
SYNCHRONIZE,
PROCESS_QUERY_INFORMATION,
FALSE,
STILL_ACTIVE,
INFINITE,
WAIT_FAILED
};
use libc::funcs::extra::kernel32::{
OpenProcess,
GetExitCodeProcess,
CloseHandle,
WaitForSingleObject
};
unsafe {
let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE,
pid as DWORD);
if process.is_null() {
return Err(super::last_error())
}
unsafe {
let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE,
pid as DWORD);
if process.is_null() {
fail!("failure in OpenProcess: {}", os::last_os_error());
loop {
let mut status = 0;
if GetExitCodeProcess(process, &mut status) == FALSE {
let err = Err(super::last_error());
assert!(CloseHandle(process) != 0);
return err;
}
loop {
let mut status = 0;
if GetExitCodeProcess(process, &mut status) == FALSE {
if status != STILL_ACTIVE {
assert!(CloseHandle(process) != 0);
return Ok(p::ExitStatus(status as int));
}
let interval = if deadline == 0 {
INFINITE
} else {
let now = ::io::timer::now();
if deadline < now {0} else {(deadline - now) as u32}
};
match WaitForSingleObject(process, interval) {
WAIT_OBJECT_0 => {}
WAIT_TIMEOUT => {
assert!(CloseHandle(process) != 0);
fail!("failure in GetExitCodeProcess: {}", os::last_os_error());
return Err(util::timeout("process wait timed out"))
}
if status != STILL_ACTIVE {
_ => {
let err = Err(super::last_error());
assert!(CloseHandle(process) != 0);
return p::ExitStatus(status as int);
}
if WaitForSingleObject(process, INFINITE) == WAIT_FAILED {
assert!(CloseHandle(process) != 0);
fail!("failure in WaitForSingleObject: {}", os::last_os_error());
return err
}
}
}
}
}
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> p::ProcessExit {
use libc::funcs::posix01::wait;
let mut status = 0 as c_int;
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
#[cfg(unix)]
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
use std::cmp;
use std::comm;
static mut WRITE_FD: libc::c_int = 0;
let mut status = 0 as c_int;
if deadline == 0 {
return match retry(|| unsafe { c::waitpid(pid, &mut status, 0) }) {
-1 => fail!("unknown waitpid error: {}", super::last_error()),
_ => translate_status(status),
_ => Ok(translate_status(status)),
}
}
// On unix, wait() and its friends have no timeout parameters, so there is
// no way to time out a thread in wait(). From some googling and some
// thinking, it appears that there are a few ways to handle timeouts in
// wait(), but the only real reasonable one for a multi-threaded program is
// to listen for SIGCHLD.
//
// With this in mind, the waiting mechanism with a timeout barely uses
// waitpid() at all. There are a few times that waitpid() is invoked with
// WNOHANG, but otherwise all the necessary blocking is done by waiting for
// a SIGCHLD to arrive (and that blocking has a timeout). Note, however,
// that waitpid() is still used to actually reap the child.
//
// Signal handling is super tricky in general, and this is no exception. Due
// to the async nature of SIGCHLD, we use the self-pipe trick to transmit
// data out of the signal handler to the rest of the application. The first
// idea would be to have each thread waiting with a timeout to read this
// output file descriptor, but a write() is akin to a signal(), not a
// broadcast(), so it would only wake up one thread, and possibly the wrong
// thread. Hence a helper thread is used.
//
// The helper thread here is responsible for farming requests for a
// waitpid() with a timeout, and then processing all of the wait requests.
// By guaranteeing that only this helper thread is reading half of the
// self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread
// is also responsible for select() to wait for incoming messages or
// incoming SIGCHLD messages, along with passing an appropriate timeout to
// select() to wake things up as necessary.
//
// The ordering of the following statements is also very purposeful. First,
// we must be guaranteed that the helper thread is booted and available to
// receive SIGCHLD signals, and then we must also ensure that we do a
// nonblocking waitpid() at least once before we go ask the sigchld helper.
// This prevents the race where the child exits, we boot the helper, and
// then we ask for the child's exit status (never seeing a sigchld).
//
// The actual communication between the helper thread and this thread is
// quite simple, just a channel moving data around.
unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
match waitpid_nowait(pid) {
Some(ret) => return Ok(ret),
None => {}
}
let (tx, rx) = channel();
unsafe { HELPER.send(NewChild(pid, tx, deadline)); }
return match rx.recv_opt() {
Ok(e) => Ok(e),
Err(()) => Err(util::timeout("wait timed out")),
};
// Register a new SIGCHLD handler, returning the reading half of the
// self-pipe plus the old handler registered (return value of sigaction).
fn register_sigchld() -> (libc::c_int, c::sigaction) {
unsafe {
let mut old: c::sigaction = mem::init();
let mut new: c::sigaction = mem::init();
new.sa_handler = sigchld_handler;
new.sa_flags = c::SA_NOCLDSTOP;
assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0);
let mut pipes = [0, ..2];
assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
util::set_nonblocking(pipes[0], true).unwrap();
util::set_nonblocking(pipes[1], true).unwrap();
WRITE_FD = pipes[1];
(pipes[0], old)
}
}
// Helper thread for processing SIGCHLD messages
fn waitpid_helper(input: libc::c_int,
messages: Receiver<Req>,
(read_fd, old): (libc::c_int, c::sigaction)) {
util::set_nonblocking(input, true).unwrap();
let mut set: c::fd_set = unsafe { mem::init() };
let mut tv: libc::timeval;
let mut active = Vec::<(libc::pid_t, Sender<p::ProcessExit>, u64)>::new();
let max = cmp::max(input, read_fd) + 1;
'outer: loop {
// Figure out the timeout of our syscall-to-happen. If we're waiting
// for some processes, then they'll have a timeout, otherwise we
// wait indefinitely for a message to arrive.
//
// FIXME: sure would be nice to not have to scan the entire array
let min = active.iter().map(|a| *a.ref2()).enumerate().min_by(|p| {
p.val1()
});
let (p, idx) = match min {
Some((idx, deadline)) => {
let now = ::io::timer::now();
let ms = if now < deadline {deadline - now} else {0};
tv = util::ms_to_timeval(ms);
(&tv as *_, idx)
}
None => (ptr::null(), -1),
};
// Wait for something to happen
c::fd_set(&mut set, input);
c::fd_set(&mut set, read_fd);
match unsafe { c::select(max, &set, ptr::null(), ptr::null(), p) } {
// interrupted, retry
-1 if os::errno() == libc::EINTR as int => continue,
// We read something, break out and process
1 | 2 => {}
// Timeout, the pending request is removed
0 => {
drop(active.remove(idx));
continue
}
n => fail!("error in select {} ({})", os::errno(), n),
}
// Process any pending messages
if drain(input) {
loop {
match messages.try_recv() {
Ok(NewChild(pid, tx, deadline)) => {
active.push((pid, tx, deadline));
}
Err(comm::Disconnected) => {
assert!(active.len() == 0);
break 'outer;
}
Err(comm::Empty) => break,
}
}
}
// If a child exited (somehow received SIGCHLD), then poll all
// children to see if any of them exited.
//
// We also attempt to be responsible netizens when dealing with
// SIGCHLD by invoking any previous SIGCHLD handler instead of just
// ignoring any previous SIGCHLD handler. Note that we don't provide
// a 1:1 mapping of our handler invocations to the previous handler
// invocations because we drain the `read_fd` entirely. This is
// probably OK because the kernel is already allowed to coalesce
// simultaneous signals, we're just doing some extra coalescing.
//
// Another point of note is that this likely runs the signal handler
// on a different thread than the one that received the signal. I
// *think* this is ok at this time.
//
// The main reason for doing this is to allow stdtest to run native
// tests as well. Both libgreen and libnative are running around
// with process timeouts, but libgreen should get there first
// (currently libuv doesn't handle old signal handlers).
if drain(read_fd) {
let i: uint = unsafe { mem::transmute(old.sa_handler) };
if i != 0 {
assert!(old.sa_flags & c::SA_SIGINFO == 0);
(old.sa_handler)(c::SIGCHLD);
}
// FIXME: sure would be nice to not have to scan the entire
// array...
active.retain(|&(pid, ref tx, _)| {
match waitpid_nowait(pid) {
Some(msg) => { tx.send(msg); false }
None => true,
}
});
}
}
// Once this helper thread is done, we re-register the old sigchld
// handler and close our intermediate file descriptors.
unsafe {
assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::mut_null()), 0);
let _ = libc::close(read_fd);
let _ = libc::close(WRITE_FD);
WRITE_FD = -1;
}
}
// Drain all pending data from the file descriptor, returning if any data
// could be drained. This requires that the file descriptor is in
// nonblocking mode.
fn drain(fd: libc::c_int) -> bool {
let mut ret = false;
loop {
let mut buf = [0u8, ..1];
match unsafe {
libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void,
buf.len() as libc::size_t)
} {
n if n > 0 => { ret = true; }
0 => return true,
-1 if util::wouldblock() => return ret,
n => fail!("bad read {} ({})", os::last_os_error(), n),
}
}
}
// Signal handler for SIGCHLD signals, must be async-signal-safe!
//
// This function will write to the writing half of the "self pipe" to wake
// up the helper thread if it's waiting. Note that this write must be
// nonblocking because if it blocks and the reader is the thread we
// interrupted, then we'll deadlock.
//
// When writing, if the write returns EWOULDBLOCK then we choose to ignore
// it. At that point we're guaranteed that there's something in the pipe
// which will wake up the other end at some point, so we just allow this
// signal to be coalesced with the pending signals on the pipe.
extern fn sigchld_handler(_signum: libc::c_int) {
let mut msg = 1;
match unsafe {
libc::write(WRITE_FD, &mut msg as *mut _ as *libc::c_void, 1)
} {
1 => {}
-1 if util::wouldblock() => {} // see above comments
n => fail!("bad error on write fd: {} {}", n, os::errno()),
}
}
}
@ -830,10 +1090,9 @@ fn waitpid_nowait(pid: pid_t) -> Option<p::ProcessExit> {
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> Option<p::ProcessExit> {
use libc::funcs::posix01::wait;
let mut status = 0 as c_int;
match retry(|| unsafe {
wait::waitpid(pid, &mut status, libc::WNOHANG)
c::waitpid(pid, &mut status, c::WNOHANG)
}) {
n if n == pid => Some(translate_status(status)),
0 => None,

View File

@ -1,149 +0,0 @@
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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.
//! Implementation of the helper thread for the timer module
//!
//! This module contains the management necessary for the timer worker thread.
//! This thread is responsible for performing the send()s on channels for timers
//! that are using channels instead of a blocking call.
//!
//! The timer thread is lazily initialized, and it's shut down via the
//! `shutdown` function provided. It must be maintained as an invariant that
//! `shutdown` is only called when the entire program is finished. No new timers
//! can be created in the future and there must be no active timers at that
//! time.
use std::mem;
use std::rt::bookkeeping;
use std::rt;
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
use io::timer::{Req, Shutdown};
use task;
// You'll note that these variables are *not* protected by a lock. These
// variables are initialized with a Once before any Timer is created and are
// only torn down after everything else has exited. This means that these
// variables are read-only during use (after initialization) and both of which
// are safe to use concurrently.
static mut HELPER_CHAN: *mut Sender<Req> = 0 as *mut Sender<Req>;
static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
static mut TIMER_HELPER_EXIT: StaticNativeMutex = NATIVE_MUTEX_INIT;
pub fn boot(helper: fn(imp::signal, Receiver<Req>)) {
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
static mut INITIALIZED: bool = false;
unsafe {
let mut _guard = LOCK.lock();
if !INITIALIZED {
let (tx, rx) = channel();
// promote this to a shared channel
drop(tx.clone());
HELPER_CHAN = mem::transmute(box tx);
let (receive, send) = imp::new();
HELPER_SIGNAL = send;
task::spawn(proc() {
bookkeeping::decrement();
helper(receive, rx);
TIMER_HELPER_EXIT.lock().signal()
});
rt::at_exit(proc() { shutdown() });
INITIALIZED = true;
}
}
}
pub fn send(req: Req) {
unsafe {
assert!(!HELPER_CHAN.is_null());
(*HELPER_CHAN).send(req);
imp::signal(HELPER_SIGNAL);
}
}
fn shutdown() {
// Request a shutdown, and then wait for the task to exit
unsafe {
let guard = TIMER_HELPER_EXIT.lock();
send(Shutdown);
guard.wait();
drop(guard);
TIMER_HELPER_EXIT.destroy();
}
// Clean up after ther helper thread
unsafe {
imp::close(HELPER_SIGNAL);
let _chan: Box<Sender<Req>> = mem::transmute(HELPER_CHAN);
HELPER_CHAN = 0 as *mut Sender<Req>;
HELPER_SIGNAL = 0 as imp::signal;
}
}
#[cfg(unix)]
mod imp {
use libc;
use std::os;
use io::file::FileDesc;
pub type signal = libc::c_int;
pub fn new() -> (signal, signal) {
let pipe = os::pipe();
(pipe.input, pipe.out)
}
pub fn signal(fd: libc::c_int) {
FileDesc::new(fd, false).inner_write([0]).unwrap();
}
pub fn close(fd: libc::c_int) {
let _fd = FileDesc::new(fd, true);
}
}
#[cfg(windows)]
mod imp {
use libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
use std::ptr;
use libc;
pub type signal = HANDLE;
pub fn new() -> (HANDLE, HANDLE) {
unsafe {
let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
ptr::null());
(handle, handle)
}
}
pub fn signal(handle: HANDLE) {
assert!(unsafe { SetEvent(handle) != 0 });
}
pub fn close(handle: HANDLE) {
assert!(unsafe { CloseHandle(handle) != 0 });
}
extern "system" {
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
bInitialState: BOOL,
lpName: LPCSTR) -> HANDLE;
fn SetEvent(hEvent: HANDLE) -> BOOL;
}
}

View File

@ -52,11 +52,14 @@ use std::os;
use std::ptr;
use std::rt::rtio;
use std::sync::atomics;
use std::comm;
use io::IoResult;
use io::c;
use io::file::FileDesc;
use io::timer_helper;
use io::helper_thread::Helper;
helper_init!(static mut HELPER: Helper<Req>)
pub struct Timer {
id: uint,
@ -79,9 +82,6 @@ pub enum Req {
// Remove a timer based on its id and then send it back on the channel
// provided
RemoveTimer(uint, Sender<Box<Inner>>),
// Shut down the loop and then ACK this channel once it's shut down
Shutdown,
}
// returns the current time (in milliseconds)
@ -93,7 +93,7 @@ pub fn now() -> u64 {
}
}
fn helper(input: libc::c_int, messages: Receiver<Req>) {
fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
let mut set: c::fd_set = unsafe { mem::init() };
let mut fd = FileDesc::new(input, true);
@ -163,7 +163,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
1 => {
loop {
match messages.try_recv() {
Ok(Shutdown) => {
Err(comm::Disconnected) => {
assert!(active.len() == 0);
break 'outer;
}
@ -202,7 +202,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
impl Timer {
pub fn new() -> IoResult<Timer> {
timer_helper::boot(helper);
unsafe { HELPER.boot(|| {}, helper); }
static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
@ -235,7 +235,7 @@ impl Timer {
Some(i) => i,
None => {
let (tx, rx) = channel();
timer_helper::send(RemoveTimer(self.id, tx));
unsafe { HELPER.send(RemoveTimer(self.id, tx)); }
rx.recv()
}
}
@ -261,7 +261,7 @@ impl rtio::RtioTimer for Timer {
inner.interval = msecs;
inner.target = now + msecs;
timer_helper::send(NewTimer(inner));
unsafe { HELPER.send(NewTimer(inner)); }
return rx;
}
@ -275,7 +275,7 @@ impl rtio::RtioTimer for Timer {
inner.interval = msecs;
inner.target = now + msecs;
timer_helper::send(NewTimer(inner));
unsafe { HELPER.send(NewTimer(inner)); }
return rx;
}
}

View File

@ -23,10 +23,13 @@
use libc;
use std::ptr;
use std::rt::rtio;
use std::comm;
use io::timer_helper;
use io::helper_thread::Helper;
use io::IoResult;
helper_init!(static mut HELPER: Helper<Req>)
pub struct Timer {
obj: libc::HANDLE,
on_worker: bool,
@ -35,10 +38,9 @@ pub struct Timer {
pub enum Req {
NewTimer(libc::HANDLE, Sender<()>, bool),
RemoveTimer(libc::HANDLE, Sender<()>),
Shutdown,
}
fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
let mut objs = vec![input];
let mut chans = vec![];
@ -67,12 +69,12 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
None => {}
}
}
Ok(Shutdown) => {
Err(comm::Disconnected) => {
assert_eq!(objs.len(), 1);
assert_eq!(chans.len(), 0);
break 'outer;
}
_ => break
Err(..) => break
}
}
} else {
@ -102,7 +104,7 @@ pub fn now() -> u64 {
impl Timer {
pub fn new() -> IoResult<Timer> {
timer_helper::boot(helper);
unsafe { HELPER.boot(|| {}, helper) }
let obj = unsafe {
imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
@ -124,7 +126,7 @@ impl Timer {
if !self.on_worker { return }
let (tx, rx) = channel();
timer_helper::send(RemoveTimer(self.obj, tx));
unsafe { HELPER.send(RemoveTimer(self.obj, tx)) }
rx.recv();
self.on_worker = false;
@ -157,7 +159,7 @@ impl rtio::RtioTimer for Timer {
ptr::mut_null(), 0)
}, 1);
timer_helper::send(NewTimer(self.obj, tx, true));
unsafe { HELPER.send(NewTimer(self.obj, tx, true)) }
self.on_worker = true;
return rx;
}
@ -173,7 +175,7 @@ impl rtio::RtioTimer for Timer {
ptr::null(), ptr::mut_null(), 0)
}, 1);
timer_helper::send(NewTimer(self.obj, tx, false));
unsafe { HELPER.send(NewTimer(self.obj, tx, false)) }
self.on_worker = true;
return rx;

View File

@ -55,6 +55,7 @@
// NB this crate explicitly does *not* allow glob imports, please seriously
// consider whether they're needed before adding that feature here (the
// answer is that you don't need them)
#![feature(macro_rules)]
extern crate libc;

View File

@ -19,6 +19,7 @@ A `BigInt` is a combination of `BigUint` and `Sign`.
use Integer;
use std::cmp;
use std::default::Default;
use std::fmt;
use std::from_str::FromStr;
use std::num::CheckedDiv;
@ -112,6 +113,11 @@ impl TotalOrd for BigUint {
}
}
impl Default for BigUint {
#[inline]
fn default() -> BigUint { BigUint::new(Vec::new()) }
}
impl fmt::Show for BigUint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}", self.to_str_radix(10))
@ -830,6 +836,11 @@ impl TotalOrd for BigInt {
}
}
impl Default for BigInt {
#[inline]
fn default() -> BigInt { BigInt::new(Zero, Vec::new()) }
}
impl fmt::Show for BigInt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}", self.to_str_radix(10))

View File

@ -54,8 +54,8 @@ fn run_ar(sess: &Session, args: &str, cwd: Option<&Path>,
cwd: cwd.map(|a| &*a),
.. ProcessConfig::new()
}) {
Ok(mut prog) => {
let o = prog.wait_with_output();
Ok(prog) => {
let o = prog.wait_with_output().unwrap();
if !o.status.success() {
sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
o.status));

View File

@ -100,6 +100,7 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
});
}
// `extern crate` must be precede `use` items
vis.push_all_move(krate.module.view_items.clone());
let new_module = ast::Mod {
view_items: vis,
@ -130,8 +131,20 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
if !no_prelude(krate.attrs.as_slice()) {
// only add `use std::prelude::*;` if there wasn't a
// `#![no_implicit_prelude]` at the crate level.
let mut attrs = krate.attrs.clone();
// fold_mod() will insert glob path.
let globs_attr = attr::mk_attr(attr::mk_list_item(
InternedString::new("feature"),
vec!(
attr::mk_word_item(InternedString::new("globs")),
)));
attrs.push(globs_attr);
ast::Crate {
module: self.fold_mod(&krate.module),
attrs: attrs,
..krate
}
} else {
@ -175,11 +188,20 @@ impl<'a> fold::Folder for PreludeInjector<'a> {
span: DUMMY_SP,
};
let vis = (vec!(vi2)).append(module.view_items.as_slice());
let (crates, uses) = module.view_items.partitioned(|x| {
match x.node {
ast::ViewItemExternCrate(..) => true,
_ => false,
}
});
// add vi2 after any `extern crate` but before any `use`
let mut view_items = crates;
view_items.push(vi2);
view_items.push_all_move(uses);
// FIXME #2543: Bad copy.
let new_module = ast::Mod {
view_items: vis,
view_items: view_items,
..(*module).clone()
};
fold::noop_fold_mod(&new_module, self)

View File

@ -398,8 +398,7 @@ pub mod llvm {
pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool;
/* Operations on array, pointer, and vector types (sequence types) */
pub fn LLVMArrayType(ElementType: TypeRef, ElementCount: c_uint)
-> TypeRef;
pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef;
pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint)
-> TypeRef;
pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint)

View File

@ -148,6 +148,33 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
}
}
}
ExprBlock(ref block) => {
// Check all statements in the block
for stmt in block.stmts.iter() {
let block_span_err = |span|
v.tcx.sess.span_err(span,
"blocks in constants are limited to \
items and tail expressions");
match stmt.node {
StmtDecl(ref span, _) => {
match span.node {
DeclLocal(_) => block_span_err(span.span),
// Item statements are allowed
DeclItem(_) => {}
}
}
StmtExpr(ref expr, _) => block_span_err(expr.span),
StmtSemi(ref semi, _) => block_span_err(semi.span),
StmtMac(..) => v.tcx.sess.span_bug(e.span,
"unexpanded statement macro in const?!")
}
}
match block.expr {
Some(ref expr) => check_expr(v, &**expr, true),
None => {}
}
}
ExprVstore(_, ExprVstoreMutSlice) |
ExprVstore(_, ExprVstoreSlice) |
ExprVec(_) |

View File

@ -239,7 +239,15 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
return not_useful
}
let real_pat = match m.iter().find(|r| r.get(0).id != 0) {
Some(r) => *r.get(0), None => v[0]
Some(r) => {
match r.get(0).node {
// An arm of the form `ref x @ sub_pat` has type
// `sub_pat`, not `&sub_pat` as `x` itself does.
PatIdent(BindByRef(_), _, Some(sub)) => sub,
_ => *r.get(0)
}
}
None => v[0]
};
let left_ty = if real_pat.id == 0 { ty::mk_nil() }
else { ty::node_id_to_type(cx.tcx, real_pat.id) };
@ -258,7 +266,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
val(const_bool(false)),
0u, left_ty)
}
ref u => (*u).clone(),
u => u,
}
}
ty::ty_enum(eid, _) => {
@ -266,7 +274,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
match is_useful_specialized(cx, m, v, variant(va.id),
va.args.len(), left_ty) {
not_useful => (),
ref u => return (*u).clone(),
u => return u,
}
}
not_useful
@ -288,7 +296,7 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
for n in iter::range(0u, max_len + 1) {
match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
not_useful => (),
ref u => return (*u).clone(),
u => return u,
}
}
not_useful
@ -304,21 +312,21 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[@Pat]) -> useful {
}
}
}
Some(ref ctor) => {
Some(ctor) => {
match is_useful(cx,
&m.iter().filter_map(|r| {
default(cx, r.as_slice())
}).collect::<matrix>(),
v.tail()) {
useful_ => useful(left_ty, (*ctor).clone()),
ref u => (*u).clone(),
useful_ => useful(left_ty, ctor),
u => u,
}
}
}
}
Some(ref v0_ctor) => {
let arity = ctor_arity(cx, v0_ctor, left_ty);
is_useful_specialized(cx, m, v, (*v0_ctor).clone(), arity, left_ty)
Some(v0_ctor) => {
let arity = ctor_arity(cx, &v0_ctor, left_ty);
is_useful_specialized(cx, m, v, v0_ctor, arity, left_ty)
}
}
}
@ -337,7 +345,7 @@ fn is_useful_specialized(cx: &MatchCheckCtxt,
cx, &ms, specialize(cx, v, &ctor, arity, lty).unwrap().as_slice());
match could_be_useful {
useful_ => useful(lty, ctor),
ref u => (*u).clone(),
u => u,
}
}
@ -408,9 +416,9 @@ fn missing_ctor(cx: &MatchCheckCtxt,
let mut found = Vec::new();
for r in m.iter() {
let r = pat_ctor_id(cx, *r.get(0));
for id in r.iter() {
if !found.contains(id) {
found.push((*id).clone());
for id in r.move_iter() {
if !found.contains(&id) {
found.push(id);
}
}
}
@ -812,30 +820,17 @@ fn specialize(cx: &MatchCheckCtxt,
let num_elements = before.len() + after.len();
if num_elements < arity && slice.is_some() {
let mut result = Vec::new();
for pat in before.iter() {
result.push((*pat).clone());
}
for _ in iter::range(0, arity - num_elements) {
result.push(wild())
}
for pat in after.iter() {
result.push((*pat).clone());
}
for pat in r.tail().iter() {
result.push((*pat).clone());
}
let wilds = Vec::from_elem(arity - num_elements, wild());
result.push_all_move(before);
result.push_all_move(wilds);
result.push_all_move(after);
result.push_all(r.tail());
Some(result)
} else if num_elements == arity {
let mut result = Vec::new();
for pat in before.iter() {
result.push((*pat).clone());
}
for pat in after.iter() {
result.push((*pat).clone());
}
for pat in r.tail().iter() {
result.push((*pat).clone());
}
result.push_all_move(before);
result.push_all_move(after);
result.push_all(r.tail());
Some(result)
} else {
None

View File

@ -47,7 +47,6 @@ use std::rc::Rc;
// fixed-size vectors and strings: [] and ""/_
// vector and string slices: &[] and &""
// tuples: (,)
// records: {...}
// enums: foo(...)
// floating point literals and operators
// & and * pointers
@ -241,6 +240,13 @@ impl<'a> ConstEvalVisitor<'a> {
ast::ExprRepeat(..) => general_const,
ast::ExprBlock(ref block) => {
match block.expr {
Some(ref e) => self.classify(&**e),
None => integral_const
}
}
_ => non_const
};
self.ccache.insert(did, cn);
@ -479,6 +485,12 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
// If we have a vstore, just keep going; it has to be a string
ExprVstore(e, _) => eval_const_expr_partial(tcx, e),
ExprParen(e) => eval_const_expr_partial(tcx, e),
ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => eval_const_expr_partial(tcx, &**expr),
None => Ok(const_int(0i64))
}
}
_ => Err("unsupported constant expr".to_strbuf())
}
}

View File

@ -46,6 +46,7 @@ use middle::typeck::astconv::{ast_ty_to_ty, AstConv};
use middle::typeck::infer;
use middle::typeck;
use util::ppaux::{ty_to_str};
use util::nodemap::NodeSet;
use std::cmp;
use collections::HashMap;
@ -453,10 +454,13 @@ struct Context<'a> {
// When recursing into an attributed node of the ast which modifies lint
// levels, this stack keeps track of the previous lint levels of whatever
// was modified.
lint_stack: Vec<(Lint, level, LintSource)> ,
lint_stack: Vec<(Lint, level, LintSource)>,
// id of the last visited negated expression
negated_expr_id: ast::NodeId
negated_expr_id: ast::NodeId,
// ids of structs/enums which have been checked for raw_pointer_deriving
checked_raw_pointers: NodeSet,
}
impl<'a> Context<'a> {
@ -1014,10 +1018,26 @@ impl<'a> Visitor<()> for RawPtrDerivingVisitor<'a> {
fn visit_block(&mut self, _: &ast::Block, _: ()) {}
}
fn check_raw_ptr_deriving(cx: &Context, item: &ast::Item) {
if !attr::contains_name(item.attrs.as_slice(), "deriving") {
fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) {
if !attr::contains_name(item.attrs.as_slice(), "automatically_derived") {
return
}
let did = match item.node {
ast::ItemImpl(..) => {
match ty::get(ty::node_id_to_type(cx.tcx, item.id)).sty {
ty::ty_enum(did, _) => did,
ty::ty_struct(did, _) => did,
_ => return,
}
}
_ => return,
};
if !ast_util::is_local(did) { return }
let item = match cx.tcx.map.find(did.node) {
Some(ast_map::NodeItem(item)) => item,
_ => return,
};
if !cx.checked_raw_pointers.insert(item.id) { return }
match item.node {
ast::ItemStruct(..) | ast::ItemEnum(..) => {
let mut visitor = RawPtrDerivingVisitor { cx: cx };
@ -1848,7 +1868,8 @@ pub fn check_crate(tcx: &ty::ctxt,
cur_struct_def_id: -1,
is_doc_hidden: false,
lint_stack: Vec::new(),
negated_expr_id: -1
negated_expr_id: -1,
checked_raw_pointers: NodeSet::new(),
};
// Install default lint levels, followed by the command line levels, and

View File

@ -1611,6 +1611,9 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
}
}
ast::ItemStatic(_, m, expr) => {
// Recurse on the expression to catch items in blocks
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(expr, ());
consts::trans_const(ccx, m, item.id);
// Do static_assert checking. It can't really be done much earlier
// because we need to get the value of the bool out of LLVM

View File

@ -672,6 +672,12 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
}
}
ast::ExprParen(e) => { const_expr(cx, e, is_local) }
ast::ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => const_expr(cx, &**expr, is_local),
None => (C_nil(cx), true)
}
}
_ => cx.sess().span_bug(e.span,
"bad constant expression type in consts::const_expr")
};

View File

@ -207,7 +207,7 @@ impl Type {
}
pub fn array(ty: &Type, len: u64) -> Type {
ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
}
pub fn vector(ty: &Type, len: u64) -> Type {

View File

@ -3554,6 +3554,12 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
_: Span,
e: &ast::Expr,
declty: ty::t) {
// Gather locals in statics (because of block expressions).
// This is technically uneccessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit a error.
GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ());
check_expr(fcx, e);
let cty = fcx.expr_ty(e);
demand::suptype(fcx, e.span, declty, cty);

View File

@ -90,7 +90,7 @@ fn get_base_type(inference_context: &InferCtxt,
}
}
fn type_is_defined_in_local_crate(original_type: t) -> bool {
fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
/*!
*
* For coherence, when we have `impl Trait for Type`, we need to
@ -109,6 +109,14 @@ fn type_is_defined_in_local_crate(original_type: t) -> bool {
found_nominal = true;
}
}
ty_uniq(..) => {
match tcx.lang_items.owned_box() {
Some(did) if did.krate == ast::LOCAL_CRATE => {
found_nominal = true;
}
_ => {}
}
}
_ => { }
}
@ -194,11 +202,10 @@ impl<'a> visit::Visitor<()> for PrivilegedScopeVisitor<'a> {
}
}
ItemImpl(_, Some(ref trait_ref), _, _) => {
let tcx = self.cc.crate_context.tcx;
// `for_ty` is `Type` in `impl Trait for Type`
let for_ty =
ty::node_id_to_type(self.cc.crate_context.tcx,
item.id);
if !type_is_defined_in_local_crate(for_ty) {
let for_ty = ty::node_id_to_type(tcx, item.id);
if !type_is_defined_in_local_crate(tcx, for_ty) {
// This implementation is not in scope of its base
// type. This still might be OK if the trait is
// defined in the same crate.

View File

@ -355,18 +355,14 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> StrBuf {
ty_bot => "!".to_strbuf(),
ty_bool => "bool".to_strbuf(),
ty_char => "char".to_strbuf(),
ty_int(t) => ast_util::int_ty_to_str(t, None),
ty_uint(t) => ast_util::uint_ty_to_str(t, None),
ty_float(t) => ast_util::float_ty_to_str(t),
ty_box(typ) => {
("@".to_owned() + ty_to_str(cx, typ).as_slice()).to_strbuf()
}
ty_uniq(typ) => {
("~".to_owned() + ty_to_str(cx, typ).as_slice()).to_strbuf()
}
ty_ptr(ref tm) => {
("*".to_owned() + mt_to_str(cx, tm).as_slice()).to_strbuf()
}
ty_int(t) => ast_util::int_ty_to_str(t, None,
ast_util::AutoSuffix).to_strbuf(),
ty_uint(t) => ast_util::uint_ty_to_str(t, None,
ast_util::AutoSuffix).to_strbuf(),
ty_float(t) => ast_util::float_ty_to_str(t).to_strbuf(),
ty_box(typ) => format_strbuf!("@{}", ty_to_str(cx, typ)),
ty_uniq(typ) => format_strbuf!("~{}", ty_to_str(cx, typ)),
ty_ptr(ref tm) => format_strbuf!("*{}", mt_to_str(cx, tm)),
ty_rptr(r, ref tm) => {
let mut buf = region_ptr_to_str(cx, r);
buf.push_str(mt_to_str(cx, tm).as_slice());
@ -374,7 +370,7 @@ pub fn ty_to_str(cx: &ctxt, typ: t) -> StrBuf {
}
ty_tup(ref elems) => {
let strs: Vec<StrBuf> = elems.iter().map(|elem| ty_to_str(cx, *elem)).collect();
("(".to_owned() + strs.connect(",") + ")").to_strbuf()
format_strbuf!("({})", strs.connect(","))
}
ty_closure(ref f) => {
closure_to_str(cx, *f)

View File

@ -26,6 +26,7 @@ use t = syntax::parse::token;
/// Highlights some source code, returning the HTML output.
pub fn highlight(src: &str, class: Option<&str>) -> StrBuf {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::new_parse_sess();
let fm = parse::string_to_filemap(&sess,
src.to_strbuf(),

View File

@ -149,6 +149,7 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque);
slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| {
let text = str::from_utf8(text).unwrap();
debug!("docblock: ==============\n{}\n=======", text);
let mut lines = text.lines().filter(|l| {
stripped_filtered_line(*l).is_none()
});

View File

@ -19,7 +19,8 @@ use std::rt::task::BlockedTask;
use homing::{HomingIO, HomeHandle};
use pipe::PipeWatcher;
use super::{UvHandle, UvError, uv_error_to_io_error,
wait_until_woken_after, wakeup};
wait_until_woken_after, wakeup, Loop};
use timer::TimerWatcher;
use uvio::UvIoFactory;
use uvll;
@ -32,6 +33,16 @@ pub struct Process {
/// Collected from the exit_cb
exit_status: Option<process::ProcessExit>,
/// Lazily initialized timeout timer
timer: Option<Box<TimerWatcher>>,
timeout_state: TimeoutState,
}
enum TimeoutState {
NoTimeout,
TimeoutPending,
TimeoutElapsed,
}
impl Process {
@ -92,6 +103,8 @@ impl Process {
home: io_loop.make_handle(),
to_wake: None,
exit_status: None,
timer: None,
timeout_state: NoTimeout,
};
match unsafe {
uvll::uv_spawn(io_loop.uv_loop(), handle, &options)
@ -223,21 +236,71 @@ impl RtioProcess for Process {
}
}
fn wait(&mut self) -> process::ProcessExit {
fn wait(&mut self) -> Result<process::ProcessExit, IoError> {
// Make sure (on the home scheduler) that we have an exit status listed
let _m = self.fire_homing_missile();
match self.exit_status {
Some(..) => {}
None => {
// If there's no exit code previously listed, then the
// process's exit callback has yet to be invoked. We just
// need to deschedule ourselves and wait to be reawoken.
wait_until_woken_after(&mut self.to_wake, &self.uv_loop(), || {});
assert!(self.exit_status.is_some());
}
Some(status) => return Ok(status),
None => {}
}
self.exit_status.unwrap()
// If there's no exit code previously listed, then the process's exit
// callback has yet to be invoked. We just need to deschedule ourselves
// and wait to be reawoken.
match self.timeout_state {
NoTimeout | TimeoutPending => {
wait_until_woken_after(&mut self.to_wake, &self.uv_loop(), || {});
}
TimeoutElapsed => {}
}
// If there's still no exit status listed, then we timed out, and we
// need to return.
match self.exit_status {
Some(status) => Ok(status),
None => Err(uv_error_to_io_error(UvError(uvll::ECANCELED)))
}
}
fn set_timeout(&mut self, timeout: Option<u64>) {
let _m = self.fire_homing_missile();
self.timeout_state = NoTimeout;
let ms = match timeout {
Some(ms) => ms,
None => {
match self.timer {
Some(ref mut timer) => timer.stop(),
None => {}
}
return
}
};
if self.timer.is_none() {
let loop_ = Loop::wrap(unsafe {
uvll::get_loop_for_uv_handle(self.uv_handle())
});
let mut timer = box TimerWatcher::new_home(&loop_, self.home().clone());
unsafe {
timer.set_data(self as *mut _ as *Process);
}
self.timer = Some(timer);
}
let timer = self.timer.get_mut_ref();
timer.stop();
timer.start(timer_cb, ms, 0);
self.timeout_state = TimeoutPending;
extern fn timer_cb(timer: *uvll::uv_timer_t) {
let p: &mut Process = unsafe {
&mut *(uvll::get_data_for_uv_handle(timer) as *mut Process)
};
p.timeout_state = TimeoutElapsed;
match p.to_wake.take() {
Some(task) => { let _t = task.wake().map(|t| t.reawaken()); }
None => {}
}
}
}
}

View File

@ -207,6 +207,13 @@ mod tests {
assert_eq!(FlagABC.bits(), 0x00000111);
}
#[test]
fn test_from_bits() {
assert!(unsafe { Flags::from_bits(0x00000000) } == Flags::empty());
assert!(unsafe { Flags::from_bits(0x00000001) } == FlagA);
assert!(unsafe { Flags::from_bits(0x00000111) } == FlagABC);
}
#[test]
fn test_is_empty(){
assert!(Flags::empty().is_empty());

View File

@ -10,6 +10,8 @@
//! Bindings for executing child processes
#![allow(experimental)]
use prelude::*;
use fmt;
@ -50,7 +52,7 @@ use rt::rtio::{RtioProcess, IoFactory, LocalIo};
/// };
///
/// let contents = child.stdout.get_mut_ref().read_to_end();
/// assert!(child.wait().success());
/// assert!(child.wait().unwrap().success());
/// ```
pub struct Process {
handle: Box<RtioProcess:Send>,
@ -284,7 +286,7 @@ impl Process {
/// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
/// ```
pub fn output(prog: &str, args: &[~str]) -> IoResult<ProcessOutput> {
Process::new(prog, args).map(|mut p| p.wait_with_output())
Process::new(prog, args).and_then(|p| p.wait_with_output())
}
/// Executes a child process and collects its exit status. This will block
@ -303,7 +305,7 @@ impl Process {
/// println!("process exited with: {}", status);
/// ```
pub fn status(prog: &str, args: &[~str]) -> IoResult<ProcessExit> {
Process::new(prog, args).map(|mut p| p.wait())
Process::new(prog, args).and_then(|mut p| p.wait())
}
/// Creates a new process with the specified configuration.
@ -378,17 +380,72 @@ impl Process {
/// after it has been called at least once.
///
/// The stdin handle to the child process will be closed before waiting.
pub fn wait(&mut self) -> ProcessExit {
///
/// # Errors
///
/// This function can fail if a timeout was previously specified via
/// `set_timeout` and the timeout expires before the child exits.
pub fn wait(&mut self) -> IoResult<ProcessExit> {
drop(self.stdin.take());
self.handle.wait()
}
/// Sets a timeout, in milliseconds, for future calls to wait().
///
/// The argument specified is a relative distance into the future, in
/// milliseconds, after which any call to wait() will return immediately
/// with a timeout error, and all future calls to wait() will not block.
///
/// A value of `None` will clear any previous timeout, and a value of `Some`
/// will override any previously set timeout.
///
/// # Example
///
/// ```no_run
/// # #![allow(experimental)]
/// use std::io::process::{Process, ProcessExit};
/// use std::io::IoResult;
///
/// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
/// let mut p = try!(Process::new("long-running-process", []));
///
/// // give the process 10 seconds to finish completely
/// p.set_timeout(Some(10_000));
/// match p.wait() {
/// Ok(status) => return Ok(status),
/// Err(..) => {}
/// }
///
/// // Attempt to exit gracefully, but don't wait for it too long
/// try!(p.signal_exit());
/// p.set_timeout(Some(1_000));
/// match p.wait() {
/// Ok(status) => return Ok(status),
/// Err(..) => {}
/// }
///
/// // Well, we did our best, forcefully kill the process
/// try!(p.signal_kill());
/// p.set_timeout(None);
/// p.wait()
/// }
/// ```
#[experimental = "the type of the timeout is likely to change"]
pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
self.handle.set_timeout(timeout_ms)
}
/// Simultaneously wait for the child to exit and collect all remaining
/// output on the stdout/stderr handles, returning a `ProcessOutput`
/// instance.
///
/// The stdin handle to the child is closed before waiting.
pub fn wait_with_output(&mut self) -> ProcessOutput {
///
/// # Errors
///
/// This function can fail for any of the same reasons that `wait()` can
/// fail.
pub fn wait_with_output(mut self) -> IoResult<ProcessOutput> {
drop(self.stdin.take());
fn read(stream: Option<io::PipeStream>) -> Receiver<IoResult<Vec<u8>>> {
let (tx, rx) = channel();
@ -404,11 +461,13 @@ impl Process {
let stdout = read(self.stdout.take());
let stderr = read(self.stderr.take());
let status = self.wait();
let status = try!(self.wait());
ProcessOutput { status: status,
output: stdout.recv().ok().unwrap_or(Vec::new()),
error: stderr.recv().ok().unwrap_or(Vec::new()) }
Ok(ProcessOutput {
status: status,
output: stdout.recv().ok().unwrap_or(Vec::new()),
error: stderr.recv().ok().unwrap_or(Vec::new()),
})
}
}
@ -421,7 +480,8 @@ impl Drop for Process {
drop(self.stderr.take());
drop(mem::replace(&mut self.extra_io, Vec::new()));
self.wait();
self.set_timeout(None);
let _ = self.wait().unwrap();
}
}
@ -441,7 +501,7 @@ mod tests {
let p = Process::configure(args);
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().success());
assert!(p.wait().unwrap().success());
})
#[cfg(not(target_os="android"))]
@ -465,7 +525,7 @@ mod tests {
let p = Process::configure(args);
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().matches_exit_status(1));
assert!(p.wait().unwrap().matches_exit_status(1));
drop(p.wait().clone());
})
@ -479,7 +539,7 @@ mod tests {
let p = Process::configure(args);
assert!(p.is_ok());
let mut p = p.unwrap();
match p.wait() {
match p.wait().unwrap() {
process::ExitSignal(1) => {},
result => fail!("not terminated by signal 1 (instead, {})", result),
}
@ -495,7 +555,7 @@ mod tests {
let mut p = p.unwrap();
assert!(p.stdout.is_some());
let ret = read_all(p.stdout.get_mut_ref() as &mut Reader);
assert!(p.wait().success());
assert!(p.wait().unwrap().success());
return ret;
}
@ -536,7 +596,7 @@ mod tests {
p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
drop(p.stdin.take());
let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
assert!(p.wait().success());
assert!(p.wait().unwrap().success());
assert_eq!(out, "foobar\n".to_owned());
})
@ -548,7 +608,7 @@ mod tests {
.. ProcessConfig::new()
};
let mut p = Process::configure(args).unwrap();
assert!(p.wait().success());
assert!(p.wait().unwrap().success());
})
#[cfg(windows)]
@ -572,7 +632,7 @@ mod tests {
.. ProcessConfig::new()
};
let mut p = Process::configure(args).unwrap();
assert!(p.wait().success());
assert!(p.wait().unwrap().success());
})
#[cfg(unix, not(target_os="android"))]
@ -635,21 +695,21 @@ mod tests {
#[cfg(not(target_os="android"))]
iotest!(fn test_finish_once() {
let mut prog = Process::new("false", []).unwrap();
assert!(prog.wait().matches_exit_status(1));
assert!(prog.wait().unwrap().matches_exit_status(1));
})
#[cfg(not(target_os="android"))]
iotest!(fn test_finish_twice() {
let mut prog = Process::new("false", []).unwrap();
assert!(prog.wait().matches_exit_status(1));
assert!(prog.wait().matches_exit_status(1));
assert!(prog.wait().unwrap().matches_exit_status(1));
assert!(prog.wait().unwrap().matches_exit_status(1));
})
#[cfg(not(target_os="android"))]
iotest!(fn test_wait_with_output_once() {
let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
let ProcessOutput {status, output, error} = prog.wait_with_output();
let prog = Process::new("echo", ["hello".to_owned()]).unwrap();
let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
let output_str = str::from_utf8(output.as_slice()).unwrap();
assert!(status.success());
@ -660,30 +720,6 @@ mod tests {
}
})
#[cfg(not(target_os="android"))]
iotest!(fn test_wait_with_output_twice() {
let mut prog = Process::new("echo", ["hello".to_owned()]).unwrap();
let ProcessOutput {status, output, error} = prog.wait_with_output();
let output_str = str::from_utf8(output.as_slice()).unwrap();
assert!(status.success());
assert_eq!(output_str.trim().to_owned(), "hello".to_owned());
// FIXME #7224
if !running_on_valgrind() {
assert_eq!(error, Vec::new());
}
let ProcessOutput {status, output, error} = prog.wait_with_output();
assert!(status.success());
assert_eq!(output, Vec::new());
// FIXME #7224
if !running_on_valgrind() {
assert_eq!(error, Vec::new());
}
})
#[cfg(unix,not(target_os="android"))]
pub fn run_pwd(dir: Option<&Path>) -> Process {
Process::configure(ProcessConfig {
@ -714,9 +750,10 @@ mod tests {
iotest!(fn test_keep_current_working_dir() {
use os;
let mut prog = run_pwd(None);
let prog = run_pwd(None);
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
let output = str::from_utf8(prog.wait_with_output().unwrap()
.output.as_slice()).unwrap().to_owned();
let parent_dir = os::getcwd();
let child_dir = Path::new(output.trim());
@ -732,9 +769,10 @@ mod tests {
// test changing to the parent of os::getcwd() because we know
// the path exists (and os::getcwd() is not expected to be root)
let parent_dir = os::getcwd().dir_path();
let mut prog = run_pwd(Some(&parent_dir));
let prog = run_pwd(Some(&parent_dir));
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
let output = str::from_utf8(prog.wait_with_output().unwrap()
.output.as_slice()).unwrap().to_owned();
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat().unwrap();
@ -777,8 +815,9 @@ mod tests {
use os;
if running_on_valgrind() { return; }
let mut prog = run_env(None);
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
let prog = run_env(None);
let output = str::from_utf8(prog.wait_with_output().unwrap()
.output.as_slice()).unwrap().to_owned();
let r = os::env();
for &(ref k, ref v) in r.iter() {
@ -791,8 +830,10 @@ mod tests {
use os;
if running_on_valgrind() { return; }
let mut prog = run_env(None);
let output = str::from_utf8(prog.wait_with_output().output.as_slice()).unwrap().to_owned();
let prog = run_env(None);
let output = str::from_utf8(prog.wait_with_output()
.unwrap().output.as_slice())
.unwrap().to_owned();
let r = os::env();
for &(ref k, ref v) in r.iter() {
@ -807,8 +848,8 @@ mod tests {
iotest!(fn test_add_to_env() {
let new_env = box [("RUN_TEST_NEW_ENV".to_owned(), "123".to_owned())];
let mut prog = run_env(Some(new_env));
let result = prog.wait_with_output();
let prog = run_env(Some(new_env));
let result = prog.wait_with_output().unwrap();
let output = str::from_utf8_lossy(result.output.as_slice()).into_owned();
assert!(output.contains("RUN_TEST_NEW_ENV=123"),
@ -830,14 +871,14 @@ mod tests {
iotest!(fn test_kill() {
let mut p = sleeper();
Process::kill(p.id(), PleaseExitSignal).unwrap();
assert!(!p.wait().success());
assert!(!p.wait().unwrap().success());
})
iotest!(fn test_exists() {
let mut p = sleeper();
assert!(Process::kill(p.id(), 0).is_ok());
p.signal_kill().unwrap();
assert!(!p.wait().success());
assert!(!p.wait().unwrap().success());
})
iotest!(fn test_zero() {
@ -845,11 +886,42 @@ mod tests {
p.signal_kill().unwrap();
for _ in range(0, 20) {
if p.signal(0).is_err() {
assert!(!p.wait().success());
assert!(!p.wait().unwrap().success());
return
}
timer::sleep(100);
}
fail!("never saw the child go away");
})
iotest!(fn wait_timeout() {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
p.set_timeout(None);
assert!(p.wait().is_ok());
})
iotest!(fn wait_timeout2() {
let (tx, rx) = channel();
let tx2 = tx.clone();
spawn(proc() {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
tx.send(());
});
spawn(proc() {
let mut p = sleeper();
p.set_timeout(Some(10));
assert_eq!(p.wait().err().unwrap().kind, TimedOut);
p.signal_kill().unwrap();
tx2.send(());
});
rx.recv();
rx.recv();
})
}

View File

@ -133,14 +133,16 @@ extern crate core;
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
#[cfg(test)] pub use ty = realstd::ty;
#[cfg(test)] pub use owned = realstd::owned;
#[cfg(not(stage0), test)] pub use owned = realstd::owned;
#[cfg(not(test))] pub use cmp = core::cmp;
#[cfg(not(test))] pub use kinds = core::kinds;
#[cfg(not(test))] pub use ops = core::ops;
#[cfg(not(test))] pub use owned = core::owned;
#[cfg(not(test))] pub use ty = core::ty;
#[cfg(stage0, test)] pub use owned = realstd::owned;
#[cfg(stage0, not(test))] pub use owned = core::owned;
pub use core::any;
pub use core::bool;
pub use core::cell;
@ -207,6 +209,8 @@ pub mod ascii;
pub mod rc;
pub mod gc;
#[cfg(not(stage0), not(test))]
pub mod owned;
/* Common traits */

101
src/libstd/owned.rs Normal file
View File

@ -0,0 +1,101 @@
// 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.
//! Operations on unique pointer types
use any::{Any, AnyRefExt};
use clone::Clone;
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
use default::Default;
use intrinsics;
use mem;
use raw::TraitObject;
use result::{Ok, Err, Result};
/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// let foo = box(HEAP) Bar::new(...);
/// let foo = box Bar::new(...);
#[lang="exchange_heap"]
pub static HEAP: () = ();
/// A type that represents a uniquely-owned value.
#[lang="owned_box"]
pub struct Box<T>(*T);
impl<T: Default> Default for Box<T> {
fn default() -> Box<T> { box Default::default() }
}
impl<T: Clone> Clone for Box<T> {
/// Return a copy of the owned box.
#[inline]
fn clone(&self) -> Box<T> { box {(**self).clone()} }
/// Perform copy-assignment from `source` by reusing the existing allocation.
#[inline]
fn clone_from(&mut self, source: &Box<T>) {
(**self).clone_from(&(**source));
}
}
// box pointers
impl<T:Eq> Eq for Box<T> {
#[inline]
fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
}
impl<T:Ord> Ord for Box<T> {
#[inline]
fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
}
impl<T: TotalOrd> TotalOrd for Box<T> {
#[inline]
fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
}
impl<T: TotalEq> TotalEq for Box<T> {}
/// Extension methods for an owning `Any` trait object
pub trait AnyOwnExt {
/// Returns the boxed value if it is of type `T`, or
/// `Err(Self)` if it isn't.
fn move<T: 'static>(self) -> Result<Box<T>, Self>;
}
impl AnyOwnExt for Box<Any> {
#[inline]
fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
let to: TraitObject =
*mem::transmute::<&Box<Any>, &TraitObject>(&self);
// Prevent destructor on self being run
intrinsics::forget(self);
// Extract the data pointer
Ok(mem::transmute(to.data))
}
} else {
Err(self)
}
}
}

View File

@ -275,7 +275,8 @@ pub trait RtioFileStream {
pub trait RtioProcess {
fn id(&self) -> libc::pid_t;
fn kill(&mut self, signal: int) -> IoResult<()>;
fn wait(&mut self) -> ProcessExit;
fn wait(&mut self) -> IoResult<ProcessExit>;
fn set_timeout(&mut self, timeout: Option<u64>);
}
pub trait RtioPipe {

View File

@ -13,7 +13,6 @@
//! local storage, and logging. Even a 'freestanding' Rust would likely want
//! to implement this.
use any::AnyOwnExt;
use cleanup;
use clone::Clone;
use comm::Sender;
@ -24,7 +23,7 @@ use local_data;
use mem;
use ops::Drop;
use option::{Option, Some, None};
use owned::Box;
use owned::{AnyOwnExt, Box};
use prelude::drop;
use result::{Result, Ok, Err};
use rt::Runtime;

View File

@ -228,25 +228,25 @@ fn canonical_sort(comb: &mut [(char, u8)]) {
}
#[deriving(Clone)]
enum NormalizationForm {
NFD,
NFKD
enum DecompositionType {
Canonical,
Compatible
}
/// External iterator for a string's normalization's characters.
/// External iterator for a string's decomposition's characters.
/// Use with the `std::iter` module.
#[deriving(Clone)]
pub struct Normalizations<'a> {
kind: NormalizationForm,
pub struct Decompositions<'a> {
kind: DecompositionType,
iter: Chars<'a>,
buffer: Vec<(char, u8)>,
sorted: bool
}
impl<'a> Iterator<char> for Normalizations<'a> {
impl<'a> Iterator<char> for Decompositions<'a> {
#[inline]
fn next(&mut self) -> Option<char> {
use unicode::decompose::canonical_combining_class;
use unicode::normalization::canonical_combining_class;
match self.buffer.as_slice().head() {
Some(&(c, 0)) => {
@ -262,8 +262,8 @@ impl<'a> Iterator<char> for Normalizations<'a> {
}
let decomposer = match self.kind {
NFD => char::decompose_canonical,
NFKD => char::decompose_compatible
Canonical => char::decompose_canonical,
Compatible => char::decompose_compatible
};
if !self.sorted {
@ -887,24 +887,24 @@ pub trait StrAllocating: Str {
/// An Iterator over the string in Unicode Normalization Form D
/// (canonical decomposition).
#[inline]
fn nfd_chars<'a>(&'a self) -> Normalizations<'a> {
Normalizations {
fn nfd_chars<'a>(&'a self) -> Decompositions<'a> {
Decompositions {
iter: self.as_slice().chars(),
buffer: Vec::new(),
sorted: false,
kind: NFD
kind: Canonical
}
}
/// An Iterator over the string in Unicode Normalization Form KD
/// (compatibility decomposition).
#[inline]
fn nfkd_chars<'a>(&'a self) -> Normalizations<'a> {
Normalizations {
fn nfkd_chars<'a>(&'a self) -> Decompositions<'a> {
Decompositions {
iter: self.as_slice().chars(),
buffer: Vec::new(),
sorted: false,
kind: NFKD
kind: Compatible
}
}
}

View File

@ -47,10 +47,11 @@ use rt::local::Local;
use rt::task::Task;
use str::{Str, SendStr, IntoMaybeOwned};
#[cfg(test)] use any::{AnyOwnExt, AnyRefExt};
#[cfg(test)] use any::AnyRefExt;
#[cfg(test)] use owned::AnyOwnExt;
#[cfg(test)] use realstd::result::ResultUnwrap;
#[cfg(test)] use result;
#[cfg(test)] use str::StrAllocating;
#[cfg(test)] use realstd::result::ResultUnwrap;
/// Indicates the manner in which a task exited.
///

View File

@ -1,4 +1,4 @@
// 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.
//
@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// The following code was generated by "src/etc/unicode.py"
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
#![allow(missing_doc, non_uppercase_statics)]
pub mod decompose {
pub mod normalization {
use option::{Some, None};
use slice::ImmutableVector;

View File

@ -711,7 +711,8 @@ pub enum IntTy {
impl fmt::Show for IntTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}", ast_util::int_ty_to_str(*self, None))
write!(f.buf, "{}",
ast_util::int_ty_to_str(*self, None, ast_util::AutoSuffix))
}
}
@ -726,7 +727,8 @@ pub enum UintTy {
impl fmt::Show for UintTy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}", ast_util::uint_ty_to_str(*self, None))
write!(f.buf, "{}",
ast_util::uint_ty_to_str(*self, None, ast_util::AutoSuffix))
}
}

View File

@ -132,11 +132,19 @@ pub fn is_path(e: @Expr) -> bool {
return match e.node { ExprPath(_) => true, _ => false };
}
pub enum SuffixMode {
ForceSuffix,
AutoSuffix,
}
// Get a string representation of a signed int type, with its value.
// We want to avoid "45int" and "-3int" in favor of "45" and "-3"
pub fn int_ty_to_str(t: IntTy, val: Option<i64>) -> StrBuf {
pub fn int_ty_to_str(t: IntTy, val: Option<i64>, mode: SuffixMode) -> StrBuf {
let s = match t {
TyI if val.is_some() => "",
TyI if val.is_some() => match mode {
AutoSuffix => "",
ForceSuffix => "i",
},
TyI => "int",
TyI8 => "i8",
TyI16 => "i16",
@ -145,7 +153,10 @@ pub fn int_ty_to_str(t: IntTy, val: Option<i64>) -> StrBuf {
};
match val {
Some(n) => format!("{}{}", n, s).to_strbuf(),
// cast to a u64 so we can correctly print INT64_MIN. All integral types
// are parsed as u64, so we wouldn't want to print an extra negative
// sign.
Some(n) => format!("{}{}", n as u64, s).to_strbuf(),
None => s.to_strbuf()
}
}
@ -161,9 +172,12 @@ pub fn int_ty_max(t: IntTy) -> u64 {
// Get a string representation of an unsigned int type, with its value.
// We want to avoid "42uint" in favor of "42u"
pub fn uint_ty_to_str(t: UintTy, val: Option<u64>) -> StrBuf {
pub fn uint_ty_to_str(t: UintTy, val: Option<u64>, mode: SuffixMode) -> StrBuf {
let s = match t {
TyU if val.is_some() => "u",
TyU if val.is_some() => match mode {
AutoSuffix => "",
ForceSuffix => "u",
},
TyU => "uint",
TyU8 => "u8",
TyU16 => "u16",

View File

@ -182,6 +182,7 @@ use std::cell::RefCell;
use ast;
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
use ast_util;
use attr::AttrMetaMethods;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use codemap;
@ -330,21 +331,34 @@ impl<'a> TraitDef<'a> {
_mitem: @ast::MetaItem,
item: @ast::Item,
push: |@ast::Item|) {
match item.node {
let newitem = match item.node {
ast::ItemStruct(struct_def, ref generics) => {
push(self.expand_struct_def(cx,
struct_def,
item.ident,
generics));
self.expand_struct_def(cx,
struct_def,
item.ident,
generics)
}
ast::ItemEnum(ref enum_def, ref generics) => {
push(self.expand_enum_def(cx,
enum_def,
item.ident,
generics));
self.expand_enum_def(cx,
enum_def,
item.ident,
generics)
}
_ => ()
}
_ => return
};
// Keep the lint attributes of the previous item to control how the
// generated implementations are linted
let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs.iter().filter(|a| {
match a.name().get() {
"allow" | "warn" | "deny" | "forbid" => true,
_ => false,
}
}).map(|a| a.clone()));
push(@ast::Item {
attrs: attrs,
..(*newitem).clone()
})
}
/**

View File

@ -156,7 +156,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
// }
// }
let local_ident = token::gensym_ident("i");
let local_ident = token::gensym_ident("__i"); // FIXME #13573
let next_ident = fld.cx.ident_of("next");
let none_ident = fld.cx.ident_of("None");
@ -262,7 +262,8 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
let it = expand_item_modifiers(it, fld);
let mut decorator_items = SmallVector::zero();
for attr in it.attrs.iter().rev() {
let mut new_attrs = Vec::new();
for attr in it.attrs.iter() {
let mname = attr.name();
match fld.extsbox.find(&intern(mname.get())) {
@ -286,7 +287,7 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
fld.cx.bt_pop();
}
_ => {}
_ => new_attrs.push((*attr).clone()),
}
}
@ -294,14 +295,21 @@ pub fn expand_item(it: @ast::Item, fld: &mut MacroExpander)
ast::ItemMac(..) => expand_item_mac(it, fld),
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
fld.cx.mod_push(it.ident);
let macro_escape = contains_macro_escape(it.attrs.as_slice());
let macro_escape = contains_macro_escape(new_attrs.as_slice());
let result = with_exts_frame!(fld.extsbox,
macro_escape,
noop_fold_item(it, fld));
fld.cx.mod_pop();
result
},
_ => noop_fold_item(it, fld)
_ => {
let it = @ast::Item {
attrs: new_attrs,
..(*it).clone()
};
noop_fold_item(it, fld)
}
};
new_items.push_all(decorator_items);

View File

@ -587,16 +587,64 @@ impl<'a> Parser<'a> {
self.replace_token(token::BINOP(token::OR), lo, self.span.hi)
}
_ => {
let token_str = self.this_token_to_str();
let found_token =
let found_token = self.this_token_to_str();
let token_str =
Parser::token_to_str(&token::BINOP(token::OR));
self.fatal(format!("expected `{}`, found `{}`",
found_token,
token_str))
token_str, found_token))
}
}
}
// Attempt to consume a `<`. If `<<` is seen, replace it with a single
// `<` and continue. If a `<` is not seen, return false.
//
// This is meant to be used when parsing generics on a path to get the
// starting token. The `force` parameter is used to forcefully break up a
// `<<` token. If `force` is false, then `<<` is only broken when a lifetime
// shows up next. For example, consider the expression:
//
// foo as bar << test
//
// The parser needs to know if `bar <<` is the start of a generic path or if
// it's a left-shift token. If `test` were a lifetime, then it's impossible
// for the token to be a left-shift, but if it's not a lifetime, then it's
// considered a left-shift.
//
// The reason for this is that the only current ambiguity with `<<` is when
// parsing closure types:
//
// foo::<<'a> ||>();
// impl Foo<<'a> ||>() { ... }
fn eat_lt(&mut self, force: bool) -> bool {
match self.token {
token::LT => { self.bump(); true }
token::BINOP(token::SHL) => {
let next_lifetime = self.look_ahead(1, |t| match *t {
token::LIFETIME(..) => true,
_ => false,
});
if force || next_lifetime {
let lo = self.span.lo + BytePos(1);
self.replace_token(token::LT, lo, self.span.hi);
true
} else {
false
}
}
_ => false,
}
}
fn expect_lt(&mut self) {
if !self.eat_lt(true) {
let found_token = self.this_token_to_str();
let token_str = Parser::token_to_str(&token::LT);
self.fatal(format!("expected `{}`, found `{}`",
token_str, found_token))
}
}
// Parse a sequence bracketed by `|` and `|`, stopping before the `|`.
fn parse_seq_to_before_or<T>(
&mut self,
@ -1500,7 +1548,7 @@ impl<'a> Parser<'a> {
// Parse the `<` before the lifetime and types, if applicable.
let (any_lifetime_or_types, lifetimes, types) = {
if mode != NoTypesAllowed && self.eat(&token::LT) {
if mode != NoTypesAllowed && self.eat_lt(false) {
let (lifetimes, types) =
self.parse_generic_values_after_lt();
(true, lifetimes, OwnedSlice::from_vec(types))
@ -1948,7 +1996,7 @@ impl<'a> Parser<'a> {
hi = self.span.hi;
self.bump();
let (_, tys) = if self.eat(&token::MOD_SEP) {
self.expect(&token::LT);
self.expect_lt();
self.parse_generic_values_after_lt()
} else {
(Vec::new(), Vec::new())
@ -2241,9 +2289,6 @@ impl<'a> Parser<'a> {
ExprVec(..) if m == MutImmutable => {
ExprVstore(e, ExprVstoreSlice)
}
ExprLit(lit) if lit_is_str(lit) && m == MutImmutable => {
ExprVstore(e, ExprVstoreSlice)
}
ExprVec(..) if m == MutMutable => {
ExprVstore(e, ExprVstoreMutSlice)
}

View File

@ -203,9 +203,11 @@ pub fn to_str(t: &Token) -> StrBuf {
res.push_char('\'');
res
}
LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i)),
LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u)),
LIT_INT_UNSUFFIXED(i) => { i.to_str().to_strbuf() }
LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i),
ast_util::ForceSuffix),
LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u),
ast_util::ForceSuffix),
LIT_INT_UNSUFFIXED(i) => { (i as u64).to_str().to_strbuf() }
LIT_FLOAT(s, t) => {
let mut body = StrBuf::from_str(get_ident(s).get());
if body.as_slice().ends_with(".") {

View File

@ -168,7 +168,7 @@ pub fn tt_to_str(tt: &ast::TokenTree) -> StrBuf {
}
pub fn tts_to_str(tts: &[ast::TokenTree]) -> StrBuf {
to_str(|s| s.print_tts(&tts))
to_str(|s| s.print_tts(tts))
}
pub fn stmt_to_str(stmt: &ast::Stmt) -> StrBuf {
@ -247,6 +247,15 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> StrBuf {
}
}
fn needs_parentheses(expr: &ast::Expr) -> bool {
match expr.node {
ast::ExprAssign(..) | ast::ExprBinary(..) |
ast::ExprFnBlock(..) | ast::ExprProc(..) |
ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
_ => false,
}
}
impl<'a> State<'a> {
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
self.boxes.push(pp::Inconsistent);
@ -714,7 +723,7 @@ impl<'a> State<'a> {
try!(self.print_ident(item.ident));
try!(self.cbox(indent_unit));
try!(self.popen());
try!(self.print_tts(&(tts.as_slice())));
try!(self.print_tts(tts.as_slice()));
try!(self.pclose());
try!(self.end());
}
@ -830,9 +839,15 @@ impl<'a> State<'a> {
/// expression arguments as expressions). It can be done! I think.
pub fn print_tt(&mut self, tt: &ast::TokenTree) -> IoResult<()> {
match *tt {
ast::TTDelim(ref tts) => self.print_tts(&(tts.as_slice())),
ast::TTDelim(ref tts) => self.print_tts(tts.as_slice()),
ast::TTTok(_, ref tk) => {
word(&mut self.s, parse::token::to_str(tk).as_slice())
try!(word(&mut self.s, parse::token::to_str(tk).as_slice()));
match *tk {
parse::token::DOC_COMMENT(..) => {
hardbreak(&mut self.s)
}
_ => Ok(())
}
}
ast::TTSeq(_, ref tts, ref sep, zerok) => {
try!(word(&mut self.s, "$("));
@ -856,7 +871,7 @@ impl<'a> State<'a> {
}
}
pub fn print_tts(&mut self, tts: & &[ast::TokenTree]) -> IoResult<()> {
pub fn print_tts(&mut self, tts: &[ast::TokenTree]) -> IoResult<()> {
try!(self.ibox(0));
for (i, tt) in tts.iter().enumerate() {
if i != 0 {
@ -1113,7 +1128,7 @@ impl<'a> State<'a> {
try!(self.print_path(pth, false));
try!(word(&mut self.s, "!"));
try!(self.popen());
try!(self.print_tts(&tts.as_slice()));
try!(self.print_tts(tts.as_slice()));
self.pclose()
}
}
@ -1136,6 +1151,18 @@ impl<'a> State<'a> {
self.pclose()
}
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> {
let needs_par = needs_parentheses(expr);
if needs_par {
try!(self.popen());
}
try!(self.print_expr(expr));
if needs_par {
try!(self.pclose());
}
Ok(())
}
pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
try!(self.maybe_print_comment(expr.span.lo));
try!(self.ibox(indent_unit));
@ -1209,7 +1236,7 @@ impl<'a> State<'a> {
try!(self.pclose());
}
ast::ExprCall(func, ref args) => {
try!(self.print_expr(func));
try!(self.print_expr_maybe_paren(func));
try!(self.print_call_post(args.as_slice()));
}
ast::ExprMethodCall(ident, ref tys, ref args) => {
@ -1233,17 +1260,12 @@ impl<'a> State<'a> {
}
ast::ExprUnary(op, expr) => {
try!(word(&mut self.s, ast_util::unop_to_str(op)));
try!(self.print_expr(expr));
try!(self.print_expr_maybe_paren(expr));
}
ast::ExprAddrOf(m, expr) => {
try!(word(&mut self.s, "&"));
try!(self.print_mutability(m));
// Avoid `& &e` => `&&e`.
match (m, &expr.node) {
(ast::MutImmutable, &ast::ExprAddrOf(..)) => try!(space(&mut self.s)),
_ => { }
}
try!(self.print_expr(expr));
try!(self.print_expr_maybe_paren(expr));
}
ast::ExprLit(lit) => try!(self.print_literal(lit)),
ast::ExprCast(expr, ty) => {
@ -1474,22 +1496,27 @@ impl<'a> State<'a> {
try!(self.popen());
try!(self.print_string(a.asm.get(), a.asm_str_style));
try!(self.word_space(":"));
for &(ref co, o) in a.outputs.iter() {
try!(self.print_string(co.get(), ast::CookedStr));
try!(self.popen());
try!(self.print_expr(o));
try!(self.pclose());
try!(self.word_space(","));
}
try!(self.commasep(Inconsistent, a.outputs.as_slice(), |s, &(ref co, o)| {
try!(s.print_string(co.get(), ast::CookedStr));
try!(s.popen());
try!(s.print_expr(o));
try!(s.pclose());
Ok(())
}));
try!(space(&mut self.s));
try!(self.word_space(":"));
for &(ref co, o) in a.inputs.iter() {
try!(self.print_string(co.get(), ast::CookedStr));
try!(self.popen());
try!(self.print_expr(o));
try!(self.pclose());
try!(self.word_space(","));
}
try!(self.commasep(Inconsistent, a.inputs.as_slice(), |s, &(ref co, o)| {
try!(s.print_string(co.get(), ast::CookedStr));
try!(s.popen());
try!(s.print_expr(o));
try!(s.pclose());
Ok(())
}));
try!(space(&mut self.s));
try!(self.word_space(":"));
try!(self.print_string(a.clobbers.get(), ast::CookedStr));
try!(self.pclose());
}
@ -2211,11 +2238,13 @@ impl<'a> State<'a> {
}
ast::LitInt(i, t) => {
word(&mut self.s,
ast_util::int_ty_to_str(t, Some(i)).as_slice())
ast_util::int_ty_to_str(t, Some(i),
ast_util::AutoSuffix).as_slice())
}
ast::LitUint(u, t) => {
word(&mut self.s,
ast_util::uint_ty_to_str(t, Some(u)).as_slice())
ast_util::uint_ty_to_str(t, Some(u),
ast_util::ForceSuffix).as_slice())
}
ast::LitIntUnsuffixed(i) => {
word(&mut self.s, format!("{}", i))

View File

@ -754,3 +754,9 @@ LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) {
*ptr = ret.data();
return ret.size();
}
// LLVMArrayType function does not support 64-bit ElementCount
extern "C" LLVMTypeRef
LLVMRustArrayType(LLVMTypeRef ElementType, uint64_t ElementCount) {
return wrap(ArrayType::get(unwrap(ElementType), ElementCount));
}

View File

@ -0,0 +1,16 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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 static BLOCK_FN_DEF: fn(uint) -> uint = {
fn foo(a: uint) -> uint {
a + 10
}
foo
};

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.
@ -10,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty very bad with line comments
extern crate collections;
extern crate rand;
extern crate time;

View File

@ -9,8 +9,8 @@
// except according to those terms.
// ignore-android: FIXME(#10393)
// ignore-pretty very bad with line comments
// ignore-pretty the `let to_child` line gets an extra newline
// multi tasking k-nucleotide
extern crate collections;

View File

@ -9,7 +9,6 @@
// except according to those terms.
// ignore-android see #10393 #13206
// ignore-pretty
extern crate sync;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty very bad with line comments
extern crate sync;
use std::io;

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty very bad with line comments
// ignore-android doesn't terminate?
// ignore-pretty
use std::iter::range_step;
use std::io::{stdin, stdout, File};

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.
@ -10,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty very bad with line comments
#![feature(managed_boxes)]
use std::io;

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.
@ -17,6 +15,8 @@
//
// The filename is a song reference; google it in quotes.
// ignore-pretty very bad with line comments
use std::comm;
use std::os;
use std::task;

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty -- comments are unfaithfully preserved
#![allow(unused_variable)]
#![allow(dead_assignment)]

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty -- comments are unfaithfully preserved
fn main() {
let mut x: Option<int> = None;
match x {

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.

View File

@ -0,0 +1,28 @@
// 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(macro_rules)]
static A: uint = { 1; 2 };
//~^ ERROR: blocks in constants are limited to items and tail expressions
static B: uint = { { } 2 };
//~^ ERROR: blocks in constants are limited to items and tail expressions
macro_rules! foo {
() => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
}
static C: uint = { foo!() 2 };
static D: uint = { let x = 4; 2 };
//~^ ERROR: blocks in constants are limited to items and tail expressions
pub fn main() {
}

View File

@ -11,6 +11,7 @@
// error-pattern:runned an unexported test
// compile-flags:--test
// check-stdout
// ignore-pretty: does not work well with `--test`
mod m {
pub fn exported() { }

View File

@ -11,6 +11,7 @@
// check-stdout
// error-pattern:task 'test_foo' failed at
// compile-flags: --test
// ignore-pretty: does not work well with `--test`
#[test]
fn test_foo() {

View File

@ -14,6 +14,7 @@
// error-pattern:should be a positive integer
// compile-flags: --test
// exec-env:RUST_TEST_TASKS=foo
// ignore-pretty: does not work well with `--test`
#[test]
fn do_nothing() {}

View File

@ -9,6 +9,8 @@
// except according to those terms.
// ignore-android
// ignore-pretty: does not work well with `--test`
#![feature(quote)]
#![deny(unused_variable)]

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty
// aux-build:anon-extern-mod-cross-crate-1.rs
extern crate anonexternmod;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(managed_boxes)]
#[deriving(Eq, Show)]
struct Point { x : int }

View File

@ -50,7 +50,7 @@ fn runtest(me: &str) {
env: Some(env.as_slice()),
.. ProcessConfig::new()
}).unwrap();
let out = p.wait_with_output();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
assert!(s.contains("stack backtrace") && s.contains("foo::h"),
@ -62,7 +62,7 @@ fn runtest(me: &str) {
args: ["fail".to_owned()],
.. ProcessConfig::new()
}).unwrap();
let out = p.wait_with_output();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
assert!(!s.contains("stack backtrace") && !s.contains("foo::h"),
@ -74,7 +74,7 @@ fn runtest(me: &str) {
args: ["double-fail".to_owned()],
.. ProcessConfig::new()
}).unwrap();
let out = p.wait_with_output();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
assert!(s.contains("stack backtrace") && s.contains("double::h"),
@ -87,7 +87,7 @@ fn runtest(me: &str) {
env: Some(env.as_slice()),
.. ProcessConfig::new()
}).unwrap();
let out = p.wait_with_output();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
let mut i = 0;

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.
@ -18,4 +16,5 @@ pub fn main() {
assert_eq!(-2147483648i32 - 1i32, 2147483647i32);
assert_eq!(-9223372036854775808i64 - 1i64, 9223372036854775807i64);
assert_eq!(-9223372036854775808 - 1, 9223372036854775807);
}

View File

@ -10,6 +10,8 @@
// Binop corner cases
#![feature(managed_boxes)]
fn test_nil() {
assert_eq!((), ());
assert!((!(() != ())));

View File

@ -1,5 +1,3 @@
// ignore-pretty
// 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.
@ -10,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty
fn match_ref(v: Option<int>) -> int {
match v {
Some(ref i) => {

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(managed_boxes)]
pub fn main() {
assert!((@1 < @3));

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty #13324
#![allow(dead_code)]
fn foo<T>() {}
@ -45,6 +43,12 @@ fn g<'a>(a: &'a int, f: proc<'b>(&'b int) -> &'b int) -> &'a int {
f(a)
}
struct A;
impl A {
fn foo<T>(&self) {}
}
fn bar<'b>() {
foo::<||>();
foo::<|| -> ()>();
@ -60,17 +64,25 @@ fn bar<'b>() {
foo::<proc():Share>();
foo::<proc<'a>(int, f32, &'a int):'static + Share -> &'a int>();
foo::<<'a>||>();
// issue #11209
let _: ||: 'b; // for comparison
let _: <'a> ||;
let _: Option<||:'b>;
// let _: Option<<'a>||>;
let _: Option<<'a>||>;
let _: Option< <'a>||>;
// issue #11210
let _: ||: 'static;
let a = A;
a.foo::<<'a>||>();
}
struct B<T>;
impl<'b> B<<'a>||: 'b> {}
pub fn main() {
}

View File

@ -0,0 +1,17 @@
// 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:cci_const_block.rs
extern crate cci_const_block;
pub fn main() {
assert_eq!(cci_const_block::BLOCK_FN_DEF(390), 400);
}

View File

@ -0,0 +1,49 @@
// 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.
// General test that function items in static blocks
// can be generated with a macro.
#![feature(macro_rules)]
struct MyType {
desc: &'static str,
data: uint,
code: fn(uint, uint) -> uint
}
impl MyType {
fn eval(&self, a: uint) -> uint {
(self.code)(self.data, a)
}
}
macro_rules! codegen {
($e:expr, $v:expr) => {
{
fn generated(a: uint, b: uint) -> uint {
a - ($e * b)
}
MyType {
desc: "test",
data: $v,
code: generated
}
}
}
}
static GENERATED_CODE_1: MyType = codegen!(2, 100);
static GENERATED_CODE_2: MyType = codegen!(5, 1000);
pub fn main() {
assert_eq!(GENERATED_CODE_1.eval(10), 80);
assert_eq!(GENERATED_CODE_2.eval(100), 500);
}

View File

@ -0,0 +1,56 @@
// 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(macro_rules)]
mod foo {
pub trait Value {
fn value(&self) -> uint;
}
}
static BLOCK_USE: uint = {
use foo::Value;
100
};
static BLOCK_PUB_USE: uint = {
pub use foo::Value;
200
};
static BLOCK_STRUCT_DEF: uint = {
struct Foo {
a: uint
}
Foo{ a: 300 }.a
};
static BLOCK_FN_DEF: fn(uint) -> uint = {
fn foo(a: uint) -> uint {
a + 10
}
foo
};
static BLOCK_MACRO_RULES: uint = {
macro_rules! baz {
() => (412)
}
baz!()
};
pub fn main() {
assert_eq!(BLOCK_USE, 100);
assert_eq!(BLOCK_PUB_USE, 200);
assert_eq!(BLOCK_STRUCT_DEF, 300);
assert_eq!(BLOCK_FN_DEF(390), 400);
assert_eq!(BLOCK_MACRO_RULES, 412);
}

View File

@ -0,0 +1,69 @@
// 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_code)]
#![allow(unused_unsafe)]
struct Foo {
a: uint,
b: *()
}
fn foo<T>(a: T) -> T {
a
}
static BLOCK_INTEGRAL: uint = { 1 };
static BLOCK_EXPLICIT_UNIT: () = { () };
static BLOCK_IMPLICIT_UNIT: () = { };
static BLOCK_FLOAT: f64 = { 1.0 };
static BLOCK_ENUM: Option<uint> = { Some(100) };
static BLOCK_STRUCT: Foo = { Foo { a: 12, b: 0 as *() } };
static BLOCK_UNSAFE: uint = unsafe { 1000 };
// FIXME: #13970
// static BLOCK_FN_INFERRED: fn(uint) -> uint = { foo };
// FIXME: #13971
// static BLOCK_FN: fn(uint) -> uint = { foo::<uint> };
// FIXME: #13972
// static BLOCK_ENUM_CONSTRUCTOR: fn(uint) -> Option<uint> = { Some };
// FIXME: #13973
// static BLOCK_UNSAFE_SAFE_PTR: &'static int = unsafe { &*(0xdeadbeef as *int) };
// static BLOCK_UNSAFE_SAFE_PTR_2: &'static int = unsafe {
// static X: *int = 0xdeadbeef as *int;
// &*X
// };
pub fn main() {
assert_eq!(BLOCK_INTEGRAL, 1);
assert_eq!(BLOCK_EXPLICIT_UNIT, ());
assert_eq!(BLOCK_IMPLICIT_UNIT, ());
assert_eq!(BLOCK_FLOAT, 1.0_f64);
assert_eq!(BLOCK_STRUCT.a, 12);
assert_eq!(BLOCK_STRUCT.b, 0 as *());
assert_eq!(BLOCK_ENUM, Some(100));
assert_eq!(BLOCK_UNSAFE, 1000);
// FIXME: #13970
// assert_eq!(BLOCK_FN_INFERRED(300), 300);
// FIXME: #13971
// assert_eq!(BLOCK_FN(300), 300);
// FIXME: #13972
// assert_eq!(BLOCK_ENUM_CONSTRUCTOR(200), Some(200));
// FIXME: #13973
// assert_eq!(BLOCK_UNSAFE_SAFE_PTR as *int as uint, 0xdeadbeef_u);
// assert_eq!(BLOCK_UNSAFE_SAFE_PTR_2 as *int as uint, 0xdeadbeef_u);
}

View File

@ -120,7 +120,7 @@ pub fn test_destroy_actually_kills(force: bool) {
() = rx1.recv() => {}
}
});
match p.wait() {
match p.wait().unwrap() {
ExitStatus(..) => fail!("expected a signal"),
ExitSignal(..) => tx.send(()),
}

View File

@ -8,20 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty - does not converge
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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 crate serialize; // {En,De}codable
extern crate rand; // Rand
extern crate serialize;
extern crate rand;
mod submod {
// if any of these are implemented without global calls for any

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty: pprust doesn't print hygiene output
#![feature(macro_rules)]
macro_rules! loop_x {

View File

@ -8,8 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-pretty-expanded unnecessary unsafe block generated
#![feature(macro_rules)]
#![feature(macro_rules, managed_boxes)]
#![deny(warnings)]
#![allow(unused_must_use)]
#![allow(deprecated_owned_vector)]
@ -76,6 +77,7 @@ pub fn main() {
t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
t!(format!("{} {0}", "a"), "a a");
t!(format!("{foo_bar}", foo_bar=1), "1");
t!(format!("{:d}", 5 + 5), "10");
// Methods should probably work
t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");

Some files were not shown because too many files have changed in this diff Show More