1
Fork 0

Auto merge of #36764 - jonathandturner:rollup, r=jonathandturner

Rollup of 14 pull requests

- Successful merges: #36563, #36574, #36586, #36662, #36663, #36669, #36676, #36721, #36723, #36727, #36729, #36742, #36754, #36756
- Failed merges:
This commit is contained in:
bors 2016-09-26 23:30:19 -07:00 committed by GitHub
commit ec7679b460
68 changed files with 1713 additions and 1064 deletions

8
configure vendored
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 } => {

View file

@ -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<Step> {
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<Step> {
set: &mut HashSet<Step<'a>>) {
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());

View file

@ -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 youre 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() {

View file

@ -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
;;

@ -1 +1 @@
Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c
Subproject commit eb708c020826a8d792a5a5275be147aabe47fe24

View file

@ -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();
}
}

View file

@ -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<String>, v: Option<&str>) -> bool {
match v {
Some(s) => { slot.push(s.to_string()); true },
None => false,
}
}
fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
-> bool {
match v {
@ -742,6 +750,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"tool to assemble archives with"),
linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
"system linker to link outputs with"),
link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
"a single extra argument to pass to the linker (can be used several times)"),
link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
"extra arguments to pass to the linker (space separated)"),
link_dead_code: bool = (false, parse_bool, [UNTRACKED],

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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()
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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,
})
}

View file

@ -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),

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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,
})
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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
}
}

View file

@ -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::<u32>();
mem::transmute_copy::<u32, [u8; size]>(&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::<u32, [u8; mem::size_of::<u32>()]>(&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::<u32, [u8; 4]>(&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

View file

@ -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<String>,
externs: config::Externs,
input: Input,
triple: Option<String>) -> (clean::Crate, RenderInfo)
triple: Option<String>,
maybe_sysroot: Option<PathBuf>) -> (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)),

View file

@ -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;

View file

@ -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::<Vec<_>>();
main_args(&s)
@ -186,6 +161,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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<Item> {
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<DefId>,
update_retained: bool,
}
impl<'a> fold::DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
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<Item> {
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<Item> {
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<Item> {
let mut avec: Vec<clean::Attribute> = 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<Item> {
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<clean::Attribute> = 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::<Vec<&str> >();
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::<Vec<_>>());
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");
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::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<Item> {
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<clean::Attribute> = 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)
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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<DefId>,
update_retained: bool,
}
impl<'a> fold::DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
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<Item> {
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<Item> {
match i.inner {
clean::ExternCrateItem(..) |
clean::ImportItem(..) if i.visibility != Some(clean::Public) => None,
_ => self.fold_item_recur(i)
}
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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<Item> {
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)
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use clean;
use fold::DocFolder;
use plugins;
use passes::ImportStripper;
pub fn strip_priv_imports(krate: clean::Crate) -> plugins::PluginResult {
ImportStripper.fold_crate(krate)
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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)
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::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<Item> {
let mut avec: Vec<clean::Attribute> = 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::<Vec<&str> >();
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::<Vec<_>>());
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");
}
}

View file

@ -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";

138
src/libstd/os/haiku/fs.rs Normal file
View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Haiku-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod raw;
pub mod fs;

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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,
}

View file

@ -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;

View file

@ -62,3 +62,7 @@ extern {}
#[cfg(target_os = "ios")]
#[link(name = "System")]
extern {}
#[cfg(target_os = "haiku")]
#[link(name = "network")]
extern {}

View file

@ -38,7 +38,8 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { 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;

View file

@ -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;
////////////////////////////////////////////////////////////////////////////////

View file

@ -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| {

View file

@ -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<FileType> {
lstat(&self.path()).map(|m| m.file_type())
}
#[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
pub fn file_type(&self) -> io::Result<FileType> {
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()

View file

@ -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;

View file

@ -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()

View file

@ -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<PathBuf> {
}
}
#[cfg(target_os = "haiku")]
pub fn current_exe() -> io::Result<PathBuf> {
// 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::<image_info>() 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<OsString>,
_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());

View file

@ -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) {

View file

@ -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),
}
}

View file

@ -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<F> 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<Self>) -> Option<SmallVector<P<ast::Item>>> {
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<Self>) -> Option<SmallVector<ast::ImplItem>> {
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<Self>) -> Option<SmallVector<ast::TraitItem>> {
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<Self>) -> Option<P<ast::Expr>> {
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<Self>) -> Option<P<ast::Pat>> {
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<Self>) -> Option<SmallVector<ast::Stmt>> {
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<Self>) -> Option<P<ast::Ty>> {
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,

View file

@ -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<P<ast::Expr>>), $( $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> {

View file

@ -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<Parser<'a>>,
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();
});
}
}
pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion {
let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
let expansion = panictry!(parser.parse_expansion(kind, true));
impl<'a> MacResult for ParserAnyMacro<'a> {
fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
let ret = panictry!(self.parser.borrow_mut().parse_expr());
self.ensure_complete_parse(true, "expression");
Some(ret)
}
fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
let ret = panictry!(self.parser.borrow_mut().parse_pat());
self.ensure_complete_parse(false, "pattern");
Some(ret)
}
fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
let mut ret = SmallVector::zero();
while let Some(item) = panictry!(self.parser.borrow_mut().parse_item()) {
ret.push(item);
// 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, "item");
Some(ret)
}
fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::ImplItem>> {
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<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::TraitItem>> {
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<ParserAnyMacro<'a>>)
-> Option<SmallVector<ast::Stmt>> {
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;
}
}
}
}
self.ensure_complete_parse(false, "statement");
Some(ret)
}
fn make_ty(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Ty>> {
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::<Vec<TokenTree>>()
}
_ => 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,

View file

@ -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()?;
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)
})?;
generics.where_clause = self.parse_where_clause()?;
let sig = ast::MethodSig {
unsafety: unsafety,
constness: constness,
decl: d,
generics: generics,
abi: abi,
};
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))
return Err(e);
}
};
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
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)
})?;
generics.where_clause = self.parse_where_clause()?;
let sig = ast::MethodSig {
unsafety: unsafety,
constness: constness,
decl: d,
generics: generics,
abi: abi,
};
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<Attribute>)
-> PResult<'a, P<Expr>> {
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<ThinVec<Attribute>>)
-> PResult<'a, ThinVec<Attribute>> {
@ -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::Attribute>, 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<P<Item>>> {
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<F>(&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);
}
}
}

View file

@ -48,10 +48,12 @@ pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
// 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"));
}
}
}

View file

@ -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<TestDescAndFn>) -> Vec<TestDescAndFn> {

View file

@ -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"),

View file

@ -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<std::unique_ptr<Archive>> archive_or =
#else
Expected<std::unique_ptr<Archive>> 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<Archive::Child>* 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<NewArchiveIterator> Members;
#else
std::vector<NewArchiveMember> 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<NewArchiveMember> 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<NewArchiveMember> 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);

View file

@ -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<Reloc::Model> 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<const char*> 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
}

View file

@ -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<DIFile>(File),
#endif
DITypeRefArray(unwrap<MDTuple>(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<MDTuple>(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<DIDescriptor>(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<CleanupPadInst>(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<Value*>(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<CatchPadInst>(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<CatchSwitchInst>(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<Function>(unwrap(Personality)));
#endif
}
#if LLVM_VERSION_MINOR >= 8
#if LLVM_VERSION_GE(3, 8)
extern "C" OperandBundleDef*
LLVMRustBuildOperandBundleDef(const char *Name,
LLVMValueRef *Inputs,

View file

@ -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"

View file

@ -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
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::mem;
fn main() {
unsafe {
let size = mem::size_of::<u32>();
mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
//~| NOTE no type for variable
}
}

View file

@ -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 `<eof>`
include!("auxiliary/issue-21146-inc.rs");
fn main() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
macro_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!();

View file

@ -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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
::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
}

View file

@ -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 } => (),

View file

@ -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() {

View file

@ -11,5 +11,6 @@
// compile-flags: -Z parse-only
trait MyTrait<T>: 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 `=`
}

View file

@ -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

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() { }

View file

@ -11,6 +11,7 @@
// ignore-windows
// ignore-android
// ignore-emscripten
// ignore-haiku
#![feature(libc)]

View file

@ -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"),