-.TH RUSTC "1" "March 2014" "rustc 0.11.0" "User Commands"
+.TH RUSTC "1" "March 2014" "rustc 0.12.0-pre" "User Commands"
.SH NAME
rustc \- The Rust compiler
.SH SYNOPSIS
.SH OPTIONS
+.TP
+\fB\-\-crate-name NAME\fR
+Specify the name of the crate being built
.TP
\fB\-\-crate-type=[bin|lib|dylib|rlib|staticlib]\fR
Configure the flavor of rust crate that is generated (default `bin`)
\fB\-\-pretty\fR [TYPE]
Pretty-print the input instead of compiling; valid types are: normal
(un-annotated source), expanded (crates expanded), typed (crates
-expanded, with type annotations), or identified (fully parenthesized,
-AST nodes and blocks with IDs)
+expanded, with type annotations), identified (fully parenthesized,
+AST nodes and blocks with IDs), or flowgraph=<nodeid> (graphviz
+formatted flowgraph for node)
.TP
\fB\-\-dep-info\fR [FILENAME]
Output dependency info to <filename> after compiling, in o format suitable
-.TH RUSTDOC "1" "March 2014" "rustdoc 0.11.0" "User Commands"
+.TH RUSTDOC "1" "March 2014" "rustdoc 0.12.0-pre" "User Commands"
.SH NAME
rustdoc \- generate documentation from Rust source code
.SH SYNOPSIS
$(Q)cd tmp/distcheck && tar -xzf ../../dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz
$(Q)mkdir -p tmp/distcheck/tarbininstall
$(Q)sh tmp/distcheck/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix=tmp/distcheck/tarbininstall
- $(Q)tmp/distcheck/tarbininstall/bin/rustc --version
$(Q)sh tmp/distcheck/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix=tmp/distcheck/tarbininstall --uninstall
$(Q)rm -Rf tmp/distcheck/$(PKG_NAME)-$(CFG_BUILD)
$(Q)rm -Rf tmp/distcheck/tarbininstall
MAYBE_DISABLE_VERIFY=
endif
-install: dist-install-dir-$(CFG_BUILD)-with-target-libs
- $(Q)sh tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
+install: dist-install-dir-$(CFG_BUILD)-with-target-libs | tmp/empty_dir
+ $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)"
# Remove tmp files while we can because they may have been created under sudo
$(Q)rm -R tmp/dist
-uninstall: dist-install-dir-$(CFG_BUILD)-with-target-libs
- $(Q)sh tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+uninstall: dist-install-dir-$(CFG_BUILD)-with-target-libs | tmp/empty_dir
+ $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
# Remove tmp files while we can because they may have been created under sudo
$(Q)rm -R tmp/dist
+tmp/empty_dir:
+ mkdir -p $@
######################################################################
# Android remote installation
######################################################################
# The version number
-CFG_RELEASE_NUM=0.11.0
-CFG_RELEASE_LABEL=
+CFG_RELEASE_NUM=0.12.0
+CFG_RELEASE_LABEL=-pre
CFG_FILENAME_EXTRA=4e7c5e5c
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::os;
use std::str;
use std::io::process::{ProcessExit, Command, Process, ProcessOutput};
use std::dynamic_lib::DynamicLibrary;
-fn target_env(lib_path: &str, aux_path: Option<&str>) -> Vec<(String, String)> {
+fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
// Need to be sure to put both the lib_path and the aux path in the dylib
// search path for the child.
let mut path = DynamicLibrary::search_path();
}
path.insert(0, Path::new(lib_path));
- // Remove the previous dylib search path var
- let var = DynamicLibrary::envvar();
- let mut env: Vec<(String,String)> = os::env();
- match env.iter().position(|&(ref k, _)| k.as_slice() == var) {
- Some(i) => { env.remove(i); }
- None => {}
- }
-
// Add the new dylib search path var
+ let var = DynamicLibrary::envvar();
let newpath = DynamicLibrary::create_path(path.as_slice());
let newpath = str::from_utf8(newpath.as_slice()).unwrap().to_string();
- env.push((var.to_string(), newpath));
- return env;
+ cmd.env(var.to_string(), newpath);
}
pub struct Result {pub status: ProcessExit, pub out: String, pub err: String}
env: Vec<(String, String)> ,
input: Option<String>) -> Option<Result> {
- let env = env.clone().append(target_env(lib_path, aux_path).as_slice());
- match Command::new(prog).args(args).env(env.as_slice()).spawn() {
+ let mut cmd = Command::new(prog);
+ cmd.args(args);
+ add_target_env(&mut cmd, lib_path, aux_path);
+ for (key, val) in env.move_iter() {
+ cmd.env(key, val);
+ }
+
+ match cmd.spawn() {
Ok(mut process) => {
for input in input.iter() {
process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
env: Vec<(String, String)> ,
input: Option<String>) -> Option<Process> {
- let env = env.clone().append(target_env(lib_path, aux_path).as_slice());
- match Command::new(prog).args(args).env(env.as_slice()).spawn() {
+ let mut cmd = Command::new(prog);
+ cmd.args(args);
+ add_target_env(&mut cmd, lib_path, aux_path);
+ for (key, val) in env.move_iter() {
+ cmd.env(key, val);
+ }
+
+ match cmd.spawn() {
Ok(mut process) => {
for input in input.iter() {
process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
cmd.arg("./src/etc/lldb_batchmode.py")
.arg(test_executable)
.arg(debugger_script)
- .env([("PYTHONPATH", config.lldb_python_dir.clone().unwrap().as_slice())]);
+ .env_set_all([("PYTHONPATH", config.lldb_python_dir.clone().unwrap().as_slice())]);
let (status, out, err) = match cmd.spawn() {
Ok(process) => {
You should see some output that looks something like this:
```{ignore}
-rustc 0.11.0-pre (443a1cd 2014-06-08 14:56:52 -0700)
+rustc 0.12.0-pre (443a1cd 2014-06-08 14:56:52 -0700)
```
If you did, Rust has been installed successfully! Congrats!
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-02-03 08:13+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-02-03 08:13+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-14 21:02+0900\n"
"Last-Translator: Automatically generated\n"
#
msgid ""
msgstr ""
-"Project-Id-Version: Rust 0.11.0-pre\n"
+"Project-Id-Version: Rust 0.12.0-pre\n"
"POT-Creation-Date: 2014-02-03 08:13+0900\n"
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
"Last-Translator: Automatically generated\n"
# The manifest lists all files to install
done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in"
+# Run ldconfig to make dynamic libraries available to the linker
+if [ "$CFG_OSTYPE" = "Linux" ]
+ then
+ ldconfig
+ if [ $? -ne 0 ]
+ then
+ warn "failed to run ldconfig."
+ warn "this may happen when not installing as root and may be fine"
+ fi
+fi
+
# Sanity check: can we run the installed binaries?
#
# As with the verification above, make sure the right LD_LIBRARY_PATH-equivalent
err "${ERR}"
else
echo
- echo " please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}"
- echo
+ echo " Note: please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}"
fi
fi
fi
-
echo
echo " Rust is ready to roll."
echo
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
]>
-<language name="Rust" version="0.11.0" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
+<language name="Rust" version="0.12.0-pre" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
<highlighting>
<list name="fn">
<item> fn </item>
-c'[Compile and assemble, but do not link]'
--cfg'[Configure the compilation environment]'
--crate-id'[Output the crate id and exit]'
- --crate-file-name'[Output the file(s) that would be written if compilation continued and exit]'
- --crate-name'[Output the crate name and exit]'
- --dep-info'[Output dependency info to <filename> after compiling]'
+ --crate-file-name'[deprecated in favor of --print-file-name]'
+ --crate-name'[Specify the name of the crate being built]'
--crate-type'[Specify the type of crate to crate]'
+ --debuginfo'[Emit DWARF debug info to the objects created: 0 = no debug info, 1 = line-tables only (for stacktraces and breakpoints), 2 = full debug info with variable and type information (same as -g)]'
+ --dep-info'[Output dependency info to <filename> after compiling]'
+ -g'[Equivalent to --debuginfo=2]'
{-h,--help}'[Display this message]'
-L'[Add a directory to the library search path]'
--linker'[Program to use for linking instead of the default.]'
--parse-only'[Parse only; do not compile, assemble, or link]'
--passes'[Comma or space separated list of pass names to use]'
--pretty'[Pretty-print the input instead of compiling]'
+ --print-crate-name'[Output the crate name and exit]'
+ --print-file-name'[Output the file(s) that would be written if compilation continued and exit]'
--save-temps'[Write intermediate files (.bc, .opt.bc, .o) in addition to normal output]'
--sysroot'[Override the system root]'
--test'[Build a test harness]'
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(unsafe_destructor)]
#![allow(missing_doc)]
mod tests {
use test::Bencher;
use std::prelude::*;
- use std::num::ToStrRadix;
+ use std::fmt;
use str::Str;
use string::String;
fn to_hex_str(r: &[u8, ..8]) -> String {
let mut s = String::new();
for b in r.iter() {
- s.push_str((*b as uint).to_str_radix(16u).as_slice());
+ s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice());
}
s
}
let r = result_bytes(h);
let mut s = String::new();
for b in r.iter() {
- s.push_str((*b as uint).to_str_radix(16u).as_slice());
+ s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice());
}
s
}
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
///
/// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
/// // CAS loop until we are able to replace `false` with `true`
- /// while spinlock.compare_and_swap(false, true, SeqCst) == false {
+ /// while spinlock.compare_and_swap(false, true, SeqCst) != false {
/// // Since tasks may not be preemptive (if they are green threads)
/// // yield to the scheduler to let the other task run. Low level
/// // concurrent code needs to take into account Rust's two threading
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
//! Operations and constants for 32-bits floats (`f32` type)
#![doc(primitive = "f32")]
+// FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353
+#![allow(type_overflow)]
use intrinsics;
use mem;
//! Operations and constants for 64-bits floats (`f64` type)
#![doc(primitive = "f64")]
+// FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353
+#![allow(type_overflow)]
use intrinsics;
use mem;
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![experimental]
#![feature(managed_boxes, macro_rules)]
#![allow(experimental)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(phase)]
#[cfg(test)] #[phase(plugin, link)] extern crate log;
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
use std::cell::Cell;
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
use std::io;
use std::str;
//! possibly pinned to a particular scheduler thread:
//!
//! ```rust
+//! extern crate green;
+//! extern crate rustuv;
+//!
+//! # fn main() {
//! use std::task::TaskBuilder;
//! use green::{SchedPool, PoolConfig, GreenTaskBuilder};
//!
-//! let config = PoolConfig::new();
+//! let mut config = PoolConfig::new();
+//!
+//! // Optional: Set the event loop to be rustuv's to allow I/O to work
+//! config.event_loop_factory = rustuv::event_loop;
+//!
//! let mut pool = SchedPool::new(config);
//!
//! // Spawn tasks into the pool of schedulers
//! // Required to shut down this scheduler pool.
//! // The task will fail if `shutdown` is not called.
//! pool.shutdown();
+//! # }
//! ```
#![crate_name = "green"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
// NB this does *not* include globs, please keep it that way.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::ptr;
use std::sync::atomics;
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
- MapNonStandardFlags, MapVirtual, getenv};
+ MapNonStandardFlags, getenv};
use libc;
/// A task's stack. The name "Stack" is a vestige of segmented stacks.
pub struct Stack {
- buf: MemoryMap,
+ buf: Option<MemoryMap>,
min_size: uint,
valgrind_id: libc::c_uint,
}
// guaranteed to be aligned properly.
if !protect_last_page(&stack) {
fail!("Could not memory-protect guard page. stack={}, errno={}",
- stack.data, errno());
+ stack.data(), errno());
}
let mut stk = Stack {
- buf: stack,
+ buf: Some(stack),
min_size: size,
valgrind_id: 0
};
/// Create a 0-length stack which starts (and ends) at 0.
pub unsafe fn dummy_stack() -> Stack {
Stack {
- buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
+ buf: None,
min_size: 0,
valgrind_id: 0
}
/// Point to the low end of the allocated stack
pub fn start(&self) -> *const uint {
- self.buf.data as *const uint
+ self.buf.as_ref().map(|m| m.data() as *const uint)
+ .unwrap_or(ptr::null())
}
/// Point one uint beyond the high end of the allocated stack
pub fn end(&self) -> *const uint {
- unsafe {
- self.buf.data.offset(self.buf.len as int) as *const uint
- }
+ self.buf.as_ref().map(|buf| unsafe {
+ buf.data().offset(buf.len() as int) as *const uint
+ }).unwrap_or(ptr::null())
}
}
// This may seem backwards: the start of the segment is the last page?
// Yes! The stack grows from higher addresses (the end of the allocated
// block) to lower addresses (the start of the allocated block).
- let last_page = stack.data as *mut libc::c_void;
+ let last_page = stack.data() as *mut libc::c_void;
libc::mprotect(last_page, page_size() as libc::size_t,
libc::PROT_NONE) != -1
}
fn protect_last_page(stack: &MemoryMap) -> bool {
unsafe {
// see above
- let last_page = stack.data as *mut libc::c_void;
+ let last_page = stack.data() as *mut libc::c_void;
let mut old_prot: libc::DWORD = 0;
libc::VirtualProtect(last_page, page_size() as libc::SIZE_T,
libc::PAGE_NOACCESS,
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]
extern crate syntax;
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
/*!
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
#![deny(missing_doc)]
}
#[cfg(unix)]
-fn with_envp<T>(env: Option<&[(CString, CString)]>,
+fn with_envp<T>(env: Option<&[(&CString, &CString)]>,
cb: proc(*const c_void) -> T) -> T {
// On posixy systems we can pass a char** for envp, which is a
// null-terminated array of "k=v\0" strings. Since we must create
}
#[cfg(windows)]
-fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: |*mut c_void| -> T) -> T {
+fn with_envp<T>(env: Option<&[(&CString, &CString)]>, cb: |*mut c_void| -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![deny(unused_result, unused_must_use)]
#![allow(non_camel_case_types, deprecated)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(deprecated)] // from_str_radix
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase, globs)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes, quote)]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(intrinsics)]
#![no_std]
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+register_diagnostic!(E0001, r##"
+ This error suggests that the expression arm corresponding to the noted pattern
+ will never be reached as for all possible values of the expression being matched,
+ one of the preceeding patterns will match.
+
+ This means that perhaps some of the preceeding patterns are too general, this
+ one is too specific or the ordering is incorrect.
+"##)
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
+ optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
optflagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: `normal` (un-annotated source),
use getopts::getopts;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
+ use syntax::diagnostics;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
Ok(m) => m,
Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
};
+ let registry = diagnostics::registry::Registry::new([]);
let sessopts = build_session_options(matches);
- let sess = build_session(sessopts, None);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess);
assert!((attr::contains_name(cfg.as_slice(), "test")));
}
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
}
};
+ let registry = diagnostics::registry::Registry::new([]);
let sessopts = build_session_options(matches);
- let sess = build_session(sessopts, None);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess);
let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
assert!(test_items.next().is_some());
use driver::{PpmIdentified};
use front;
use lib::llvm::{ContextRef, ModuleRef};
+use lint;
use metadata::common::LinkMeta;
use metadata::creader;
use middle::cfg;
use plugin::load::Plugins;
use plugin::registry::Registry;
use plugin;
-use lint;
+
use util::common::time;
use util::ppaux;
use util::nodemap::{NodeSet};
use syntax::ast;
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
+use syntax::diagnostics;
use syntax::parse;
use syntax::parse::token;
use syntax::print::{pp, pprust};
let mut registry = Registry::new(&krate);
time(time_passes, "plugin registration", (), |_| {
+ if sess.features.rustc_diagnostic_macros.get() {
+ registry.register_macro("__diagnostic_used",
+ diagnostics::plugin::expand_diagnostic_used);
+ registry.register_macro("__register_diagnostic",
+ diagnostics::plugin::expand_register_diagnostic);
+ registry.register_macro("__build_diagnostic_array",
+ diagnostics::plugin::expand_build_diagnostic_array);
+ }
+
for ®istrar in registrars.iter() {
registrar(&mut registry);
}
}
);
+ // JBC: make CFG processing part of expansion to avoid this problem:
+
// strip again, in case expansion added anything with a #[cfg].
krate = time(time_passes, "configuration 2", krate, |krate|
front::config::strip_unconfigured_items(krate));
krate.encode(&mut json).unwrap();
}
+ time(time_passes, "checking that all macro invocations are gone", &krate, |krate|
+ syntax::ext::expand::check_for_macros(&sess.parse_sess, krate));
+
Some((krate, map))
}
pub name: String,
}
+
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
krate: &ast::Crate,
ast_map: syntax::ast_map::Map,
name: String) -> CrateAnalysis {
-
let time_passes = sess.time_passes();
time(time_passes, "external crate/lib resolution", (), |_|
use syntax::ast;
use syntax::parse;
use syntax::diagnostic::Emitter;
+use syntax::diagnostics;
use getopts;
Some(matches) => matches,
None => return
};
- let sopts = config::build_session_options(&matches);
+ let descriptions = diagnostics::registry::Registry::new(super::DIAGNOSTICS);
+ match matches.opt_str("explain") {
+ Some(ref code) => {
+ match descriptions.find_description(code.as_slice()) {
+ Some(ref description) => {
+ println!("{}", description);
+ }
+ None => {
+ early_error(format!("no extended information for {}", code).as_slice());
+ }
+ }
+ return;
+ },
+ None => ()
+ }
+
+ let sopts = config::build_session_options(&matches);
let (input, input_file_path) = match matches.free.len() {
0u => {
if sopts.describe_lints {
_ => early_error("multiple input filenames provided")
};
- let sess = build_session(sopts, input_file_path);
+ let sess = build_session(sopts, input_file_path, descriptions);
let cfg = config::build_configuration(&sess);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
let ofile = matches.opt_str("o").map(|o| Path::new(o));
}
pub fn early_error(msg: &str) -> ! {
- let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
- emitter.emit(None, msg, diagnostic::Fatal);
+ let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
+ emitter.emit(None, msg, None, diagnostic::Fatal);
fail!(diagnostic::FatalError);
}
pub fn early_warn(msg: &str) {
- let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
- emitter.emit(None, msg, diagnostic::Warning);
+ let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
+ emitter.emit(None, msg, None, diagnostic::Warning);
}
pub fn list_metadata(sess: &Session, path: &Path,
Err(value) => {
// Task failed without emitting a fatal diagnostic
if !value.is::<diagnostic::FatalError>() {
- let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
+ let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
// a .span_bug or .bug call has already printed what
// it wants to print.
emitter.emit(
None,
"unexpected failure",
+ None,
diagnostic::Bug);
}
"run with `RUST_BACKTRACE=1` for a backtrace".to_string(),
];
for note in xs.iter() {
- emitter.emit(None, note.as_slice(), diagnostic::Note)
+ emitter.emit(None, note.as_slice(), None, diagnostic::Note)
}
match r.read_to_string() {
format!("failed to read internal \
stderr: {}",
e).as_slice(),
+ None,
diagnostic::Error)
}
}
use syntax::ast::NodeId;
use syntax::codemap::Span;
use syntax::diagnostic;
+use syntax::diagnostics;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::ParseSess;
use std::os;
use std::cell::{Cell, RefCell};
-
+// Represents the data associated with a compilation
+// session for a single crate.
pub struct Session {
pub targ_cfg: config::Config,
pub opts: config::Options,
pub fn span_err(&self, sp: Span, msg: &str) {
self.diagnostic().span_err(sp, msg)
}
+ pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
+ self.diagnostic().span_err_with_code(sp, msg, code)
+ }
pub fn err(&self, msg: &str) {
self.diagnostic().handler().err(msg)
}
}
pub fn build_session(sopts: config::Options,
- local_crate_source_file: Option<Path>)
+ local_crate_source_file: Option<Path>,
+ registry: diagnostics::registry::Registry)
-> Session {
let codemap = codemap::CodeMap::new();
let diagnostic_handler =
- diagnostic::default_handler(sopts.color);
+ diagnostic::default_handler(sopts.color, Some(registry));
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
use std::gc::{Gc, GC};
+/// A folder that strips out items that do not belong in the current
+/// configuration.
struct Context<'a> {
in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
}
fn fold_expr(&mut self, expr: Gc<ast::Expr>) -> Gc<ast::Expr> {
fold_expr(self, expr)
}
+ fn fold_mac(&mut self, mac: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(mac, self)
+ }
}
pub fn strip_items(krate: ast::Crate,
("quad_precision_float", Removed),
+ ("rustc_diagnostic_macros", Active),
+
// A temporary feature gate used to enable parser extensions needed
// to bootstrap fix for #5723.
("issue_5723_bootstrap", Active),
pub default_type_params: Cell<bool>,
pub issue_5723_bootstrap: Cell<bool>,
pub overloaded_calls: Cell<bool>,
+ pub rustc_diagnostic_macros: Cell<bool>
}
impl Features {
default_type_params: Cell::new(false),
issue_5723_bootstrap: Cell::new(false),
overloaded_calls: Cell::new(false),
+ rustc_diagnostic_macros: Cell::new(false)
}
}
}
sess.features.default_type_params.set(cx.has_feature("default_type_params"));
sess.features.issue_5723_bootstrap.set(cx.has_feature("issue_5723_bootstrap"));
sess.features.overloaded_calls.set(cx.has_feature("overloaded_calls"));
+ sess.features.rustc_diagnostic_macros.set(cx.has_feature("rustc_diagnostic_macros"));
}
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![allow(deprecated)]
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
#![feature(default_type_params, phase, unsafe_destructor)]
+#![allow(unknown_features)] // NOTE: Remove after next snapshot
+#![feature(rustc_diagnostic_macros)]
+
extern crate arena;
extern crate debug;
extern crate flate;
extern crate graphviz;
extern crate libc;
extern crate serialize;
-extern crate syntax;
extern crate time;
#[phase(plugin, link)] extern crate log;
+#[phase(plugin, link)] extern crate syntax;
+
+mod diagnostics;
pub mod middle {
pub mod def;
pub mod llvmdeps;
}
+__build_diagnostic_array!(DIAGNOSTICS)
+
// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
use std::cmp;
use std::collections::HashMap;
-use std::i16;
-use std::i32;
-use std::i64;
-use std::i8;
-use std::u16;
-use std::u32;
-use std::u64;
-use std::u8;
+use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
use std::gc::Gc;
use syntax::abi;
use syntax::ast_map;
"literal out of range for its type");
}
},
-
+ ty::ty_float(t) => {
+ let (min, max) = float_ty_range(t);
+ let lit_val: f64 = match lit.node {
+ ast::LitFloat(ref v, _) |
+ ast::LitFloatUnsuffixed(ref v) => match from_str(v.get()) {
+ Some(f) => f,
+ None => return
+ },
+ _ => fail!()
+ };
+ if lit_val < min || lit_val > max {
+ cx.span_lint(TYPE_OVERFLOW, e.span,
+ "literal out of range for its type");
+ }
+ },
_ => ()
};
},
}
}
+ fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
+ match float_ty {
+ ast::TyF32 => (f32::MIN_VALUE as f64, f32::MAX_VALUE as f64),
+ ast::TyF64 => (f64::MIN_VALUE, f64::MAX_VALUE)
+ }
+ }
+
fn check_limits(tcx: &ty::ctxt, binop: ast::BinOp,
l: &ast::Expr, r: &ast::Expr) -> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
should_match_name: true,
};
let library = match load_ctxt.maybe_load_library_crate() {
- Some (l) => l,
+ Some(l) => l,
None if is_cross => {
// try loading from target crates (only valid if there are
// no syntax extensions)
let registrar = decoder::get_plugin_registrar_fn(library.metadata.as_slice()).map(|id| {
decoder::get_symbol(library.metadata.as_slice(), id)
});
+ if library.dylib.is_none() && registrar.is_some() {
+ let message = format!("plugin crate `{}` only found in rlib format, \
+ but must be available in dylib format",
+ info.ident);
+ self.env.sess.span_err(krate.span, message.as_slice());
+ // No need to abort because the loading code will just ignore this
+ // empty dylib.
+ }
let pc = PluginMetadata {
lib: library.dylib.clone(),
macros: macros,
encode_name(ebml_w, nm);
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
encode_def_id(ebml_w, local_def(id));
+
+ let stab = stability::lookup(ecx.tcx, field.id);
+ encode_stability(ebml_w, stab);
+
ebml_w.end_tag();
}
index
}
}
-struct MacroDefVisitor<'a, 'b, 'c> {
- ecx: &'a EncodeContext<'b>,
- ebml_w: &'a mut Encoder<'c>
-}
-
-impl<'a, 'b, 'c> Visitor<()> for MacroDefVisitor<'a, 'b, 'c> {
- fn visit_item(&mut self, item: &Item, _: ()) {
- match item.node {
- ItemMac(..) => {
- let def = self.ecx.tcx.sess.codemap().span_to_snippet(item.span)
- .expect("Unable to find source for macro");
- self.ebml_w.start_tag(tag_macro_def);
- self.ebml_w.wr_str(def.as_slice());
- self.ebml_w.end_tag();
- }
- _ => {}
- }
- visit::walk_item(self, item, ());
- }
+/// Given a span, write the text of that span into the output stream
+/// as an exported macro
+fn encode_macro_def(ecx: &EncodeContext,
+ ebml_w: &mut Encoder,
+ span: &syntax::codemap::Span) {
+ let def = ecx.tcx.sess.codemap().span_to_snippet(*span)
+ .expect("Unable to find source for macro");
+ ebml_w.start_tag(tag_macro_def);
+ ebml_w.wr_str(def.as_slice());
+ ebml_w.end_tag();
}
-fn encode_macro_defs<'a>(ecx: &'a EncodeContext,
- krate: &Crate,
- ebml_w: &'a mut Encoder) {
+/// Serialize the text of the exported macros
+fn encode_macro_defs(ecx: &EncodeContext,
+ krate: &Crate,
+ ebml_w: &mut Encoder) {
ebml_w.start_tag(tag_exported_macros);
- {
- let mut visitor = MacroDefVisitor {
- ecx: ecx,
- ebml_w: ebml_w,
- };
- visit::walk_crate(&mut visitor, krate, ());
+ for span in krate.exported_macros.iter() {
+ encode_macro_def(ecx, ebml_w, span);
}
ebml_w.end_tag();
}
let v = vec!(*pat);
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
- NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
+ NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"),
Useful => (),
UsefulWithWitness(_) => unreachable!()
}
use util::nodemap::{NodeMap, DefIdMap};
use syntax::codemap::Span;
use syntax::{attr, visit};
+use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
-use syntax::ast::{Generics, StructDef, Ident};
+use syntax::ast::{Generics, StructDef, StructField, Ident};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
use syntax::visit::{FnKind, FkMethod, Visitor};
s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
visit::walk_struct_def(self, s, parent)
}
+
+ fn visit_struct_field(&mut self, s: &StructField, parent: Option<Stability>) {
+ let stab = self.annotate(s.node.id, s.node.attrs.as_slice(), parent);
+ visit::walk_struct_field(self, s, stab)
+ }
}
impl Index {
extern_cache: DefIdMap::new()
}
};
- visit::walk_crate(&mut annotator, krate,
- attr::find_stability(krate.attrs.as_slice()));
+ let stab = annotator.annotate(ast::CRATE_NODE_ID, krate.attrs.as_slice(), None);
+ visit::walk_crate(&mut annotator, krate, stab);
annotator.index
}
}
actual,
fcx.infcx().ty_to_string(t_1))
}, t_e, None);
+ } else if ty::type_is_unsafe_ptr(t_e) && t_1_is_float {
+ fcx.type_error_message(span, |actual| {
+ format!("cannot cast from pointer to float directly: `{}` as `{}`; cast through an \
+ integer first",
+ actual,
+ fcx.infcx().ty_to_string(t_1))
+ }, t_e, None);
}
fcx.write_ty(id, t_1);
fn emit(&mut self,
_cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
+ _: Option<&str>,
lvl: Level)
{
remove_message(self, msg, lvl);
loader.plugins
}
+// note that macros aren't expanded yet, and therefore macros can't add plugins.
impl<'a> Visitor<()> for PluginLoader<'a> {
fn visit_view_item(&mut self, vi: &ast::ViewItem, _: ()) {
match vi.node {
_ => (),
}
}
+ fn visit_mac(&mut self, _: &ast::Mac, _:()) {
+ // bummer... can't see plugins inside macros.
+ // do nothing.
+ }
}
impl<'a> PluginLoader<'a> {
name: Some(name.clean()),
attrs: Vec::new(),
visibility: Some(ast::Public),
- stability: get_stability(self.id),
// FIXME: this is not accurate, we need an id for
// the specific field but we're using the id
- // for the whole variant. Nothing currently
- // uses this so we should be good for now.
+ // for the whole variant. Thus we read the
+ // stability from the whole variant as well.
+ // Struct variants are experimental and need
+ // more infrastructure work before we can get
+ // at the needed information here.
def_id: self.id,
+ stability: get_stability(self.id),
inner: StructFieldItem(
TypedStructField(ty.clean())
)
visibility: Some(ast::Public),
def_id: self.id,
inner: VariantItem(Variant { kind: kind }),
- stability: None,
+ stability: get_stability(self.id),
}
}
}
source: self.span.clean(),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(),
- stability: None,
+ stability: get_stability(ast_util::local_def(self.id)),
inner: inner,
}
}
PatWildMulti => "..".to_string(),
PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
PatEnum(ref p, _) => path_to_string(p),
- PatStruct(..) => fail!("tried to get argument name from pat_struct, \
- which is not allowed in function arguments"),
- PatTup(..) => "(tuple arg NYI)".to_string(),
+ PatStruct(ref name, ref fields, etc) => {
+ format!("{} {{ {}{} }}", path_to_string(name),
+ fields.iter().map(|fp|
+ format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat)))
+ .collect::<Vec<String>>().connect(", "),
+ if etc { ", ..." } else { "" }
+ )
+ },
+ PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
+ .collect::<Vec<String>>().connect(", ")),
PatBox(p) => name_from_pat(&*p),
PatRegion(p) => name_from_pat(&*p),
PatLit(..) => {
let codemap = syntax::codemap::CodeMap::new();
- let diagnostic_handler = syntax::diagnostic::default_handler(syntax::diagnostic::Auto);
+ let diagnostic_handler = syntax::diagnostic::default_handler(syntax::diagnostic::Auto, None);
let span_diagnostic_handler =
syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
use syntax::ast_util;
use clean;
+use stability_summary::ModuleSummary;
use html::item_type;
use html::item_type::ItemType;
use html::render;
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
/// Similar to VisSpace, but used for mutability
pub struct MutableSpace(pub clean::Mutability);
+/// Similar to VisSpace, but used for mutability
+pub struct RawMutableSpace(pub clean::Mutability);
/// Wrapper struct for properly emitting the stability level.
pub struct Stability<'a>(pub &'a Option<clean::Stability>);
/// Wrapper struct for emitting the stability level concisely.
}
clean::Tuple(ref typs) => {
primitive_link(f, clean::PrimitiveTuple,
- format!("({:#})", typs).as_slice())
+ match typs.as_slice() {
+ [ref one] => format!("({},)", one),
+ many => format!("({:#})", many)
+ }.as_slice())
}
clean::Vector(ref t) => {
primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice())
clean::Unique(ref t) => write!(f, "Box<{}>", **t),
clean::Managed(ref t) => write!(f, "Gc<{}>", **t),
clean::RawPointer(m, ref t) => {
- write!(f, "*{}{}", MutableSpace(m), **t)
+ write!(f, "*{}{}", RawMutableSpace(m), **t)
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
}
}
+impl fmt::Show for RawMutableSpace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ RawMutableSpace(clean::Immutable) => write!(f, "const "),
+ RawMutableSpace(clean::Mutable) => write!(f, "mut "),
+ }
+ }
+}
+
impl<'a> fmt::Show for Stability<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Stability(stab) = *self;
}
}
}
+
+impl fmt::Show for ModuleSummary {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fn fmt_inner<'a>(f: &mut fmt::Formatter,
+ context: &mut Vec<&'a str>,
+ m: &'a ModuleSummary)
+ -> fmt::Result {
+ let cnt = m.counts;
+ let tot = cnt.total();
+ if tot == 0 { return Ok(()) }
+
+ context.push(m.name.as_slice());
+ let path = context.connect("::");
+
+ // the total width of each row's stability summary, in pixels
+ let width = 500;
+
+ try!(write!(f, "<tr>"));
+ try!(write!(f, "<td class='summary'>\
+ <a class='summary' href='{}'>{}</a></td>",
+ Vec::from_slice(context.slice_from(1))
+ .append_one("index.html").connect("/"),
+ path));
+ try!(write!(f, "<td>"));
+ try!(write!(f, "<span class='summary Stable' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.stable)/tot));
+ try!(write!(f, "<span class='summary Unstable' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.unstable)/tot));
+ try!(write!(f, "<span class='summary Experimental' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.experimental)/tot));
+ try!(write!(f, "<span class='summary Deprecated' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.deprecated)/tot));
+ try!(write!(f, "<span class='summary Unmarked' \
+ style='width: {}px; display: inline-block'> </span>",
+ (width * cnt.unmarked)/tot));
+ try!(write!(f, "</td></tr>"));
+
+ for submodule in m.submodules.iter() {
+ try!(fmt_inner(f, context, submodule));
+ }
+ context.pop();
+ Ok(())
+ }
+
+ let mut context = Vec::new();
+
+ try!(write!(f,
+r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{}</a></h1>
+This dashboard summarizes the stability levels for all of the public modules of
+the crate, according to the total number of items at each level in the module and its children:
+<blockquote>
+<a class='stability Stable'></a> stable,<br/>
+<a class='stability Unstable'></a> unstable,<br/>
+<a class='stability Experimental'></a> experimental,<br/>
+<a class='stability Deprecated'></a> deprecated,<br/>
+<a class='stability Unmarked'></a> unmarked
+</blockquote>
+The counts do not include methods or trait
+implementations that are visible only through a re-exported type.",
+self.name));
+ try!(write!(f, "<table>"))
+ try!(fmt_inner(f, &mut context, self));
+ write!(f, "</table>")
+ }
+}
use externalfiles::ExternalHtml;
+use serialize::json;
+use serialize::Encodable;
use serialize::json::ToJson;
use syntax::ast;
use syntax::ast_util;
use html::layout;
use html::markdown::Markdown;
use html::markdown;
+use stability_summary;
/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
try!(mkdir(&cx.dst));
+ // Crawl the crate, building a summary of the stability levels. NOTE: this
+ // summary *must* be computed with the original `krate`; the folding below
+ // removes the impls from their modules.
+ let summary = stability_summary::build(&krate);
+
// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
let krate = try!(render_sources(&mut cx, krate));
// And finally render the whole crate's documentation
- cx.krate(krate)
+ cx.krate(krate, summary)
}
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult<String> {
include_bin!("static/FiraSans-Regular.woff")));
try!(write(cx.dst.join("FiraSans-Medium.woff"),
include_bin!("static/FiraSans-Medium.woff")));
- try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
- include_bin!("static/SourceSerifPro-Bold.woff")));
try!(write(cx.dst.join("Heuristica-Italic.woff"),
include_bin!("static/Heuristica-Italic.woff")));
+ try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
+ include_bin!("static/SourceSerifPro-Regular.woff")));
try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
include_bin!("static/SourceSerifPro-Bold.woff")));
try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
- fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> {
+ fn krate(mut self, mut krate: clean::Crate,
+ stability: stability_summary::ModuleSummary) -> io::IoResult<()> {
let mut item = match krate.module.take() {
Some(i) => i,
None => return Ok(())
};
item.name = Some(krate.name);
+ // render stability dashboard
+ try!(self.recurse(stability.name.clone(), |this| {
+ let json_dst = &this.dst.join("stability.json");
+ let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
+ try!(stability.encode(&mut json::Encoder::new(&mut json_out)));
+
+ let title = stability.name.clone().append(" - Stability dashboard");
+ let page = layout::Page {
+ ty: "mod",
+ root_path: this.root_path.as_slice(),
+ title: title.as_slice(),
+ };
+ let html_dst = &this.dst.join("stability.html");
+ let mut html_out = BufferedWriter::new(try!(File::create(html_dst)));
+ layout::render(&mut html_out, &this.layout, &page,
+ &Sidebar{ cx: this, item: &item },
+ &stability)
+ }));
+
+ // render the crate documentation
let mut work = vec!((self, item));
loop {
match work.pop() {
None => break,
}
}
+
Ok(())
}
}
}
+
+
impl<'a> fmt::Show for Item<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
// Write the breadcrumb trail header for the top
// Write stability level
try!(write!(fmt, "{}", Stability(&self.item.stability)));
+ // Links to out-of-band information, i.e. src and stability dashboard
+ try!(write!(fmt, "<span class='out-of-band'>"));
+
+ // Write stability dashboard link
+ match self.item.inner {
+ clean::ModuleItem(ref m) if m.is_crate => {
+ try!(write!(fmt, "<a href='stability.html'>[stability dashboard]</a> "));
+ }
+ _ => {}
+ };
+
// Write `src` tag
//
// When this item is part of a `pub use` in a downstream crate, the
if self.cx.include_sources && !is_primitive {
match self.href() {
Some(l) => {
- try!(write!(fmt,
- "<a class='source' id='src-{}' \
- href='{}'>[src]</a>",
+ try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>",
self.item.def_id.node, l));
}
None => {}
}
}
+
+ try!(write!(fmt, "</span>"));
+
try!(write!(fmt, "</h1>\n"));
match self.item.inner {
fn item_module(w: &mut fmt::Formatter, cx: &Context,
item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
try!(document(w, item));
+
let mut indices = range(0, items.len()).filter(|i| {
!ignore_private_item(&items[*i])
}).collect::<Vec<uint>>();
}
}
}
+
write!(w, "</table>")
}
.docblock h2 { font-size: 1.15em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
-.content .source {
+.content .out-of-band {
float: right;
font-size: 23px;
}
.stability.Locked { border-color: #0084B6; color: #00668c; }
.stability.Unmarked { border-color: #FFFFFF; }
+.summary {
+ padding-right: 0px;
+}
+.summary.Deprecated { background-color: #A071A8; }
+.summary.Experimental { background-color: #D46D6A; }
+.summary.Unstable { background-color: #D4B16A; }
+.summary.Stable { background-color: #54A759; }
+.summary.Unmarked { background-color: #FFFFFF; }
+
:target { background: #FDFFD3; }
/* Code highlighting */
pub mod markdown;
pub mod passes;
pub mod plugins;
+pub mod stability_summary;
pub mod visit_ast;
pub mod test;
mod flock;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module crawls a `clean::Crate` and produces a summarization of the
+//! stability levels within the crate. The summary contains the module
+//! hierarchy, with item counts for every stability level per module. A parent
+//! module's count includes its childrens's.
+
+use std::ops::Add;
+use std::num::Zero;
+use std::iter::AdditiveIterator;
+
+use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
+use syntax::ast::Public;
+
+use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum};
+use clean::{ImplItem, Impl, TraitItem, Trait, TraitMethod, Provided, Required};
+use clean::{ViewItemItem, PrimitiveItem};
+
+#[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
+/// The counts for each stability level.
+pub struct Counts {
+ pub deprecated: uint,
+ pub experimental: uint,
+ pub unstable: uint,
+ pub stable: uint,
+ pub frozen: uint,
+ pub locked: uint,
+
+ /// No stability level, inherited or otherwise.
+ pub unmarked: uint,
+}
+
+impl Add<Counts, Counts> for Counts {
+ fn add(&self, other: &Counts) -> Counts {
+ Counts {
+ deprecated: self.deprecated + other.deprecated,
+ experimental: self.experimental + other.experimental,
+ unstable: self.unstable + other.unstable,
+ stable: self.stable + other.stable,
+ frozen: self.frozen + other.frozen,
+ locked: self.locked + other.locked,
+ unmarked: self.unmarked + other.unmarked,
+ }
+ }
+}
+
+impl Counts {
+ pub fn total(&self) -> uint {
+ self.deprecated + self.experimental + self.unstable + self.stable +
+ self.frozen + self.locked + self.unmarked
+ }
+}
+
+#[deriving(Encodable, Decodable, PartialEq, Eq)]
+/// A summarized module, which includes total counts and summarized chilcren
+/// modules.
+pub struct ModuleSummary {
+ pub name: String,
+ pub counts: Counts,
+ pub submodules: Vec<ModuleSummary>,
+}
+
+impl PartialOrd for ModuleSummary {
+ fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> {
+ self.name.partial_cmp(&other.name)
+ }
+}
+
+impl Ord for ModuleSummary {
+ fn cmp(&self, other: &ModuleSummary) -> Ordering {
+ self.name.cmp(&other.name)
+ }
+}
+
+// is the item considered publically visible?
+fn visible(item: &Item) -> bool {
+ match item.inner {
+ ImplItem(_) => true,
+ _ => item.visibility == Some(Public)
+ }
+}
+
+// Produce the summary for an arbitrary item. If the item is a module, include a
+// module summary. The counts for items with nested items (e.g. modules, traits,
+// impls) include all children counts.
+fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
+ // count this item
+ let item_counts = match item.stability {
+ None => Counts { unmarked: 1, .. Zero::zero() },
+ Some(ref stab) => match stab.level {
+ Deprecated => Counts { deprecated: 1, .. Zero::zero() },
+ Experimental => Counts { experimental: 1, .. Zero::zero() },
+ Unstable => Counts { unstable: 1, .. Zero::zero() },
+ Stable => Counts { stable: 1, .. Zero::zero() },
+ Frozen => Counts { frozen: 1, .. Zero::zero() },
+ Locked => Counts { locked: 1, .. Zero::zero() },
+ }
+ };
+
+ // Count this item's children, if any. Note that a trait impl is
+ // considered to have no children.
+ match item.inner {
+ // Require explicit `pub` to be visible
+ StructItem(Struct { fields: ref subitems, .. }) |
+ ImplItem(Impl { methods: ref subitems, trait_: None, .. }) => {
+ let subcounts = subitems.iter().filter(|i| visible(*i))
+ .map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ // `pub` automatically
+ EnumItem(Enum { variants: ref subitems, .. }) => {
+ let subcounts = subitems.iter().map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ TraitItem(Trait { methods: ref methods, .. }) => {
+ fn extract_item<'a>(meth: &'a TraitMethod) -> &'a Item {
+ match *meth {
+ Provided(ref item) | Required(ref item) => item
+ }
+ }
+ let subcounts = methods.iter().map(extract_item)
+ .map(summarize_item)
+ .map(|s| s.val0())
+ .sum();
+ (item_counts + subcounts, None)
+ }
+ ModuleItem(Module { items: ref items, .. }) => {
+ let mut counts = item_counts;
+ let mut submodules = Vec::new();
+
+ for (subcounts, submodule) in items.iter().filter(|i| visible(*i))
+ .map(summarize_item) {
+ counts = counts + subcounts;
+ submodule.map(|m| submodules.push(m));
+ }
+ submodules.sort();
+
+ (counts, Some(ModuleSummary {
+ name: item.name.as_ref().map_or("".to_string(), |n| n.clone()),
+ counts: counts,
+ submodules: submodules,
+ }))
+ }
+ // no stability information for the following items:
+ ViewItemItem(_) | PrimitiveItem(_) => (Zero::zero(), None),
+ _ => (item_counts, None)
+ }
+}
+
+/// Summarizes the stability levels in a crate.
+pub fn build(krate: &Crate) -> ModuleSummary {
+ match krate.module {
+ None => ModuleSummary {
+ name: krate.name.clone(),
+ counts: Zero::zero(),
+ submodules: Vec::new(),
+ },
+ Some(ref item) => ModuleSummary {
+ name: krate.name.clone(), .. summarize_item(item).val1().unwrap()
+ }
+ }
+}
let codemap = CodeMap::new();
- let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto);
+ let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
};
io::util::copy(&mut p, &mut err).unwrap();
});
- let emitter = diagnostic::EmitterWriter::new(box w2);
+ let emitter = diagnostic::EmitterWriter::new(box w2, None);
// Compile the code
let codemap = CodeMap::new();
// environment to ensure that the target loads the right libraries at
// runtime. It would be a sad day if the *host* libraries were loaded as a
// mistake.
- let exe = outdir.path().join("rust_out");
- let env = {
+ let mut cmd = Command::new(outdir.path().join("rust_out"));
+ let newpath = {
let mut path = DynamicLibrary::search_path();
path.insert(0, libdir.clone());
-
- // Remove the previous dylib search path var
- let var = DynamicLibrary::envvar();
- let mut env: Vec<(String,String)> = os::env().move_iter().collect();
- match env.iter().position(|&(ref k, _)| k.as_slice() == var) {
- Some(i) => { env.remove(i); }
- None => {}
- };
-
- // Add the new dylib search path var
- let newpath = DynamicLibrary::create_path(path.as_slice());
- env.push((var.to_string(),
- str::from_utf8(newpath.as_slice()).unwrap().to_string()));
- env
+ DynamicLibrary::create_path(path.as_slice())
};
- match Command::new(exe).env(env.as_slice()).output() {
+ cmd.env(DynamicLibrary::envvar(), newpath.as_slice());
+
+ match cmd.output() {
Err(e) => fail!("couldn't run the test: {}{}", e,
if e.kind == io::PermissionDenied {
" - maybe your tempdir is mounted with noexec?"
use alloc::libc_heap::malloc_raw;
use collections::string::String;
+use collections::hash;
use core::kinds::marker;
use core::mem;
use core::ptr;
}
}
+impl PartialOrd for CString {
+ #[inline]
+ fn partial_cmp(&self, other: &CString) -> Option<Ordering> {
+ self.as_bytes().partial_cmp(&other.as_bytes())
+ }
+}
+
+impl Eq for CString {}
+
+impl<S: hash::Writer> hash::Hash<S> for CString {
+ #[inline]
+ fn hash(&self, state: &mut S) {
+ self.as_bytes().hash(state)
+ }
+}
+
impl CString {
/// Create a C String from a pointer.
pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString {
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
-#![feature(linkage, lang_items, unsafe_destructor)]
+#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
#![no_std]
#![experimental]
/// Optional environment to specify for the program. If this is None, then
/// it will inherit the current process's environment.
- pub env: Option<&'a [(CString, CString)]>,
+ pub env: Option<&'a [(&'a CString, &'a CString)]>,
/// Optional working directory for the new process. If this is None, then
/// the current directory of the running process is inherited.
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, unsafe_destructor)]
}
/// Converts the environment to the env array expected by libuv
-fn with_env<T>(env: Option<&[(CString, CString)]>,
+fn with_env<T>(env: Option<&[(&CString, &CString)]>,
cb: |*const *const libc::c_char| -> T) -> T {
// We can pass a char** for envp, which is a null-terminated array
// of "k=v\0" strings. Since we must create these strings locally,
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
+#![feature(default_type_params)]
use std::char;
use std::cmp;
-use std::fmt;
use std::fmt::Show;
-use std::option::{Option, Some, None};
-use std::string::String;
+use std::fmt;
+use std::hash;
/// An identifier in the pre-release or build metadata. If the identifier can
/// be parsed as a decimal value, it will be represented with `Numeric`.
-#[deriving(Clone, PartialEq)]
+#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_doc)]
pub enum Identifier {
Numeric(uint),
AlphaNumeric(String)
}
-impl cmp::PartialOrd for Identifier {
- #[inline]
- fn partial_cmp(&self, other: &Identifier) -> Option<Ordering> {
- match (self, other) {
- (&Numeric(a), &Numeric(ref b)) => a.partial_cmp(b),
- (&Numeric(_), _) => Some(Less),
- (&AlphaNumeric(ref a), &AlphaNumeric(ref b)) => a.partial_cmp(b),
- (&AlphaNumeric(_), _) => Some(Greater)
- }
- }
-}
-
impl fmt::Show for Identifier {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// Represents a version number conforming to the semantic versioning scheme.
-#[deriving(Clone)]
+#[deriving(Clone, Eq)]
pub struct Version {
/// The major version, to be incremented on incompatible changes.
pub major: uint,
}
impl cmp::PartialOrd for Version {
- #[inline]
fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
- match self.major.partial_cmp(&other.major) {
- Some(Equal) => {}
+ Some(self.cmp(other))
+ }
+}
+
+impl cmp::Ord for Version {
+ fn cmp(&self, other: &Version) -> Ordering {
+ match self.major.cmp(&other.major) {
+ Equal => {}
r => return r,
}
- match self.minor.partial_cmp(&other.minor) {
- Some(Equal) => {}
+ match self.minor.cmp(&other.minor) {
+ Equal => {}
r => return r,
}
- match self.patch.partial_cmp(&other.patch) {
- Some(Equal) => {}
+ match self.patch.cmp(&other.patch) {
+ Equal => {}
r => return r,
}
// but the version of ord defined for vec
// says that [] < [pre] so we alter it here
match (self.pre.len(), other.pre.len()) {
- (0, 0) => Some(Equal),
- (0, _) => Some(Greater),
- (_, 0) => Some(Less),
- (_, _) => self.pre.partial_cmp(&other.pre)
+ (0, 0) => Equal,
+ (0, _) => Greater,
+ (_, 0) => Less,
+ (_, _) => self.pre.cmp(&other.pre)
}
}
}
+impl<S: hash::Writer> hash::Hash<S> for Version {
+ fn hash(&self, into: &mut S) {
+ self.major.hash(into);
+ self.minor.hash(into);
+ self.patch.hash(into);
+ self.pre.hash(into);
+ }
+}
+
fn take_nonempty_prefix<T:Iterator<char>>(rdr: &mut T, pred: |char| -> bool)
-> (String, Option<char>) {
let mut buf = String::new();
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
* ```
*/
+#![experimental]
+
pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip};
use default::Default;
#[inline]
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
// return an error if the entire write does not fit in the buffer
- let max_size = self.buf.len();
- if self.pos >= max_size || (self.pos + buf.len()) > max_size {
+ let cap = if self.pos >= self.buf.len() { 0 } else { self.buf.len() - self.pos };
+ if buf.len() > cap {
return Err(IoError {
kind: io::OtherIoError,
desc: "Trying to write past end of buffer",
writer.write([1, 2, 3]).unwrap();
writer.write([4, 5, 6, 7]).unwrap();
assert_eq!(writer.tell(), Ok(8));
+ writer.write([]).unwrap();
+ assert_eq!(writer.tell(), Ok(8));
}
assert_eq!(buf.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
}
use str;
use fmt;
+use os;
use io::{IoResult, IoError};
use io;
use libc;
use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo};
use rt::rtio;
use c_str::CString;
+use collections::HashMap;
/// Signal a process to exit, without forcibly killing it. Corresponds to
/// SIGTERM on unix platforms.
pub extra_io: Vec<Option<io::PipeStream>>,
}
+/// A HashMap representation of environment variables.
+pub type EnvMap = HashMap<CString, CString>;
+
/// The `Command` type acts as a process builder, providing fine-grained control
/// over how a new process should be spawned. A default configuration can be
/// generated using `Command::new(program)`, where `program` gives a path to the
// methods below, and serialized into rt::rtio::ProcessConfig.
program: CString,
args: Vec<CString>,
- env: Option<Vec<(CString, CString)>>,
+ env: Option<EnvMap>,
cwd: Option<CString>,
stdin: StdioContainer,
stdout: StdioContainer,
}
/// Add an argument to pass to the program.
- pub fn arg<'a, T:ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
+ pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
self.args.push(arg.to_c_str());
self
}
/// Add multiple arguments to pass to the program.
- pub fn args<'a, T:ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
+ pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
self.args.extend(args.iter().map(|arg| arg.to_c_str()));;
self
}
+ // Get a mutable borrow of the environment variable map for this `Command`.
+ fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap {
+ match self.env {
+ Some(ref mut map) => map,
+ None => {
+ // if the env is currently just inheriting from the parent's,
+ // materialize the parent's env into a hashtable.
+ self.env = Some(os::env_as_bytes().move_iter()
+ .map(|(k, v)| (k.as_slice().to_c_str(),
+ v.as_slice().to_c_str()))
+ .collect());
+ self.env.as_mut().unwrap()
+ }
+ }
+ }
- /// Sets the environment for the child process (rather than inheriting it
- /// from the current process).
-
- // FIXME (#13851): We should change this interface to allow clients to (1)
- // build up the env vector incrementally and (2) allow both inheriting the
- // current process's environment AND overriding/adding additional
- // environment variables. The underlying syscalls assume that the
- // environment has no duplicate names, so we really want to use a hashtable
- // to compute the environment to pass down to the syscall; resolving issue
- // #13851 will make it possible to use the standard hashtable.
- pub fn env<'a, T:ToCStr>(&'a mut self, env: &[(T,T)]) -> &'a mut Command {
- self.env = Some(env.iter().map(|&(ref name, ref val)| {
- (name.to_c_str(), val.to_c_str())
- }).collect());
+ /// Inserts or updates an environment variable mapping.
+ pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U)
+ -> &'a mut Command {
+ self.get_env_map().insert(key.to_c_str(), val.to_c_str());
+ self
+ }
+
+ /// Removes an environment variable mapping.
+ pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command {
+ self.get_env_map().remove(&key.to_c_str());
+ self
+ }
+
+ /// Sets the entire environment map for the child process.
+ ///
+ /// If the given slice contains multiple instances of an environment
+ /// variable, the *rightmost* instance will determine the value.
+ pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)])
+ -> &'a mut Command {
+ self.env = Some(env.iter().map(|&(ref k, ref v)| (k.to_c_str(), v.to_c_str()))
+ .collect());
self
}
let extra_io: Vec<rtio::StdioContainer> =
self.extra_io.iter().map(|x| to_rtio(*x)).collect();
LocalIo::maybe_raise(|io| {
+ let env = match self.env {
+ None => None,
+ Some(ref env_map) =>
+ Some(env_map.iter().collect::<Vec<_>>())
+ };
let cfg = ProcessConfig {
program: &self.program,
args: self.args.as_slice(),
- env: self.env.as_ref().map(|env| env.as_slice()),
+ env: env.as_ref().map(|e| e.as_slice()),
cwd: self.cwd.as_ref(),
stdin: to_rtio(self.stdin),
stdout: to_rtio(self.stdout),
}
})
- iotest!(fn test_add_to_env() {
+ iotest!(fn test_override_env() {
let new_env = vec![("RUN_TEST_NEW_ENV", "123")];
- let prog = env_cmd().env(new_env.as_slice()).spawn().unwrap();
+ let prog = env_cmd().env_set_all(new_env.as_slice()).spawn().unwrap();
let result = prog.wait_with_output().unwrap();
let output = str::from_utf8_lossy(result.output.as_slice()).into_string();
"didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
})
+ iotest!(fn test_add_to_env() {
+ let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap();
+ let result = prog.wait_with_output().unwrap();
+ let output = str::from_utf8_lossy(result.output.as_slice()).into_string();
+
+ assert!(output.as_slice().contains("RUN_TEST_NEW_ENV=123"),
+ "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ })
+
+ iotest!(fn test_remove_from_env() {
+ use os;
+
+ // save original environment
+ let old_env = os::getenv("RUN_TEST_NEW_ENV");
+
+ os::setenv("RUN_TEST_NEW_ENV", "123");
+ let prog = env_cmd().env_remove("RUN_TEST_NEW_ENV").spawn().unwrap();
+ let result = prog.wait_with_output().unwrap();
+ let output = str::from_utf8_lossy(result.output.as_slice()).into_string();
+
+ // restore original environment
+ match old_env {
+ None => {
+ os::unsetenv("RUN_TEST_NEW_ENV");
+ }
+ Some(val) => {
+ os::setenv("RUN_TEST_NEW_ENV", val.as_slice());
+ }
+ }
+
+ assert!(!output.as_slice().contains("RUN_TEST_NEW_ENV"),
+ "found RUN_TEST_NEW_ENV inside of:\n\n{}", output);
+ })
+
#[cfg(unix)]
pub fn sleeper() -> Process {
Command::new("sleep").arg("1000").spawn().unwrap()
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, globs, managed_boxes, linkage)]
// The test runner requires std::slice::Vector, so re-export std::slice just for it.
#[cfg(test)] pub use slice;
}
-
-#[deprecated]
-#[allow(missing_doc)]
-#[doc(hiden)]
-pub mod unstable {
- #[deprecated = "use std::dynamic_lib"]
- pub use dynamic_lib;
-}
/// The memory map is released (unmapped) when the destructor is run, so don't
/// let it leave scope by accident if you want it to stick around.
pub struct MemoryMap {
- /// Pointer to the memory created or modified by this map.
- pub data: *mut u8,
- /// Number of bytes this map applies to
- pub len: uint,
- /// Type of mapping
- pub kind: MemoryMapKind,
+ data: *mut u8,
+ len: uint,
+ kind: MemoryMapKind,
}
/// Type of memory map
}
}
+impl MemoryMap {
+ /// Returns the pointer to the memory created or modified by this map.
+ pub fn data(&self) -> *mut u8 { self.data }
+ /// Returns the number of bytes this map applies to.
+ pub fn len(&self) -> uint { self.len }
+ /// Returns the type of mapping this represents.
+ pub fn kind(&self) -> MemoryMapKind { self.kind }
+}
+
#[cfg(target_os = "linux")]
pub mod consts {
pub use os::arch_consts::ARCH;
use c_str::{CString, ToCStr};
use clone::Clone;
-use cmp::{PartialEq, Eq};
+use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use collections::Collection;
use from_str::FromStr;
use hash;
impl Eq for Path {}
+impl PartialOrd for Path {
+ fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Path {
+ fn cmp(&self, other: &Path) -> Ordering {
+ self.repr.cmp(&other.repr)
+ }
+}
+
impl FromStr for Path {
fn from_str(s: &str) -> Option<Path> {
Path::new_opt(s)
use ascii::AsciiCast;
use c_str::{CString, ToCStr};
use clone::Clone;
-use cmp::{PartialEq, Eq};
+use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use collections::Collection;
use from_str::FromStr;
use hash;
impl Eq for Path {}
+impl PartialOrd for Path {
+ fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Path {
+ fn cmp(&self, other: &Path) -> Ordering {
+ self.repr.cmp(&other.repr)
+ }
+}
+
impl FromStr for Path {
fn from_str(s: &str) -> Option<Path> {
Path::new_opt(s)
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase, globs, macro_rules, unsafe_destructor)]
pub attrs: Vec<Attribute>,
pub config: CrateConfig,
pub span: Span,
+ pub exported_macros: Vec<Span>
}
pub type MetaItem = Spanned<MetaItem_>;
hi: BytePos(20),
expn_info: None,
},
+ exported_macros: Vec::new(),
};
// doesn't matter which encoder we use....
let _f = &e as &serialize::Encodable<json::Encoder, io::IoError>;
NodeLifetime(Gc<Lifetime>),
}
+/// Represents an entry and its parent Node ID
/// The odd layout is to bring down the total size.
#[deriving(Clone)]
enum MapEntry {
}
}
+/// Represents a mapping from Node IDs to AST elements and their parent
+/// Node IDs
pub struct Map {
/// NodeIds are sequential integers from 0, so we can be
/// super-compact by storing them in a vector. Not everything with
}
}
+/// A Folder that walks over an AST and constructs a Node ID Map. Its
+/// fold_ops argument has the opportunity to replace Node IDs and spans.
pub struct Ctx<'a, F> {
map: &'a Map,
/// The node in which we are currently mapping (an item or a method).
self.insert(lifetime.id, EntryLifetime(self.parent, box(GC) lifetime));
lifetime
}
+
+ fn fold_mac(&mut self, mac: &Mac) -> Mac {
+ fold::fold_mac(mac, self)
+ }
}
pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
use codemap::{Pos, Span};
use codemap;
+use diagnostics;
use std::cell::{RefCell, Cell};
use std::fmt;
pub trait Emitter {
fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
- msg: &str, lvl: Level);
+ msg: &str, code: Option<&str>, lvl: Level);
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: RenderSpan, msg: &str, lvl: Level);
}
self.handler.emit(Some((&self.cm, sp)), msg, Error);
self.handler.bump_err_count();
}
+ pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
+ self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error);
+ self.handler.bump_err_count();
+ }
pub fn span_warn(&self, sp: Span, msg: &str) {
self.handler.emit(Some((&self.cm, sp)), msg, Warning);
}
impl Handler {
pub fn fatal(&self, msg: &str) -> ! {
- self.emit.borrow_mut().emit(None, msg, Fatal);
+ self.emit.borrow_mut().emit(None, msg, None, Fatal);
fail!(FatalError);
}
pub fn err(&self, msg: &str) {
- self.emit.borrow_mut().emit(None, msg, Error);
+ self.emit.borrow_mut().emit(None, msg, None, Error);
self.bump_err_count();
}
pub fn bump_err_count(&self) {
self.fatal(s.as_slice());
}
pub fn warn(&self, msg: &str) {
- self.emit.borrow_mut().emit(None, msg, Warning);
+ self.emit.borrow_mut().emit(None, msg, None, Warning);
}
pub fn note(&self, msg: &str) {
- self.emit.borrow_mut().emit(None, msg, Note);
+ self.emit.borrow_mut().emit(None, msg, None, Note);
}
pub fn bug(&self, msg: &str) -> ! {
- self.emit.borrow_mut().emit(None, msg, Bug);
+ self.emit.borrow_mut().emit(None, msg, None, Bug);
fail!(ExplicitBug);
}
pub fn unimpl(&self, msg: &str) -> ! {
cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
lvl: Level) {
- self.emit.borrow_mut().emit(cmsp, msg, lvl);
+ self.emit.borrow_mut().emit(cmsp, msg, None, lvl);
+ }
+ pub fn emit_with_code(&self,
+ cmsp: Option<(&codemap::CodeMap, Span)>,
+ msg: &str,
+ code: &str,
+ lvl: Level) {
+ self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl);
}
pub fn custom_emit(&self, cm: &codemap::CodeMap,
sp: RenderSpan, msg: &str, lvl: Level) {
}
}
-pub fn default_handler(color_config: ColorConfig) -> Handler {
- mk_handler(box EmitterWriter::stderr(color_config))
+pub fn default_handler(color_config: ColorConfig,
+ registry: Option<diagnostics::registry::Registry>) -> Handler {
+ mk_handler(box EmitterWriter::stderr(color_config, registry))
}
pub fn mk_handler(e: Box<Emitter + Send>) -> Handler {
}
}
-fn print_diagnostic(dst: &mut EmitterWriter,
- topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
+fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level,
+ msg: &str, code: Option<&str>) -> io::IoResult<()> {
if !topic.is_empty() {
try!(write!(&mut dst.dst, "{} ", topic));
}
format!("{}: ", lvl.to_string()).as_slice(),
term::attr::ForegroundColor(lvl.color())));
try!(print_maybe_styled(dst,
- format!("{}\n", msg).as_slice(),
+ format!("{}", msg).as_slice(),
term::attr::Bold));
+
+ match code {
+ Some(code) => {
+ let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
+ try!(print_maybe_styled(dst, format!(" [{}]", code.clone()).as_slice(), style));
+ match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
+ Some(_) => {
+ try!(write!(&mut dst.dst,
+ " (pass `--explain {}` to see a detailed explanation)",
+ code
+ ));
+ }
+ None => ()
+ }
+ }
+ None => ()
+ }
+ try!(dst.dst.write_char('\n'));
Ok(())
}
pub struct EmitterWriter {
dst: Destination,
+ registry: Option<diagnostics::registry::Registry>
}
enum Destination {
}
impl EmitterWriter {
- pub fn stderr(color_config: ColorConfig) -> EmitterWriter {
+ pub fn stderr(color_config: ColorConfig,
+ registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
let stderr = io::stderr();
let use_color = match color_config {
Some(t) => Terminal(t),
None => Raw(box stderr),
};
- EmitterWriter { dst: dst }
+ EmitterWriter { dst: dst, registry: registry }
} else {
- EmitterWriter { dst: Raw(box stderr) }
+ EmitterWriter { dst: Raw(box stderr), registry: registry }
}
}
- pub fn new(dst: Box<Writer + Send>) -> EmitterWriter {
- EmitterWriter { dst: Raw(dst) }
+ pub fn new(dst: Box<Writer + Send>,
+ registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
+ EmitterWriter { dst: Raw(dst), registry: registry }
}
}
impl Emitter for EmitterWriter {
fn emit(&mut self,
cmsp: Option<(&codemap::CodeMap, Span)>,
- msg: &str,
- lvl: Level) {
+ msg: &str, code: Option<&str>, lvl: Level) {
let error = match cmsp {
- Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, lvl, false),
- None => print_diagnostic(self, "", lvl, msg),
+ Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false),
+ None => print_diagnostic(self, "", lvl, msg, code),
};
match error {
fn custom_emit(&mut self, cm: &codemap::CodeMap,
sp: RenderSpan, msg: &str, lvl: Level) {
- match emit(self, cm, sp, msg, lvl, true) {
+ match emit(self, cm, sp, msg, None, lvl, true) {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
- msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
+ msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::IoResult<()> {
let sp = rsp.span();
let ss = cm.span_to_string(sp);
let lines = cm.span_to_lines(sp);
// the span)
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
let ses = cm.span_to_string(span_end);
- try!(print_diagnostic(dst, ses.as_slice(), lvl, msg));
+ try!(print_diagnostic(dst, ses.as_slice(), lvl, msg, code));
if rsp.is_full_span() {
try!(custom_highlight_lines(dst, cm, sp, lvl, lines));
}
} else {
- try!(print_diagnostic(dst, ss.as_slice(), lvl, msg));
+ try!(print_diagnostic(dst, ss.as_slice(), lvl, msg, code));
if rsp.is_full_span() {
try!(highlight_lines(dst, cm, sp, lvl, lines));
}
try!(print_diagnostic(w, ss.as_slice(), Note,
format!("in expansion of {}{}{}", pre,
ei.callee.name,
- post).as_slice()));
+ post).as_slice(), None));
let ss = cm.span_to_string(ei.call_site);
- try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site"));
+ try!(print_diagnostic(w, ss.as_slice(), Note, "expansion site", None));
try!(print_macro_backtrace(w, cm, ei.call_site));
}
Ok(())
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![macro_escape]
+
+// NOTE: remove after next snapshot
+#[cfg(stage0)]
+#[macro_export]
+macro_rules! __register_diagnostic(
+ ($code:tt, $description:tt) => ();
+ ($code:tt) => ()
+)
+
+#[macro_export]
+macro_rules! register_diagnostic(
+ ($code:tt, $description:tt) => (__register_diagnostic!($code, $description));
+ ($code:tt) => (__register_diagnostic!($code))
+)
+
+// NOTE: remove after next snapshot
+#[cfg(stage0)]
+#[macro_export]
+macro_rules! __build_diagnostic_array(
+ ($name:ident) => {
+ pub static $name: [(&'static str, &'static str), ..0] = [];
+ }
+)
+
+// NOTE: remove after next snapshot
+#[cfg(stage0)]
+#[macro_export]
+macro_rules! __diagnostic_used(
+ ($code:ident) => {
+ ()
+ }
+)
+
+#[macro_export]
+macro_rules! span_err(
+ ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({
+ __diagnostic_used!($code);
+ ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code))
+ })
+)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::gc::Gc;
+use ast;
+use ast::{Ident, Name, TokenTree};
+use codemap::Span;
+use ext::base::{ExtCtxt, MacExpr, MacItem, MacResult};
+use ext::build::AstBuilder;
+use parse::token;
+
+local_data_key!(registered_diagnostics: RefCell<HashMap<Name, Option<Name>>>)
+local_data_key!(used_diagnostics: RefCell<HashMap<Name, Span>>)
+
+fn with_registered_diagnostics<T>(f: |&mut HashMap<Name, Option<Name>>| -> T) -> T {
+ match registered_diagnostics.get() {
+ Some(cell) => f(cell.borrow_mut().deref_mut()),
+ None => {
+ let mut map = HashMap::new();
+ let value = f(&mut map);
+ registered_diagnostics.replace(Some(RefCell::new(map)));
+ value
+ }
+ }
+}
+
+fn with_used_diagnostics<T>(f: |&mut HashMap<Name, Span>| -> T) -> T {
+ match used_diagnostics.get() {
+ Some(cell) => f(cell.borrow_mut().deref_mut()),
+ None => {
+ let mut map = HashMap::new();
+ let value = f(&mut map);
+ used_diagnostics.replace(Some(RefCell::new(map)));
+ value
+ }
+ }
+}
+
+pub fn expand_diagnostic_used(ecx: &mut ExtCtxt, span: Span,
+ token_tree: &[TokenTree]) -> Box<MacResult> {
+ let code = match token_tree {
+ [ast::TTTok(_, token::IDENT(code, _))] => code,
+ _ => unreachable!()
+ };
+ with_registered_diagnostics(|diagnostics| {
+ if !diagnostics.contains_key(&code.name) {
+ ecx.span_err(span, format!(
+ "unknown diagnostic code {}", token::get_ident(code).get()
+ ).as_slice());
+ }
+ ()
+ });
+ with_used_diagnostics(|diagnostics| {
+ match diagnostics.swap(code.name, span) {
+ Some(previous_span) => {
+ ecx.span_warn(span, format!(
+ "diagnostic code {} already used", token::get_ident(code).get()
+ ).as_slice());
+ ecx.span_note(previous_span, "previous invocation");
+ },
+ None => ()
+ }
+ ()
+ });
+ MacExpr::new(quote_expr!(ecx, ()))
+}
+
+pub fn expand_register_diagnostic(ecx: &mut ExtCtxt, span: Span,
+ token_tree: &[TokenTree]) -> Box<MacResult> {
+ let (code, description) = match token_tree {
+ [ast::TTTok(_, token::IDENT(ref code, _))] => {
+ (code, None)
+ },
+ [ast::TTTok(_, token::IDENT(ref code, _)),
+ ast::TTTok(_, token::COMMA),
+ ast::TTTok(_, token::LIT_STR_RAW(description, _))] => {
+ (code, Some(description))
+ }
+ _ => unreachable!()
+ };
+ with_registered_diagnostics(|diagnostics| {
+ if !diagnostics.insert(code.name, description) {
+ ecx.span_err(span, format!(
+ "diagnostic code {} already registered", token::get_ident(*code).get()
+ ).as_slice());
+ }
+ });
+ let sym = Ident::new(token::gensym((
+ "__register_diagnostic_".to_string() + token::get_ident(*code).get()
+ ).as_slice()));
+ MacItem::new(quote_item!(ecx, mod $sym {}).unwrap())
+}
+
+pub fn expand_build_diagnostic_array(ecx: &mut ExtCtxt, span: Span,
+ token_tree: &[TokenTree]) -> Box<MacResult> {
+ let name = match token_tree {
+ [ast::TTTok(_, token::IDENT(ref name, _))] => name,
+ _ => unreachable!()
+ };
+
+ let (count, expr) = with_used_diagnostics(|diagnostics_in_use| {
+ with_registered_diagnostics(|diagnostics| {
+ let descriptions: Vec<Gc<ast::Expr>> = diagnostics
+ .iter().filter_map(|(code, description)| {
+ if !diagnostics_in_use.contains_key(code) {
+ ecx.span_warn(span, format!(
+ "diagnostic code {} never used", token::get_name(*code).get()
+ ).as_slice());
+ }
+ description.map(|description| {
+ ecx.expr_tuple(span, vec![
+ ecx.expr_str(span, token::get_name(*code)),
+ ecx.expr_str(span, token::get_name(description))
+ ])
+ })
+ }).collect();
+ (descriptions.len(), ecx.expr_vec(span, descriptions))
+ })
+ });
+ MacItem::new(quote_item!(ecx,
+ pub static $name: [(&'static str, &'static str), ..$count] = $expr;
+ ).unwrap())
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+
+pub struct Registry {
+ descriptions: HashMap<&'static str, &'static str>
+}
+
+impl Registry {
+ pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry {
+ Registry { descriptions: descriptions.iter().map(|&tuple| tuple).collect() }
+ }
+
+ pub fn find_description(&self, code: &str) -> Option<&'static str> {
+ self.descriptions.find_equiv(&code).map(|desc| *desc)
+ }
+}
pub span: Option<Span>
}
-pub trait MacroExpander {
+/// Represents a thing that maps token trees to Macro Results
+pub trait TTMacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
-> Box<MacResult>;
-impl MacroExpander for BasicMacroExpander {
+impl TTMacroExpander for BasicMacroExpander {
fn expand(&self,
ecx: &mut ExtCtxt,
span: Span,
/// A normal, function-like syntax extension.
///
/// `bytes!` is a `NormalTT`.
- NormalTT(Box<MacroExpander + 'static>, Option<Span>),
+ NormalTT(Box<TTMacroExpander + 'static>, Option<Span>),
/// A function-like syntax extension that has an extra ident before
/// the block.
pub mod_path: Vec<ast::Ident> ,
pub trace_mac: bool,
+ pub exported_macros: Vec<codemap::Span>
}
impl<'a> ExtCtxt<'a> {
backtrace: None,
mod_path: Vec::new(),
ecfg: ecfg,
- trace_mac: false
+ trace_mac: false,
+ exported_macros: Vec::new(),
}
}
pub fn name_of(&self, st: &str) -> ast::Name {
token::intern(st)
}
+ pub fn push_exported_macro(&mut self, span: codemap::Span) {
+ self.exported_macros.push(span);
+ }
}
/// Extract a string literal from the macro expanded version of `expr`,
fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>;
fn expr_none(&self, sp: Span) -> Gc<ast::Expr>;
+ fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>;
+
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr>;
fn expr_unreachable(&self, span: Span) -> Gc<ast::Expr>;
self.expr_path(none)
}
+ fn expr_tuple(&self, sp: Span, exprs: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr> {
+ self.expr(sp, ast::ExprTup(exprs))
+ }
+
fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr> {
let loc = self.codemap().lookup_char_pos(span.lo);
self.expr_call_global(
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_clone("Clone", c, s, sub)
}),
ctor_ident = variant.node.name;
all_fields = af;
},
- EnumNonMatching(..) => {
+ EnumNonMatchingCollapsed (..) => {
cx.span_bug(trait_span,
format!("non-matching enum variants in \
`deriving({})`",
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
$f(a, b, c)
})
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
})
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
})
trait_def.expand(cx, mitem, item, push)
}
-pub fn some_ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> Gc<ast::Expr> {
- let cnst = match cnst {
- Less => "Less",
- Equal => "Equal",
- Greater => "Greater"
+pub enum OrderingOp {
+ PartialCmpOp, LtOp, LeOp, GtOp, GeOp,
+}
+
+pub fn some_ordering_collapsed(cx: &mut ExtCtxt,
+ span: Span,
+ op: OrderingOp,
+ self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
+ let lft = cx.expr_ident(span, self_arg_tags[0]);
+ let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+ let op_str = match op {
+ PartialCmpOp => "partial_cmp",
+ LtOp => "lt", LeOp => "le",
+ GtOp => "gt", GeOp => "ge",
};
- let ordering = cx.path_global(span,
- vec!(cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)));
- let ordering = cx.expr_path(ordering);
- cx.expr_some(span, ordering)
+ cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {
let test_id = cx.ident_of("__test");
- let equals_expr = some_ordering_const(cx, span, Equal);
+ let ordering = cx.path_global(span,
+ vec!(cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of("Equal")));
+ let ordering = cx.expr_path(ordering);
+ let equals_expr = cx.expr_some(span, ordering);
/*
Builds:
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
equals_expr.clone(),
- |cx, span, list, _| {
- match list {
- // an earlier nonmatching variant is Less than a
- // later one.
- [(self_var, _, _), (other_var, _, _)] =>
- some_ordering_const(cx, span, self_var.cmp(&other_var)),
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ } else {
+ some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
}
},
cx, span, substr)
cx.expr_binary(span, ast::BiOr, cmp, and)
},
cx.expr_bool(span, equal),
- |cx, span, args, _| {
- // nonmatching enums, order by the order the variants are
- // written
- match args {
- [(self_var, _, _),
- (other_var, _, _)] =>
- cx.expr_bool(span,
- if less {
- self_var < other_var
- } else {
- self_var > other_var
- }),
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ } else {
+ let op = match (less, equal) {
+ (true, true) => LeOp, (true, false) => LtOp,
+ (false, true) => GeOp, (false, false) => GtOp,
+ };
+ some_ordering_collapsed(cx, span, op, tag_tuple)
}
},
cx, span, substr)
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
cs_total_eq_assert(a, b, c)
})
use ext::deriving::generic::ty::*;
use parse::token::InternedString;
-use std::cmp::{Ordering, Equal, Less, Greater};
use std::gc::Gc;
pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
args: vec!(borrowed_self()),
ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
cs_cmp(a, b, c)
}),
}
-pub fn ordering_const(cx: &mut ExtCtxt, span: Span, cnst: Ordering) -> ast::Path {
- let cnst = match cnst {
- Less => "Less",
- Equal => "Equal",
- Greater => "Greater"
- };
- cx.path_global(span,
- vec!(cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)))
+pub fn ordering_collapsed(cx: &mut ExtCtxt,
+ span: Span,
+ self_arg_tags: &[ast::Ident]) -> Gc<ast::Expr> {
+ let lft = cx.expr_ident(span, self_arg_tags[0]);
+ let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
+ cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
}
pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> Gc<Expr> {
let test_id = cx.ident_of("__test");
- let equals_path = ordering_const(cx, span, Equal);
+ let equals_path = cx.path_global(span,
+ vec!(cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of("Equal")));
/*
Builds:
cx.expr_block(cx.block(span, vec!(assign), Some(if_)))
},
cx.expr_path(equals_path.clone()),
- |cx, span, list, _| {
- match list {
- // an earlier nonmatching variant is Less than a
- // later one.
- [(self_var, _, _),
- (other_var, _, _)] => {
- let order = ordering_const(cx, span, self_var.cmp(&other_var));
- cx.expr_path(order)
- }
- _ => cx.span_bug(span, "not exactly 2 arguments in `deriving(Ord)`")
+ |cx, span, (self_args, tag_tuple), _non_self_args| {
+ if self_args.len() != 2 {
+ cx.span_bug(span, "not exactly 2 arguments in `deriving(TotalOrd)`")
+ } else {
+ ordering_collapsed(cx, span, tag_tuple)
}
},
cx, span, substr)
vec!(box Self,
box Literal(Path::new_local("__E"))), true)),
attributes: Vec::new(),
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
decodable_substructure(a, b, c)
}),
args: Vec::new(),
ret_ty: Self,
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
default_substructure(a, b, c)
})
box Literal(Path::new_local("__E"))),
true)),
attributes: Vec::new(),
- const_nonmatching: true,
combine_substructure: combine_substructure(|a, b, c| {
encodable_substructure(a, b, c)
}),
//! `struct T(int, char)`).
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
//! same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`)
-//! - `EnumNonMatching` when `Self` is an enum and the arguments are not
-//! the same variant (e.g. `None`, `Some(1)` and `None`). If
-//! `const_nonmatching` is true, this will contain an empty list.
+//! - `EnumNonMatchingCollapsed` when `Self` is an enum and the arguments
+//! are not the same variant (e.g. `None`, `Some(1)` and `None`).
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
//! being derived upon is either an enum or struct respectively. (Any
//! argument with type Self is just grouped among the non-self
//! arguments.)
//!
//! In the first two cases, the values from the corresponding fields in
-//! all the arguments are grouped together. In the `EnumNonMatching` case
+//! all the arguments are grouped together. For `EnumNonMatchingCollapsed`
//! this isn't possible (different variants have different fields), so the
-//! fields are grouped by which argument they come from. There are no
+//! fields are inaccessible. (Previous versions of the deriving infrastructure
+//! had a way to expand into code that could access them, at the cost of
+//! generating exponential amounts of code; see issue #15375). There are no
//! fields with values in the static cases, so these are treated entirely
//! differently.
//!
//! For `C0(a)` and `C1 {x}` ,
//!
//! ~~~text
-//! EnumNonMatching(~[(0, <ast::Variant for B0>,
-//! ~[(<span of int>, None, <expr for &a>)]),
-//! (1, <ast::Variant for B1>,
-//! ~[(<span of x>, Some(<ident of x>),
-//! <expr for &other.x>)])])
+//! EnumNonMatchingCollapsed(
+//! ~[<ident of self>, <ident of __arg_1>],
+//! &[<ast::Variant for C0>, <ast::Variant for C1>],
+//! &[<ident for self index value>, <ident of __arg_1 index value>])
//! ~~~
//!
-//! (and vice versa, but with the order of the outermost list flipped.)
+//! It is the same for when the arguments are flipped to `C1 {x}` and
+//! `C0(a)`; the only difference is what the values of the identifiers
+//! <ident for self index value> and <ident of __arg_1 index value> will
+//! be in the generated code.
+//!
+//! `EnumNonMatchingCollapsed` deliberately provides far less information
+//! than is generally available for a given pair of variants; see #15375
+//! for discussion.
//!
//! ## Static
//!
pub attributes: Vec<ast::Attribute>,
- /// if the value of the nonmatching enums is independent of the
- /// actual enum variants, i.e. can use _ => .. match.
- pub const_nonmatching: bool,
-
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
}
EnumMatching(uint, &'a ast::Variant, Vec<FieldInfo>),
/**
- non-matching variants of the enum, [(variant index, ast::Variant,
- [field span, field ident, fields])] \(i.e. all fields for self are in the
- first tuple, for other1 are in the second tuple, etc.)
+ non-matching variants of the enum, but with all state hidden from
+ the consequent code. The first component holds Idents for all of
+ the Self arguments; the second component is a slice of all of the
+ variants for the enum itself, and the third component is a list of
+ Idents bound to the variant index values for each of the actual
+ input Self arguments.
*/
- EnumNonMatching(&'a [(uint, P<ast::Variant>,
- Vec<(Span, Option<Ident>, Gc<Expr>)>)]),
+ EnumNonMatchingCollapsed(Vec<Ident>, &'a [Gc<ast::Variant>], &'a [Ident]),
/// A static method where Self is a struct.
StaticStruct(&'a ast::StructDef, StaticFields),
|&mut ExtCtxt, Span, &Substructure|: 'a -> Gc<Expr>;
/**
-Deal with non-matching enum variants, the arguments are a list
-representing each variant: (variant index, ast::Variant instance,
-[variant fields]), and a list of the nonself args of the type
+Deal with non-matching enum variants. The tuple is a list of
+identifiers (one for each Self argument, which could be any of the
+variants since they have been collapsed together) and the identifiers
+holding the variant index value for each of the Self arguments. The
+last argument is all the non-Self args of the method being derived.
*/
-pub type EnumNonMatchFunc<'a> =
+pub type EnumNonMatchCollapsedFunc<'a> =
|&mut ExtCtxt,
Span,
- &[(uint, P<ast::Variant>, Vec<(Span, Option<Ident>, Gc<Expr>)>)],
+ (&[Ident], &[Ident]),
&[Gc<Expr>]|: 'a
-> Gc<Expr>;
}
}
+fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, variant: &ast::Variant)
+ -> Gc<ast::Pat> {
+ let ident = cx.path_ident(sp, variant.node.name);
+ cx.pat(sp, match variant.node.kind {
+ ast::TupleVariantKind(..) => ast::PatEnum(ident, None),
+ ast::StructVariantKind(..) => ast::PatStruct(ident, Vec::new(), true),
+ })
+}
+
impl<'a> MethodDef<'a> {
fn call_substructure_method(&self,
cx: &mut ExtCtxt,
~~~
#[deriving(PartialEq)]
enum A {
- A1
+ A1,
A2(int)
}
- // is equivalent to (with const_nonmatching == false)
+ // is equivalent to
impl PartialEq for A {
- fn eq(&self, __arg_1: &A) {
- match *self {
- A1 => match *__arg_1 {
- A1 => true
- A2(ref __arg_1_1) => false
- },
- A2(self_1) => match *__arg_1 {
- A1 => false,
- A2(ref __arg_1_1) => self_1.eq(__arg_1_1)
+ fn eq(&self, __arg_1: &A) -> ::bool {
+ match (&*self, &*__arg_1) {
+ (&A1, &A1) => true,
+ (&A2(ref __self_0),
+ &A2(ref __arg_1_0)) => (*__self_0).eq(&(*__arg_1_0)),
+ _ => {
+ let __self_vi = match *self { A1(..) => 0u, A2(..) => 1u };
+ let __arg_1_vi = match *__arg_1 { A1(..) => 0u, A2(..) => 1u };
+ false
}
}
}
}
~~~
+
+ (Of course `__self_vi` and `__arg_1_vi` are unused for
+ `PartialEq`, and those subcomputations will hopefully be removed
+ as their results are unused. The point of `__self_vi` and
+ `__arg_1_vi` is for `PartialOrd`; see #15503.)
*/
fn expand_enum_method_body(&self,
cx: &mut ExtCtxt,
self_args: &[Gc<Expr>],
nonself_args: &[Gc<Expr>])
-> Gc<Expr> {
- let mut matches = Vec::new();
- self.build_enum_match(cx, trait_, enum_def, type_ident,
- self_args, nonself_args,
- None, &mut matches, 0)
+ self.build_enum_match_tuple(
+ cx, trait_, enum_def, type_ident, self_args, nonself_args)
}
/**
- Creates the nested matches for an enum definition recursively, i.e.
-
- ~~~text
- match self {
- Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... },
- Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... },
- ...
+ Creates a match for a tuple of all `self_args`, where either all
+ variants match, or it falls into a catch-all for when one variant
+ does not match.
+
+ There are N + 1 cases because is a case for each of the N
+ variants where all of the variants match, and one catch-all for
+ when one does not match.
+
+ The catch-all handler is provided access the variant index values
+ for each of the self-args, carried in precomputed variables. (Nota
+ bene: the variant index values are not necessarily the
+ discriminant values. See issue #15523.)
+
+ ~~~text
+ match (this, that, ...) {
+ (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
+ (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
+ ...
+ _ => {
+ let __this_vi = match this { Variant1 => 0u, Variant2 => 1u, ... };
+ let __that_vi = match that { Variant1 => 0u, Variant2 => 1u, ... };
+ ... // catch-all remainder can inspect above variant index values.
+ }
}
- ~~~
-
- It acts in the most naive way, so every branch (and subbranch,
- subsubbranch, etc) exists, not just the ones where all the variants in
- the tree are the same. Hopefully the optimisers get rid of any
- repetition, otherwise derived methods with many Self arguments will be
- exponentially large.
-
- `matching` is Some(n) if all branches in the tree above the
- current position are variant `n`, `None` otherwise (including on
- the first call).
+ ~~~
*/
- fn build_enum_match(&self,
- cx: &mut ExtCtxt,
- trait_: &TraitDef,
- enum_def: &EnumDef,
- type_ident: Ident,
- self_args: &[Gc<Expr>],
- nonself_args: &[Gc<Expr>],
- matching: Option<uint>,
- matches_so_far: &mut Vec<(uint, P<ast::Variant>,
- Vec<(Span, Option<Ident>, Gc<Expr>)>)> ,
- match_count: uint) -> Gc<Expr> {
- if match_count == self_args.len() {
- // we've matched against all arguments, so make the final
- // expression at the bottom of the match tree
- if matches_so_far.len() == 0 {
- cx.span_bug(trait_.span,
- "no self match on an enum in \
- generic `deriving`");
- }
-
- // `ref` inside let matches is buggy. Causes havoc with rusc.
- // let (variant_index, ref self_vec) = matches_so_far[0];
- let (variant, self_vec) = match matches_so_far.get(0) {
- &(_, v, ref s) => (v, s)
- };
-
- // we currently have a vec of vecs, where each
- // subvec is the fields of one of the arguments,
- // but if the variants all match, we want this as
- // vec of tuples, where each tuple represents a
- // field.
-
- // most arms don't have matching variants, so do a
- // quick check to see if they match (even though
- // this means iterating twice) instead of being
- // optimistic and doing a pile of allocations etc.
- let substructure = match matching {
- Some(variant_index) => {
- let mut enum_matching_fields = Vec::from_elem(self_vec.len(), Vec::new());
-
- for triple in matches_so_far.tail().iter() {
- match triple {
- &(_, _, ref other_fields) => {
- for (i, &(_, _, e)) in other_fields.iter().enumerate() {
- enum_matching_fields.get_mut(i).push(e);
- }
- }
- }
- }
- let field_tuples =
- self_vec.iter()
- .zip(enum_matching_fields.iter())
- .map(|(&(span, id, self_f), other)| {
- FieldInfo {
- span: span,
- name: id,
- self_: self_f,
- other: (*other).clone()
- }
- }).collect();
- EnumMatching(variant_index, &*variant, field_tuples)
- }
- None => {
- EnumNonMatching(matches_so_far.as_slice())
+ fn build_enum_match_tuple(
+ &self,
+ cx: &mut ExtCtxt,
+ trait_: &TraitDef,
+ enum_def: &EnumDef,
+ type_ident: Ident,
+ self_args: &[Gc<Expr>],
+ nonself_args: &[Gc<Expr>]) -> Gc<Expr> {
+
+ let sp = trait_.span;
+ let variants = &enum_def.variants;
+
+ let self_arg_names = self_args.iter().enumerate()
+ .map(|(arg_count, _self_arg)| {
+ if arg_count == 0 {
+ "__self".to_string()
+ } else {
+ format!("__arg_{}", arg_count)
}
- };
- self.call_substructure_method(cx, trait_, type_ident,
- self_args, nonself_args,
- &substructure)
+ })
+ .collect::<Vec<String>>();
+
+ let self_arg_idents = self_arg_names.iter()
+ .map(|name|cx.ident_of(name.as_slice()))
+ .collect::<Vec<ast::Ident>>();
+
+ // The `vi_idents` will be bound, solely in the catch-all, to
+ // a series of let statements mapping each self_arg to a uint
+ // corresponding to its variant index.
+ let vi_idents : Vec<ast::Ident> = self_arg_names.iter()
+ .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice());
+ cx.ident_of(vi_suffix.as_slice()) })
+ .collect::<Vec<ast::Ident>>();
+
+ // Builds, via callback to call_substructure_method, the
+ // delegated expression that handles the catch-all case,
+ // using `__variants_tuple` to drive logic if necessary.
+ let catch_all_substructure = EnumNonMatchingCollapsed(
+ self_arg_idents, variants.as_slice(), vi_idents.as_slice());
+
+ // These arms are of the form:
+ // (Variant1, Variant1, ...) => Body1
+ // (Variant2, Variant2, ...) => Body2
+ // ...
+ // where each tuple has length = self_args.len()
+ let mut match_arms : Vec<ast::Arm> = variants.iter().enumerate()
+ .map(|(index, &variant)| {
+
+ // These self_pats have form Variant1, Variant2, ...
+ let self_pats : Vec<(Gc<ast::Pat>,
+ Vec<(Span, Option<Ident>, Gc<Expr>)>)>;
+ self_pats = self_arg_names.iter()
+ .map(|self_arg_name|
+ trait_.create_enum_variant_pattern(
+ cx, &*variant, self_arg_name.as_slice(),
+ ast::MutImmutable))
+ .collect();
+
+ // A single arm has form (&VariantK, &VariantK, ...) => BodyK
+ // (see "Final wrinkle" note below for why.)
+ let subpats = self_pats.iter()
+ .map(|&(p, ref _idents)| cx.pat(sp, ast::PatRegion(p)))
+ .collect::<Vec<Gc<ast::Pat>>>();
+
+ // Here is the pat = `(&VariantK, &VariantK, ...)`
+ let single_pat = cx.pat(sp, ast::PatTup(subpats));
+
+ // For the BodyK, we need to delegate to our caller,
+ // passing it an EnumMatching to indicate which case
+ // we are in.
+
+ // All of the Self args have the same variant in these
+ // cases. So we transpose the info in self_pats to
+ // gather the getter expressions together, in the form
+ // that EnumMatching expects.
+
+ // The transposition is driven by walking across the
+ // arg fields of the variant for the first self pat.
+ let &(_, ref self_arg_fields) = self_pats.get(0);
+
+ let field_tuples : Vec<FieldInfo>;
+
+ field_tuples = self_arg_fields.iter().enumerate()
+ // For each arg field of self, pull out its getter expr ...
+ .map(|(field_index, &(sp, opt_ident, self_getter_expr))| {
+ // ... but FieldInfo also wants getter expr
+ // for matching other arguments of Self type;
+ // so walk across the *other* self_pats and
+ // pull out getter for same field in each of
+ // them (using `field_index` tracked above).
+ // That is the heart of the transposition.
+ let others = self_pats.tail().iter()
+ .map(|&(_pat, ref fields)| {
+
+ let &(_, _opt_ident, other_getter_expr) =
+ fields.get(field_index);
+
+ // All Self args have same variant, so
+ // opt_idents are the same. (Assert
+ // here to make it self-evident that
+ // it is okay to ignore `_opt_ident`.)
+ assert!(opt_ident == _opt_ident);
+
+ other_getter_expr
+ }).collect::<Vec<Gc<Expr>>>();
+
+ FieldInfo { span: sp,
+ name: opt_ident,
+ self_: self_getter_expr,
+ other: others,
+ }
+ }).collect::<Vec<FieldInfo>>();
+
+ // Now, for some given VariantK, we have built up
+ // expressions for referencing every field of every
+ // Self arg, assuming all are instances of VariantK.
+ // Build up code associated with such a case.
+ let substructure = EnumMatching(index, variant, field_tuples);
+ let arm_expr = self.call_substructure_method(
+ cx, trait_, type_ident, self_args, nonself_args,
+ &substructure);
+
+ cx.arm(sp, vec![single_pat], arm_expr)
+ }).collect();
- } else { // there are still matches to create
- let current_match_str = if match_count == 0 {
- "__self".to_string()
- } else {
- format!("__arg_{}", match_count)
- };
+ // We will usually need the catch-all after matching the
+ // tuples `(VariantK, VariantK, ...)` for each VariantK of the
+ // enum. But:
+ //
+ // * when there is only one Self arg, the arms above suffice
+ // (and the deriving we call back into may not be prepared to
+ // handle EnumNonMatchCollapsed), and,
+ //
+ // * when the enum has only one variant, the single arm that
+ // is already present always suffices.
+ //
+ // * In either of the two cases above, if we *did* add a
+ // catch-all `_` match, it would trigger the
+ // unreachable-pattern error.
+ //
+ if variants.len() > 1 && self_args.len() > 1 {
+ let arms : Vec<ast::Arm> = variants.iter().enumerate()
+ .map(|(index, &variant)| {
+ let pat = variant_to_pat(cx, sp, &*variant);
+ let lit = ast::LitUint(index as u64, ast::TyU);
+ cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
+ }).collect();
- let mut arms = Vec::new();
-
- // the code for nonmatching variants only matters when
- // we've seen at least one other variant already
- if self.const_nonmatching && match_count > 0 {
- // make a matching-variant match, and a _ match.
- let index = match matching {
- Some(i) => i,
- None => cx.span_bug(trait_.span,
- "non-matching variants when required to \
- be matching in generic `deriving`")
- };
-
- // matching-variant match
- let variant = *enum_def.variants.get(index);
- let (pattern, idents) = trait_.create_enum_variant_pattern(
- cx,
- &*variant,
- current_match_str.as_slice(),
- ast::MutImmutable);
-
- matches_so_far.push((index, variant, idents));
- let arm_expr = self.build_enum_match(cx,
- trait_,
- enum_def,
- type_ident,
- self_args, nonself_args,
- matching,
- matches_so_far,
- match_count + 1);
- matches_so_far.pop().unwrap();
- arms.push(cx.arm(trait_.span, vec!( pattern ), arm_expr));
-
- if enum_def.variants.len() > 1 {
- let e = &EnumNonMatching(&[]);
- let wild_expr = self.call_substructure_method(cx, trait_, type_ident,
- self_args, nonself_args,
- e);
- let wild_arm = cx.arm(
- trait_.span,
- vec!( cx.pat_wild(trait_.span) ),
- wild_expr);
- arms.push(wild_arm);
- }
- } else {
- // create an arm matching on each variant
- for (index, &variant) in enum_def.variants.iter().enumerate() {
- let (pattern, idents) =
- trait_.create_enum_variant_pattern(
- cx,
- &*variant,
- current_match_str.as_slice(),
- ast::MutImmutable);
-
- matches_so_far.push((index, variant, idents));
- let new_matching =
- match matching {
- _ if match_count == 0 => Some(index),
- Some(i) if index == i => Some(i),
- _ => None
- };
- let arm_expr = self.build_enum_match(cx,
- trait_,
- enum_def,
- type_ident,
- self_args, nonself_args,
- new_matching,
- matches_so_far,
- match_count + 1);
- matches_so_far.pop().unwrap();
-
- let arm = cx.arm(trait_.span, vec!( pattern ), arm_expr);
- arms.push(arm);
- }
+ // Build a series of let statements mapping each self_arg
+ // to a uint corresponding to its variant index.
+ // i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
+ // with three Self args, builds three statements:
+ //
+ // ```
+ // let __self0_vi = match self {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // let __self1_vi = match __arg1 {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // let __self2_vi = match __arg2 {
+ // A => 0u, B(..) => 1u, C(..) => 2u
+ // };
+ // ```
+ let mut index_let_stmts : Vec<Gc<ast::Stmt>> = Vec::new();
+ for (&ident, &self_arg) in vi_idents.iter().zip(self_args.iter()) {
+ let variant_idx = cx.expr_match(sp, self_arg, arms.clone());
+ let let_stmt = cx.stmt_let(sp, false, ident, variant_idx);
+ index_let_stmts.push(let_stmt);
}
- // match foo { arm, arm, arm, ... }
- cx.expr_match(trait_.span, self_args[match_count], arms)
+ let arm_expr = self.call_substructure_method(
+ cx, trait_, type_ident, self_args, nonself_args,
+ &catch_all_substructure);
+
+ // Builds the expression:
+ // {
+ // let __self0_vi = ...;
+ // let __self1_vi = ...;
+ // ...
+ // <delegated expression referring to __self0_vi, et al.>
+ // }
+ let arm_expr = cx.expr_block(
+ cx.block_all(sp, Vec::new(), index_let_stmts, Some(arm_expr)));
+
+ // Builds arm:
+ // _ => { let __self0_vi = ...;
+ // let __self1_vi = ...;
+ // ...
+ // <delegated expression as above> }
+ let catch_all_match_arm =
+ cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
+
+ match_arms.push(catch_all_match_arm);
+
+ } else if variants.len() == 0 {
+ // As an additional wrinkle, For a zero-variant enum A,
+ // currently the compiler
+ // will accept `fn (a: &Self) { match *a { } }`
+ // but rejects `fn (a: &Self) { match (&*a,) { } }`
+ // as well as `fn (a: &Self) { match ( *a,) { } }`
+ //
+ // This means that the strategy of building up a tuple of
+ // all Self arguments fails when Self is a zero variant
+ // enum: rustc rejects the expanded program, even though
+ // the actual code tends to be impossible to execute (at
+ // least safely), according to the type system.
+ //
+ // The most expedient fix for this is to just let the
+ // code fall through to the catch-all. But even this is
+ // error-prone, since the catch-all as defined above would
+ // generate code like this:
+ //
+ // _ => { let __self0 = match *self { };
+ // let __self1 = match *__arg_0 { };
+ // <catch-all-expr> }
+ //
+ // Which is yields bindings for variables which type
+ // inference cannot resolve to unique types.
+ //
+ // One option to the above might be to add explicit type
+ // annotations. But the *only* reason to go down that path
+ // would be to try to make the expanded output consistent
+ // with the case when the number of enum variants >= 1.
+ //
+ // That just isn't worth it. In fact, trying to generate
+ // sensible code for *any* deriving on a zero-variant enum
+ // does not make sense. But at the same time, for now, we
+ // do not want to cause a compile failure just because the
+ // user happened to attach a deriving to their
+ // zero-variant enum.
+ //
+ // Instead, just generate a failing expression for the
+ // zero variant case, skipping matches and also skipping
+ // delegating back to the end user code entirely.
+ //
+ // (See also #4499 and #12609; note that some of the
+ // discussions there influence what choice we make here;
+ // e.g. if we feature-gate `match x { ... }` when x refers
+ // to an uninhabited type (e.g. a zero-variant enum or a
+ // type holding such an enum), but do not feature-gate
+ // zero-variant enums themselves, then attempting to
+ // derive Show on such a type could here generate code
+ // that needs the feature gate enabled.)
+
+ return cx.expr_unreachable(sp);
}
+
+ // Final wrinkle: the self_args are expressions that deref
+ // down to desired l-values, but we cannot actually deref
+ // them when they are fed as r-values into a tuple
+ // expression; here add a layer of borrowing, turning
+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+ let borrowed_self_args = self_args.iter()
+ .map(|&self_arg| cx.expr_addr_of(sp, self_arg))
+ .collect::<Vec<Gc<ast::Expr>>>();
+ let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+ cx.expr_match(sp, match_arg, match_arms)
}
fn expand_static_enum_method_body(&self,
pub fn cs_fold(use_foldl: bool,
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>, &[Gc<Expr>]| -> Gc<Expr>,
base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
})
}
},
- EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
- *all_enums,
- substructure.nonself_args),
+ EnumNonMatchingCollapsed(ref all_args, _, tuple) =>
+ enum_nonmatch_f(cx, trait_span, (all_args.as_slice(), tuple),
+ substructure.nonself_args),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `deriving`")
}
*/
#[inline]
pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
f(cx, trait_span, called)
},
- EnumNonMatching(ref all_enums) => enum_nonmatch_f(cx, trait_span,
- *all_enums,
- substructure.nonself_args),
+ EnumNonMatchingCollapsed(ref all_self_args, _, tuple) =>
+ enum_nonmatch_f(cx, trait_span, (all_self_args.as_slice(), tuple),
+ substructure.nonself_args),
StaticEnum(..) | StaticStruct(..) => {
cx.span_bug(trait_span, "static function in `deriving`")
}
pub fn cs_same_method_fold(use_foldl: bool,
f: |&mut ExtCtxt, Span, Gc<Expr>, Gc<Expr>| -> Gc<Expr>,
base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
*/
#[inline]
pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
- enum_nonmatch_f: EnumNonMatchFunc,
+ enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, trait_span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_same_method_fold(
/// cs_binop with binop == or
#[inline]
-pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
+pub fn cs_or(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_binop(ast::BiOr, cx.expr_bool(span, false),
/// cs_binop with binop == and
#[inline]
-pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc,
+pub fn cs_and(enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt, span: Span,
substructure: &Substructure) -> Gc<Expr> {
cs_binop(ast::BiAnd, cx.expr_bool(span, true),
args: vec!(Ptr(box Literal(args), Borrowed(None, MutMutable))),
ret_ty: nil_ty(),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
hash_substructure(a, b, c)
})
true)),
// #[inline] liable to cause code-bloat
attributes: attrs.clone(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("i64", c, s, sub)
}),
true)),
// #[inline] liable to cause code-bloat
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("u64", c, s, sub)
}),
),
ret_ty: Self,
attributes: Vec::new(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
rand_substructure(a, b, c)
})
args: vec!(fmtr),
ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))),
attributes: Vec::new(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
show_substructure(a, b, c)
})
let name = match *substr.fields {
Struct(_) => substr.type_ident,
EnumMatching(_, v, _) => v.node.name,
-
- EnumNonMatching(..) | StaticStruct(..) | StaticEnum(..) => {
+ EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
cx.span_bug(span, "nonsensical .fields in `#[deriving(Show)]`")
}
};
args: Vec::new(),
ret_ty: Self,
attributes: attrs.clone(),
- const_nonmatching: false,
combine_substructure: combine_substructure(|a, b, c| {
zero_substructure(a, b, c)
})
args: Vec::new(),
ret_ty: Literal(Path::new(vec!("bool"))),
attributes: attrs,
- const_nonmatching: false,
combine_substructure: combine_substructure(|cx, span, substr| {
cs_and(|cx, span, _, _| cx.span_bug(span,
"Non-matching enum \
None => {
fld.cx.span_err(
pth.span,
- format!("macro undefined: '{}'",
+ format!("macro undefined: '{}!'",
extnamestr.get()).as_slice());
// let compilation continue
// create issue to recommend refactoring here?
fld.extsbox.insert(intern(name.as_slice()), ext);
if attr::contains_name(it.attrs.as_slice(), "macro_export") {
- SmallVector::one(it)
- } else {
- SmallVector::zero()
+ fld.cx.push_exported_macro(it.span);
}
+ SmallVector::zero()
}
None => {
match expanded.make_items() {
let marked_after = match fld.extsbox.find(&extname.name) {
None => {
fld.cx.span_err(pth.span,
- format!("macro undefined: '{}'",
+ format!("macro undefined: '{}!'",
extnamestr).as_slice());
return SmallVector::zero();
}
_ => visit::walk_pat(self, pattern, ())
}
}
-
}
/// find the PatIdent paths in a pattern
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
}
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
/// A tree-folder that applies every rename in its list to
_ => noop_fold_pat(pat, self)
}
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
// expand a method
pub fn expand_crate(parse_sess: &parse::ParseSess,
cfg: ExpansionConfig,
+ // these are the macros being imported to this crate:
macros: Vec<ExportedMacros>,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
expander.extsbox.insert(name, extension);
}
- let ret = expander.fold_crate(c);
+ let mut ret = expander.fold_crate(c);
+ ret.exported_macros = expander.cx.exported_macros.clone();
parse_sess.span_diagnostic.handler().abort_if_errors();
return ret;
}
return einfo;
}
+/// Check that there are no macro invocations left in the AST:
+pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
+ visit::walk_crate(&mut MacroExterminator{sess:sess}, krate, ());
+}
+
+/// A visitor that ensures that no macro invocations remain in an AST.
+struct MacroExterminator<'a>{
+ sess: &'a parse::ParseSess
+}
+
+impl<'a> visit::Visitor<()> for MacroExterminator<'a> {
+ fn visit_mac(&mut self, macro: &ast::Mac, _:()) {
+ self.sess.span_diagnostic.span_bug(macro.span,
+ "macro exterminator: expected AST \
+ with no macro invocations");
+ }
+}
+
+
#[cfg(test)]
mod test {
use super::{pattern_bindings, expand_crate, contains_macro_escape};
use ast;
use codemap::{Span, Spanned, DUMMY_SP};
use ext::base::{ExtCtxt, MacResult, MacroDef};
-use ext::base::{NormalTT, MacroExpander};
+use ext::base::{NormalTT, TTMacroExpander};
use ext::base;
use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
rhses: Vec<Rc<NamedMatch>>,
}
-impl MacroExpander for MacroRulesMacroExpander {
+impl TTMacroExpander for MacroRulesMacroExpander {
fn expand(&self,
cx: &mut ExtCtxt,
sp: Span,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+//! A Folder represents an AST->AST fold; it accepts an AST piece,
+//! and returns a piece of the same type. So, for instance, macro
+//! expansion is a Folder that walks over an AST and produces another
+//! AST.
+//!
+//! Note: using a Folder (other than the MacroExpander Folder) on
+//! an AST before macro expansion is probably a bad idea. For instance,
+//! a folder renaming item names in a module will miss all of those
+//! that are created by the expansion of a macro.
+
use ast::*;
use ast;
use ast_util;
}
}
- fn fold_mac(&mut self, macro: &Mac) -> Mac {
- Spanned {
- node: match macro.node {
- MacInvocTT(ref p, ref tts, ctxt) => {
- MacInvocTT(self.fold_path(p),
- fold_tts(tts.as_slice(), self),
- ctxt)
- }
- },
- span: self.new_span(macro.span)
- }
+ fn fold_mac(&mut self, _macro: &Mac) -> Mac {
+ fail!("fold_mac disabled by default");
+ // NB: see note about macros above.
+ // if you really want a folder that
+ // works on macros, use this
+ // definition in your trait impl:
+ // fold::fold_mac(_macro, self)
}
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
}
+
+pub fn fold_mac<T: Folder>(macro: &Mac, fld: &mut T) -> Mac {
+ Spanned {
+ node: match macro.node {
+ MacInvocTT(ref p, ref tts, ctxt) => {
+ MacInvocTT(fld.fold_path(p),
+ fold_tts(tts.as_slice(), fld),
+ ctxt)
+ }
+ },
+ span: fld.new_span(macro.span)
+ }
+}
+
/* some little folds that probably aren't useful to have in Folder itself*/
//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
attrs: c.attrs.iter().map(|x| folder.fold_attribute(*x)).collect(),
config: c.config.iter().map(|x| fold_meta_item_(*x, folder)).collect(),
span: folder.new_span(c.span),
+ exported_macros: c.exported_macros.iter().map(|sp| folder.new_span(*sp)).collect(),
}
}
use util::parser_testing::{string_to_crate, matches_codepattern};
use parse::token;
use print::pprust;
+ use fold;
use super::*;
// this version doesn't care about getting comments or docstrings in.
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
token::str_to_ident("zz")
}
+ fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+ fold::fold_mac(macro, self)
+ }
}
// maybe add to expand.rs...
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
#![feature(quote, unsafe_destructor)]
#![allow(deprecated)]
-extern crate serialize;
-extern crate term;
-#[phase(plugin, link)] extern crate log;
-
extern crate fmt_macros;
extern crate debug;
+#[phase(plugin, link)] extern crate log;
+extern crate serialize;
+extern crate term;
pub mod util {
pub mod interner;
pub mod small_vector;
}
+pub mod diagnostics {
+ pub mod macros;
+ pub mod plugin;
+ pub mod registry;
+}
+
pub mod syntax {
pub use ext;
pub use parse;
pub use ast;
}
-pub mod owned_slice;
-pub mod attr;
-pub mod diagnostic;
-pub mod codemap;
pub mod abi;
pub mod ast;
-pub mod ast_util;
pub mod ast_map;
-pub mod visit;
+pub mod ast_util;
+pub mod attr;
+pub mod codemap;
+pub mod crateid;
+pub mod diagnostic;
pub mod fold;
-
-
+pub mod owned_slice;
pub mod parse;
-pub mod crateid;
+pub mod visit;
pub mod print {
pub mod pp;
pub mod ext {
pub mod asm;
pub mod base;
+ pub mod build;
+ pub mod bytes;
+ pub mod cfg;
+ pub mod concat;
+ pub mod concat_idents;
+ pub mod deriving;
+ pub mod env;
pub mod expand;
-
+ pub mod fmt;
+ pub mod format;
+ pub mod log_syntax;
+ pub mod mtwt;
pub mod quote;
-
- pub mod deriving;
-
- pub mod build;
+ pub mod source_util;
+ pub mod trace_macros;
pub mod tt {
pub mod transcribe;
pub mod macro_parser;
pub mod macro_rules;
}
-
- pub mod mtwt;
-
- pub mod cfg;
- pub mod fmt;
- pub mod format;
- pub mod env;
- pub mod bytes;
- pub mod concat;
- pub mod concat_idents;
- pub mod log_syntax;
- pub mod source_util;
-
- pub mod trace_macros;
}
self.expect(&token::LBRACKET);
let meta_item = self.parse_meta_item();
+ let hi = self.span.hi;
self.expect(&token::RBRACKET);
- let hi = self.span.hi;
(mk_sp(lo, hi), meta_item, style)
}
_ => {
use std::io::util;
fn mk_sh() -> diagnostic::SpanHandler {
- let emitter = diagnostic::EmitterWriter::new(box util::NullWriter);
+ let emitter = diagnostic::EmitterWriter::new(box util::NullWriter, None);
let handler = diagnostic::mk_handler(box emitter);
diagnostic::mk_span_handler(handler, CodeMap::new())
}
pub fn new_parse_sess() -> ParseSess {
ParseSess {
- span_diagnostic: mk_span_handler(default_handler(Auto), CodeMap::new()),
+ span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()),
included_mod_stack: RefCell::new(Vec::new()),
}
}
module: m,
attrs: inner,
config: self.cfg.clone(),
- span: mk_sp(lo, self.span.lo)
+ span: mk_sp(lo, self.span.lo),
+ exported_macros: Vec::new(),
}
}
//! execute before AST node B, then A is visited first. The borrow checker in
//! particular relies on this property.
//!
+//! Note: walking an AST before macro expansion is probably a bad idea. For
+//! instance, a walker looking for item names in a module will miss all of
+//! those that are created by the expansion of a macro.
+
use abi::Abi;
use ast::*;
use ast;
fn visit_explicit_self(&mut self, es: &ExplicitSelf, e: E) {
walk_explicit_self(self, es, e)
}
- fn visit_mac(&mut self, macro: &Mac, e: E) {
- walk_mac(self, macro, e)
+ fn visit_mac(&mut self, _macro: &Mac, _e: E) {
+ fail!("visit_mac disabled by default");
+ // NB: see note about macros above.
+ // if you really want a visitor that
+ // works on macros, use this
+ // definition in your trait impl:
+ // visit::walk_mac(self, _macro, _e)
}
fn visit_path(&mut self, path: &Path, _id: ast::NodeId, e: E) {
walk_path(self, path, e)
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/")]
+ html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(asm, macro_rules, phase)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase)]
//! provide for basic string-related manipulations. This crate does not
//! (yet) aim to provide a full set of Unicode tables.
-#![crate_id = "unicode#0.11.0"]
#![crate_name = "unicode"]
#![experimental]
#![license = "MIT/ASL2"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![feature(plugin_registrar)]
+
+extern crate rustc;
+
+use rustc::plugin::Registry;
+
+#[plugin_registrar]
+pub fn plugin_registrar(_: &mut Registry) {}
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rlib_crate_test.rs
+// ignore-stage1
+// ignore-tidy-linelength
+// ignore-android
+
+#![feature(phase)]
+#[phase(plugin)] extern crate rlib_crate_test;
+//~^ ERROR: plugin crate `rlib_crate_test` only found in rlib format, but must be available in dylib format
+
+fn main() {}
extern crate macro_crate_test;
fn main() {
- assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro'
+ assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro!'
}
fn main() {
print!(test!());
- //~^ ERROR: macro undefined: 'test'
+ //~^ ERROR: macro undefined: 'test!'
//~^^ ERROR: format argument must be a string literal
concat!(test!());
- //~^ ERROR: macro undefined: 'test'
+ //~^ ERROR: macro undefined: 'test!'
}
let x = -2147483648_i32; // should be OK
let x: i32 = -2147483649; //~ error: literal out of range for its type
let x = -2147483649_i32; //~ error: literal out of range for its type
+
+ let x = -3.40282348e+38_f32; //~ error: literal out of range for its type
+ let x = 3.40282348e+38_f32; //~ error: literal out of range for its type
+ let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for its type
+ let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for its type
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_diagnostic_macros)]
+
+__register_diagnostic!(E0001)
+__register_diagnostic!(E0003)
+
+fn main() {
+ __diagnostic_used!(E0002);
+ //~^ ERROR unknown diagnostic code E0002
+
+ __diagnostic_used!(E0001);
+ //~^ NOTE previous invocation
+
+ __diagnostic_used!(E0001);
+ //~^ WARNING diagnostic code E0001 already used
+}
+
+__build_diagnostic_array!(DIAGNOSTICS)
+//~^ WARN diagnostic code E0003 never used
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_diagnostic_macros)]
+
+__register_diagnostic!(E0001)
+__register_diagnostic!(E0001)
+//~^ ERROR diagnostic code E0001 already registered
+
+fn main() {
+}
+
+__build_diagnostic_array!(DIAGNOSTICS)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+__register_diagnostic!(E0001)
+//~^ ERROR macro undefined: '__register_diagnostic!'
+
+fn main() {
+ __diagnostic_used!(E0001);
+ //~^ ERROR macro undefined: '__diagnostic_used!'
+}
+
+__build_diagnostic_array!(DIAGNOSTICS)
+//~^ ERROR macro undefined: '__build_diagnostic_array!'
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x : i16 = 22;
+ ((&x) as *const i16) as f32;
+ //~^ ERROR: cannot cast from pointer to float directly: `*const i16` as `f32`
+}
/// *wow*
pub trait Doge { }
+
+ pub struct Foo { x: int, y: uint }
+
+ pub fn prawns((a, b): (int, uint), Foo { x, y }: Foo) { }
}
}
fn runtest(me: &str) {
- let mut env = os::env().move_iter()
- .map(|(ref k, ref v)| {
- (k.to_string(), v.to_string())
- }).collect::<Vec<(String,String)>>();
- match env.iter()
- .position(|&(ref s, _)| "RUST_BACKTRACE" == s.as_slice()) {
- Some(i) => { env.remove(i); }
- None => {}
- }
- env.push(("RUST_BACKTRACE".to_string(), "1".to_string()));
-
// Make sure that the stack trace is printed
- let mut p = Command::new(me).arg("fail").env(env.as_slice()).spawn().unwrap();
+ let mut p = Command::new(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
"bad output3: {}", s);
// Make sure a stack trace isn't printed too many times
- let mut p = Command::new(me).arg("double-fail").env(env.as_slice()).spawn().unwrap();
+ let mut p = Command::new(me).arg("double-fail")
+ .env("RUST_BACKTRACE", "1").spawn().unwrap();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(out.error.as_slice()).unwrap();
let p = Command::new(&child_path)
.arg(arg)
.cwd(&cwd)
- .env(my_env.append_one(env).as_slice())
+ .env_set_all(my_env.append_one(env).as_slice())
.spawn().unwrap().wait_with_output().unwrap();
// display the output