]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15610 : brson/rust/0.12.0, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 12 Jul 2014 18:06:36 +0000 (18:06 +0000)
committerbors <bors@rust-lang.org>
Sat, 12 Jul 2014 18:06:36 +0000 (18:06 +0000)
48 files changed:
man/rustc.1
mk/install.mk
src/etc/install.sh
src/etc/zsh/_rust
src/libcollections/hash/sip.rs
src/libcore/atomics.rs
src/libgreen/lib.rs
src/libgreen/stack.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/front/config.rs
src/librustc/metadata/creader.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/stability.rs
src/librustc/plugin/load.rs
src/librustdoc/clean/mod.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/libstd/io/mem.rs
src/libstd/lib.rs
src/libstd/os.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map.rs
src/libsyntax/ext/base.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/parse/parser.rs
src/libsyntax/visit.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]

index 95d99a88781bdc94fb5124d6b70c0d2e4d741118..f49faf2ec6e3a8d68fa76631158f4a06fb0bd7a0 100644 (file)
@@ -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 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 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 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 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 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 c9c2dcc374cf12a9665add75d806a01a4970de00..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"]
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 8173e2ab582a043315a3882cd0e561f0c799284c..d03bf3593fa41bc19aa4ed3ef767b7de0e31e07c 100644 (file)
@@ -270,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));
@@ -290,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))
 }
 
@@ -302,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.
@@ -309,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 8669a733f61345a7f7fb5d4f9d908036afa86189..313b2bd6bf0d46e7c1db8e5ee77c81a50d870b36 100644 (file)
@@ -29,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,
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 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 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 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..24f23761286f024f295809942c6d00321fa1e580 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,
         }
     }
index 382e299d28d9690b81c40315d1ab228f9850b6b3..e2ff80b9fd928f029eded07f085d5f71ff5962f1 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.
@@ -441,7 +444,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 +604,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 +643,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 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 df2fb9a82ad2f5cf91c614f9e60ba935d642e632..4b4ec367826d51b2c446c1da02d6bd07444bd1d7 100644 (file)
@@ -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 778f77ac7a8181383aae92d48cf0e41226e0848b..dd8304014433a5acdaf5a50c1e31f27869cbfb2c 100644 (file)
@@ -249,6 +249,7 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub config: CrateConfig,
     pub span: Span,
+    pub exported_macros: Vec<Span>
 }
 
 pub type MetaItem = Spanned<MetaItem_>;
@@ -1245,6 +1246,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 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 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 b5f7005c2a3e005f2fdca7153e0260596456701d..6e44bfa6747eb405eef00f66feee6cda5769a073 100644 (file)
@@ -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() {
@@ -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 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)
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() {}