diff --git a/configure b/configure index 586b29646c59e..fd0397e5f87c5 100755 --- a/configure +++ b/configure @@ -437,6 +437,10 @@ case $CFG_OSTYPE in CFG_CPUTYPE=$(isainfo -n) ;; + Haiku) + CFG_OSTYPE=unknown-haiku + ;; + MINGW*) # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: @@ -532,6 +536,10 @@ case $CFG_CPUTYPE in CFG_CPUTYPE=x86_64 ;; + BePC) + CFG_CPUTYPE=i686 + ;; + *) err "unknown CPU type: $CFG_CPUTYPE" esac diff --git a/mk/cfg/i686-unknown-haiku.mk b/mk/cfg/i686-unknown-haiku.mk new file mode 100644 index 0000000000000..cbacbff070e88 --- /dev/null +++ b/mk/cfg/i686-unknown-haiku.mk @@ -0,0 +1,27 @@ +# i686-unknown-haiku configuration +CROSS_PREFIX_i686-unknown-haiku=i586-pc-haiku- +CC_i686-unknown-haiku=$(CC) +CXX_i686-unknown-haiku=$(CXX) +CPP_i686-unknown-haiku=$(CPP) +AR_i686-unknown-haiku=$(AR) +CFG_LIB_NAME_i686-unknown-haiku=lib$(1).so +CFG_STATIC_LIB_NAME_i686-unknown-haiku=lib$(1).a +CFG_LIB_GLOB_i686-unknown-haiku=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_i686-unknown-haiku=lib$(1)-*.dylib.dSYM +CFG_CFLAGS_i686-unknown-haiku := -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-unknown-haiku := -Wall -Werror -g -fPIC -m32 $(CFLAGS) +CFG_GCCISH_CXXFLAGS_i686-unknown-haiku := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_i686-unknown-haiku := -shared -fPIC -ldl -pthread -lrt -g -m32 +CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-haiku := -Wl,-whole-archive +CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-haiku := -Wl,-no-whole-archive +CFG_DEF_SUFFIX_i686-unknown-haiku := .linux.def +CFG_LLC_FLAGS_i686-unknown-haiku := +CFG_INSTALL_NAME_i686-unknown-haiku = +CFG_EXE_SUFFIX_i686-unknown-haiku = +CFG_WINDOWSY_i686-unknown-haiku := +CFG_UNIXY_i686-unknown-haiku := 1 +CFG_PATH_MUNGE_i686-unknown-haiku := true +CFG_LDPATH_i686-unknown-haiku := +CFG_RUN_i686-unknown-haiku=$(2) +CFG_RUN_TARG_i686-unknown-haiku=$(call CFG_RUN_i686-unknown-haiku,,$(2)) +CFG_GNU_TRIPLE_i686-unknown-haiku := i686-unknown-haiku diff --git a/mk/cfg/x86_64-unknown-haiku.mk b/mk/cfg/x86_64-unknown-haiku.mk new file mode 100644 index 0000000000000..4c2d888be06fb --- /dev/null +++ b/mk/cfg/x86_64-unknown-haiku.mk @@ -0,0 +1,27 @@ +# x86_64-unknown-haiku configuration +CROSS_PREFIX_x86_64-unknown-haiku=x86_64-unknown-haiku- +CC_x86_64-unknown-haiku=$(CC) +CXX_x86_64-unknown-haiku=$(CXX) +CPP_x86_64-unknown-haiku=$(CPP) +AR_x86_64-unknown-haiku=$(AR) +CFG_LIB_NAME_x86_64-unknown-haiku=lib$(1).so +CFG_STATIC_LIB_NAME_x86_64-unknown-haiku=lib$(1).a +CFG_LIB_GLOB_x86_64-unknown-haiku=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_x86_64-unknown-haiku=lib$(1)-*.dylib.dSYM +CFG_CFLAGS_x86_64-unknown-haiku := -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-haiku := -Wall -Werror -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CXXFLAGS_x86_64-unknown-haiku := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_x86_64-unknown-haiku := -shared -fPIC -ldl -pthread -lrt -g -m64 +CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-whole-archive +CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-haiku := -Wl,-no-whole-archive +CFG_DEF_SUFFIX_x86_64-unknown-haiku := .linux.def +CFG_LLC_FLAGS_x86_64-unknown-haiku := +CFG_INSTALL_NAME_x86_64-unknown-haiku = +CFG_EXE_SUFFIX_x86_64-unknown-haiku = +CFG_WINDOWSY_x86_64-unknown-haiku := +CFG_UNIXY_x86_64-unknown-haiku := 1 +CFG_PATH_MUNGE_x86_64-unknown-haiku := true +CFG_LDPATH_x86_64-unknown-haiku := +CFG_RUN_x86_64-unknown-haiku=$(2) +CFG_RUN_TARG_x86_64-unknown-haiku=$(call CFG_RUN_x86_64-unknown-haiku,,$(2)) +CFG_GNU_TRIPLE_x86_64-unknown-haiku := x86_64-unknown-haiku diff --git a/mk/main.mk b/mk/main.mk index 7dcf3a7f3acd4..f06f6baa79d0a 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -512,10 +512,14 @@ ifeq ($$(OSTYPE_$(3)),apple-darwin) else ifeq ($$(CFG_WINDOWSY_$(3)),1) LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := PATH +else +ifeq ($$(OSTYPE_$(3)),unknown-haiku) + LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LIBRARY_PATH else LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LD_LIBRARY_PATH endif endif +endif LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \ $$(CURDIR)/$$(HLIB$(1)_H_$(3)):$$(CFG_LLVM_INST_DIR_$(3))/lib diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a5146c846ce28..bcc53129f8d8e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -243,7 +243,14 @@ impl Build { // Almost all of these are simple one-liners that shell out to the // corresponding functionality in the extra modules, where more // documentation can be found. - for target in step::all(self) { + let steps = step::all(self); + + self.verbose("bootstrap build plan:"); + for step in &steps { + self.verbose(&format!("{:?}", step)); + } + + for target in steps { let doc_out = self.out.join(&target.target).join("doc"); match target.src { Llvm { _dummy } => { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 5f391b70fbe88..4b5a26d205af7 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -171,6 +171,8 @@ targets!(define_source); /// into a topologically sorted list which when executed left-to-right will /// correctly sequence the entire build. pub fn all(build: &Build) -> Vec { + build.verbose("inferred build steps:"); + let mut ret = Vec::new(); let mut all = HashSet::new(); for target in top_level(build) { @@ -184,6 +186,7 @@ pub fn all(build: &Build) -> Vec { set: &mut HashSet>) { if set.insert(target.clone()) { for dep in target.deps(build) { + build.verbose(&format!("{:?}\n -> {:?}", target, dep)); fill(build, &dep, ret, set); } ret.push(target.clone()); diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index 700ab2be58932..bff448aadd5dc 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -230,12 +230,13 @@ $ cd hello_world ## Writing and Running a Rust Program -Next, make a new source file and call it *main.rs*. Rust files always end -in a *.rs* extension. If you’re using more than one word in your filename, use -an underscore to separate them; for example, you'd use *hello_world.rs* rather -than *helloworld.rs*. +We need to create a source file for our Rust program. Rust files always end +in a *.rs* extension. If you are using more than one word in your filename, +use an underscore to separate them; for example, you would use +*my_program.rs* rather than *myprogram.rs*. -Now open the *main.rs* file you just created, and type the following code: +Now, make a new file and call it *main.rs*. Open the file and type +the following code: ```rust fn main() { diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index f5f39d264a6b0..645a80ab8b581 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -18,7 +18,7 @@ LIB_PREFIX=lib OS=`uname -s` case $OS in - ("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS") + ("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS"|"Haiku") BIN_SUF= LIB_SUF=.so ;; diff --git a/src/liblibc b/src/liblibc index d4f6a19c55a03..eb708c020826a 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c +Subproject commit eb708c020826a8d792a5a5275be147aabe47fe24 diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 61bcc05bbb4f4..1acd0fb0f79c0 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -103,11 +103,16 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { } }; - span_err!(self.infcx.tcx.sess, span, E0512, + struct_span_err!(self.infcx.tcx.sess, span, E0512, "transmute called with differently sized types: \ {} ({}) to {} ({})", from, skeleton_string(from, sk_from), - to, skeleton_string(to, sk_to)); + to, skeleton_string(to, sk_to)) + .span_label(span, + &format!("transmuting between {} and {}", + skeleton_string(from, sk_from), + skeleton_string(to, sk_to))) + .emit(); } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 87f0c8b67a0ec..e906c24df0ff1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -605,6 +605,7 @@ macro_rules! options { pub const parse_opt_bool: Option<&'static str> = Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); pub const parse_string: Option<&'static str> = Some("a string"); + pub const parse_string_push: Option<&'static str> = Some("a string"); pub const parse_opt_string: Option<&'static str> = Some("a string"); pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings"); @@ -667,6 +668,13 @@ macro_rules! options { } } + fn parse_string_push(slot: &mut Vec, v: Option<&str>) -> bool { + match v { + Some(s) => { slot.push(s.to_string()); true }, + None => false, + } + } + fn parse_list(slot: &mut Vec, v: Option<&str>) -> bool { match v { @@ -742,6 +750,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "tool to assemble archives with"), linker: Option = (None, parse_opt_string, [UNTRACKED], "system linker to link outputs with"), + link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], + "a single extra argument to pass to the linker (can be used several times)"), link_args: Option> = (None, parse_opt_list, [UNTRACKED], "extra arguments to pass to the linker (space separated)"), link_dead_code: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs new file mode 100644 index 0000000000000..5e319ba1838a0 --- /dev/null +++ b/src/librustc_back/target/haiku_base.rs @@ -0,0 +1,23 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::TargetOptions; +use std::default::Default; + +pub fn opts() -> TargetOptions { + TargetOptions { + linker: "cc".to_string(), + dynamic_linking: true, + executables: true, + has_rpath: true, + linker_is_gnu: true, + .. Default::default() + } +} diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs new file mode 100644 index 0000000000000..862016704f47c --- /dev/null +++ b/src/librustc_back/target/i686_unknown_haiku.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::haiku_base::opts(); + base.cpu = "pentium4".to_string(); + base.max_atomic_width = 64; + base.pre_link_args.push("-m32".to_string()); + + Ok(Target { + llvm_target: "i686-unknown-haiku".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(), + arch: "x86".to_string(), + target_os: "haiku".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 756586602b45a..087078021a188 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -56,6 +56,7 @@ mod apple_ios_base; mod bitrig_base; mod dragonfly_base; mod freebsd_base; +mod haiku_base; mod linux_base; mod linux_musl_base; mod openbsd_base; @@ -165,6 +166,9 @@ supported_targets! { ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), + ("i686_unknown_haiku", i686_unknown_haiku), + ("x86_64_unknown_haiku", x86_64_unknown_haiku), + ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs new file mode 100644 index 0000000000000..171e88cee50c4 --- /dev/null +++ b/src/librustc_back/target/x86_64_unknown_haiku.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::haiku_base::opts(); + base.cpu = "x86-64".to_string(); + base.max_atomic_width = 64; + base.pre_link_args.push("-m64".to_string()); + + Ok(Target { + llvm_target: "x86_64-unknown-haiku".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "haiku".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 4a184d3174dff..510c9ceef0960 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -94,6 +94,27 @@ mod imp { pub const F_SETLKW: libc::c_int = 9; } + #[cfg(target_os = "haiku")] + mod os { + use libc; + + pub struct flock { + pub l_type: libc::c_short, + pub l_whence: libc::c_short, + pub l_start: libc::off_t, + pub l_len: libc::off_t, + pub l_pid: libc::pid_t, + + // not actually here, but brings in line with freebsd + pub l_sysid: libc::c_int, + } + + pub const F_UNLCK: libc::c_short = 0x0200; + pub const F_WRLCK: libc::c_short = 0x0400; + pub const F_SETLK: libc::c_int = 0x0080; + pub const F_SETLKW: libc::c_int = 0x0100; + } + #[cfg(any(target_os = "macos", target_os = "ios"))] mod os { use libc; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 201e1e5f2ec4c..5dab82dbc7ac4 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -754,7 +754,8 @@ fn link_args(cmd: &mut Linker, let empty_vec = Vec::new(); let empty_str = String::new(); let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); - let mut args = args.iter().chain(used_link_args.iter()); + let more_args = &sess.opts.cg.link_arg; + let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); let relocation_model = sess.opts.cg.relocation_model.as_ref() .unwrap_or(&empty_str); if (t.options.relocation_model == "pic" || *relocation_model == "pic") @@ -844,6 +845,7 @@ fn link_args(cmd: &mut Linker, if let Some(ref args) = sess.opts.cg.link_args { cmd.args(args); } + cmd.args(&sess.opts.cg.link_arg); cmd.args(&used_link_args); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 543fdca84edf2..ee00cb2f5a3e4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1525,9 +1525,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.locals.borrow().get(&nid) { Some(&t) => t, None => { - span_err!(self.tcx.sess, span, E0513, - "no type for local variable {}", - nid); + struct_span_err!(self.tcx.sess, span, E0513, + "no type for local variable {}", + self.tcx.map.node_to_string(nid)) + .span_label(span, &"no type for variable") + .emit(); self.tcx.types.err } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e5c901f223ffb..0d6b43b59c6ad 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3766,6 +3766,45 @@ extern "platform-intrinsic" { ``` "##, +E0513: r##" +The type of the variable couldn't be found out. + +Erroneous code example: + +```compile_fail,E0513 +use std::mem; + +unsafe { + let size = mem::size_of::(); + mem::transmute_copy::(&8_8); + // error: no type for local variable +} +``` + +To fix this error, please use a constant size instead of `size`. To make +this error more obvious, you could run: + +```compile_fail,E0080 +use std::mem; + +unsafe { + mem::transmute_copy::()]>(&8_8); + // error: constant evaluation error +} +``` + +So now, you can fix your code by setting the size directly: + +``` +use std::mem; + +unsafe { + mem::transmute_copy::(&8_8); + // `u32` is 4 bytes so we replace the `mem::size_of` call with its size +} +``` +"##, + E0516: r##" The `typeof` keyword is currently reserved but unimplemented. Erroneous code example: @@ -4064,7 +4103,6 @@ register_diagnostics! { E0399, // trait items need to be implemented because the associated // type `{}` was overridden E0436, // functional record update requires a struct - E0513, // no type for local variable .. E0521, // redundant default implementations of trait E0533, // `{}` does not name a unit variant, unit struct or a constant E0562, // `impl Trait` not allowed outside of function diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c52497dc89bd6..49e467e5cbe3b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,6 +32,7 @@ use errors::emitter::ColorConfig; use std::cell::{RefCell, Cell}; use std::mem; use std::rc::Rc; +use std::path::PathBuf; use visit_ast::RustdocVisitor; use clean; @@ -127,7 +128,8 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: config::Externs, input: Input, - triple: Option) -> (clean::Crate, RenderInfo) + triple: Option, + maybe_sysroot: Option) -> (clean::Crate, RenderInfo) { // Parse, resolve, and typecheck the given crate. @@ -139,7 +141,7 @@ pub fn run_core(search_paths: SearchPaths, let warning_lint = lint::builtin::WARNINGS.name_lower(); let sessopts = config::Options { - maybe_sysroot: None, + maybe_sysroot: maybe_sysroot, search_paths: search_paths, crate_types: vec!(config::CrateTypeRlib), lint_opts: vec!((warning_lint, lint::Allow)), diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 9a6cded5b4ce7..cad5fae690fb8 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -378,6 +378,11 @@ h4 > code, h3 > code, .invisible > code { font-size: 90%; } +/* Shift where in trait listing down a line */ +pre.trait .where::before { + content: '\a '; +} + nav { border-bottom: 1px solid; padding-bottom: 10px; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cc5cdf9f4e74c..1ff84b95da6a4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -91,31 +91,6 @@ pub mod test; use clean::Attributes; -type Pass = (&'static str, // name - fn(clean::Crate) -> plugins::PluginResult, // fn - &'static str); // description - -const PASSES: &'static [Pass] = &[ - ("strip-hidden", passes::strip_hidden, - "strips all doc(hidden) items from the output"), - ("unindent-comments", passes::unindent_comments, - "removes excess indentation on comments in order for markdown to like it"), - ("collapse-docs", passes::collapse_docs, - "concatenates all document attributes into one document attribute"), - ("strip-private", passes::strip_private, - "strips all private items from a crate which cannot be seen externally, \ - implies strip-priv-imports"), - ("strip-priv-imports", passes::strip_priv_imports, - "strips all private import statements (`use`, `extern crate`) from a crate"), -]; - -const DEFAULT_PASSES: &'static [&'static str] = &[ - "strip-hidden", - "strip-private", - "collapse-docs", - "unindent-comments", -]; - struct Output { krate: clean::Crate, renderinfo: html::render::RenderInfo, @@ -123,7 +98,7 @@ struct Output { } pub fn main() { - const STACK_SIZE: usize = 32000000; // 32MB + const STACK_SIZE: usize = 32_000_000; // 32MB let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) @@ -186,6 +161,7 @@ pub fn opts() -> Vec { own theme", "PATH")), unstable(optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG")), + stable(optopt("", "sysroot", "Override the system root", "PATH")), ) } @@ -222,11 +198,11 @@ pub fn main_args(args: &[String]) -> isize { if matches.opt_strs("passes") == ["list"] { println!("Available passes for running rustdoc:"); - for &(name, _, description) in PASSES { + for &(name, _, description) in passes::PASSES { println!("{:>20} - {}", name, description); } println!("\nDefault passes for rustdoc:"); - for &name in DEFAULT_PASSES { + for &name in passes::DEFAULT_PASSES { println!("{:>20}", name); } return 0; @@ -235,7 +211,8 @@ pub fn main_args(args: &[String]) -> isize { if matches.free.is_empty() { println!("expected an input file to act on"); return 1; - } if matches.free.len() > 1 { + } + if matches.free.len() > 1 { println!("only one input file may be specified"); return 1; } @@ -370,6 +347,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> } let cfgs = matches.opt_strs("cfg"); let triple = matches.opt_str("target"); + let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let cr = PathBuf::from(cratefile); info!("starting to run rustc"); @@ -379,7 +357,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> use rustc::session::config::Input; tx.send(core::run_core(paths, cfgs, externs, Input::File(cr), - triple)).unwrap(); + triple, maybe_sysroot)).unwrap(); }); let (mut krate, renderinfo) = rx.recv().unwrap(); info!("finished with rustc"); @@ -410,7 +388,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> } if default_passes { - for name in DEFAULT_PASSES.iter().rev() { + for name in passes::DEFAULT_PASSES.iter().rev() { passes.insert(0, name.to_string()); } } @@ -420,11 +398,11 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> .unwrap_or("/tmp/rustdoc/plugins".to_string()); let mut pm = plugins::PluginManager::new(PathBuf::from(path)); for pass in &passes { - let plugin = match PASSES.iter() - .position(|&(p, ..)| { - p == *pass - }) { - Some(i) => PASSES[i].1, + let plugin = match passes::PASSES.iter() + .position(|&(p, ..)| { + p == *pass + }) { + Some(i) => passes::PASSES[i].1, None => { error!("unknown pass {}, skipping", *pass); continue diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs deleted file mode 100644 index c60e22824965f..0000000000000 --- a/src/librustdoc/passes.rs +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::hir::def_id::DefId; -use rustc::middle::privacy::AccessLevels; -use rustc::util::nodemap::DefIdSet; -use std::cmp; -use std::mem; -use std::string::String; -use std::usize; - -use clean::{self, Attributes, GetDefId}; -use clean::Item; -use plugins; -use fold; -use fold::DocFolder; -use fold::FoldItem::Strip; - -/// Strip items marked `#[doc(hidden)]` -pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { - let mut retained = DefIdSet(); - - // strip all #[doc(hidden)] items - let krate = { - struct Stripper<'a> { - retained: &'a mut DefIdSet, - update_retained: bool, - } - impl<'a> fold::DocFolder for Stripper<'a> { - fn fold_item(&mut self, i: Item) -> Option { - if i.attrs.list("doc").has_word("hidden") { - debug!("found one in strip_hidden; removing"); - // use a dedicated hidden item for given item type if any - match i.inner { - clean::StructFieldItem(..) | clean::ModuleItem(..) => { - // We need to recurse into stripped modules to - // strip things like impl methods but when doing so - // we must not add any items to the `retained` set. - let old = mem::replace(&mut self.update_retained, false); - let ret = Strip(self.fold_item_recur(i).unwrap()).fold(); - self.update_retained = old; - return ret; - } - _ => return None, - } - } else { - if self.update_retained { - self.retained.insert(i.def_id); - } - } - self.fold_item_recur(i) - } - } - let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; - stripper.fold_crate(krate) - }; - - // strip all impls referencing stripped items - let mut stripper = ImplStripper { retained: &retained }; - stripper.fold_crate(krate) -} - -/// Strip private items from the point of view of a crate or externally from a -/// crate, specified by the `xcrate` flag. -pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { - // This stripper collects all *retained* nodes. - let mut retained = DefIdSet(); - let access_levels = krate.access_levels.clone(); - - // strip all private items - { - let mut stripper = Stripper { - retained: &mut retained, - access_levels: &access_levels, - update_retained: true, - }; - krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); - } - - // strip all impls referencing private items - let mut stripper = ImplStripper { retained: &retained }; - stripper.fold_crate(krate) -} - -struct Stripper<'a> { - retained: &'a mut DefIdSet, - access_levels: &'a AccessLevels, - update_retained: bool, -} - -impl<'a> fold::DocFolder for Stripper<'a> { - fn fold_item(&mut self, i: Item) -> Option { - match i.inner { - clean::StrippedItem(..) => { - // We need to recurse into stripped modules to strip things - // like impl methods but when doing so we must not add any - // items to the `retained` set. - let old = mem::replace(&mut self.update_retained, false); - let ret = self.fold_item_recur(i); - self.update_retained = old; - return ret; - } - // These items can all get re-exported - clean::TypedefItem(..) | clean::StaticItem(..) | - clean::StructItem(..) | clean::EnumItem(..) | - clean::TraitItem(..) | clean::FunctionItem(..) | - clean::VariantItem(..) | clean::MethodItem(..) | - clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | - clean::ConstantItem(..) | clean::UnionItem(..) => { - if i.def_id.is_local() { - if !self.access_levels.is_exported(i.def_id) { - return None; - } - } - } - - clean::StructFieldItem(..) => { - if i.visibility != Some(clean::Public) { - return Strip(i).fold(); - } - } - - clean::ModuleItem(..) => { - if i.def_id.is_local() && i.visibility != Some(clean::Public) { - let old = mem::replace(&mut self.update_retained, false); - let ret = Strip(self.fold_item_recur(i).unwrap()).fold(); - self.update_retained = old; - return ret; - } - } - - // handled in the `strip-priv-imports` pass - clean::ExternCrateItem(..) | clean::ImportItem(..) => {} - - clean::DefaultImplItem(..) | clean::ImplItem(..) => {} - - // tymethods/macros have no control over privacy - clean::MacroItem(..) | clean::TyMethodItem(..) => {} - - // Primitives are never stripped - clean::PrimitiveItem(..) => {} - - // Associated consts and types are never stripped - clean::AssociatedConstItem(..) | - clean::AssociatedTypeItem(..) => {} - } - - let fastreturn = match i.inner { - // nothing left to do for traits (don't want to filter their - // methods out, visibility controlled by the trait) - clean::TraitItem(..) => true, - - // implementations of traits are always public. - clean::ImplItem(ref imp) if imp.trait_.is_some() => true, - // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant { - kind: clean::StructVariant(..) - }) => true, - _ => false, - }; - - let i = if fastreturn { - if self.update_retained { - self.retained.insert(i.def_id); - } - return Some(i); - } else { - self.fold_item_recur(i) - }; - - i.and_then(|i| { - match i.inner { - // emptied modules have no need to exist - clean::ModuleItem(ref m) - if m.items.is_empty() && - i.doc_value().is_none() => None, - _ => { - if self.update_retained { - self.retained.insert(i.def_id); - } - Some(i) - } - } - }) - } -} - -// This stripper discards all impls which reference stripped items -struct ImplStripper<'a> { - retained: &'a DefIdSet -} - -impl<'a> fold::DocFolder for ImplStripper<'a> { - fn fold_item(&mut self, i: Item) -> Option { - if let clean::ImplItem(ref imp) = i.inner { - // emptied none trait impls can be stripped - if imp.trait_.is_none() && imp.items.is_empty() { - return None; - } - if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && - !self.retained.contains(&did) - { - return None; - } - } - if let Some(did) = imp.trait_.def_id() { - if did.is_local() && !self.retained.contains(&did) { - return None; - } - } - } - self.fold_item_recur(i) - } -} - -// This stripper discards all private import statements (`use`, `extern crate`) -struct ImportStripper; -impl fold::DocFolder for ImportStripper { - fn fold_item(&mut self, i: Item) -> Option { - match i.inner { - clean::ExternCrateItem(..) | - clean::ImportItem(..) if i.visibility != Some(clean::Public) => None, - _ => self.fold_item_recur(i) - } - } -} - -pub fn strip_priv_imports(krate: clean::Crate) -> plugins::PluginResult { - ImportStripper.fold_crate(krate) -} - -pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult { - struct CommentCleaner; - impl fold::DocFolder for CommentCleaner { - fn fold_item(&mut self, mut i: Item) -> Option { - let mut avec: Vec = Vec::new(); - for attr in &i.attrs { - match attr { - &clean::NameValue(ref x, ref s) - if "doc" == *x => { - avec.push(clean::NameValue("doc".to_string(), - unindent(s))) - } - x => avec.push(x.clone()) - } - } - i.attrs = avec; - self.fold_item_recur(i) - } - } - let mut cleaner = CommentCleaner; - let krate = cleaner.fold_crate(krate); - krate -} - -pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { - struct Collapser; - impl fold::DocFolder for Collapser { - fn fold_item(&mut self, mut i: Item) -> Option { - let mut docstr = String::new(); - for attr in &i.attrs { - if let clean::NameValue(ref x, ref s) = *attr { - if "doc" == *x { - docstr.push_str(s); - docstr.push('\n'); - } - } - } - let mut a: Vec = i.attrs.iter().filter(|&a| match a { - &clean::NameValue(ref x, _) if "doc" == *x => false, - _ => true - }).cloned().collect(); - if !docstr.is_empty() { - a.push(clean::NameValue("doc".to_string(), docstr)); - } - i.attrs = a; - self.fold_item_recur(i) - } - } - let mut collapser = Collapser; - let krate = collapser.fold_crate(krate); - krate -} - -pub fn unindent(s: &str) -> String { - let lines = s.lines().collect:: >(); - let mut saw_first_line = false; - let mut saw_second_line = false; - let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { - - // After we see the first non-whitespace line, look at - // the line we have. If it is not whitespace, and therefore - // part of the first paragraph, then ignore the indentation - // level of the first line - let ignore_previous_indents = - saw_first_line && - !saw_second_line && - !line.chars().all(|c| c.is_whitespace()); - - let min_indent = if ignore_previous_indents { - usize::MAX - } else { - min_indent - }; - - if saw_first_line { - saw_second_line = true; - } - - if line.chars().all(|c| c.is_whitespace()) { - min_indent - } else { - saw_first_line = true; - let mut whitespace = 0; - line.chars().all(|char| { - // Compare against either space or tab, ignoring whether they - // are mixed or not - if char == ' ' || char == '\t' { - whitespace += 1; - true - } else { - false - } - }); - cmp::min(min_indent, whitespace) - } - }); - - if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim().to_string() ]; - unindented.extend_from_slice(&lines[1..].iter().map(|&line| { - if line.chars().all(|c| c.is_whitespace()) { - line.to_string() - } else { - assert!(line.len() >= min_indent); - line[min_indent..].to_string() - } - }).collect::>()); - unindented.join("\n") - } else { - s.to_string() - } -} - -#[cfg(test)] -mod unindent_tests { - use super::unindent; - - #[test] - fn should_unindent() { - let s = " line1\n line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\nline2"); - } - - #[test] - fn should_unindent_multiple_paragraphs() { - let s = " line1\n\n line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\n\nline2"); - } - - #[test] - fn should_leave_multiple_indent_levels() { - // Line 2 is indented another level beyond the - // base indentation and should be preserved - let s = " line1\n\n line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\n\n line2"); - } - - #[test] - fn should_ignore_first_line_indent() { - // The first line of the first paragraph may not be indented as - // far due to the way the doc string was written: - // - // #[doc = "Start way over here - // and continue here"] - let s = "line1\n line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\nline2"); - } - - #[test] - fn should_not_ignore_first_line_indent_in_a_single_line_para() { - let s = "line1\n\n line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\n\n line2"); - } - - #[test] - fn should_unindent_tabs() { - let s = "\tline1\n\tline2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\nline2"); - } - - #[test] - fn should_trim_mixed_indentation() { - let s = "\t line1\n\t line2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\nline2"); - - let s = " \tline1\n \tline2".to_string(); - let r = unindent(&s); - assert_eq!(r, "line1\nline2"); - } -} diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs new file mode 100644 index 0000000000000..c034ef9326846 --- /dev/null +++ b/src/librustdoc/passes/collapse_docs.rs @@ -0,0 +1,47 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::string::String; + +use clean::{self, Item}; +use plugins; +use fold; +use fold::DocFolder; + +pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { + let mut collapser = Collapser; + let krate = collapser.fold_crate(krate); + krate +} + +struct Collapser; + +impl fold::DocFolder for Collapser { + fn fold_item(&mut self, mut i: Item) -> Option { + let mut docstr = String::new(); + for attr in &i.attrs { + if let clean::NameValue(ref x, ref s) = *attr { + if "doc" == *x { + docstr.push_str(s); + docstr.push('\n'); + } + } + } + let mut a: Vec = i.attrs.iter().filter(|&a| match a { + &clean::NameValue(ref x, _) if "doc" == *x => false, + _ => true + }).cloned().collect(); + if !docstr.is_empty() { + a.push(clean::NameValue("doc".to_string(), docstr)); + } + i.attrs = a; + self.fold_item_recur(i) + } +} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs new file mode 100644 index 0000000000000..a1b330e9b8423 --- /dev/null +++ b/src/librustdoc/passes/mod.rs @@ -0,0 +1,204 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::def_id::DefId; +use rustc::middle::privacy::AccessLevels; +use rustc::util::nodemap::DefIdSet; +use std::mem; + +use clean::{self, GetDefId, Item}; +use fold; +use fold::FoldItem::Strip; +use plugins; + +mod collapse_docs; +pub use self::collapse_docs::collapse_docs; + +mod strip_hidden; +pub use self::strip_hidden::strip_hidden; + +mod strip_private; +pub use self::strip_private::strip_private; + +mod strip_priv_imports; +pub use self::strip_priv_imports::strip_priv_imports; + +mod unindent_comments; +pub use self::unindent_comments::unindent_comments; + +type Pass = (&'static str, // name + fn(clean::Crate) -> plugins::PluginResult, // fn + &'static str); // description + +pub const PASSES: &'static [Pass] = &[ + ("strip-hidden", strip_hidden, + "strips all doc(hidden) items from the output"), + ("unindent-comments", unindent_comments, + "removes excess indentation on comments in order for markdown to like it"), + ("collapse-docs", collapse_docs, + "concatenates all document attributes into one document attribute"), + ("strip-private", strip_private, + "strips all private items from a crate which cannot be seen externally, \ + implies strip-priv-imports"), + ("strip-priv-imports", strip_priv_imports, + "strips all private import statements (`use`, `extern crate`) from a crate"), +]; + +pub const DEFAULT_PASSES: &'static [&'static str] = &[ + "strip-hidden", + "strip-private", + "collapse-docs", + "unindent-comments", +]; + + +struct Stripper<'a> { + retained: &'a mut DefIdSet, + access_levels: &'a AccessLevels, + update_retained: bool, +} + +impl<'a> fold::DocFolder for Stripper<'a> { + fn fold_item(&mut self, i: Item) -> Option { + match i.inner { + clean::StrippedItem(..) => { + // We need to recurse into stripped modules to strip things + // like impl methods but when doing so we must not add any + // items to the `retained` set. + let old = mem::replace(&mut self.update_retained, false); + let ret = self.fold_item_recur(i); + self.update_retained = old; + return ret; + } + // These items can all get re-exported + clean::TypedefItem(..) | clean::StaticItem(..) | + clean::StructItem(..) | clean::EnumItem(..) | + clean::TraitItem(..) | clean::FunctionItem(..) | + clean::VariantItem(..) | clean::MethodItem(..) | + clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | + clean::ConstantItem(..) | clean::UnionItem(..) => { + if i.def_id.is_local() { + if !self.access_levels.is_exported(i.def_id) { + return None; + } + } + } + + clean::StructFieldItem(..) => { + if i.visibility != Some(clean::Public) { + return Strip(i).fold(); + } + } + + clean::ModuleItem(..) => { + if i.def_id.is_local() && i.visibility != Some(clean::Public) { + let old = mem::replace(&mut self.update_retained, false); + let ret = Strip(self.fold_item_recur(i).unwrap()).fold(); + self.update_retained = old; + return ret; + } + } + + // handled in the `strip-priv-imports` pass + clean::ExternCrateItem(..) | clean::ImportItem(..) => {} + + clean::DefaultImplItem(..) | clean::ImplItem(..) => {} + + // tymethods/macros have no control over privacy + clean::MacroItem(..) | clean::TyMethodItem(..) => {} + + // Primitives are never stripped + clean::PrimitiveItem(..) => {} + + // Associated consts and types are never stripped + clean::AssociatedConstItem(..) | + clean::AssociatedTypeItem(..) => {} + } + + let fastreturn = match i.inner { + // nothing left to do for traits (don't want to filter their + // methods out, visibility controlled by the trait) + clean::TraitItem(..) => true, + + // implementations of traits are always public. + clean::ImplItem(ref imp) if imp.trait_.is_some() => true, + // Struct variant fields have inherited visibility + clean::VariantItem(clean::Variant { + kind: clean::StructVariant(..) + }) => true, + _ => false, + }; + + let i = if fastreturn { + if self.update_retained { + self.retained.insert(i.def_id); + } + return Some(i); + } else { + self.fold_item_recur(i) + }; + + i.and_then(|i| { + match i.inner { + // emptied modules have no need to exist + clean::ModuleItem(ref m) + if m.items.is_empty() && + i.doc_value().is_none() => None, + _ => { + if self.update_retained { + self.retained.insert(i.def_id); + } + Some(i) + } + } + }) + } +} + +// This stripper discards all impls which reference stripped items +struct ImplStripper<'a> { + retained: &'a DefIdSet +} + +impl<'a> fold::DocFolder for ImplStripper<'a> { + fn fold_item(&mut self, i: Item) -> Option { + if let clean::ImplItem(ref imp) = i.inner { + // emptied none trait impls can be stripped + if imp.trait_.is_none() && imp.items.is_empty() { + return None; + } + if let Some(did) = imp.for_.def_id() { + if did.is_local() && !imp.for_.is_generic() && + !self.retained.contains(&did) + { + return None; + } + } + if let Some(did) = imp.trait_.def_id() { + if did.is_local() && !self.retained.contains(&did) { + return None; + } + } + } + self.fold_item_recur(i) + } +} + +// This stripper discards all private import statements (`use`, `extern crate`) +struct ImportStripper; +impl fold::DocFolder for ImportStripper { + fn fold_item(&mut self, i: Item) -> Option { + match i.inner { + clean::ExternCrateItem(..) | + clean::ImportItem(..) if i.visibility != Some(clean::Public) => None, + _ => self.fold_item_recur(i) + } + } +} diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs new file mode 100644 index 0000000000000..927ccf9171999 --- /dev/null +++ b/src/librustdoc/passes/strip_hidden.rs @@ -0,0 +1,66 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::util::nodemap::DefIdSet; +use std::mem; + +use clean::{self, Attributes}; +use clean::Item; +use plugins; +use fold; +use fold::DocFolder; +use fold::FoldItem::Strip; +use passes::ImplStripper; + +/// Strip items marked `#[doc(hidden)]` +pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { + let mut retained = DefIdSet(); + + // strip all #[doc(hidden)] items + let krate = { + let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; + stripper.fold_crate(krate) + }; + + // strip all impls referencing stripped items + let mut stripper = ImplStripper { retained: &retained }; + stripper.fold_crate(krate) +} + +struct Stripper<'a> { + retained: &'a mut DefIdSet, + update_retained: bool, +} + +impl<'a> fold::DocFolder for Stripper<'a> { + fn fold_item(&mut self, i: Item) -> Option { + if i.attrs.list("doc").has_word("hidden") { + debug!("found one in strip_hidden; removing"); + // use a dedicated hidden item for given item type if any + match i.inner { + clean::StructFieldItem(..) | clean::ModuleItem(..) => { + // We need to recurse into stripped modules to + // strip things like impl methods but when doing so + // we must not add any items to the `retained` set. + let old = mem::replace(&mut self.update_retained, false); + let ret = Strip(self.fold_item_recur(i).unwrap()).fold(); + self.update_retained = old; + return ret; + } + _ => return None, + } + } else { + if self.update_retained { + self.retained.insert(i.def_id); + } + } + self.fold_item_recur(i) + } +} diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs new file mode 100644 index 0000000000000..91f8be43c281a --- /dev/null +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use clean; +use fold::DocFolder; +use plugins; +use passes::ImportStripper; + +pub fn strip_priv_imports(krate: clean::Crate) -> plugins::PluginResult { + ImportStripper.fold_crate(krate) +} diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs new file mode 100644 index 0000000000000..acd735739e488 --- /dev/null +++ b/src/librustdoc/passes/strip_private.rs @@ -0,0 +1,38 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::util::nodemap::DefIdSet; + +use clean; +use plugins; +use fold::DocFolder; +use passes::{ImplStripper, ImportStripper, Stripper}; + +/// Strip private items from the point of view of a crate or externally from a +/// crate, specified by the `xcrate` flag. +pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { + // This stripper collects all *retained* nodes. + let mut retained = DefIdSet(); + let access_levels = krate.access_levels.clone(); + + // strip all private items + { + let mut stripper = Stripper { + retained: &mut retained, + access_levels: &access_levels, + update_retained: true, + }; + krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); + } + + // strip all impls referencing private items + let mut stripper = ImplStripper { retained: &retained }; + stripper.fold_crate(krate) +} diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs new file mode 100644 index 0000000000000..20640f3f88518 --- /dev/null +++ b/src/librustdoc/passes/unindent_comments.rs @@ -0,0 +1,168 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::string::String; +use std::usize; + +use clean::{self, Item}; +use plugins; +use fold::{self, DocFolder}; + +pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult { + let mut cleaner = CommentCleaner; + let krate = cleaner.fold_crate(krate); + krate +} + +struct CommentCleaner; + +impl fold::DocFolder for CommentCleaner { + fn fold_item(&mut self, mut i: Item) -> Option { + let mut avec: Vec = Vec::new(); + for attr in &i.attrs { + match attr { + &clean::NameValue(ref x, ref s) + if "doc" == *x => { + avec.push(clean::NameValue("doc".to_string(), + unindent(s))) + } + x => avec.push(x.clone()) + } + } + i.attrs = avec; + self.fold_item_recur(i) + } +} + +fn unindent(s: &str) -> String { + let lines = s.lines().collect:: >(); + let mut saw_first_line = false; + let mut saw_second_line = false; + let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { + + // After we see the first non-whitespace line, look at + // the line we have. If it is not whitespace, and therefore + // part of the first paragraph, then ignore the indentation + // level of the first line + let ignore_previous_indents = + saw_first_line && + !saw_second_line && + !line.chars().all(|c| c.is_whitespace()); + + let min_indent = if ignore_previous_indents { + usize::MAX + } else { + min_indent + }; + + if saw_first_line { + saw_second_line = true; + } + + if line.chars().all(|c| c.is_whitespace()) { + min_indent + } else { + saw_first_line = true; + let mut whitespace = 0; + line.chars().all(|char| { + // Compare against either space or tab, ignoring whether they + // are mixed or not + if char == ' ' || char == '\t' { + whitespace += 1; + true + } else { + false + } + }); + cmp::min(min_indent, whitespace) + } + }); + + if !lines.is_empty() { + let mut unindented = vec![ lines[0].trim().to_string() ]; + unindented.extend_from_slice(&lines[1..].iter().map(|&line| { + if line.chars().all(|c| c.is_whitespace()) { + line.to_string() + } else { + assert!(line.len() >= min_indent); + line[min_indent..].to_string() + } + }).collect::>()); + unindented.join("\n") + } else { + s.to_string() + } +} + +#[cfg(test)] +mod unindent_tests { + use super::unindent; + + #[test] + fn should_unindent() { + let s = " line1\n line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } + + #[test] + fn should_unindent_multiple_paragraphs() { + let s = " line1\n\n line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\n\nline2"); + } + + #[test] + fn should_leave_multiple_indent_levels() { + // Line 2 is indented another level beyond the + // base indentation and should be preserved + let s = " line1\n\n line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\n\n line2"); + } + + #[test] + fn should_ignore_first_line_indent() { + // The first line of the first paragraph may not be indented as + // far due to the way the doc string was written: + // + // #[doc = "Start way over here + // and continue here"] + let s = "line1\n line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } + + #[test] + fn should_not_ignore_first_line_indent_in_a_single_line_para() { + let s = "line1\n\n line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\n\n line2"); + } + + #[test] + fn should_unindent_tabs() { + let s = "\tline1\n\tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } + + #[test] + fn should_trim_mixed_indentation() { + let s = "\t line1\n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + + let s = " \tline1\n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } +} diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 76eb92bd55989..5171fbdf03e80 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -903,6 +903,17 @@ mod os { pub const EXE_EXTENSION: &'static str = "js"; } +#[cfg(target_os = "haiku")] +mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "haiku"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + #[cfg(target_arch = "x86")] mod arch { pub const ARCH: &'static str = "x86"; diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs new file mode 100644 index 0000000000000..54f8ea1b71b3e --- /dev/null +++ b/src/libstd/os/haiku/fs.rs @@ -0,0 +1,138 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use libc; + +use fs::Metadata; +use sys_common::AsInner; + +#[allow(deprecated)] +use os::haiku::raw; + +/// OS-specific extension methods for `fs::Metadata` +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned `stat` are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated(since = "1.8.0", + reason = "deprecated in favor of the accessor \ + methods of this trait")] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_crtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_crtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { + &*(self.as_inner().as_inner() as *const libc::stat + as *const raw::stat) + } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_crtime(&self) -> i64 { + self.as_inner().as_inner().st_crtime as i64 + } + fn st_crtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_crtime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/src/libstd/os/haiku/mod.rs b/src/libstd/os/haiku/mod.rs new file mode 100644 index 0000000000000..dd1675cc9b51f --- /dev/null +++ b/src/libstd/os/haiku/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Haiku-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/src/libstd/os/haiku/raw.rs b/src/libstd/os/haiku/raw.rs new file mode 100644 index 0000000000000..95353d999f952 --- /dev/null +++ b/src/libstd/os/haiku/raw.rs @@ -0,0 +1,74 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Haiku-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +#![allow(deprecated)] + +use os::raw::{c_long}; +use os::unix::raw::{uid_t, gid_t}; + +// Use the direct definition of usize, instead of uintptr_t like in libc +#[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = usize; + +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32; + +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: blksize_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_crtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_crtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_type: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: blkcnt_t, +} diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index a91d251fc120a..7622ef886935c 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -24,6 +24,7 @@ pub use sys::ext as windows; #[cfg(target_os = "bitrig")] pub mod bitrig; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "freebsd")] pub mod freebsd; +#[cfg(target_os = "haiku")] pub mod haiku; #[cfg(target_os = "ios")] pub mod ios; #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "macos")] pub mod macos; diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index a11200873d500..5dc6ee2bc8c66 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -62,3 +62,7 @@ extern {} #[cfg(target_os = "ios")] #[link(name = "System")] extern {} + +#[cfg(target_os = "haiku")] +#[link(name = "network")] +extern {} diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs index fad2c277da417..b5330463e30c4 100644 --- a/src/libstd/sys/common/args.rs +++ b/src/libstd/sys/common/args.rs @@ -38,7 +38,8 @@ pub fn clone() -> Option>> { imp::clone() } target_os = "netbsd", target_os = "openbsd", target_os = "solaris", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "haiku"))] mod imp { use libc::c_char; use mem; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index a777cfe35e56d..18280e497db1d 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -24,22 +24,22 @@ use time::Duration; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris")))] + target_os = "solaris", taget_os = "haiku")))] use sys::net::netc::IPV6_ADD_MEMBERSHIP; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris")))] + target_os = "solaris", target_os = "haiku")))] use sys::net::netc::IPV6_DROP_MEMBERSHIP; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index b2b1f16f20a9a..60c1750b4693c 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -59,14 +59,20 @@ impl FileDesc { Ok(ret as usize) } - #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))] + #[cfg(not(any(target_env = "newlib", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku")))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { cvt(libc::ioctl(self.fd, libc::FIOCLEX))?; Ok(()) } } - #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))] + #[cfg(any(target_env = "newlib", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku"))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; @@ -104,9 +110,9 @@ impl FileDesc { // resolve so we at least compile this. // // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_os = "haiku"))] use libc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(target_os = "android"))] + #[cfg(not(any(target_os = "android", target_os="haiku")))] use libc::F_DUPFD_CLOEXEC; let make_filedesc = |fd| { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index e6fe3eb112a60..d015aeee338db 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -279,7 +279,12 @@ impl DirEntry { stat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(target_os = "solaris"))] + #[cfg(target_os = "haiku")] + pub fn file_type(&self) -> io::Result { + lstat(&self.path()).map(|m| m.file_type()) + } + + #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] pub fn file_type(&self) -> io::Result { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -298,7 +303,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "android", - target_os = "solaris"))] + target_os = "solaris", + target_os = "haiku"))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } @@ -327,7 +333,8 @@ impl DirEntry { } #[cfg(any(target_os = "android", target_os = "linux", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "haiku"))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 23687e10e476d..3fbeda58e821d 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -17,6 +17,7 @@ use libc; #[cfg(target_os = "bitrig")] pub use os::bitrig as platform; #[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; #[cfg(target_os = "freebsd")] pub use os::freebsd as platform; +#[cfg(target_os = "haiku")] pub use os::haiku as platform; #[cfg(target_os = "ios")] pub use os::ios as platform; #[cfg(target_os = "linux")] pub use os::linux as platform; #[cfg(target_os = "macos")] pub use os::macos as platform; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index f124ea651ec2c..ec7ccdf5894fd 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -10,7 +10,7 @@ use ffi::CStr; use io; -use libc::{self, c_int, size_t, sockaddr, socklen_t}; +use libc::{self, c_int, size_t, sockaddr, socklen_t, EAI_SYSTEM}; use net::{SocketAddr, Shutdown}; use str; use sys::fd::FileDesc; @@ -38,7 +38,12 @@ pub struct Socket(FileDesc); pub fn init() {} pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { return Ok(()) } + if err == 0 { + return Ok(()) + } + if err == EAI_SYSTEM { + return Err(io::Error::last_os_error()) + } let detail = unsafe { str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap() diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 82606d2c728ea..850c3d5271536 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -51,6 +51,7 @@ extern { target_os = "ios", target_os = "freebsd"), link_name = "__error")] + #[cfg_attr(target_os = "haiku", link_name = "_errnop")] fn errno_location() -> *mut c_int; } @@ -303,6 +304,49 @@ pub fn current_exe() -> io::Result { } } +#[cfg(target_os = "haiku")] +pub fn current_exe() -> io::Result { + // Use Haiku's image info functions + #[repr(C)] + struct image_info { + id: i32, + type_: i32, + sequence: i32, + init_order: i32, + init_routine: *mut libc::c_void, // function pointer + term_routine: *mut libc::c_void, // function pointer + device: libc::dev_t, + node: libc::ino_t, + name: [libc::c_char; 1024], // MAXPATHLEN + text: *mut libc::c_void, + data: *mut libc::c_void, + text_size: i32, + data_size: i32, + api_version: i32, + abi: i32, + } + + unsafe { + extern { + fn _get_next_image_info(team_id: i32, cookie: *mut i32, + info: *mut image_info, size: i32) -> i32; + } + + let mut info: image_info = mem::zeroed(); + let mut cookie: i32 = 0; + // the executable can be found at team id 0 + let result = _get_next_image_info(0, &mut cookie, &mut info, + mem::size_of::() as i32); + if result != 0 { + use io::ErrorKind; + Err(io::Error::new(ErrorKind::Other, "Error getting executable path")) + } else { + let name = CStr::from_ptr(info.name.as_ptr()).to_bytes(); + Ok(PathBuf::from(OsStr::from_bytes(name))) + } + } +} + pub struct Args { iter: vec::IntoIter, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -412,7 +456,8 @@ pub fn args() -> Args { target_os = "openbsd", target_os = "solaris", target_os = "nacl", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "haiku"))] pub fn args() -> Args { use sys_common; let bytes = sys_common::args::clone().unwrap_or(Vec::new()); diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 5db7086e42752..980ef01f549c3 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -115,9 +115,12 @@ impl Thread { name.as_ptr() as *mut libc::c_void); } } - #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))] + #[cfg(any(target_env = "newlib", + target_os = "solaris", + target_os = "haiku", + target_os = "emscripten"))] pub fn set_name(_name: &CStr) { - // Newlib, Illumos and Emscripten have no way to set a thread name. + // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. } pub fn sleep(dur: Duration) { diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 64a71133a8c02..1f2dc228ded34 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -24,6 +24,7 @@ pub enum Os { Netbsd, Openbsd, NaCl, + Haiku, Solaris, } @@ -146,6 +147,7 @@ impl fmt::Display for Os { Os::Netbsd => "netbsd".fmt(f), Os::Openbsd => "openbsd".fmt(f), Os::NaCl => "nacl".fmt(f), + Os::Haiku => "haiku".fmt(f), Os::Solaris => "solaris".fmt(f), } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3e85565beb6d1..495ad176542c1 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -18,8 +18,7 @@ use errors::DiagnosticBuilder; use ext::expand::{self, Invocation, Expansion}; use ext::hygiene::Mark; use fold::{self, Folder}; -use parse; -use parse::parser::{self, Parser}; +use parse::{self, parser}; use parse::token; use parse::token::{InternedString, str_to_ident}; use ptr::P; @@ -188,146 +187,6 @@ impl AttrProcMacro for F } } -pub struct TokResult<'a> { - pub parser: Parser<'a>, - pub span: Span, -} - -impl<'a> TokResult<'a> { - // There is quite a lot of overlap here with ParserAnyMacro in ext/tt/macro_rules.rs - // We could probably share more code. - // FIXME(#36641) Unify TokResult and ParserAnyMacro. - fn ensure_complete_parse(&mut self, allow_semi: bool) { - let macro_span = &self.span; - self.parser.ensure_complete_parse(allow_semi, |parser| { - let token_str = parser.this_token_to_string(); - let msg = format!("macro expansion ignores token `{}` and any following", token_str); - let span = parser.span; - parser.diagnostic() - .struct_span_err(span, &msg) - .span_note(*macro_span, "caused by the macro expansion here") - .emit(); - }); - } -} - -impl<'a> MacResult for TokResult<'a> { - fn make_items(mut self: Box) -> Option>> { - if self.parser.sess.span_diagnostic.has_errors() { - return Some(SmallVector::zero()); - } - - let mut items = SmallVector::zero(); - loop { - match self.parser.parse_item() { - Ok(Some(item)) => items.push(item), - Ok(None) => { - self.ensure_complete_parse(false); - return Some(items); - } - Err(mut e) => { - e.emit(); - return Some(SmallVector::zero()); - } - } - } - } - - fn make_impl_items(mut self: Box) -> Option> { - let mut items = SmallVector::zero(); - loop { - if self.parser.token == token::Eof { - break; - } - match self.parser.parse_impl_item() { - Ok(item) => items.push(item), - Err(mut e) => { - e.emit(); - return Some(SmallVector::zero()); - } - } - } - self.ensure_complete_parse(false); - Some(items) - } - - fn make_trait_items(mut self: Box) -> Option> { - let mut items = SmallVector::zero(); - loop { - if self.parser.token == token::Eof { - break; - } - match self.parser.parse_trait_item() { - Ok(item) => items.push(item), - Err(mut e) => { - e.emit(); - return Some(SmallVector::zero()); - } - } - } - self.ensure_complete_parse(false); - Some(items) - } - - fn make_expr(mut self: Box) -> Option> { - match self.parser.parse_expr() { - Ok(e) => { - self.ensure_complete_parse(true); - Some(e) - } - Err(mut e) => { - e.emit(); - Some(DummyResult::raw_expr(self.span)) - } - } - } - - fn make_pat(mut self: Box) -> Option> { - match self.parser.parse_pat() { - Ok(e) => { - self.ensure_complete_parse(false); - Some(e) - } - Err(mut e) => { - e.emit(); - Some(P(DummyResult::raw_pat(self.span))) - } - } - } - - fn make_stmts(mut self: Box) -> Option> { - let mut stmts = SmallVector::zero(); - loop { - if self.parser.token == token::Eof { - break; - } - match self.parser.parse_full_stmt(false) { - Ok(Some(stmt)) => stmts.push(stmt), - Ok(None) => { /* continue */ } - Err(mut e) => { - e.emit(); - return Some(SmallVector::zero()); - } - } - } - self.ensure_complete_parse(false); - Some(stmts) - } - - fn make_ty(mut self: Box) -> Option> { - match self.parser.parse_ty() { - Ok(e) => { - self.ensure_complete_parse(false); - Some(e) - } - Err(mut e) => { - e.emit(); - Some(DummyResult::raw_ty(self.span)) - } - } - } -} - /// Represents a thing that maps token trees to Macro Results pub trait TTMacroExpander { fn expand<'cx>(&self, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 43c622189632a..8436835da3e1d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{Block, Crate, Ident, Mac_, PatKind}; -use ast::{MacStmtStyle, StmtKind, ItemKind}; +use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; use ext::placeholders::{placeholder, PlaceholderExpander}; @@ -21,9 +21,9 @@ use ext::base::*; use feature_gate::{self, Features}; use fold; use fold::*; -use parse::{ParseSess, lexer}; +use parse::{ParseSess, PResult, lexer}; use parse::parser::Parser; -use parse::token::{intern, keywords}; +use parse::token::{self, intern, keywords}; use print::pprust; use ptr::P; use tokenstream::{TokenTree, TokenStream}; @@ -38,12 +38,12 @@ macro_rules! expansions { ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*, $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { - #[derive(Copy, Clone)] + #[derive(Copy, Clone, PartialEq, Eq)] pub enum ExpansionKind { OptExpr, $( $kind, )* } pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* } impl ExpansionKind { - fn name(self) -> &'static str { + pub fn name(self) -> &'static str { match self { ExpansionKind::OptExpr => "expression", $( ExpansionKind::$kind => $kind_name, )* @@ -106,6 +106,12 @@ macro_rules! expansions { self.expand(Expansion::$kind(SmallVector::one(node))).$make() })*)* } + + impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> { + $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> { + Some(self.make(ExpansionKind::$kind).$make()) + })* + } } } @@ -293,10 +299,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); + let name = intern(&attr.name()); self.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(intern(&attr.name())), + format: MacroAttribute(name), span: Some(attr.span), allow_internal_unstable: false, } @@ -319,14 +326,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item_toks = TokenStream::from_tts(tts_for_item(&item, &self.cx.parse_sess)); let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); - let parser = self.cx.new_parser_from_tts(&tok_result.to_tts()); - let result = Box::new(TokResult { parser: parser, span: attr.span }); - - kind.make_from(result).unwrap_or_else(|| { - let msg = format!("macro could not be expanded into {} position", kind.name()); - self.cx.span_err(attr.span, &msg); - kind.dummy(attr.span) - }) + self.parse_expansion(tok_result, kind, name, attr.span) } _ => unreachable!(), } @@ -423,14 +423,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }, }); - - let tok_result = expandfun.expand(self.cx, - span, - TokenStream::from_tts(marked_tts)); - let parser = self.cx.new_parser_from_tts(&tok_result.to_tts()); - let result = Box::new(TokResult { parser: parser, span: span }); - // FIXME better span info. - kind.make_from(result).map(|i| i.fold_with(&mut ChangeSpan { span: span })) + let toks = TokenStream::from_tts(marked_tts); + let tok_result = expandfun.expand(self.cx, span, toks); + Some(self.parse_expansion(tok_result, kind, extname, span)) } }; @@ -448,6 +443,75 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expn_id: Some(self.cx.backtrace()), }) } + + fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span) + -> Expansion { + let mut parser = self.cx.new_parser_from_tts(&toks.to_tts()); + let expansion = match parser.parse_expansion(kind, false) { + Ok(expansion) => expansion, + Err(mut err) => { + err.emit(); + return kind.dummy(span); + } + }; + parser.ensure_complete_parse(name, kind.name(), span); + // FIXME better span info + expansion.fold_with(&mut ChangeSpan { span: span }) + } +} + +impl<'a> Parser<'a> { + pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool) + -> PResult<'a, Expansion> { + Ok(match kind { + ExpansionKind::Items => { + let mut items = SmallVector::zero(); + while let Some(item) = self.parse_item()? { + items.push(item); + } + Expansion::Items(items) + } + ExpansionKind::TraitItems => { + let mut items = SmallVector::zero(); + while self.token != token::Eof { + items.push(self.parse_trait_item()?); + } + Expansion::TraitItems(items) + } + ExpansionKind::ImplItems => { + let mut items = SmallVector::zero(); + while self.token != token::Eof { + items.push(self.parse_impl_item()?); + } + Expansion::ImplItems(items) + } + ExpansionKind::Stmts => { + let mut stmts = SmallVector::zero(); + while self.token != token::Eof { + if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? { + stmts.push(stmt); + } + } + Expansion::Stmts(stmts) + } + ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), + ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)), + ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), + ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), + }) + } + + pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) { + if self.token != token::Eof { + let msg = format!("macro expansion ignores token `{}` and any following", + self.this_token_to_string()); + let mut err = self.diagnostic().struct_span_err(self.span, &msg); + let msg = format!("caused by the macro expansion here; the usage \ + of `{}!` is likely invalid in {} context", + macro_name, kind_name); + err.span_note(span, &msg).emit(); + } + } } struct InvocationCollector<'a, 'b: 'a> { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 0eed3e5898c00..9f4c0b5eb808f 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,6 +12,7 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension}; use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander}; +use ext::expand::{Expansion, ExpansionKind}; use ext::placeholders; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; @@ -22,18 +23,14 @@ use parse::parser::{Parser, Restrictions}; use parse::token::{self, gensym_ident, NtTT, Token}; use parse::token::Token::*; use print; -use ptr::P; use tokenstream::{self, TokenTree}; -use util::small_vector::SmallVector; - -use std::cell::RefCell; use std::collections::{HashMap}; use std::collections::hash_map::{Entry}; use std::rc::Rc; -struct ParserAnyMacro<'a> { - parser: RefCell>, +pub struct ParserAnyMacro<'a> { + parser: Parser<'a>, /// Span of the expansion site of the macro this parser is for site_span: Span, @@ -42,106 +39,20 @@ struct ParserAnyMacro<'a> { } impl<'a> ParserAnyMacro<'a> { - /// Make sure we don't have any tokens left to parse, so we don't - /// silently drop anything. `allow_semi` is so that "optional" - /// semicolons at the end of normal expressions aren't complained - /// about e.g. the semicolon in `macro_rules! kapow { () => { - /// panic!(); } }` doesn't get picked up by .parse_expr(), but it's - /// allowed to be there. - fn ensure_complete_parse(&self, allow_semi: bool, context: &str) { - let mut parser = self.parser.borrow_mut(); - parser.ensure_complete_parse(allow_semi, |parser| { - let token_str = parser.this_token_to_string(); - let msg = format!("macro expansion ignores token `{}` and any \ - following", - token_str); - let span = parser.span; - let mut err = parser.diagnostic().struct_span_err(span, &msg); - let msg = format!("caused by the macro expansion here; the usage \ - of `{}!` is likely invalid in {} context", - self.macro_ident, context); - err.span_note(self.site_span, &msg) - .emit(); - }); - } -} - -impl<'a> MacResult for ParserAnyMacro<'a> { - fn make_expr(self: Box>) -> Option> { - let ret = panictry!(self.parser.borrow_mut().parse_expr()); - self.ensure_complete_parse(true, "expression"); - Some(ret) - } - fn make_pat(self: Box>) -> Option> { - let ret = panictry!(self.parser.borrow_mut().parse_pat()); - self.ensure_complete_parse(false, "pattern"); - Some(ret) - } - fn make_items(self: Box>) -> Option>> { - let mut ret = SmallVector::zero(); - while let Some(item) = panictry!(self.parser.borrow_mut().parse_item()) { - ret.push(item); - } - self.ensure_complete_parse(false, "item"); - Some(ret) - } - - fn make_impl_items(self: Box>) - -> Option> { - let mut ret = SmallVector::zero(); - loop { - let mut parser = self.parser.borrow_mut(); - match parser.token { - token::Eof => break, - _ => ret.push(panictry!(parser.parse_impl_item())) - } - } - self.ensure_complete_parse(false, "item"); - Some(ret) - } - - fn make_trait_items(self: Box>) - -> Option> { - let mut ret = SmallVector::zero(); - loop { - let mut parser = self.parser.borrow_mut(); - match parser.token { - token::Eof => break, - _ => ret.push(panictry!(parser.parse_trait_item())) - } - } - self.ensure_complete_parse(false, "item"); - Some(ret) - } - - - fn make_stmts(self: Box>) - -> Option> { - let mut ret = SmallVector::zero(); - loop { - let mut parser = self.parser.borrow_mut(); - match parser.token { - token::Eof => break, - _ => match parser.parse_full_stmt(true) { - Ok(maybe_stmt) => match maybe_stmt { - Some(stmt) => ret.push(stmt), - None => (), - }, - Err(mut e) => { - e.emit(); - break; - } - } - } + pub fn make(mut self: Box>, kind: ExpansionKind) -> Expansion { + let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self; + let expansion = panictry!(parser.parse_expansion(kind, true)); + + // We allow semicolons at the end of expressions -- e.g. the semicolon in + // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`, + // but `m!()` is allowed in expression positions (c.f. issue #34706). + if kind == ExpansionKind::Expr && parser.token == token::Semi { + parser.bump(); } - self.ensure_complete_parse(false, "statement"); - Some(ret) - } - fn make_ty(self: Box>) -> Option> { - let ret = panictry!(self.parser.borrow_mut().parse_ty()); - self.ensure_complete_parse(false, "type"); - Some(ret) + // Make sure we don't have any tokens left to parse so we don't silently drop anything. + parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span); + expansion } } @@ -219,7 +130,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { - parser: RefCell::new(p), + parser: p, // Pass along the original expansion site and the name of the macro // so we can print a useful error message if the parse of the expanded @@ -332,7 +243,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { (**tt).clone() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") - }).collect() + }).collect::>() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }; @@ -351,6 +262,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { valid &= check_rhs(sess, rhs); } + // don't abort iteration early, so that errors for multiple lhses can be reported + for lhs in &lhses { + valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()]) + } + let exp: Box<_> = Box::new(MacroRulesMacroExpander { name: def.ident, imported_from: def.imported_from, @@ -377,6 +293,38 @@ fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool { // after parsing/expansion. we can report every error in every macro this way. } +/// Check that the lhs contains no repetition which could match an empty token +/// tree, because then the matcher would hang indefinitely. +fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool { + for tt in tts { + match *tt { + TokenTree::Token(_, _) => (), + TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) { + return false; + }, + TokenTree::Sequence(span, ref seq) => { + if seq.separator.is_none() { + if seq.tts.iter().all(|seq_tt| { + match *seq_tt { + TokenTree::Sequence(_, ref sub_seq) => + sub_seq.op == tokenstream::KleeneOp::ZeroOrMore, + _ => false, + } + }) { + sess.span_diagnostic.span_err(span, "repetition matches empty token tree"); + return false; + } + } + if !check_lhs_no_empty_seq(sess, &seq.tts) { + return false; + } + } + } + } + + true +} + fn check_rhs(sess: &ParseSess, rhs: &TokenTree) -> bool { match *rhs { TokenTree::Delimited(..) => return true, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 23085fadc5e60..d5ed1d157e47a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -542,11 +542,6 @@ impl<'a> Parser<'a> { } } - fn parse_ident_into_path(&mut self) -> PResult<'a, ast::Path> { - let ident = self.parse_ident()?; - Ok(ast::Path::from_ident(self.last_span, ident)) - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -1202,94 +1197,87 @@ impl<'a> Parser<'a> { None }; (ident, TraitItemKind::Const(ty, default)) - } else if !self.token.is_any_keyword() - && self.look_ahead(1, |t| *t == token::Not) - && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) - || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { - // trait item macro. - // code copied from parse_macro_use_or_failure... abstraction! - let lo = self.span.lo; - let pth = self.parse_ident_into_path()?; - self.expect(&token::Not)?; + } else if self.token.is_path_start() { + // trait item macro. + // code copied from parse_macro_use_or_failure... abstraction! + let lo = self.span.lo; + let pth = self.parse_path(PathStyle::Mod)?; + self.expect(&token::Not)?; - // eat a matched-delimiter token tree: - let delim = self.expect_open_delim()?; - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), - SeqSep::none(), - |pp| pp.parse_token_tree())?; - let m_ = Mac_ { path: pth, tts: tts }; - let m: ast::Mac = codemap::Spanned { node: m_, - span: mk_sp(lo, - self.last_span.hi) }; - if delim != token::Brace { - self.expect(&token::Semi)? - } - (keywords::Invalid.ident(), ast::TraitItemKind::Macro(m)) - } else { - let (constness, unsafety, abi) = match self.parse_fn_front_matter() { - Ok(cua) => cua, - Err(e) => { - loop { - match self.token { - token::Eof => break, - token::CloseDelim(token::Brace) | - token::Semi => { - self.bump(); - break; - } - token::OpenDelim(token::Brace) => { - self.parse_token_tree()?; - break; - } - _ => self.bump() + // eat a matched-delimiter token tree: + let delim = self.expect_open_delim()?; + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + SeqSep::none(), + |pp| pp.parse_token_tree())?; + if delim != token::Brace { + self.expect(&token::Semi)? + } + + let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts }); + (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) + } else { + let (constness, unsafety, abi) = match self.parse_fn_front_matter() { + Ok(cua) => cua, + Err(e) => { + loop { + match self.token { + token::Eof => break, + token::CloseDelim(token::Brace) | + token::Semi => { + self.bump(); + break; + } + token::OpenDelim(token::Brace) => { + self.parse_token_tree()?; + break; } + _ => self.bump(), } - - return Err(e); } - }; - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; + return Err(e); + } + }; - let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ - // This is somewhat dubious; We don't want to allow - // argument names to be left off if there is a - // definition... - p.parse_arg_general(false) - })?; + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; - generics.where_clause = self.parse_where_clause()?; - let sig = ast::MethodSig { - unsafety: unsafety, - constness: constness, - decl: d, - generics: generics, - abi: abi, - }; + let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a + // definition... + p.parse_arg_general(false) + })?; - let body = match self.token { - token::Semi => { - self.bump(); - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - let (inner_attrs, body) = - self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } + generics.where_clause = self.parse_where_clause()?; + let sig = ast::MethodSig { + unsafety: unsafety, + constness: constness, + decl: d, + generics: generics, + abi: abi, + }; - _ => { - let token_str = self.this_token_to_string(); - return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", - token_str)[..])) - } - }; - (ident, ast::TraitItemKind::Method(sig, body)) + let body = match self.token { + token::Semi => { + self.bump(); + debug!("parse_trait_methods(): parsing required method"); + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_methods(): parsing provided method"); + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str))); + } }; + (ident, ast::TraitItemKind::Method(sig, body)) + }; + Ok(TraitItem { id: ast::DUMMY_NODE_ID, ident: name, @@ -1430,9 +1418,8 @@ impl<'a> Parser<'a> { TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Type)?; - if self.check(&token::Not) { + if self.eat(&token::Not) { // MACRO INVOCATION - self.bump(); let delim = self.expect_open_delim()?; let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), @@ -2310,21 +2297,14 @@ impl<'a> Parser<'a> { let pth = self.parse_path(PathStyle::Expr)?; // `!`, as an operator, is prefix, so we know this isn't that - if self.check(&token::Not) { + if self.eat(&token::Not) { // MACRO INVOCATION expression - self.bump(); - let delim = self.expect_open_delim()?; - let tts = self.parse_seq_to_end( - &token::CloseDelim(delim), - SeqSep::none(), - |p| p.parse_token_tree())?; + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + SeqSep::none(), + |p| p.parse_token_tree())?; let hi = self.last_span.hi; - - return Ok(self.mk_mac_expr(lo, - hi, - Mac_ { path: pth, tts: tts }, - attrs)); + return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited @@ -2333,51 +2313,7 @@ impl<'a> Parser<'a> { Restrictions::RESTRICTION_NO_STRUCT_LITERAL ); if !prohibited { - // It's a struct literal. - self.bump(); - let mut fields = Vec::new(); - let mut base = None; - - attrs.extend(self.parse_inner_attributes()?); - - while self.token != token::CloseDelim(token::Brace) { - if self.eat(&token::DotDot) { - match self.parse_expr() { - Ok(e) => { - base = Some(e); - } - Err(mut e) => { - e.emit(); - self.recover_stmt(); - } - } - break; - } - - match self.parse_field() { - Ok(f) => fields.push(f), - Err(mut e) => { - e.emit(); - self.recover_stmt(); - break; - } - } - - match self.expect_one_of(&[token::Comma], - &[token::CloseDelim(token::Brace)]) { - Ok(()) => {} - Err(mut e) => { - e.emit(); - self.recover_stmt(); - break; - } - } - } - - hi = self.span.hi; - self.expect(&token::CloseDelim(token::Brace))?; - ex = ExprKind::Struct(pth, fields, base); - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return self.parse_struct_expr(lo, pth, attrs); } } @@ -2403,6 +2339,53 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo, hi, ex, attrs)); } + fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec) + -> PResult<'a, P> { + self.bump(); + let mut fields = Vec::new(); + let mut base = None; + + attrs.extend(self.parse_inner_attributes()?); + + while self.token != token::CloseDelim(token::Brace) { + if self.eat(&token::DotDot) { + match self.parse_expr() { + Ok(e) => { + base = Some(e); + } + Err(mut e) => { + e.emit(); + self.recover_stmt(); + } + } + break; + } + + match self.parse_field() { + Ok(f) => fields.push(f), + Err(mut e) => { + e.emit(); + self.recover_stmt(); + break; + } + } + + match self.expect_one_of(&[token::Comma], + &[token::CloseDelim(token::Brace)]) { + Ok(()) => {} + Err(mut e) => { + e.emit(); + self.recover_stmt(); + break; + } + } + } + + let hi = self.span.hi; + self.expect(&token::CloseDelim(token::Brace))?; + return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs)); + } + fn parse_or_use_outer_attributes(&mut self, already_parsed_attrs: Option>) -> PResult<'a, ThinVec> { @@ -3577,39 +3560,37 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let pat; match self.token { - token::Underscore => { - // Parse _ - self.bump(); - pat = PatKind::Wild; - } - token::BinOp(token::And) | token::AndAnd => { - // Parse &pat / &mut pat - self.expect_and()?; - let mutbl = self.parse_mutability()?; - if let token::Lifetime(ident) = self.token { - return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); + token::Underscore => { + // Parse _ + self.bump(); + pat = PatKind::Wild; + } + token::BinOp(token::And) | token::AndAnd => { + // Parse &pat / &mut pat + self.expect_and()?; + let mutbl = self.parse_mutability()?; + if let token::Lifetime(ident) = self.token { + return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); + } + let subpat = self.parse_pat()?; + pat = PatKind::Ref(subpat, mutbl); + } + token::OpenDelim(token::Paren) => { + // Parse (pat,pat,pat,...) as tuple pattern + self.bump(); + let (fields, ddpos) = self.parse_pat_tuple_elements(true)?; + self.expect(&token::CloseDelim(token::Paren))?; + pat = PatKind::Tuple(fields, ddpos); + } + token::OpenDelim(token::Bracket) => { + // Parse [pat,pat,...] as slice pattern + self.bump(); + let (before, slice, after) = self.parse_pat_vec_elements()?; + self.expect(&token::CloseDelim(token::Bracket))?; + pat = PatKind::Vec(before, slice, after); } - - let subpat = self.parse_pat()?; - pat = PatKind::Ref(subpat, mutbl); - } - token::OpenDelim(token::Paren) => { - // Parse (pat,pat,pat,...) as tuple pattern - self.bump(); - let (fields, ddpos) = self.parse_pat_tuple_elements(true)?; - self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::Tuple(fields, ddpos); - } - token::OpenDelim(token::Bracket) => { - // Parse [pat,pat,...] as slice pattern - self.bump(); - let (before, slice, after) = self.parse_pat_vec_elements()?; - self.expect(&token::CloseDelim(token::Bracket))?; - pat = PatKind::Vec(before, slice, after); - } - _ => { // At this point, token != _, &, &&, (, [ - if self.eat_keyword(keywords::Mut) { + _ => if self.eat_keyword(keywords::Mut) { // Parse mut ident @ pat pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?; } else if self.eat_keyword(keywords::Ref) { @@ -3620,43 +3601,39 @@ impl<'a> Parser<'a> { // Parse box pat let subpat = self.parse_pat()?; pat = PatKind::Box(subpat); + } else if self.token.is_ident() && self.token.is_path_start() && + self.look_ahead(1, |t| match *t { + token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | + token::DotDotDot | token::ModSep | token::Not => false, + _ => true, + }) { + // Parse ident @ pat + // This can give false positives and parse nullary enums, + // they are dealt with later in resolve + let binding_mode = BindingMode::ByValue(Mutability::Immutable); + pat = self.parse_pat_ident(binding_mode)?; } else if self.token.is_path_start() { // Parse pattern starting with a path - if self.token.is_ident() && self.look_ahead(1, |t| *t != token::DotDotDot && - *t != token::OpenDelim(token::Brace) && - *t != token::OpenDelim(token::Paren) && - *t != token::ModSep) { - // Plain idents have some extra abilities here compared to general paths - if self.look_ahead(1, |t| *t == token::Not) { + let (qself, path) = if self.eat_lt() { + // Parse a qualified path + let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?; + (Some(qself), path) + } else { + // Parse an unqualified path + (None, self.parse_path(PathStyle::Expr)?) + }; + match self.token { + token::Not if qself.is_none() => { // Parse macro invocation - let path = self.parse_ident_into_path()?; self.bump(); let delim = self.expect_open_delim()?; - let tts = self.parse_seq_to_end( - &token::CloseDelim(delim), - SeqSep::none(), |p| p.parse_token_tree())?; - let mac = Mac_ { path: path, tts: tts }; - pat = PatKind::Mac(codemap::Spanned {node: mac, - span: mk_sp(lo, self.last_span.hi)}); - } else { - // Parse ident @ pat - // This can give false positives and parse nullary enums, - // they are dealt with later in resolve - let binding_mode = BindingMode::ByValue(Mutability::Immutable); - pat = self.parse_pat_ident(binding_mode)?; + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + SeqSep::none(), + |p| p.parse_token_tree())?; + let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts }); + pat = PatKind::Mac(mac); } - } else { - let (qself, path) = if self.eat_lt() { - // Parse a qualified path - let (qself, path) = - self.parse_qualified_path(PathStyle::Expr)?; - (Some(qself), path) - } else { - // Parse an unqualified path - (None, self.parse_path(PathStyle::Expr)?) - }; - match self.token { - token::DotDotDot => { + token::DotDotDot => { // Parse range let hi = self.last_span.hi; let begin = @@ -3664,9 +3641,9 @@ impl<'a> Parser<'a> { self.bump(); let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end); - } - token::OpenDelim(token::Brace) => { - if qself.is_some() { + } + token::OpenDelim(token::Brace) => { + if qself.is_some() { return Err(self.fatal("unexpected `{` after qualified path")); } // Parse struct pattern @@ -3678,8 +3655,8 @@ impl<'a> Parser<'a> { }); self.bump(); pat = PatKind::Struct(path, fields, etc); - } - token::OpenDelim(token::Paren) => { + } + token::OpenDelim(token::Paren) => { if qself.is_some() { return Err(self.fatal("unexpected `(` after qualified path")); } @@ -3688,11 +3665,8 @@ impl<'a> Parser<'a> { let (fields, ddpos) = self.parse_pat_tuple_elements(false)?; self.expect(&token::CloseDelim(token::Paren))?; pat = PatKind::TupleStruct(path, fields, ddpos) - } - _ => { - pat = PatKind::Path(qself, path); - } } + _ => pat = PatKind::Path(qself, path), } } else { // Try to parse everything else as literal with optional minus @@ -3712,7 +3686,6 @@ impl<'a> Parser<'a> { } } } - } } let hi = self.last_span.hi; @@ -3894,16 +3867,33 @@ impl<'a> Parser<'a> { node: StmtKind::Local(self.parse_local(attrs.into())?), span: mk_sp(lo, self.last_span.hi), } - } else if self.token.is_ident() - && !self.token.is_any_keyword() - && self.look_ahead(1, |t| *t == token::Not) { - // it's a macro invocation: + } else if self.token.is_path_start() && self.token != token::Lt && { + !self.check_keyword(keywords::Union) || + self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep) + } { + let pth = self.parse_path(PathStyle::Expr)?; - // Potential trouble: if we allow macros with paths instead of - // idents, we'd need to look ahead past the whole path here... - let pth = self.parse_ident_into_path()?; - self.bump(); + if !self.eat(&token::Not) { + let expr = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_struct_expr(lo, pth, ThinVec::new())? + } else { + let hi = self.last_span.hi; + self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) + }; + + let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| { + let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + })?; + return Ok(Some(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Expr(expr), + span: mk_sp(lo, self.last_span.hi), + })); + } + + // it's a macro invocation let id = match self.token { token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier _ => self.parse_ident()?, @@ -4857,17 +4847,14 @@ impl<'a> Parser<'a> { fn parse_impl_method(&mut self, vis: &Visibility) -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! - if !self.token.is_any_keyword() - && self.look_ahead(1, |t| *t == token::Not) - && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) - || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { + if self.token.is_path_start() { // method macro. let last_span = self.last_span; self.complain_if_pub_macro(&vis, last_span); let lo = self.span.lo; - let pth = self.parse_ident_into_path()?; + let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; // eat a matched-delimiter token tree: @@ -4875,14 +4862,12 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - let m_ = Mac_ { path: pth, tts: tts }; - let m: ast::Mac = codemap::Spanned { node: m_, - span: mk_sp(lo, - self.last_span.hi) }; if delim != token::Brace { self.expect(&token::Semi)? } - Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(m))) + + let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts }); + Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; @@ -5979,11 +5964,7 @@ impl<'a> Parser<'a> { lo: BytePos, visibility: Visibility ) -> PResult<'a, Option>> { - if macros_allowed && !self.token.is_any_keyword() - && self.look_ahead(1, |t| *t == token::Not) - && (self.look_ahead(2, |t| t.is_ident()) - || self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) - || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { + if macros_allowed && self.token.is_path_start() { // MACRO INVOCATION ITEM let last_span = self.last_span; @@ -5992,7 +5973,7 @@ impl<'a> Parser<'a> { let mac_lo = self.span.lo; // item macro. - let pth = self.parse_ident_into_path()?; + let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; // a 'special' identifier (like what `macro_rules!` uses) @@ -6008,12 +5989,6 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - // single-variant-enum... : - let m = Mac_ { path: pth, tts: tts }; - let m: ast::Mac = codemap::Spanned { node: m, - span: mk_sp(mac_lo, - self.last_span.hi) }; - if delim != token::Brace { if !self.eat(&token::Semi) { let last_span = self.last_span; @@ -6024,14 +5999,9 @@ impl<'a> Parser<'a> { } } - let item_ = ItemKind::Mac(m); - let last_span = self.last_span; - let item = self.mk_item(lo, - last_span.hi, - id, - item_, - visibility, - attrs); + let hi = self.last_span.hi; + let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); + let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } @@ -6171,15 +6141,4 @@ impl<'a> Parser<'a> { _ => Err(self.fatal("expected string literal")) } } - - pub fn ensure_complete_parse(&mut self, allow_semi: bool, on_err: F) - where F: FnOnce(&Parser) - { - if allow_semi && self.token == token::Semi { - self.bump(); - } - if self.token != token::Eof { - on_err(self); - } - } } diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index e869c5083373c..4b1df7d170dbc 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -48,10 +48,12 @@ pub fn get_dbpath_for_term(term: &str) -> Option { // According to /etc/terminfo/README, after looking at // ~/.terminfo, ncurses will search /etc/terminfo, then // /lib/terminfo, and eventually /usr/share/terminfo. + // On Haiku the database can be found at /boot/system/data/terminfo Err(..) => { dirs_to_search.push(PathBuf::from("/etc/terminfo")); dirs_to_search.push(PathBuf::from("/lib/terminfo")); dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); } } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 2b4193306ddf5..13d57f784e795 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1080,6 +1080,12 @@ fn get_concurrency() -> usize { } cpus as usize } + + #[cfg(target_os = "haiku")] + fn num_cpus() -> usize { + // FIXME: implement + 1 + } } pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec { diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 3900ba65293c0..30de859f1501a 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -241,6 +241,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", target_os = "solaris", + target_os = "haiku", all(target_os = "linux", target_env = "musl", not(target_arch = "x86"), diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 1e873b5345c43..12cd81ec70044 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -22,7 +22,7 @@ struct RustArchiveMember { Archive::Child child; RustArchiveMember(): filename(NULL), name(NULL), -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) child(NULL, NULL, NULL) #else child(NULL, NULL) @@ -35,7 +35,7 @@ struct RustArchiveMember { struct RustArchiveIterator { Archive::child_iterator cur; Archive::child_iterator end; -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_GE(3, 9) Error err; #endif }; @@ -81,7 +81,7 @@ LLVMRustOpenArchive(char *path) { return nullptr; } -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) ErrorOr> archive_or = #else Expected> archive_or = @@ -89,7 +89,7 @@ LLVMRustOpenArchive(char *path) { Archive::create(buf_or.get()->getMemBufferRef()); if (!archive_or) { -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) LLVMRustSetLastError(archive_or.getError().message().c_str()); #else LLVMRustSetLastError(toString(archive_or.takeError()).c_str()); @@ -112,7 +112,7 @@ extern "C" LLVMRustArchiveIteratorRef LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) rai->cur = ar->child_begin(); #else rai->cur = ar->child_begin(rai->err); @@ -127,7 +127,7 @@ LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) { extern "C" LLVMRustArchiveChildConstRef LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) { -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_GE(3, 9) if (rai->err) { LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); return NULL; @@ -135,7 +135,7 @@ LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) { #endif if (rai->cur == rai->end) return NULL; -#if LLVM_VERSION_MINOR == 8 +#if LLVM_VERSION_EQ(3, 8) const ErrorOr* cur = rai->cur.operator->(); if (!*cur) { LLVMRustSetLastError(cur->getError().message().c_str()); @@ -207,7 +207,7 @@ LLVMRustWriteArchive(char *Dst, bool WriteSymbtab, LLVMRustArchiveKind rust_kind) { -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) std::vector Members; #else std::vector Members; @@ -218,20 +218,20 @@ LLVMRustWriteArchive(char *Dst, auto Member = NewMembers[i]; assert(Member->name); if (Member->filename) { -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_GE(3, 9) Expected MOrErr = NewArchiveMember::getFile(Member->filename, true); if (!MOrErr) { LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); return LLVMRustResult::Failure; } Members.push_back(std::move(*MOrErr)); -#elif LLVM_VERSION_MINOR == 8 +#elif LLVM_VERSION_EQ(3, 8) Members.push_back(NewArchiveIterator(Member->filename)); #else Members.push_back(NewArchiveIterator(Member->filename, Member->name)); #endif } else { -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) Members.push_back(NewArchiveIterator(Member->child, Member->name)); #else Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); @@ -243,7 +243,7 @@ LLVMRustWriteArchive(char *Dst, #endif } } -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); #else auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a271987210b67..60093e9bd37a8 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -46,7 +46,7 @@ LLVMInitializePasses() { initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); -#if LLVM_VERSION_MINOR == 7 +#if LLVM_VERSION_EQ(3, 7) initializeIPA(Registry); #endif initializeTransformUtils(Registry); @@ -297,7 +297,7 @@ LLVMRustCreateTargetMachine(const char *triple, bool FunctionSections, bool DataSections) { -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) Reloc::Model RM; #else Optional RM; @@ -316,7 +316,7 @@ LLVMRustCreateTargetMachine(const char *triple, RM = Reloc::DynamicNoPIC; break; default: -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) RM = Reloc::Default; #endif break; @@ -337,7 +337,7 @@ LLVMRustCreateTargetMachine(const char *triple, } TargetOptions Options; -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) Options.PositionIndependentExecutable = PositionIndependentExecutable; #endif @@ -539,7 +539,7 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **symbols, size_t len) { llvm::legacy::PassManager passes; -#if LLVM_VERSION_MINOR <= 8 +#if LLVM_VERSION_LE(3, 8) ArrayRef ref(symbols, len); passes.add(llvm::createInternalizePass(ref)); #else @@ -593,7 +593,7 @@ LLVMRustGetModuleDataLayout(LLVMModuleRef M) { extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_GE(3, 9) unwrap(M)->setPIELevel(PIELevel::Level::Large); #endif } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 124eb1eba4f7b..672ab117f15f3 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -394,7 +394,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateSubroutineType( LLVMRustMetadataRef File, LLVMRustMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( -#if LLVM_VERSION_MINOR == 7 +#if LLVM_VERSION_EQ(3, 7) unwrapDI(File), #endif DITypeRefArray(unwrap(ParameterTypes)))); @@ -416,7 +416,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( LLVMValueRef Fn, LLVMRustMetadataRef TParam, LLVMRustMetadataRef Decl) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) DITemplateParameterArray TParams = DITemplateParameterArray(unwrap(TParam)); DISubprogram *Sub = Builder->createFunction( @@ -565,7 +565,7 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( int64_t* AddrOps, unsigned AddrOpsCount, unsigned ArgNo) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( unwrapDI(Scope), Name, @@ -814,7 +814,7 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) if (Linker::linkModules(*Dst, std::move(Src.get()))) { #else if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { @@ -937,14 +937,14 @@ to_rust(DiagnosticKind kind) return LLVMRustDiagnosticKind::OptimizationRemarkMissed; case DK_OptimizationRemarkAnalysis: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis; -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) case DK_OptimizationRemarkAnalysisFPCommute: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute; case DK_OptimizationRemarkAnalysisAliasing: return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing; #endif default: -#if LLVM_VERSION_MINOR >= 9 +#if LLVM_VERSION_GE(3, 9) return (kind >= DK_FirstRemark && kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther : LLVMRustDiagnosticKind::Other; @@ -994,7 +994,7 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { return LLVMVectorTypeKind; case Type::X86_MMXTyID: return LLVMX86_MMXTypeKind; -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) case Type::TokenTyID: return LLVMTokenTypeKind; #endif @@ -1043,7 +1043,7 @@ LLVMRustBuildCleanupPad(LLVMBuilderRef Builder, unsigned ArgCnt, LLVMValueRef *LLArgs, const char *Name) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) Value **Args = unwrap(LLArgs); if (ParentPad == NULL) { Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext()); @@ -1061,7 +1061,7 @@ extern "C" LLVMValueRef LLVMRustBuildCleanupRet(LLVMBuilderRef Builder, LLVMValueRef CleanupPad, LLVMBasicBlockRef UnwindBB) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) CleanupPadInst *Inst = cast(unwrap(CleanupPad)); return wrap(unwrap(Builder)->CreateCleanupRet(Inst, unwrap(UnwindBB))); #else @@ -1075,7 +1075,7 @@ LLVMRustBuildCatchPad(LLVMBuilderRef Builder, unsigned ArgCnt, LLVMValueRef *LLArgs, const char *Name) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) Value **Args = unwrap(LLArgs); return wrap(unwrap(Builder)->CreateCatchPad(unwrap(ParentPad), ArrayRef(Args, ArgCnt), @@ -1089,7 +1089,7 @@ extern "C" LLVMValueRef LLVMRustBuildCatchRet(LLVMBuilderRef Builder, LLVMValueRef Pad, LLVMBasicBlockRef BB) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) return wrap(unwrap(Builder)->CreateCatchRet(cast(unwrap(Pad)), unwrap(BB))); #else @@ -1103,7 +1103,7 @@ LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder, LLVMBasicBlockRef BB, unsigned NumHandlers, const char *Name) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) if (ParentPad == NULL) { Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext()); ParentPad = wrap(Constant::getNullValue(Ty)); @@ -1120,7 +1120,7 @@ LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder, extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, LLVMBasicBlockRef Handler) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) Value *CatchSwitch = unwrap(CatchSwitchRef); cast(CatchSwitch)->addHandler(unwrap(Handler)); #endif @@ -1129,14 +1129,14 @@ LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, extern "C" void LLVMRustSetPersonalityFn(LLVMBuilderRef B, LLVMValueRef Personality) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) unwrap(B)->GetInsertBlock() ->getParent() ->setPersonalityFn(cast(unwrap(Personality))); #endif } -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_GE(3, 8) extern "C" OperandBundleDef* LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 5aae11fb456b6..ffe94d1e22f20 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -45,7 +45,16 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Object.h" -#if LLVM_VERSION_MINOR >= 7 +#define LLVM_VERSION_GE(major, minor) \ + (LLVM_VERSION_MAJOR > (major) || LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR >= (minor)) + +#define LLVM_VERSION_EQ(major, minor) \ + (LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR == (minor)) + +#define LLVM_VERSION_LE(major, minor) \ + (LLVM_VERSION_MAJOR < (major) || LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR <= (minor)) + +#if LLVM_VERSION_GE(3, 7) #include "llvm/IR/LegacyPassManager.h" #else #include "llvm/PassManager.h" diff --git a/src/test/compile-fail/E0512.rs b/src/test/compile-fail/E0512.rs index 25f9627164131..2b89873ee45ff 100644 --- a/src/test/compile-fail/E0512.rs +++ b/src/test/compile-fail/E0512.rs @@ -12,4 +12,5 @@ fn takes_u8(_: u8) {} fn main() { unsafe { takes_u8(::std::mem::transmute(0u16)); } //~ ERROR E0512 + //~| transmuting between 16 bits and 8 bits } diff --git a/src/test/compile-fail/E0513.rs b/src/test/compile-fail/E0513.rs new file mode 100644 index 0000000000000..726e23265241d --- /dev/null +++ b/src/test/compile-fail/E0513.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +fn main() { + unsafe { + let size = mem::size_of::(); + mem::transmute_copy::(&8_8); //~ ERROR E0513 + //~| NOTE no type for variable + } +} diff --git a/src/test/compile-fail/issue-21146.rs b/src/test/compile-fail/issue-21146.rs index 02f128e1f5644..457d40e62b037 100644 --- a/src/test/compile-fail/issue-21146.rs +++ b/src/test/compile-fail/issue-21146.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: expected item, found `parse_error` +// error-pattern: expected one of `!` or `::`, found `` include!("auxiliary/issue-21146-inc.rs"); fn main() {} diff --git a/src/test/compile-fail/issue-5067.rs b/src/test/compile-fail/issue-5067.rs new file mode 100644 index 0000000000000..b7b5553dc74e4 --- /dev/null +++ b/src/test/compile-fail/issue-5067.rs @@ -0,0 +1,62 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! foo { + ( $()* ) => {}; + //~^ ERROR repetition matches empty token tree + ( $()+ ) => {}; + //~^ ERROR repetition matches empty token tree + + ( $(),* ) => {}; // PASS + ( $(),+ ) => {}; // PASS + + ( [$()*] ) => {}; + //~^ ERROR repetition matches empty token tree + ( [$()+] ) => {}; + //~^ ERROR repetition matches empty token tree + + ( [$(),*] ) => {}; // PASS + ( [$(),+] ) => {}; // PASS + + ( $($()* $(),* $(a)* $(a),* )* ) => {}; + //~^ ERROR repetition matches empty token tree + ( $($()* $(),* $(a)* $(a),* )+ ) => {}; + //~^ ERROR repetition matches empty token tree + + ( $(a $(),* $(a)* $(a),* )* ) => {}; // PASS + ( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS + + ( $(a $()+)* ) => {}; + //~^ ERROR repetition matches empty token tree + ( $(a $()*)+ ) => {}; + //~^ ERROR repetition matches empty token tree +} + + +// --- Original Issue --- // + +macro_rules! make_vec { + (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]); + //~^ ERROR repetition matches empty token tree +} + +fn main() { + let _ = make_vec!(a 1, a 2, a 3); +} + + +// --- Minified Issue --- // + +macro_rules! m { + ( $()* ) => {} + //~^ ERROR repetition matches empty token tree +} + +m!(); diff --git a/src/test/compile-fail/macro-context.rs b/src/test/compile-fail/macro-context.rs index 4aa0a3023bb10..80802e19f8401 100644 --- a/src/test/compile-fail/macro-context.rs +++ b/src/test/compile-fail/macro-context.rs @@ -14,11 +14,8 @@ macro_rules! m { //~| ERROR macro expansion ignores token `typeof` //~| ERROR macro expansion ignores token `;` //~| ERROR macro expansion ignores token `;` - //~| ERROR macro expansion ignores token `i` } -m!(); //~ NOTE the usage of `m!` is likely invalid in item context - fn main() { let a: m!(); //~ NOTE the usage of `m!` is likely invalid in type context let i = m!(); //~ NOTE the usage of `m!` is likely invalid in expression context diff --git a/src/test/compile-fail/paths-in-macro-invocations.rs b/src/test/compile-fail/paths-in-macro-invocations.rs new file mode 100644 index 0000000000000..c69b7e526cc3b --- /dev/null +++ b/src/test/compile-fail/paths-in-macro-invocations.rs @@ -0,0 +1,38 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +::foo::bar!(); //~ ERROR expected macro name without module separators +foo::bar!(); //~ ERROR expected macro name without module separators + +trait T { + foo::bar!(); //~ ERROR expected macro name without module separators + ::foo::bar!(); //~ ERROR expected macro name without module separators +} + +struct S { + x: foo::bar!(), //~ ERROR expected macro name without module separators + y: ::foo::bar!(), //~ ERROR expected macro name without module separators +} + +impl S { + foo::bar!(); //~ ERROR expected macro name without module separators + ::foo::bar!(); //~ ERROR expected macro name without module separators +} + +fn main() { + foo::bar!(); //~ ERROR expected macro name without module separators + ::foo::bar!(); //~ ERROR expected macro name without module separators + + let _ = foo::bar!(); //~ ERROR expected macro name without module separators + let _ = ::foo::bar!(); //~ ERROR expected macro name without module separators + + let foo::bar!() = 0; //~ ERROR expected macro name without module separators + let ::foo::bar!() = 0; //~ ERROR expected macro name without module separators +} diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs index b9c9d7a389b95..911606ef01213 100644 --- a/src/test/compile-fail/self_type_keyword.rs +++ b/src/test/compile-fail/self_type_keyword.rs @@ -30,8 +30,7 @@ pub fn main() { ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` Self!() => (), - //~^ ERROR expected identifier, found keyword `Self` - //~^^ ERROR macro undefined: 'Self!' + //~^ ERROR macro undefined: 'Self!' Foo { x: Self } => (), //~^ ERROR expected identifier, found keyword `Self` Foo { Self } => (), diff --git a/src/test/parse-fail/extern-no-fn.rs b/src/test/parse-fail/extern-no-fn.rs index acf7187cf436f..ff3fefde40ece 100644 --- a/src/test/parse-fail/extern-no-fn.rs +++ b/src/test/parse-fail/extern-no-fn.rs @@ -11,7 +11,7 @@ // compile-flags: -Z parse-only extern { - f(); //~ ERROR expected one of `fn`, `pub`, `static`, or `}`, found `f` + f(); //~ ERROR expected one of `!` or `::`, found `(` } fn main() { diff --git a/src/test/parse-fail/issue-21153.rs b/src/test/parse-fail/issue-21153.rs index 76a4687f544da..c03e0ef73217c 100644 --- a/src/test/parse-fail/issue-21153.rs +++ b/src/test/parse-fail/issue-21153.rs @@ -11,5 +11,6 @@ // compile-flags: -Z parse-only trait MyTrait: Iterator { - Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item` + Item = T; //~ ERROR expected one of `!` or `::`, found `=` + //~| ERROR expected item, found `=` } diff --git a/src/test/run-make/link-arg/Makefile b/src/test/run-make/link-arg/Makefile new file mode 100644 index 0000000000000..0ee239af0fa6c --- /dev/null +++ b/src/test/run-make/link-arg/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk +RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" -Z print-link-args + +all: + $(RUSTC) $(RUSTC_FLAGS) empty.rs | grep lfoo | grep lbar diff --git a/src/test/run-make/link-arg/empty.rs b/src/test/run-make/link-arg/empty.rs new file mode 100644 index 0000000000000..2b76fb24e5f1e --- /dev/null +++ b/src/test/run-make/link-arg/empty.rs @@ -0,0 +1,11 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { } diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs index 7d49bd25309f5..0abe44d82591d 100644 --- a/src/test/run-pass/fds-are-cloexec.rs +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -11,6 +11,7 @@ // ignore-windows // ignore-android // ignore-emscripten +// ignore-haiku #![feature(libc)] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 2db53947d881d..428bbcfe5761d 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -17,6 +17,7 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[("android", "android ("darwin", "macos"), ("dragonfly", "dragonfly"), ("freebsd", "freebsd"), + ("haiku", "haiku"), ("ios", "ios"), ("linux", "linux"), ("mingw32", "windows"),