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:
commit
ec7679b460
68 changed files with 1713 additions and 1064 deletions
8
configure
vendored
8
configure
vendored
|
@ -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
|
||||
|
|
27
mk/cfg/i686-unknown-haiku.mk
Normal file
27
mk/cfg/i686-unknown-haiku.mk
Normal 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
|
27
mk/cfg/x86_64-unknown-haiku.mk
Normal file
27
mk/cfg/x86_64-unknown-haiku.mk
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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 } => {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -230,12 +230,13 @@ $ cd hello_world
|
|||
|
||||
## Writing and Running a Rust Program
|
||||
|
||||
Next, make a new source file and call it *main.rs*. Rust files always end
|
||||
in a *.rs* extension. If you’re using more than one word in your filename, use
|
||||
an underscore to separate them; for example, you'd use *hello_world.rs* rather
|
||||
than *helloworld.rs*.
|
||||
We need to create a source file for our Rust program. Rust files always end
|
||||
in a *.rs* extension. If you are using more than one word in your filename,
|
||||
use an underscore to separate them; for example, you would use
|
||||
*my_program.rs* rather than *myprogram.rs*.
|
||||
|
||||
Now open the *main.rs* file you just created, and type the following code:
|
||||
Now, make a new file and call it *main.rs*. Open the file and type
|
||||
the following code:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
23
src/librustc_back/target/haiku_base.rs
Normal file
23
src/librustc_back/target/haiku_base.rs
Normal 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()
|
||||
}
|
||||
}
|
30
src/librustc_back/target/i686_unknown_haiku.rs
Normal file
30
src/librustc_back/target/i686_unknown_haiku.rs
Normal 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,
|
||||
})
|
||||
}
|
|
@ -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),
|
||||
|
||||
|
|
30
src/librustc_back/target/x86_64_unknown_haiku.rs
Normal file
30
src/librustc_back/target/x86_64_unknown_haiku.rs
Normal 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,
|
||||
})
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
47
src/librustdoc/passes/collapse_docs.rs
Normal file
47
src/librustdoc/passes/collapse_docs.rs
Normal 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)
|
||||
}
|
||||
}
|
204
src/librustdoc/passes/mod.rs
Normal file
204
src/librustdoc/passes/mod.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
66
src/librustdoc/passes/strip_hidden.rs
Normal file
66
src/librustdoc/passes/strip_hidden.rs
Normal 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)
|
||||
}
|
||||
}
|
18
src/librustdoc/passes/strip_priv_imports.rs
Normal file
18
src/librustdoc/passes/strip_priv_imports.rs
Normal 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)
|
||||
}
|
38
src/librustdoc/passes/strip_private.rs
Normal file
38
src/librustdoc/passes/strip_private.rs
Normal 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)
|
||||
}
|
168
src/librustdoc/passes/unindent_comments.rs
Normal file
168
src/librustdoc/passes/unindent_comments.rs
Normal 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");
|
||||
}
|
||||
}
|
|
@ -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
138
src/libstd/os/haiku/fs.rs
Normal 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
|
||||
}
|
||||
}
|
16
src/libstd/os/haiku/mod.rs
Normal file
16
src/libstd/os/haiku/mod.rs
Normal 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;
|
74
src/libstd/os/haiku/raw.rs
Normal file
74
src/libstd/os/haiku/raw.rs
Normal 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,
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -62,3 +62,7 @@ extern {}
|
|||
#[cfg(target_os = "ios")]
|
||||
#[link(name = "System")]
|
||||
extern {}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
#[link(name = "network")]
|
||||
extern {}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
19
src/test/compile-fail/E0513.rs
Normal file
19
src/test/compile-fail/E0513.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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() {}
|
||||
|
|
62
src/test/compile-fail/issue-5067.rs
Normal file
62
src/test/compile-fail/issue-5067.rs
Normal 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!();
|
|
@ -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
|
||||
|
|
38
src/test/compile-fail/paths-in-macro-invocations.rs
Normal file
38
src/test/compile-fail/paths-in-macro-invocations.rs
Normal 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
|
||||
}
|
|
@ -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 } => (),
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 `=`
|
||||
}
|
||||
|
|
5
src/test/run-make/link-arg/Makefile
Normal file
5
src/test/run-make/link-arg/Makefile
Normal 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
|
11
src/test/run-make/link-arg/empty.rs
Normal file
11
src/test/run-make/link-arg/empty.rs
Normal 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() { }
|
|
@ -11,6 +11,7 @@
|
|||
// ignore-windows
|
||||
// ignore-android
|
||||
// ignore-emscripten
|
||||
// ignore-haiku
|
||||
|
||||
#![feature(libc)]
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue