]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15584 : alexcrichton/rust/warn-annoyances, r=cmr
authorbors <bors@rust-lang.org>
Sun, 13 Jul 2014 04:46:31 +0000 (04:46 +0000)
committerbors <bors@rust-lang.org>
Sun, 13 Jul 2014 04:46:31 +0000 (04:46 +0000)
* Don't warn about `#[crate_name]` if `--crate-name` is specified
* Don't warn about non camel case identifiers on `#[repr(C)]` structs
* Switch `mode` to `mode_t` in libc.

139 files changed:
man/rustc.1
man/rustdoc.1
mk/dist.mk
mk/install.mk
mk/main.mk
src/compiletest/procsrv.rs
src/compiletest/runtest.rs
src/doc/guide.md
src/doc/po/ja/complement-cheatsheet.md.po
src/doc/po/ja/complement-lang-faq.md.po
src/doc/po/ja/complement-project-faq.md.po
src/doc/po/ja/complement-usage-faq.md.po
src/doc/po/ja/guide-conditions.md.po
src/doc/po/ja/guide-container.md.po
src/doc/po/ja/guide-ffi.md.po
src/doc/po/ja/guide-lifetimes.md.po
src/doc/po/ja/guide-macros.md.po
src/doc/po/ja/guide-pointers.md.po
src/doc/po/ja/guide-runtime.md.po
src/doc/po/ja/guide-tasks.md.po
src/doc/po/ja/guide-testing.md.po
src/doc/po/ja/index.md.po
src/doc/po/ja/rustdoc.md.po
src/etc/install.sh
src/etc/kate/rust.xml
src/etc/zsh/_rust
src/libarena/lib.rs
src/libcollections/hash/sip.rs
src/libcollections/lib.rs
src/libcore/atomics.rs
src/libcore/lib.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libdebug/lib.rs
src/libflate/lib.rs
src/libfourcc/lib.rs
src/libgetopts/lib.rs
src/libglob/lib.rs
src/libgraphviz/lib.rs
src/libgreen/lib.rs
src/libgreen/stack.rs
src/libhexfloat/lib.rs
src/liblibc/lib.rs
src/liblog/lib.rs
src/libnative/io/process.rs
src/libnative/lib.rs
src/libnum/lib.rs
src/librand/lib.rs
src/libregex/lib.rs
src/libregex_macros/lib.rs
src/librlibc/lib.rs
src/librustc/diagnostics.rs [new file with mode: 0644]
src/librustc/driver/config.rs
src/librustc/driver/driver.rs
src/librustc/driver/mod.rs
src/librustc/driver/session.rs
src/librustc/front/config.rs
src/librustc/front/feature_gate.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/check_match.rs
src/librustc/middle/stability.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/infer/test.rs
src/librustc/plugin/load.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.css
src/librustdoc/lib.rs
src/librustdoc/stability_summary.rs [new file with mode: 0644]
src/librustdoc/test.rs
src/librustrt/c_str.rs
src/librustrt/lib.rs
src/librustrt/rtio.rs
src/librustuv/lib.rs
src/librustuv/process.rs
src/libsemver/lib.rs
src/libserialize/lib.rs
src/libstd/hash.rs
src/libstd/io/mem.rs
src/libstd/io/process.rs
src/libstd/lib.rs
src/libstd/os.rs
src/libstd/path/posix.rs
src/libstd/path/windows.rs
src/libsync/lib.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map.rs
src/libsyntax/diagnostic.rs
src/libsyntax/diagnostics/macros.rs [new file with mode: 0644]
src/libsyntax/diagnostics/plugin.rs [new file with mode: 0644]
src/libsyntax/diagnostics/registry.rs [new file with mode: 0644]
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/clone.rs
src/libsyntax/ext/deriving/cmp/eq.rs
src/libsyntax/ext/deriving/cmp/ord.rs
src/libsyntax/ext/deriving/cmp/totaleq.rs
src/libsyntax/ext/deriving/cmp/totalord.rs
src/libsyntax/ext/deriving/decodable.rs
src/libsyntax/ext/deriving/default.rs
src/libsyntax/ext/deriving/encodable.rs
src/libsyntax/ext/deriving/generic/mod.rs
src/libsyntax/ext/deriving/hash.rs
src/libsyntax/ext/deriving/primitive.rs
src/libsyntax/ext/deriving/rand.rs
src/libsyntax/ext/deriving/show.rs
src/libsyntax/ext/deriving/zero.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/fold.rs
src/libsyntax/lib.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/visit.rs
src/libterm/lib.rs
src/libtest/lib.rs
src/libtime/lib.rs
src/libunicode/lib.rs
src/liburl/lib.rs
src/libuuid/lib.rs
src/test/auxiliary/rlib_crate_test.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/macro-crate-rlib.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs
src/test/compile-fail/issue-11692.rs
src/test/compile-fail/lint-type-overflow.rs
src/test/compile-fail/rustc-diagnostics-1.rs [new file with mode: 0644]
src/test/compile-fail/rustc-diagnostics-2.rs [new file with mode: 0644]
src/test/compile-fail/rustc-diagnostics-3.rs [new file with mode: 0644]
src/test/compile-fail/typeck-cast-pointer-to-float.rs [new file with mode: 0644]
src/test/run-make/rustdoc-smoke/foo.rs
src/test/run-pass/backtrace.rs
src/test/run-pass/process-spawn-with-unicode-params.rs

index 2484960cac6da5f2d9b78056b573ca9a62bbd1a2..f49faf2ec6e3a8d68fa76631158f4a06fb0bd7a0 100644 (file)
@@ -1,4 +1,4 @@
-.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
@@ -11,6 +11,9 @@ This program is a compiler for the Rust language, available at
 
 .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`)
@@ -60,8 +63,9 @@ Parse only; do not compile, assemble, or link
 \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
index 03414ca163ec2a01e09e4d83e5942fe4ccf32b51..12e776b98618e988405e28c49bae5c58ad3958f5 100644 (file)
@@ -1,4 +1,4 @@
-.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
index 76ebfe9b49fd64929ce5b07b49b2faba38ece8e9..c73d66a999ec7750df61f2913cf0c602d834a815 100644 (file)
@@ -259,7 +259,6 @@ distcheck-tar-bins: dist-tar-bins
        $(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
index 206046faeb6ef34e52c9715e4c9ed2d42bd380ef..b9baf6e02e1024b009583de9342511b5932f2432 100644 (file)
@@ -14,16 +14,18 @@ else
 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
index 7400b39c9680ca2d278e948f398b78fdbb7ab971..8f54b2735a575d03ef455bff94b913e4285f342b 100644 (file)
@@ -13,8 +13,8 @@
 ######################################################################
 
 # 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
 
index 797477d29202d57d00c5eb0033059fbceef68c16..1ee6f2b500c138fbceec3c74baa53be31cef3e52 100644 (file)
@@ -8,12 +8,11 @@
 // 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();
@@ -23,19 +22,11 @@ fn target_env(lib_path: &str, aux_path: Option<&str>) -> Vec<(String, String)> {
     }
     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}
@@ -47,8 +38,14 @@ pub fn run(lib_path: &str,
            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();
@@ -73,8 +70,14 @@ pub fn run_background(lib_path: &str,
            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();
index 7c8e7e85e4607a97edee73af6fff8f4959d6c26d..f28604908e0b3fb938b99aca02e7bd630b698d28 100644 (file)
@@ -574,7 +574,7 @@ fn run_lldb(config: &Config, test_executable: &Path, debugger_script: &Path) ->
         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) => {
index 7915d54acbc096343f74e32f8664edd308fa4701..4265e4f07d6ce84859d384558abb49fdd8fdfbb0 100644 (file)
@@ -90,7 +90,7 @@ $ rustc --version
 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!
index b429f3020a73c1414ca293193b2ee27735823f1c..b8eab539c6119a64d13597f218b39af77110fa18 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index f28abcf1d524fcc7e2a512dd291c348413b082fa..6668975473d38a660f829b635ad272624f239d50 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 0361c67b9dc360e21251d3ed6cbeb7deafe8d8e4..3e10a3bc956d051bc2617e75b2429878caf1f57c 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 819e12ccd13a7ae47cc06c30c7b1600e44a48d36..c068b630ca7e44daf4d91de5a5d88e3d24971757 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 69f5ea1c733566c7a9dc0a244540fe50be0512aa..089ad6d60a9cbb367cd865f28db7a7717d5ccafc 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index d20ad9568730411c3deeca270e7cacd371f8c010..399443b6e21d11c96a89eff3fb5d0d3847d46e17 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index fe7d1d911efdd43b2f491f62164e1e8add479b5e..08089f30d2458ae0b1f211c0e0053a6d05d21295 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 44984c4a25fb7ea12cbb9830c844eab3d6a4c308..b5c0761324d2597ea57cf017447c3d791cfdbfaa 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 39d71dafd8c9fa2f01536b3fa422174205cee6a8..bf35bcd4ca68c311fe8a0e8c4deca79dc3b58e2b 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index f1005caedd5c117af2ff08ca8238d3781efbf5f9..0c0ca5e73a1ddddb2e967da8e15de33f2c09c780 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 216a854db2a26c04273fe3fa2bcb86daaed71249..1cfdfad28367d38125def87ceeb8e70635353614 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 480d1351e56432b409692ba76e2bc9ec700573ee..bb5252cb7375cd7e1675dd34038425de1eed995a 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 55a9e00f54d27aa17b81765b25726097dc6806e0..9025ae1505467037eb0247c30e556904f11778b0 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index 6a2e512da26548b7d9575e1d63114de5500f8546..4e226cbfe37e2e05651386c07867c1d0800387bf 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index eaf954333152e32dd7fbea12aa18eebc485c4a44..e2bc4716d7064904f5cb0625261662e11d103d84 100644 (file)
@@ -5,7 +5,7 @@
 #
 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"
index a89b616edf031f076e1c01ad1da6dfa4540e6319..c949743ea75949f4bd84b4e1b6812b391ec7f5d9 100644 (file)
@@ -466,6 +466,17 @@ while read p; do
 # 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
@@ -489,13 +500,11 @@ then
             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
index deb713ac1ae01bcc7f057d27d48c5e33a4965762..f2f54d9d307037a545b0f8ed5180c438759e4168 100644 (file)
@@ -7,7 +7,7 @@
        <!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>
index 9c821117205422427ae9f68f7321a706833fff17..b423191d54ad74c6fa7762e683fe3567fcdace0a 100644 (file)
@@ -9,10 +9,12 @@ _rustc_opts_switches=(
     -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.]'
@@ -29,6 +31,8 @@ _rustc_opts_switches=(
     --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]'
index 0118828ae18ecaa3a994c386e1b4fb16bcc74d38..e672c555b804df163b6d259d4a29ce09590c0f2d 100644 (file)
@@ -26,7 +26,7 @@
 #![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)]
index 4fd98538af7ddc93068901d28b657698a6d20f05..1c7e03f70c8896531a6c4b6bea254f6d06faff85 100644 (file)
@@ -269,7 +269,7 @@ pub fn hash_with_keys<T: Hash<SipState>>(k0: u64, k1: u64, value: &T) -> u64 {
 mod tests {
     use test::Bencher;
     use std::prelude::*;
-    use std::num::ToStrRadix;
+    use std::fmt;
 
     use str::Str;
     use string::String;
@@ -370,7 +370,7 @@ fn test_siphash() {
         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
         }
@@ -391,7 +391,7 @@ fn result_str(h: u64) -> String {
             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
         }
index cce2d14efa9f7bbfacfe206ca79a1db64b02d8fd..06ec2588ac332d96acb88afa7938469149078da4 100644 (file)
@@ -18,7 +18,7 @@
 #![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)]
index 971799acc7862e61efb2112990ddf8fa045a5bef..e022fa2c370f2b8aeb69d3a99f3419c6199aee24 100644 (file)
@@ -141,7 +141,7 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     ///
     /// 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
index 6d76f7c36e87b0dddf1c78c8847c1ba4f59f03a3..faa4b75d7faab6fe2df726a97af6b9ee2b4d0cbf 100644 (file)
@@ -53,7 +53,7 @@
 #![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]
index cadc874891d2042109c0316e3db1a65439a1941f..82745663e0cad3bd8711493bc88af8065e0e7ae7 100644 (file)
@@ -11,6 +11,8 @@
 //! 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;
index 5e19015dd02819209f3d69f1f932dc6cc932e582..a3a82aeec5ec78f1cb8cbf453a8435ee874f15fc 100644 (file)
@@ -11,6 +11,8 @@
 //! 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;
index 1d15c62e75234f19e9ae9860709811d86ff36876..6341a38056359bf495d21bd1798c3f241643d23e 100644 (file)
@@ -23,7 +23,7 @@
 #![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)]
index b9d61ab3868401c265c26afae1669fa7b8aa3d24..4226ac14118a40a232c2b0c92d01aa30b82f5083 100644 (file)
@@ -25,7 +25,7 @@
 #![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;
index b490f0903020c6db3a59171bf069b1e8abe0e106..aa8d84bec1711010c25973642ad12c24a5ff8708 100644 (file)
@@ -46,7 +46,7 @@ fn main() {
 #![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)]
 
index cf879c5d7efebf6fc76df49f77fdd38c8de5e7f4..eaec31a45f42180fab1f4cb3ae95ac19a0d00bcd 100644 (file)
@@ -83,7 +83,7 @@
 #![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)]
index 637ceb00ce67378d0d5c9cf601efe2dc8833402c..7aa1cf6eb1dccf252ef07978588f688629b4046f 100644 (file)
@@ -30,7 +30,7 @@
 #![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;
index e5c2cdb43657fe0c6eef0510b193e8f080c74961..9d2f43b9513e6b3ea1f656a467bf55ca156f8388 100644 (file)
@@ -273,7 +273,7 @@ pub fn main() {
 #![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;
index 3574f415815d7c7bcfb4c62ad4787478565697dc..6e4e2ac0feee39999fa78548913f7c8ad7861f6e 100644 (file)
 //! 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.
index 5faa9cfe6f6a2bd0cbbb0c7d80cf95754de2331f..633bd3c041a3d586f2d35ee3e440587ef53bc17e 100644 (file)
@@ -8,14 +8,15 @@
 // 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,
 }
@@ -52,11 +53,11 @@ pub fn new(size: uint) -> Stack {
         // 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
         };
@@ -71,7 +72,7 @@ pub fn new(size: uint) -> Stack {
     /// 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
         }
@@ -79,14 +80,15 @@ pub unsafe fn dummy_stack() -> Stack {
 
     /// 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())
     }
 }
 
@@ -96,7 +98,7 @@ fn protect_last_page(stack: &MemoryMap) -> bool {
         // 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
     }
@@ -106,7 +108,7 @@ fn protect_last_page(stack: &MemoryMap) -> bool {
 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,
index 57c187b5c64cbf38be668c10811266194e6f7037..2859e1c985f5e5beb96666faeb8d916150e054ba 100644 (file)
@@ -43,7 +43,7 @@ fn main() {
 #![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;
index 894779fa06b54bec98172a1fe7c88440f651d885..fc4144a2868638c2f7598aaf0aabb6ba4347bed5 100644 (file)
@@ -16,7 +16,7 @@
 #![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/")]
 
 /*!
index c4c18ab6d39f8fdb969d20ea13757d78f7ad1019..554f27b881b7269700937bdac03eb50f7fae7b69 100644 (file)
@@ -112,7 +112,7 @@ fn main() {
 #![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)]
index 71702d180b9e0efaffb630e01fcecb23803e1c65..21da0104c2f8d70eb2539791fde4d2b22a7c681a 100644 (file)
@@ -729,7 +729,7 @@ fn with_argv<T>(prog: &CString, args: &[CString],
 }
 
 #[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
@@ -762,7 +762,7 @@ fn with_envp<T>(env: Option<&[(CString, CString)]>,
 }
 
 #[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.
index f9a6ef3a9634a59b584e3fb15eb117884a6c2ba4..d358aa6b6453ebf2981ee3def9fe9e3044d5b666 100644 (file)
@@ -53,7 +53,7 @@
 #![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)]
index 36207266e58e6587aca3a4a4569d51d34f28877d..5cc2eee7da75c2743695c41c1f414621f661e8b4 100644 (file)
@@ -51,7 +51,7 @@
 #![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
 
index 9c01cb9e9dbe1d3ed23e90ffc7d851f62991bf38..9c33b713e4a6b1f8b3d7853b2d9bcbd512f5714d 100644 (file)
@@ -21,7 +21,7 @@
 #![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)]
index 67ab8e052d15b5bd43a3479a74cee8faf68904a3..1bb7f605e5474878d8a4837e4f18eb2d1fecebbd 100644 (file)
 #![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)]
index 0ef8f056b3f4e427596d70a00bae25a99f3f3660..6545163fdbb68199ccb5a98ce581631c0a3cd8aa 100644 (file)
@@ -17,7 +17,7 @@
 #![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)]
 
index 98ba9990d9b958af2fc88bc29750b837f426b7ae..cb27596c98c6b1a92159b30e24cda00239f353ce 100644 (file)
@@ -25,7 +25,7 @@
 #![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]
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
new file mode 100644 (file)
index 0000000..0499795
--- /dev/null
@@ -0,0 +1,18 @@
+// 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.
+"##)
index 9daaa2792ebad0e0140f55234769fc236645fc7d..b726c50afe9d1202850cbfdc5b7b73fb20a2d0a6 100644 (file)
@@ -532,6 +532,7 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
         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),
@@ -807,6 +808,7 @@ mod test {
     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]
@@ -816,8 +818,9 @@ fn test_switch_implies_cfg_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")));
     }
@@ -834,8 +837,9 @@ fn test_switch_implies_cfg_test_unless_cfg_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());
index 6a016edcd2868fce87671e901d207f62464ec2b5..d03bf3593fa41bc19aa4ed3ef767b7de0e31e07c 100644 (file)
@@ -16,6 +16,7 @@
 use driver::{PpmIdentified};
 use front;
 use lib::llvm::{ContextRef, ModuleRef};
+use lint;
 use metadata::common::LinkMeta;
 use metadata::creader;
 use middle::cfg;
@@ -26,7 +27,7 @@
 use plugin::load::Plugins;
 use plugin::registry::Registry;
 use plugin;
-use lint;
+
 use util::common::time;
 use util::ppaux;
 use util::nodemap::{NodeSet};
@@ -41,6 +42,7 @@
 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};
@@ -213,6 +215,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
     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 &registrar in registrars.iter() {
             registrar(&mut registry);
         }
@@ -259,6 +270,8 @@ pub fn phase_2_configure_and_expand(sess: &Session,
         }
     );
 
+    // 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));
@@ -279,6 +292,9 @@ pub fn phase_2_configure_and_expand(sess: &Session,
         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))
 }
 
@@ -291,6 +307,7 @@ pub struct CrateAnalysis {
     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.
@@ -298,7 +315,6 @@ pub fn phase_3_run_analysis_passes(sess: Session,
                                    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", (), |_|
index ad0d8cac1e3578fa8aebf0ec4d13d56b2a2aea3d..2614c9ebf98b003fa74d2fb3678bd519afb603cd 100644 (file)
@@ -26,6 +26,7 @@
 use syntax::ast;
 use syntax::parse;
 use syntax::diagnostic::Emitter;
+use syntax::diagnostics;
 
 use getopts;
 
@@ -49,8 +50,24 @@ fn run_compiler(args: &[String]) {
         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 {
@@ -75,7 +92,7 @@ fn run_compiler(args: &[String]) {
         _ => 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));
@@ -383,14 +400,14 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
 }
 
 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,
@@ -429,7 +446,7 @@ fn monitor(f: proc():Send) {
         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.
@@ -437,6 +454,7 @@ fn monitor(f: proc():Send) {
                     emitter.emit(
                         None,
                         "unexpected failure",
+                        None,
                         diagnostic::Bug);
                 }
 
@@ -447,7 +465,7 @@ fn monitor(f: proc():Send) {
                     "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() {
@@ -457,6 +475,7 @@ fn monitor(f: proc():Send) {
                                      format!("failed to read internal \
                                               stderr: {}",
                                              e).as_slice(),
+                                     None,
                                      diagnostic::Error)
                     }
                 }
index 50f61f8f06a5be795e5df197238e7ca01b473876..313b2bd6bf0d46e7c1db8e5ee77c81a50d870b36 100644 (file)
@@ -20,6 +20,7 @@
 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;
@@ -28,7 +29,8 @@
 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,
@@ -65,6 +67,9 @@ pub fn fatal(&self, msg: &str) -> ! {
     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)
     }
@@ -197,11 +202,12 @@ pub fn host_filesearch<'a>(&'a self) -> filesearch::FileSearch<'a> {
 }
 
 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);
 
index 9bff6620aaafd624aea35b1acb4a7bd9f2c1f23e..0c39cf350a613c02b06e57deacc1f6ede7cfb872 100644 (file)
@@ -14,6 +14,8 @@
 
 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,
 }
@@ -41,6 +43,9 @@ fn fold_item_underscore(&mut self, item: &ast::Item_) -> ast::Item_ {
     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,
index 931f0312f579c809686a3e7d76c223c06e7acbd1..8b92166388d8608aadec35fbca6e4934948c3794 100644 (file)
@@ -66,6 +66,8 @@
 
     ("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),
@@ -93,6 +95,7 @@ pub struct Features {
     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 {
@@ -101,6 +104,7 @@ pub fn new() -> Features {
             default_type_params: Cell::new(false),
             issue_5723_bootstrap: Cell::new(false),
             overloaded_calls: Cell::new(false),
+            rustc_diagnostic_macros: Cell::new(false)
         }
     }
 }
@@ -425,4 +429,5 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
     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"));
 }
index 6e28d0cce3220762a64e526fb65347ce5a2056ba..63fba0fd4b4e932a06032b9bca5f15e684cab27b 100644 (file)
 #![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;
@@ -127,6 +132,8 @@ pub mod lib {
     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.
 //
index 3049904fc4494e8ed66353a5ebd76be2ef69d941..62236d753ad26e8dc80ad4b8ac08fae63ce3710b 100644 (file)
 
 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;
@@ -214,7 +207,21 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
                                          "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");
+                        }
+                    },
                     _ => ()
                 };
             },
@@ -265,6 +272,13 @@ fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
             }
         }
 
+        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) {
index edf46c214ba63fa4b94757ab2dafc19f9fc91aed..2314b3f74e3c4e07048f103de06b76c0226f33e5 100644 (file)
@@ -446,7 +446,7 @@ pub fn read_plugin_metadata(&mut self, krate: &ast::ViewItem) -> PluginMetadata
             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)
@@ -473,6 +473,14 @@ pub fn read_plugin_metadata(&mut self, krate: &ast::ViewItem) -> PluginMetadata
         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,
index fbf0288418ab8f8e83865255fd3959fe88097f3f..493fd575a8408e06fff2c6d8d3400c8361aa099b 100644 (file)
@@ -693,6 +693,10 @@ fn encode_info_for_struct(ecx: &EncodeContext,
         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
@@ -1584,37 +1588,25 @@ fn encode_plugin_registrar_fn(ecx: &EncodeContext, ebml_w: &mut Encoder) {
     }
 }
 
-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();
 }
index 599f5f4024f28ab2d98c3a29156790f22a7a5e80..f31c247abd38c3c83935d0d5bad13221db1ffddf 100644 (file)
@@ -194,7 +194,7 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
 
             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!()
             }
index ac17bd07503521212b46b40f71055095d86649e3..a3fa5a5f85ba4cd5237d3d43d37ebb49bffbd148 100644 (file)
 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};
@@ -91,6 +92,11 @@ fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics,
         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 {
@@ -102,8 +108,8 @@ pub fn build(krate: &Crate) -> 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
     }
 }
index 9f5fcb61f5fd0e9646416a7d13f12b9c1853376d..cdf434f4099dc831ab493330caace47c54738a92 100644 (file)
@@ -1219,6 +1219,13 @@ fn types_compatible(fcx: &FnCtxt, sp: Span,
                     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);
index e66dcd118c92892186cb85857d2e6a4b4ef801c7..c06e40fce14f915e410208e5393bb57eccbf885f 100644 (file)
@@ -78,6 +78,7 @@ impl Emitter for ExpectErrorEmitter {
     fn emit(&mut self,
             _cmsp: Option<(&codemap::CodeMap, Span)>,
             msg: &str,
+            _: Option<&str>,
             lvl: Level)
     {
         remove_message(self, msg, lvl);
index 79d0690653faf9d3a6a99d501bea05f3fb947b72..499cffa42aac9f124913adb549a0c81175765ffc 100644 (file)
@@ -72,6 +72,7 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate) -> Plugins {
     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 {
@@ -109,6 +110,10 @@ fn visit_view_item(&mut self, vi: &ast::ViewItem, _: ()) {
             _ => (),
         }
     }
+    fn visit_mac(&mut self, _: &ast::Mac, _:()) {
+        // bummer... can't see plugins inside macros.
+        // do nothing.
+    }
 }
 
 impl<'a> PluginLoader<'a> {
index af0b6a1cb21d104d496de178bd696f1db0c8920d..a5c6725bd819c484cded2d9707d243662c8847e6 100644 (file)
@@ -1461,12 +1461,15 @@ fn clean(&self) -> Item {
                             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())
                             )
@@ -1482,7 +1485,7 @@ fn clean(&self) -> Item {
             visibility: Some(ast::Public),
             def_id: self.id,
             inner: VariantItem(Variant { kind: kind }),
-            stability: None,
+            stability: get_stability(self.id),
         }
     }
 }
@@ -1890,7 +1893,7 @@ fn clean(&self) -> Item {
             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,
         }
     }
@@ -1948,9 +1951,16 @@ fn name_from_pat(p: &ast::Pat) -> String {
         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(..) => {
index 9ef671ef2fcbbddc79e6fc125b6492fd330b29f0..e62c8b63a294070b0c873f5cccecc9775b22a24f 100644 (file)
@@ -101,7 +101,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
 
 
     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);
 
index 382e299d28d9690b81c40315d1ab228f9850b6b3..c549469dcdeaaa19e90ef72caec2f9d438ebf4ea 100644 (file)
@@ -22,6 +22,7 @@
 use syntax::ast_util;
 
 use clean;
+use stability_summary::ModuleSummary;
 use html::item_type;
 use html::item_type::ItemType;
 use html::render;
@@ -37,6 +38,8 @@
 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.
@@ -428,7 +431,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
             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())
@@ -441,7 +447,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             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 {
@@ -601,6 +607,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+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;
@@ -631,3 +646,72 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
     }
 }
+
+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'>&nbsp</span>",
+                        (width * cnt.stable)/tot));
+            try!(write!(f, "<span class='summary Unstable' \
+                            style='width: {}px; display: inline-block'>&nbsp</span>",
+                        (width * cnt.unstable)/tot));
+            try!(write!(f, "<span class='summary Experimental' \
+                            style='width: {}px; display: inline-block'>&nbsp</span>",
+                        (width * cnt.experimental)/tot));
+            try!(write!(f, "<span class='summary Deprecated' \
+                            style='width: {}px; display: inline-block'>&nbsp</span>",
+                        (width * cnt.deprecated)/tot));
+            try!(write!(f, "<span class='summary Unmarked' \
+                            style='width: {}px; display: inline-block'>&nbsp</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>")
+    }
+}
index 70edbcf86e1a759653dd33659f3efdde7e49688a..ed047ef629dff600f72ff9cdffe7751c93fa651e 100644 (file)
@@ -43,6 +43,8 @@
 
 use externalfiles::ExternalHtml;
 
+use serialize::json;
+use serialize::Encodable;
 use serialize::json::ToJson;
 use syntax::ast;
 use syntax::ast_util;
@@ -59,6 +61,7 @@
 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
@@ -249,6 +252,11 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
 
     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(&[])) {
@@ -361,7 +369,7 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
     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> {
@@ -478,10 +486,10 @@ fn write_shared(cx: &Context,
                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"),
@@ -1045,13 +1053,34 @@ fn recurse<T>(&mut self, s: String, f: |&mut Context| -> T) -> T {
     ///
     /// 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() {
@@ -1061,6 +1090,7 @@ fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> {
                 None => break,
             }
         }
+
         Ok(())
     }
 
@@ -1233,6 +1263,8 @@ fn href(&self) -> Option<String> {
     }
 }
 
+
+
 impl<'a> fmt::Show for Item<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         // Write the breadcrumb trail header for the top
@@ -1269,6 +1301,17 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         // 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
@@ -1278,14 +1321,15 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         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 {
@@ -1355,6 +1399,7 @@ fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
 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>>();
@@ -1514,6 +1559,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
         }
     }
+
     write!(w, "</table>")
 }
 
index f65198fcfe28984cbb4a1d8b534c807fe8369dce..4f790f96750286c9442ded17339bf560d92b7915 100644 (file)
@@ -238,7 +238,7 @@ nav.sub {
 .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;
 }
@@ -409,6 +409,15 @@ h1 .stability {
 .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 */
index fc2fe00afbc0766e5d48a59196ca8f8c3752b3b3..76b9f11089f9bb5c78ef6153ddeaafa572ff9193 100644 (file)
@@ -56,6 +56,7 @@ pub mod html {
 pub mod markdown;
 pub mod passes;
 pub mod plugins;
+pub mod stability_summary;
 pub mod visit_ast;
 pub mod test;
 mod flock;
diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs
new file mode 100644 (file)
index 0000000..18e90d5
--- /dev/null
@@ -0,0 +1,174 @@
+// 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()
+        }
+    }
+}
index 18f823317808156b88ac86cf49d0af4be814d089..055019aa481ffebaf06edc9aab9f3a467be8efd8 100644 (file)
@@ -54,7 +54,7 @@ pub fn run(input: &str,
 
 
     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);
 
@@ -150,7 +150,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
         };
         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();
@@ -176,26 +176,15 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
     // 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?"
index 06f4e71871d40ba4c3d36a483a1d62b8abcd5ef3..396d51f4fcb13a4128d62046199608646d72c385 100644 (file)
@@ -69,6 +69,7 @@ fn main() {
 
 use alloc::libc_heap::malloc_raw;
 use collections::string::String;
+use collections::hash;
 use core::kinds::marker;
 use core::mem;
 use core::ptr;
@@ -116,6 +117,22 @@ fn eq(&self, other: &CString) -> bool {
     }
 }
 
+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 {
index b707c62bb70275c753c4ed975fb07fce649deb52..7cfbc4401c94135c5547b59070312e0213f66b79 100644 (file)
 #![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]
 
index 0205f2405f9ce8e1345f214a103e39fad5cde3b3..7a91cca6265a0a782e29492eca9d0a69f7ed1e00 100644 (file)
@@ -75,7 +75,7 @@ pub struct ProcessConfig<'a> {
 
     /// 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.
index 0151be81e6377a97adf7c9c734bc30f521a4a07d..4874e123b2b8eb31839febe8921c92e6e9b0eadf 100644 (file)
@@ -41,7 +41,7 @@
 #![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)]
index 61325d0ce948eb5bb6926ec4bcee141f30af0f7a..0486f376bc80658bfb0c7bf39480e1db195e32e1 100644 (file)
@@ -193,7 +193,7 @@ fn with_argv<T>(prog: &CString, args: &[CString],
 }
 
 /// 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,
index 22664ba26281e362c6333fda8fd52769f956bdfa..41f7aa5012d49bab88d1e4bb3808a808f59e57b6 100644 (file)
 #![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 {
@@ -77,7 +65,7 @@ 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,
@@ -129,20 +117,25 @@ fn eq(&self, other: &Version) -> bool {
 }
 
 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,
         }
 
@@ -150,14 +143,23 @@ fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
         // 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();
index 7e31d1d59216e766790044e3b0c0130737ed0525..5cb272a19eb886fff9edac35180c253c8dae5088 100644 (file)
@@ -21,7 +21,7 @@
 #![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)]
 
index 2cc7e70747a794403675e44d28ea6a4b0b8d829d..55d1411d77ed2a0d4fb42390f57f47a286b0f4d9 100644 (file)
@@ -61,6 +61,8 @@
  * ```
  */
 
+#![experimental]
+
 pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip};
 
 use default::Default;
index 7f9a1180785d99486dce89a3b0e0b09aad36d6a1..1c0251c8369dedc4a8709d8f1cc74ae60c7edcc4 100644 (file)
@@ -259,8 +259,8 @@ impl<'a> Writer for BufWriter<'a> {
     #[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",
@@ -416,6 +416,8 @@ fn test_buf_writer() {
             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]);
     }
index d781c414d08a71fbbb0213f87c216f65fb58e0a8..6ef730237795cd243d0395c737a11b74943ff06d 100644 (file)
@@ -16,6 +16,7 @@
 
 use str;
 use fmt;
+use os;
 use io::{IoResult, IoError};
 use io;
 use libc;
@@ -24,6 +25,7 @@
 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.
@@ -78,6 +80,9 @@ pub struct Process {
     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
@@ -100,7 +105,7 @@ pub struct Command {
     // 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,
@@ -147,31 +152,53 @@ pub fn new<T:ToCStr>(program: T) -> Command {
     }
 
     /// 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
     }
 
@@ -245,10 +272,15 @@ fn to_rtio(p: StdioContainer) -> rtio::StdioContainer {
         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),
@@ -872,9 +904,9 @@ pub fn env_cmd() -> Command {
         }
     })
 
-    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();
 
@@ -882,6 +914,40 @@ pub fn env_cmd() -> Command {
                 "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()
index 14782cafce34781a6aed1cc8b3b3fed67368bd0b..4b4ec367826d51b2c446c1da02d6bd07444bd1d7 100644 (file)
 #![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)]
@@ -286,11 +286,3 @@ mod std {
     // 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;
-}
index db56b387f8d023965888ad71043105c3a46e6248..1a5be089252de359155943187993d49be2f78d78 100644 (file)
@@ -1277,12 +1277,9 @@ pub fn page_size() -> uint {
 /// 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
@@ -1617,6 +1614,15 @@ fn drop(&mut self) {
     }
 }
 
+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;
index 5c6e140bd29b30aa2827273f5882a9f95719bea6..007686aa05cd5865cf03a4f4d52344653ff462df 100644 (file)
@@ -12,7 +12,7 @@
 
 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;
@@ -68,6 +68,18 @@ fn eq(&self, other: &Path) -> bool {
 
 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)
index 5e42d740e0333a0890e02ef8a796e80901fa0931..88ae0d4837e569febda914a30ad4ab82d9a31800 100644 (file)
@@ -13,7 +13,7 @@
 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;
@@ -90,6 +90,18 @@ fn eq(&self, other: &Path) -> bool {
 
 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)
index 45e8f348ff5105e5cbd680ca952c027a4aefd2f1..f6a1684b669404b421c3cae502d1b0a8c0c2706c 100644 (file)
@@ -24,7 +24,7 @@
 #![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)]
index 8ba01914648869df04798b6a7c0690cb2b5d3efc..d51054542b9c8a62ad4879a12018a9c562a3cfa9 100644 (file)
@@ -256,6 +256,7 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub config: CrateConfig,
     pub span: Span,
+    pub exported_macros: Vec<Span>
 }
 
 pub type MetaItem = Spanned<MetaItem_>;
@@ -1252,6 +1253,7 @@ fn check_asts_encodable() {
                 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>;
index 25c8e81bdbc91397bb5e5bb8436eb69be026289a..de2ecd9a2640488fcf3db7c4d6aa67423498448b 100644 (file)
@@ -112,6 +112,7 @@ pub enum Node {
     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 {
@@ -184,6 +185,8 @@ fn to_node(&self) -> Option<Node> {
     }
 }
 
+/// 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
@@ -430,6 +433,8 @@ fn new_span(&self, span: Span) -> Span {
     }
 }
 
+/// 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).
@@ -584,6 +589,10 @@ fn fold_lifetime(&mut self, lifetime: &Lifetime) -> Lifetime {
         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) {
index e469f327ae8ba403a3620ad65d0189978095f4a0..9bb5eae2ed2d66c893378ee316e419c01e53f90b 100644 (file)
@@ -12,6 +12,7 @@
 
 use codemap::{Pos, Span};
 use codemap;
+use diagnostics;
 
 use std::cell::{RefCell, Cell};
 use std::fmt;
@@ -59,7 +60,7 @@ pub enum ColorConfig {
 
 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);
 }
@@ -90,6 +91,10 @@ pub fn span_err(&self, sp: Span, msg: &str) {
         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);
     }
@@ -124,11 +129,11 @@ pub struct Handler {
 
 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) {
@@ -153,13 +158,13 @@ pub fn abort_if_errors(&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) -> ! {
@@ -169,7 +174,14 @@ pub fn emit(&self,
                 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) {
@@ -184,8 +196,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
     }
 }
 
-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 {
@@ -262,8 +275,8 @@ fn print_maybe_styled(w: &mut EmitterWriter,
     }
 }
 
-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));
     }
@@ -272,13 +285,32 @@ fn print_diagnostic(dst: &mut EmitterWriter,
                             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 {
@@ -287,7 +319,8 @@ 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 {
@@ -301,14 +334,15 @@ pub fn stderr(color_config: ColorConfig) -> EmitterWriter {
                 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 }
     }
 }
 
@@ -324,11 +358,10 @@ fn write(&mut self, bytes: &[u8]) -> io::IoResult<()> {
 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 {
@@ -339,7 +372,7 @@ fn emit(&mut self,
 
     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),
         }
@@ -347,7 +380,7 @@ fn custom_emit(&mut self, cm: &codemap::CodeMap,
 }
 
 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);
@@ -357,12 +390,12 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
         // 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));
         }
@@ -501,9 +534,9 @@ fn print_macro_backtrace(w: &mut EmitterWriter,
         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(())
diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs
new file mode 100644 (file)
index 0000000..b0260e1
--- /dev/null
@@ -0,0 +1,51 @@
+// 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))
+    })
+)
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
new file mode 100644 (file)
index 0000000..6582d2e
--- /dev/null
@@ -0,0 +1,132 @@
+// 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())
+}
diff --git a/src/libsyntax/diagnostics/registry.rs b/src/libsyntax/diagnostics/registry.rs
new file mode 100644 (file)
index 0000000..7bc191d
--- /dev/null
@@ -0,0 +1,25 @@
+// 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)
+    }
+}
index 9a5c7e86d21c6df035f0df0fa52f617eed43e8c8..dcb69ae8f7e64df0c08bf8f5fa49293c6aa6240e 100644 (file)
@@ -48,7 +48,8 @@ pub struct BasicMacroExpander {
     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,
@@ -60,7 +61,7 @@ fn expand(&self,
     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,
@@ -259,7 +260,7 @@ pub enum SyntaxExtension {
     /// 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.
@@ -409,6 +410,7 @@ pub struct ExtCtxt<'a> {
 
     pub mod_path: Vec<ast::Ident> ,
     pub trace_mac: bool,
+    pub exported_macros: Vec<codemap::Span>
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -420,7 +422,8 @@ pub fn new<'a>(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
             backtrace: None,
             mod_path: Vec::new(),
             ecfg: ecfg,
-            trace_mac: false
+            trace_mac: false,
+            exported_macros: Vec::new(),
         }
     }
 
@@ -538,6 +541,9 @@ pub fn ident_of(&self, st: &str) -> ast::Ident {
     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`,
index 4d79ff3257a9a20cd3b58cd5e330ff923a019e97..4d3913da3656a2c90e048c6276665be2a045f05b 100644 (file)
@@ -148,6 +148,8 @@ fn expr_struct_ident(&self, span: Span, id: ast::Ident,
     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>;
 
@@ -674,6 +676,10 @@ fn expr_none(&self, sp: 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(
index 93e4920bc1de43f5df09cda2be599d4018d10e3c..bbe96018f4b3ddbd080bee76e71ffc5eaddd0b74 100644 (file)
@@ -39,7 +39,6 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
                 args: Vec::new(),
                 ret_ty: Self,
                 attributes: attrs,
-                const_nonmatching: false,
                 combine_substructure: combine_substructure(|c, s, sub| {
                     cs_clone("Clone", c, s, sub)
                 }),
@@ -69,7 +68,7 @@ fn cs_clone(
             ctor_ident = variant.node.name;
             all_fields = af;
         },
-        EnumNonMatching(..) => {
+        EnumNonMatchingCollapsed (..) => {
             cx.span_bug(trait_span,
                         format!("non-matching enum variants in \
                                  `deriving({})`",
index ef8d477a98e678f83e9ecd3108c5ca5cf3c44857..19a979a5655ba060912d52838fa8b6faabc1701e 100644 (file)
@@ -45,7 +45,6 @@ macro_rules! md (
                 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)
                 })
index 59cdec1ea88f07f240ad27aca105053111f6b475..dcf59ba820e4cc39c0a81dd85844e00890fed6de 100644 (file)
@@ -35,7 +35,6 @@ macro_rules! md (
                 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)
                 })
@@ -59,7 +58,6 @@ macro_rules! md (
         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)
         })
@@ -82,24 +80,33 @@ macro_rules! md (
     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:
@@ -141,13 +148,11 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
             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)
@@ -191,19 +196,15 @@ fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span,
             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)
index 8b1e0498d253c43907b43ce5dc0ae37c2b0ae89d..42365936c9d4f5e56507ef736b2ea6bb8d8ff5bc 100644 (file)
@@ -57,7 +57,6 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span,
                 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)
                 })
index 271aa90cd24a4f5ea1114745a08fdedd16cbc3c7..e010b635fe41a666244d7c82fd45458fceefdcea 100644 (file)
@@ -17,7 +17,6 @@
 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,
@@ -41,7 +40,6 @@ 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)
                 }),
@@ -53,22 +51,21 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
 }
 
 
-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:
@@ -110,16 +107,11 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
             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)
index 6da5f1e2700f1a969c5cb962f22a06697171dea9..d909ffd2b49fb56aa24361e419641ab1113b5642 100644 (file)
@@ -54,7 +54,6 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
                                           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)
                 }),
index dfebc0f5e642111a25a1015b857e67cbd66faf43..f7d0308e1bd21d52cd1b1a401d878c8d9b22e142 100644 (file)
@@ -39,7 +39,6 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
                 args: Vec::new(),
                 ret_ty: Self,
                 attributes: attrs,
-                const_nonmatching: false,
                 combine_substructure: combine_substructure(|a, b, c| {
                     default_substructure(a, b, c)
                 })
index 3b34407edfeaa364b0d98a667e6cfdb1aa593f42..7e289e7676aa92c908353371364c142bf173de71 100644 (file)
@@ -121,7 +121,6 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
                                                 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)
                 }),
index c9f5936a9bb0532cc94deabae2a2a46380c75e5c..7d454016d602d3f118adec1126dfba0e1e7e85cc 100644 (file)
 //!   `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
 //!
@@ -232,10 +239,6 @@ pub struct MethodDef<'a> {
 
     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>>,
 }
 
@@ -286,12 +289,14 @@ pub enum SubstructureFields<'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),
@@ -309,14 +314,16 @@ pub enum SubstructureFields<'a> {
     |&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>;
 
@@ -516,6 +523,15 @@ fn expand_enum_def(&self,
     }
 }
 
+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,
@@ -754,27 +770,32 @@ fn expand_static_struct_method_body(&self,
    ~~~
     #[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,
@@ -784,190 +805,296 @@ fn expand_enum_method_body(&self,
                                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,
@@ -1168,7 +1295,7 @@ fn create_enum_variant_pattern(&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)
@@ -1193,9 +1320,9 @@ pub fn cs_fold(use_foldl: bool,
                 })
             }
         },
-        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`")
         }
@@ -1214,7 +1341,7 @@ pub fn cs_fold(use_foldl: bool,
 */
 #[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)
@@ -1233,9 +1360,9 @@ pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
 
             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`")
         }
@@ -1251,7 +1378,7 @@ pub fn cs_same_method(f: |&mut ExtCtxt, Span, Vec<Gc<Expr>>| -> Gc<Expr>,
 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)
@@ -1278,7 +1405,7 @@ pub fn cs_same_method_fold(use_foldl: bool,
 */
 #[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(
@@ -1296,7 +1423,7 @@ pub fn cs_binop(binop: ast::BinOp, base: Gc<Expr>,
 
 /// 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),
@@ -1306,7 +1433,7 @@ pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc,
 
 /// 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),
index 1b3ac47092a2d2e4dde17efc74a904ff3af74774..f469139177a0b24e8ebb2551a036faf4897e797a 100644 (file)
@@ -54,7 +54,6 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
                 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)
                 })
index 735497d9a2cf6ccfd6d50e9473d4545851cda2d5..30dd8e9683ad51b320d3e36d8c462d4d145205c0 100644 (file)
@@ -45,7 +45,6 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                            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)
                 }),
@@ -62,7 +61,6 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                            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)
                 }),
index 34b5f120d6ab8a62c4e094b30da52323b0960eba..c652b5a5bed9a60c223ee7b6839927c98759d727 100644 (file)
@@ -45,7 +45,6 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
                 ),
                 ret_ty: Self,
                 attributes: Vec::new(),
-                const_nonmatching: false,
                 combine_substructure: combine_substructure(|a, b, c| {
                     rand_substructure(a, b, c)
                 })
index 05b5131d7e4d332d6843e089e39ae192233bb425..e0dfbb232f554fcf0c7343f29ef89f608f4a4ed0 100644 (file)
@@ -45,7 +45,6 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
                 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)
                 })
@@ -66,8 +65,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
     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)]`")
         }
     };
index 93947251223fd18eacc5a2e6f6d3eab521f48f88..973f9d518cd70563c373cce5e0d9e2c50f26c450 100644 (file)
@@ -39,7 +39,6 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
                 args: Vec::new(),
                 ret_ty: Self,
                 attributes: attrs.clone(),
-                const_nonmatching: false,
                 combine_substructure: combine_substructure(|a, b, c| {
                     zero_substructure(a, b, c)
                 })
@@ -51,7 +50,6 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
                 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 \
index b7d72ae4debc130342fe3d5dc3e2a8577b4a4d0d..6e44bfa6747eb405eef00f66feee6cda5769a073 100644 (file)
@@ -58,7 +58,7 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
                         None => {
                             fld.cx.span_err(
                                 pth.span,
-                                format!("macro undefined: '{}'",
+                                format!("macro undefined: '{}!'",
                                         extnamestr.get()).as_slice());
 
                             // let compilation continue
@@ -518,10 +518,9 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
             // 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() {
@@ -567,7 +566,7 @@ fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> {
     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();
         }
@@ -754,7 +753,6 @@ fn visit_pat(&mut self, pattern: &ast::Pat, _: ()) {
             _ => visit::walk_pat(self, pattern, ())
         }
     }
-
 }
 
 /// find the PatIdent paths in a pattern
@@ -903,6 +901,9 @@ fn fold_ident(&mut self, id: Ident) -> Ident {
             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
@@ -932,6 +933,9 @@ fn fold_pat(&mut self, pat: Gc<ast::Pat>) -> Gc<ast::Pat> {
             _ => noop_fold_pat(pat, self)
         }
     }
+    fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
+        fold::fold_mac(macro, self)
+    }
 }
 
 // expand a method
@@ -1039,6 +1043,7 @@ pub struct ExportedMacros {
 
 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 {
@@ -1066,7 +1071,8 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
         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;
 }
@@ -1145,6 +1151,25 @@ fn original_span(cx: &ExtCtxt) -> Gc<codemap::ExpnInfo> {
     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};
index 249e9305150d665acf4da8d348ea4c45b0359461..923b3e78731a09c635a65d448def5cd93c578ed3 100644 (file)
@@ -13,7 +13,7 @@
 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};
@@ -95,7 +95,7 @@ struct MacroRulesMacroExpander {
     rhses: Vec<Rc<NamedMatch>>,
 }
 
-impl MacroExpander for MacroRulesMacroExpander {
+impl TTMacroExpander for MacroRulesMacroExpander {
     fn expand(&self,
               cx: &mut ExtCtxt,
               sp: Span,
index bcdf920e5dd41779d76bfe020ee324c04a0841b0..3e3b57be6e40650ff77c14ed99fc93d30aa37317 100644 (file)
@@ -8,6 +8,16 @@
 // 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;
@@ -299,17 +309,13 @@ fn fold_local(&mut self, l: Gc<Local>) -> Gc<Local> {
         }
     }
 
-    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>,
@@ -361,6 +367,20 @@ fn fold_attribute(&mut self, at: Attribute) -> Attribute {
 
 }
 
+
+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
@@ -713,6 +733,7 @@ pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
         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(),
     }
 }
 
@@ -985,6 +1006,7 @@ mod test {
     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.
@@ -1000,6 +1022,9 @@ impl Folder for ToZzIdentFolder {
         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...
index 1ef376c6615ec393c751e40b3f41d5609302d335..8b9cb086949725001bdfeeefc9d27ea4510c802e 100644 (file)
 #![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;
@@ -41,26 +40,30 @@ pub mod util {
     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;
@@ -70,31 +73,25 @@ pub mod print {
 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;
 }
index 55ad1b771231011d9c1168103af456be83fffcdb..550dbfdab71f77ee42a171cd1d057a79cbd45ca8 100644 (file)
@@ -85,9 +85,9 @@ fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
 
                 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)
             }
             _ => {
index 0aaddacfab624783179153e274e848263b6ac381..5c5943f0cd47c10e5fd461800b0ffbae3024a978 100644 (file)
@@ -1308,7 +1308,7 @@ mod test {
     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())
     }
index 37c84c95af654e3f98ce63060c94b1bd7161c4a1..a3e169cd5116d53c0c22834e70ea6c85c8ca33d1 100644 (file)
@@ -40,7 +40,7 @@ pub struct ParseSess {
 
 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()),
     }
 }
index 743eeed9da5e247c4dc8fe77a6e0f94e8b993180..84db2bc5a2217cf6ba00c09ce2529ab355070d3b 100644 (file)
@@ -5386,7 +5386,8 @@ pub fn parse_crate_mod(&mut self) -> Crate {
             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(),
         }
     }
 
index 9298b58c4267d9c2c3493f6b403e82946224f2a3..7caaf2f6cc1faccee1c1b98ab774e3b08ef17e1f 100644 (file)
 //! 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;
@@ -124,8 +128,13 @@ fn visit_lifetime_decl(&mut self, _lifetime: &Lifetime, _e: E) {
     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)
index 66a1d4e797d189514ef919083da3e015ee756748..3fc631422d5f3a3e78cba2a5400ca0119f83c635 100644 (file)
@@ -46,7 +46,7 @@
 #![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)]
index 4c982aa27c573db150e814030a9122e641212c89..8fbb821d0b96e484b2762af5cc4e0757f41b5588 100644 (file)
@@ -31,7 +31,7 @@
 #![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)]
 
index 19168469b5b6a6032cd06afc4ce5112e8dd6756e..7655ace0ecb08c78699fcdbb19ad86076e9a183a 100644 (file)
@@ -18,7 +18,7 @@
 #![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)]
 
index 49e8bb66b4241f3c57920ecd25d1126fc51274fe..608bdbfaf0d128fad4498c6ec024f6b7b792046a 100644 (file)
@@ -20,7 +20,6 @@
 //! 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"]
index be94f117b539ec81a36f87bfd433b9a4088c2015..b95fc3c495eed1a994e3d0cd7f4423d30c5d5520 100644 (file)
@@ -17,7 +17,7 @@
 #![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)]
 
index 1579b676660b265ca2aaab872acaf59ffdb7c8ff..1f84306f9ccc9274bfc5bb84ee6c6b7fbf7a3d97 100644 (file)
@@ -61,7 +61,7 @@ fn main() {
 #![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)]
diff --git a/src/test/auxiliary/rlib_crate_test.rs b/src/test/auxiliary/rlib_crate_test.rs
new file mode 100644 (file)
index 0000000..be03a36
--- /dev/null
@@ -0,0 +1,21 @@
+// 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) {}
diff --git a/src/test/compile-fail-fulldeps/macro-crate-rlib.rs b/src/test/compile-fail-fulldeps/macro-crate-rlib.rs
new file mode 100644 (file)
index 0000000..625245d
--- /dev/null
@@ -0,0 +1,20 @@
+// 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() {}
index 39c2accaddf3327dd0259ac7b5344720b4ab4ad6..6a3b0b91ffe297ed9d24f03a8d685f687c0c344e 100644 (file)
@@ -18,5 +18,5 @@
 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!'
 }
index 848deac4d55c04822b94ba8d10d6b77e8dab8ed6..09cf9739614040679a39ddb73be474e7b7d50b71 100644 (file)
@@ -10,9 +10,9 @@
 
 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!'
 }
index e5a5c7dd1c7c26a589bc9cc82ed2b68cfbfb7f1e..676a6e7cb4452f5e2843c207a339084095626336 100644 (file)
@@ -47,4 +47,9 @@ fn main() {
     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
 }
diff --git a/src/test/compile-fail/rustc-diagnostics-1.rs b/src/test/compile-fail/rustc-diagnostics-1.rs
new file mode 100644 (file)
index 0000000..55d8360
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(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
diff --git a/src/test/compile-fail/rustc-diagnostics-2.rs b/src/test/compile-fail/rustc-diagnostics-2.rs
new file mode 100644 (file)
index 0000000..c4e011b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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)
diff --git a/src/test/compile-fail/rustc-diagnostics-3.rs b/src/test/compile-fail/rustc-diagnostics-3.rs
new file mode 100644 (file)
index 0000000..d160664
--- /dev/null
@@ -0,0 +1,20 @@
+// 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!'
diff --git a/src/test/compile-fail/typeck-cast-pointer-to-float.rs b/src/test/compile-fail/typeck-cast-pointer-to-float.rs
new file mode 100644 (file)
index 0000000..22a0978
--- /dev/null
@@ -0,0 +1,15 @@
+// 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`
+}
index dda66f051bc8e5f829c2d93ace664476755e29f2..b783dd39a061a52724b639ba4569ae7c956aa443 100644 (file)
@@ -22,4 +22,8 @@ pub fn baz() { }
 
     /// *wow*
     pub trait Doge { }
+
+    pub struct Foo { x: int, y: uint }
+
+    pub fn prawns((a, b): (int, uint), Foo { x, y }: Foo) { }
 }
index 97862844030b2c7c52ba97f790bfdec300246ea3..c2a1c01b919ab05f3a29bb9b63f5acde3778424a 100644 (file)
@@ -37,19 +37,8 @@ fn double() {
 }
 
 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();
@@ -73,7 +62,8 @@ fn runtest(me: &str) {
             "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();
index 70839c1884791f5b987fa2f56127694fd954414a..de86ca179b7d75c0cf9c1e0bf525a71a6c591632 100644 (file)
@@ -58,7 +58,7 @@ fn main() {
         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