]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #12370 : rcxdude/rust/macro_fix, r=alexcrichton
authorbors <bors@rust-lang.org>
Wed, 19 Feb 2014 12:41:45 +0000 (04:41 -0800)
committerbors <bors@rust-lang.org>
Wed, 19 Feb 2014 12:41:45 +0000 (04:41 -0800)
Closes #11692. Instead of returning the original expression, a dummy expression
(with identical span) is returned. This prevents infinite loops of failed
expansions as well as odd double error messages in certain situations.

This is a slightly better fix than #12197, because it does not produce a double error and also fixes a few other cases where an infinite loop could happen.

This does not fix the other issue in #11692 (non-builtin macros not being recognised when expanded inside macros), which I think should be moved into a separate issue.

29 files changed:
Makefile.in
mk/main.mk
src/compiler-rt
src/doc/tutorial.md
src/libextra/json.rs
src/libnative/io/file.rs
src/librustc/middle/privacy.rs
src/librustc/middle/resolve.rs
src/librustdoc/clean.rs
src/librustdoc/doctree.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.css
src/librustdoc/lib.rs
src/librustdoc/passes.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/os.rs
src/libstd/str.rs
src/libstd/unstable/lang.rs
src/libsync/arc.rs
src/test/compile-fail/mutex-arc-nested.rs [deleted file]
src/test/compile-fail/privacy-ns1.rs [new file with mode: 0644]
src/test/compile-fail/privacy-ns2.rs [new file with mode: 0644]
src/test/run-make/rustdoc-json/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-json/foo.rs [new file with mode: 0644]
src/test/run-pass/privacy-ns.rs [new file with mode: 0644]
src/test/run-pass/self-re-assign.rs [new file with mode: 0644]

index 5e6e8f310c7814e1a5078163d6299a80e5f87802..04ff606d0b93991c71f87a8870bffa372fcc2dfb 100644 (file)
 #
 # First, start with one of these build targets:
 #
-#   * all - The default. Builds a complete, bootstrapped compiler.
+#   * all - The default. Build a complete, bootstrapped compiler.
 #           `rustc` will be in `${target-triple}/stage2/bin/`. Run it
 #           directly from the build directory if you like. This also
 #           comes with docs in `doc/`.
 #
 #   * check - Run the complete test suite
 #
+#   * clean - Clean the build repertory. It is advised to run this
+#             command if you want to build Rust again, after an update
+#             of the git repository.
+#
 #   * install - Install Rust. Note that installation is not necessary
 #               to use the compiler.
 #
 #
 # </tips>
 #
-# <nittygritty>
+# <nitty-gritty>
 #
 # # The Rust Build System
 #
 # libraries are managed and versioned without polluting the common
 # areas of the filesystem.
 #
-# General rust binaries may stil live in the host bin directory; they
+# General rust binaries may still live in the host bin directory; they
 # will just link against the libraries in the target lib directory.
 #
 # Admittedly this is a little convoluted.
 #
-# </nittygritty>
+# </nitty-gritty>
 #
 
 ######################################################################
index 53ba07e65cbdd6ede725175eb9a0b6ec50d6262b..2c7c7c7cecd6d278248c64f27f11b527e3e81ab5 100644 (file)
@@ -446,13 +446,13 @@ all: $(ALL_TARGET_RULES) $(GENERATED) docs
 # $(1) is the name of the doc <section> in Makefile.in
 # pick everything between tags | remove first line | remove last line
 # | remove extra (?) line | strip leading `#` from lines
-SHOW_DOCS = $(Q)awk '/$(1)/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
+SHOW_DOCS = $(Q)awk '/<$(1)>/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
 
 help:
        $(call SHOW_DOCS,help)
 
-hot-tips:
-       $(call SHOW_DOCS,hottips)
+tips:
+       $(call SHOW_DOCS,tips)
 
 nitty-gritty:
-       $(call SHOW_DOCS,nittygritty)
+       $(call SHOW_DOCS,nitty-gritty)
index d4606f1818dd8dfeaa3e509cd1cbac4482c3513e..f4b221571ce6f05714c1f1c6fa48f1393499989c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d4606f1818dd8dfeaa3e509cd1cbac4482c3513e
+Subproject commit f4b221571ce6f05714c1f1c6fa48f1393499989c
index d5181f4cea42946e0ad1de907b47b248ee851dd4..094771897f4f60aa2640387928e095e581e55d02 100644 (file)
@@ -1750,6 +1750,24 @@ closures, but they also own them: that is, no other code can access
 them. Owned closures are used in concurrent code, particularly
 for spawning [tasks][tasks].
 
+Closures can be used to spawn tasks.
+A practical example of this pattern is found when using the `spawn` function,
+which starts a new task.
+
+~~~~
+use std::task::spawn;
+
+// proc is the closure which will be spawned.
+spawn(proc() {
+    debug!("I'm a new task")
+});
+~~~~
+
+> ***Note:*** If you want to see the output of `debug!` statements, you will need to turn on
+> `debug!` logging.  To enable `debug!` logging, set the RUST_LOG environment
+> variable to the name of your crate, which, for a file named `foo.rs`, will be
+> `foo` (e.g., with bash, `export RUST_LOG=foo`).
+
 ## Closure compatibility
 
 Rust closures have a convenient subtyping property: you can pass any kind of
@@ -1771,45 +1789,6 @@ call_twice(function);
 > in small ways. At the moment they can be unsound in some
 > scenarios, particularly with non-copyable types.
 
-## Do syntax
-
-The `do` expression makes it easier to call functions that take procedures
-as arguments.
-
-Consider this function that takes a procedure:
-
-~~~~
-fn call_it(op: proc(v: int)) {
-    op(10)
-}
-~~~~
-
-As a caller, if we use a closure to provide the final operator
-argument, we can write it in a way that has a pleasant, block-like
-structure.
-
-~~~~
-# fn call_it(op: proc(v: int)) { }
-call_it(proc(n) {
-    println!("{}", n);
-});
-~~~~
-
-A practical example of this pattern is found when using the `spawn` function,
-which starts a new task.
-
-~~~~
-use std::task::spawn;
-spawn(proc() {
-    debug!("I'm a new task")
-});
-~~~~
-
-If you want to see the output of `debug!` statements, you will need to turn on
-`debug!` logging.  To enable `debug!` logging, set the RUST_LOG environment
-variable to the name of your crate, which, for a file named `foo.rs`, will be
-`foo` (e.g., with bash, `export RUST_LOG=foo`).
-
 # Methods
 
 Methods are like functions except that they always begin with a special argument,
index edf5bb63b300421eebb3f153beaaba0555d6ef48..5043cad6f200cca9bb1d174584d0c53bc2f63684 100644 (file)
@@ -59,6 +59,7 @@
 To encode using Encodable :
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use extra::json;
 use std::io;
@@ -98,6 +99,7 @@ fn main() {
 
 
 ```rust
+extern crate extra;
 extern crate collections;
 
 use extra::json;
@@ -128,6 +130,7 @@ fn main() {
 To decode a JSON string using `Decodable` trait :
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use serialize::Decodable;
 
@@ -154,6 +157,7 @@ fn main() {
 using the serialization API, using the derived serialization code.
 
 ```rust
+extern crate extra;
 extern crate serialize;
 use extra::json;
 use serialize::{Encodable, Decodable};
@@ -186,6 +190,7 @@ fn main() {
 Example of `ToJson` trait implementation for TestStruct1.
 
 ```rust
+extern crate extra;
 extern crate serialize;
 extern crate collections;
 
index e9c9f51966c60e0604a1fef365c266b478856837..6d3a156a2b01a9711e0e7a71136ebfe3cbe9bf0b 100644 (file)
@@ -571,7 +571,9 @@ unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
                         else {
                             let fp_vec = vec::from_buf(
                                 fp_buf, wcslen(fp_buf) as uint);
-                            let fp_str = str::from_utf16(fp_vec);
+                            let fp_trimmed = str::truncate_utf16_at_nul(fp_vec);
+                            let fp_str = str::from_utf16(fp_trimmed)
+                                    .expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
                             paths.push(Path::new(fp_str));
                         }
                         more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
index 8c5654d3fcecb0b8a8aec4c018ce7bcb8e7341ac..1ab5ebc6d61004b90f260cab2b39fd48432e610f 100644 (file)
 /// reexporting a public struct doesn't inline the doc).
 pub type PublicItems = HashSet<ast::NodeId>;
 
+/// Result of a checking operation - None => no errors were found. Some => an
+/// error and contains the span and message for reporting that error and
+/// optionally the same for a note about the error.
+type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
+
 ////////////////////////////////////////////////////////////////////////////////
 /// The parent visitor, used to determine what's the parent of what (node-wise)
 ////////////////////////////////////////////////////////////////////////////////
@@ -510,40 +515,50 @@ fn private_accessible(&self, id: ast::NodeId) -> bool {
         }
     }
 
-    /// Guarantee that a particular definition is public, possibly emitting an
-    /// error message if it's not.
+    fn report_error(&self, result: CheckResult) -> bool {
+        match result {
+            None => true,
+            Some((span, msg, note)) => {
+                self.tcx.sess.span_err(span, msg);
+                match note {
+                    Some((span, msg)) => self.tcx.sess.span_note(span, msg),
+                    None => {},
+                }
+                false
+            },
+        }
+    }
+
+    /// Guarantee that a particular definition is public. Returns a CheckResult
+    /// which contains any errors found. These can be reported using `report_error`.
+    /// If the result is `None`, no errors were found.
     fn ensure_public(&self, span: Span, to_check: ast::DefId,
-                     source_did: Option<ast::DefId>, msg: &str) -> bool {
+                     source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
         match self.def_privacy(to_check) {
-            ExternallyDenied => {
-                self.tcx.sess.span_err(span, format!("{} is private", msg))
-            }
+            ExternallyDenied => Some((span, format!("{} is private", msg), None)),
             DisallowedBy(id) => {
-                if id == source_did.unwrap_or(to_check).node {
-                    self.tcx.sess.span_err(span, format!("{} is private", msg));
-                    return false;
+                let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+                    return Some((span, format!("{} is private", msg), None));
                 } else {
-                    self.tcx.sess.span_err(span, format!("{} is inaccessible",
-                                                         msg));
-                }
+                    (span, format!("{} is inaccessible", msg))
+                };
                 match self.tcx.map.find(id) {
                     Some(ast_map::NodeItem(item)) => {
                         let desc = match item.node {
                             ast::ItemMod(..) => "module",
                             ast::ItemTrait(..) => "trait",
-                            _ => return false,
+                            _ => return Some((err_span, err_msg, None)),
                         };
                         let msg = format!("{} `{}` is private",
                                           desc,
                                           token::get_ident(item.ident));
-                        self.tcx.sess.span_note(span, msg);
-                    }
-                    Some(..) | None => {}
+                        Some((err_span, err_msg, Some((span, msg))))
+                    },
+                    _ => Some((err_span, err_msg, None)),
                 }
-            }
-            Allowable => return true
+            },
+            Allowable => None,
         }
-        return false;
     }
 
     // Checks that a field is in scope.
@@ -613,34 +628,99 @@ fn check_static_method(&mut self, span: Span, method_id: ast::DefId,
         let method_id = ty::method(self.tcx, method_id).provided_source
                                                        .unwrap_or(method_id);
 
-        self.ensure_public(span,
-                           method_id,
-                           None,
-                           format!("method `{}`", token::get_ident(name)));
+        let string = token::get_ident(name);
+        self.report_error(self.ensure_public(span,
+                                             method_id,
+                                             None,
+                                             format!("method `{}`", string)));
     }
 
     // Checks that a path is in scope.
     fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
         debug!("privacy - path {}", self.nodestr(path_id));
         let def_map = self.tcx.def_map.borrow();
-        let def = def_map.get().get_copy(&path_id);
+        let orig_def = def_map.get().get_copy(&path_id);
         let ck = |tyname: &str| {
-            let origdid = def_id_of_def(def);
+            let ck_public = |def: ast::DefId| {
+                let name = token::get_ident(path.segments
+                                                .last()
+                                                .unwrap()
+                                                .identifier);
+                let origdid = def_id_of_def(orig_def);
+                self.ensure_public(span,
+                                   def,
+                                   Some(origdid),
+                                   format!("{} `{}`",
+                                           tyname,
+                                           name))
+            };
+
             match *self.last_private_map.get(&path_id) {
-                resolve::AllPublic => {},
-                resolve::DependsOn(def) => {
-                    let name = token::get_ident(path.segments
-                                                    .last()
-                                                    .unwrap()
-                                                    .identifier);
-                    self.ensure_public(span,
-                                       def,
-                                       Some(origdid),
-                                       format!("{} `{}`",
-                                               tyname, name));
-                }
+                resolve::LastMod(resolve::AllPublic) => {},
+                resolve::LastMod(resolve::DependsOn(def)) => {
+                    self.report_error(ck_public(def));
+                },
+                resolve::LastImport{value_priv: value_priv,
+                                    value_used: check_value,
+                                    type_priv: type_priv,
+                                    type_used: check_type} => {
+                    // This dance with found_error is because we don't want to report
+                    // a privacy error twice for the same directive.
+                    let found_error = match (type_priv, check_type) {
+                        (Some(resolve::DependsOn(def)), resolve::Used) => {
+                            !self.report_error(ck_public(def))
+                        },
+                        _ => false,
+                    };
+                    if !found_error {
+                        match (value_priv, check_value) {
+                            (Some(resolve::DependsOn(def)), resolve::Used) => {
+                                self.report_error(ck_public(def));
+                            },
+                            _ => {},
+                        }
+                    }
+                    // If an import is not used in either namespace, we still want to check
+                    // that it could be legal. Therefore we check in both namespaces and only
+                    // report an error if both would be illegal. We only report one error,
+                    // even if it is illegal to import from both namespaces.
+                    match (value_priv, check_value, type_priv, check_type) {
+                        (Some(p), resolve::Unused, None, _) |
+                        (None, _, Some(p), resolve::Unused) => {
+                            let p = match p {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            if p.is_some() {
+                                self.report_error(p);
+                            }
+                        },
+                        (Some(v), resolve::Unused, Some(t), resolve::Unused) => {
+                            let v = match v {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            let t = match t {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            match (v, t) {
+                                (Some(_), Some(t)) => {
+                                    self.report_error(Some(t));
+                                },
+                                _ => {},
+                            }
+                        },
+                        _ => {},
+                    }
+                },
             }
         };
+        // FIXME(#12334) Imports can refer to definitions in both the type and
+        // value namespaces. The privacy information is aware of this, but the
+        // def map is not. Therefore the names we work out below will not always
+        // be accurate and we can get slightly wonky error messages (but type
+        // checking is always correct).
         let def_map = self.tcx.def_map.borrow();
         match def_map.get().get_copy(&path_id) {
             ast::DefStaticMethod(..) => ck("static method"),
@@ -668,7 +748,7 @@ fn check_method(&mut self, span: Span, origin: &method_origin,
             // is whether the trait itself is accessible or not.
             method_param(method_param { trait_id: trait_id, .. }) |
             method_object(method_object { trait_id: trait_id, .. }) => {
-                self.ensure_public(span, trait_id, None, "source trait");
+                self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
             }
         }
     }
index 1d28c781ea0c80019d0326a85eb36e181a9ff55a..327001fcd27036ec38635f96adb9d8a80537e850 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 use driver::session::Session;
 use metadata::csearch;
 use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
@@ -64,14 +63,34 @@ pub struct Export2 {
 pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
 
 pub enum LastPrivate {
+    LastMod(PrivateDep),
+    // `use` directives (imports) can refer to two separate definitions in the
+    // type and value namespaces. We record here the last private node for each
+    // and whether the import is in fact used for each.
+    // If the Option<PrivateDep> fields are None, it means there is no defintion
+    // in that namespace.
+    LastImport{value_priv: Option<PrivateDep>,
+               value_used: ImportUse,
+               type_priv: Option<PrivateDep>,
+               type_used: ImportUse},
+}
+
+pub enum PrivateDep {
     AllPublic,
     DependsOn(DefId),
 }
 
+// How an import is used.
+#[deriving(Eq)]
+pub enum ImportUse {
+    Unused,       // The import is not used.
+    Used,         // The import is used.
+}
+
 impl LastPrivate {
     fn or(self, other: LastPrivate) -> LastPrivate {
         match (self, other) {
-            (me, AllPublic) => me,
+            (me, LastMod(AllPublic)) => me,
             (_, other) => other,
         }
     }
@@ -84,7 +103,7 @@ enum PatternBindingMode {
     ArgumentIrrefutableMode,
 }
 
-#[deriving(Eq)]
+#[deriving(Eq, IterBytes)]
 enum Namespace {
     TypeNS,
     ValueNS
@@ -869,7 +888,7 @@ struct Resolver {
     // so as to avoid printing duplicate errors
     emit_errors: bool,
 
-    used_imports: HashSet<NodeId>,
+    used_imports: HashSet<(NodeId, Namespace)>,
 }
 
 struct BuildReducedGraphVisitor<'a> {
@@ -904,7 +923,7 @@ fn visit_block(&mut self, block: &Block, context: ReducedGraphParent) {
 
 }
 
-struct UnusedImportCheckVisitor<'a> { resolver: &'a Resolver }
+struct UnusedImportCheckVisitor<'a> { resolver: &'a mut Resolver }
 
 impl<'a> Visitor<()> for UnusedImportCheckVisitor<'a> {
     fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@@ -2152,7 +2171,7 @@ fn resolve_import_for_module(&mut self,
         // First, resolve the module path for the directive, if necessary.
         let container = if module_path.len() == 0 {
             // Use the crate root.
-            Some((self.graph_root.get_module(), AllPublic))
+            Some((self.graph_root.get_module(), LastMod(AllPublic)))
         } else {
             match self.resolve_module_path(module_,
                                            *module_path,
@@ -2257,6 +2276,12 @@ fn resolve_single_import(&mut self,
                directive.id,
                lp);
 
+        let lp = match lp {
+            LastMod(lp) => lp,
+            LastImport{..} => self.session.span_bug(directive.span,
+                                                    "Not expecting Import here, must be LastMod"),
+        };
+
         // We need to resolve both namespaces for this to succeed.
         //
 
@@ -2287,7 +2312,8 @@ fn resolve_single_import(&mut self,
 
         // Unless we managed to find a result in both namespaces (unlikely),
         // search imports as well.
-        let mut used_reexport = false;
+        let mut value_used_reexport = false;
+        let mut type_used_reexport = false;
         match (value_result, type_result) {
             (BoundResult(..), BoundResult(..)) => {} // Continue.
             _ => {
@@ -2342,7 +2368,7 @@ fn get_binding(this: &mut Resolver,
                                 }
                                 Some(target) => {
                                     let id = import_resolution.id(namespace);
-                                    this.used_imports.insert(id);
+                                    this.used_imports.insert((id, namespace));
                                     return BoundResult(target.target_module,
                                                        target.bindings);
                                 }
@@ -2354,12 +2380,12 @@ fn get_binding(this: &mut Resolver,
                         if value_result.is_unknown() {
                             value_result = get_binding(self, *import_resolution,
                                                        ValueNS);
-                            used_reexport = import_resolution.is_public.get();
+                            value_used_reexport = import_resolution.is_public.get();
                         }
                         if type_result.is_unknown() {
                             type_result = get_binding(self, *import_resolution,
                                                       TypeNS);
-                            used_reexport = import_resolution.is_public.get();
+                            type_used_reexport = import_resolution.is_public.get();
                         }
 
                     }
@@ -2375,7 +2401,8 @@ fn get_binding(this: &mut Resolver,
 
         // If we didn't find a result in the type namespace, search the
         // external modules.
-        let mut used_public = false;
+        let mut value_used_public = false;
+        let mut type_used_public = false;
         match type_result {
             BoundResult(..) => {}
             _ => {
@@ -2393,7 +2420,7 @@ fn get_binding(this: &mut Resolver,
                                 module);
                         type_result = BoundResult(containing_module,
                                                   name_bindings);
-                        used_public = true;
+                        type_used_public = true;
                     }
                 }
             }
@@ -2412,7 +2439,7 @@ fn get_binding(this: &mut Resolver,
                 import_resolution.value_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.value_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(ValueNS);
+                value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2426,7 +2453,7 @@ fn get_binding(this: &mut Resolver,
                 import_resolution.type_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.type_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(TypeNS);
+                type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2443,7 +2470,8 @@ fn get_binding(this: &mut Resolver,
             self.resolve_error(directive.span, msg);
             return Failed;
         }
-        let used_public = used_reexport || used_public;
+        let value_used_public = value_used_reexport || value_used_public;
+        let type_used_public = type_used_reexport || type_used_public;
 
         assert!(import_resolution.outstanding_references.get() >= 1);
         import_resolution.outstanding_references.set(
@@ -2452,28 +2480,33 @@ fn get_binding(this: &mut Resolver,
         // record what this import resolves to for later uses in documentation,
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
-        match import_resolution.value_target.get() {
+        let value_private = match import_resolution.value_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(ValueNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
-        match import_resolution.type_target.get() {
+                if value_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            // AllPublic here and below is a dummy value, it should never be used because
+            // _exists is false.
+            None => None,
+        };
+        let type_private = match import_resolution.type_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(TypeNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
+                if type_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            None => None,
+        };
+
+        self.last_private.insert(directive.id, LastImport{value_priv: value_private,
+                                                          value_used: Used,
+                                                          type_priv: type_private,
+                                                          type_used: Used});
 
         debug!("(resolving single import) successfully resolved import");
         return Success(());
@@ -2732,7 +2765,7 @@ fn resolve_module_path_from_root(&mut self,
                                                                    .get() {
                                                     Some(did) => {
                                                         closest_private =
-                                                            DependsOn(did);
+                                                            LastMod(DependsOn(did));
                                                     }
                                                     None => {}
                                                 }
@@ -2817,7 +2850,7 @@ fn resolve_module_path(&mut self,
                         // resolution process at index zero.
                         search_module = self.graph_root.get_module();
                         start_index = 0;
-                        last_private = AllPublic;
+                        last_private = LastMod(AllPublic);
                     }
                     UseLexicalScope => {
                         // This is not a crate-relative path. We resolve the
@@ -2839,7 +2872,7 @@ fn resolve_module_path(&mut self,
                             Success(containing_module) => {
                                 search_module = containing_module;
                                 start_index = 1;
-                                last_private = AllPublic;
+                                last_private = LastMod(AllPublic);
                             }
                         }
                     }
@@ -2848,9 +2881,9 @@ fn resolve_module_path(&mut self,
             Success(PrefixFound(containing_module, index)) => {
                 search_module = containing_module;
                 start_index = index;
-                last_private = DependsOn(containing_module.def_id
-                                                          .get()
-                                                          .unwrap());
+                last_private = LastMod(DependsOn(containing_module.def_id
+                                                                  .get()
+                                                                  .unwrap()));
             }
         }
 
@@ -2914,7 +2947,7 @@ fn resolve_item_in_lexical_scope(&mut self,
                     Some(target) => {
                         debug!("(resolving item in lexical scope) using \
                                 import resolution");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, false));
                     }
                 }
@@ -3199,7 +3232,7 @@ fn resolve_name_in_module(&mut self,
                     Some(target) => {
                         debug!("(resolving name in module) resolved to \
                                 import");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, true));
                     }
                 }
@@ -3808,7 +3841,7 @@ fn with_type_parameter_rib(&mut self,
                     // Associate this type parameter with
                     // the item that bound it
                     self.record_def(type_parameter.id,
-                                    (DefTyParamBinder(node_id), AllPublic));
+                                    (DefTyParamBinder(node_id), LastMod(AllPublic)));
                     // plain insert (no renaming)
                     let mut bindings = function_type_rib.bindings
                                                         .borrow_mut();
@@ -4269,7 +4302,7 @@ fn resolve_type(&mut self, ty: &Ty) {
 
                         Some(&primitive_type) => {
                             result_def =
-                                Some((DefPrimTy(primitive_type), AllPublic));
+                                Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
 
                             if path.segments
                                    .iter()
@@ -4438,7 +4471,7 @@ struct in scope",
                             // will be able to distinguish variants from
                             // locals in patterns.
 
-                            self.record_def(pattern.id, (def, AllPublic));
+                            self.record_def(pattern.id, (def, LastMod(AllPublic)));
 
                             // Add the binding to the local ribs, if it
                             // doesn't already exist in the bindings list. (We
@@ -4632,10 +4665,10 @@ fn resolve_bare_identifier_pattern(&mut self, name: Ident)
                         // the lookup happened only within the current module.
                         match def.def {
                             def @ DefVariant(..) | def @ DefStruct(..) => {
-                                return FoundStructOrEnumVariant(def, AllPublic);
+                                return FoundStructOrEnumVariant(def, LastMod(AllPublic));
                             }
                             def @ DefStatic(_, false) => {
-                                return FoundConst(def, AllPublic);
+                                return FoundConst(def, LastMod(AllPublic));
                             }
                             _ => {
                                 return BareIdentifierPatternUnresolved;
@@ -4711,7 +4744,7 @@ fn resolve_identifier(&mut self,
                                                       namespace,
                                                       span) {
                 Some(def) => {
-                    return Some((def, AllPublic));
+                    return Some((def, LastMod(AllPublic)));
                 }
                 None => {
                     // Continue.
@@ -4741,8 +4774,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                             // Found it. Stop the search here.
                             let p = child_name_bindings.defined_in_public_namespace(
                                             namespace);
-                            let lp = if p {AllPublic} else {
-                                DependsOn(def_id_of_def(def))
+                            let lp = if p {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id_of_def(def)))
                             };
                             return ChildNameDefinition(def, lp);
                         }
@@ -4764,8 +4797,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                             Some(def) => {
                                 // Found it.
                                 let id = import_resolution.id(namespace);
-                                self.used_imports.insert(id);
-                                return ImportNameDefinition(def, AllPublic);
+                                self.used_imports.insert((id, namespace));
+                                return ImportNameDefinition(def, LastMod(AllPublic));
                             }
                             None => {
                                 // This can happen with external impls, due to
@@ -4792,8 +4825,8 @@ fn resolve_definition_of_name_in_module(&mut self,
                     match module.def_id.get() {
                         None => {} // Continue.
                         Some(def_id) => {
-                            let lp = if module.is_public {AllPublic} else {
-                                DependsOn(def_id)
+                            let lp = if module.is_public {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id))
                             };
                             return ChildNameDefinition(DefMod(def_id), lp);
                         }
@@ -4887,7 +4920,7 @@ fn resolve_crate_relative_path(&mut self,
                                                  0,
                                                  path.span,
                                                  PathSearch,
-                                                 AllPublic) {
+                                                 LastMod(AllPublic)) {
             Failed => {
                 let msg = format!("use of undeclared module `::{}`",
                                   self.idents_to_str(module_path_idents));
@@ -4983,7 +5016,7 @@ fn resolve_item_by_identifier_in_lexical_scope(&mut self,
                         // This lookup is "all public" because it only searched
                         // for one identifier in the current module (couldn't
                         // have passed through reexports or anything like that.
-                        return Some((def, AllPublic));
+                        return Some((def, LastMod(AllPublic)));
                     }
                 }
             }
@@ -5194,8 +5227,8 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                               format!("use of undeclared label `{}`",
                                                    token::get_name(label))),
                     Some(DlDef(def @ DefLabel(_))) => {
-                        // FIXME: is AllPublic correct?
-                        self.record_def(expr.id, (def, AllPublic))
+                        // Since this def is a label, it is never read.
+                        self.record_def(expr.id, (def, LastMod(AllPublic)))
                     }
                     Some(_) => {
                         self.session.span_bug(expr.span,
@@ -5353,7 +5386,7 @@ fn search_for_traits_containing_method(&mut self, name: Ident) -> ~[DefId] {
                     };
                     if candidate_traits.contains(&did) {
                         self.add_trait_info(&mut found_traits, did, name);
-                        self.used_imports.insert(import.type_id.get());
+                        self.used_imports.insert((import.type_id.get(), TypeNS));
                     }
                 }
 
@@ -5395,6 +5428,8 @@ fn add_fixed_trait_for_expr(&mut self,
     fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
         debug!("(recording def) recording {:?} for {:?}, last private {:?}",
                 def, node_id, lp);
+        assert!(match lp {LastImport{..} => false, _ => true},
+                "Import should only be used for `use` directives");
         self.last_private.insert(node_id, lp);
         let mut def_map = self.def_map.borrow_mut();
         def_map.get().insert_or_update_with(node_id, def, |_, old_value| {
@@ -5426,16 +5461,17 @@ fn enforce_default_binding_mode(&mut self,
     //
     // Unused import checking
     //
-    // Although this is a lint pass, it lives in here because it depends on
-    // resolve data structures.
+    // Although this is mostly a lint pass, it lives in here because it depends on
+    // resolve data structures and because it finalises the privacy information for
+    // `use` directives.
     //
 
-    fn check_for_unused_imports(&self, krate: &ast::Crate) {
+    fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
         let mut visitor = UnusedImportCheckVisitor{ resolver: self };
         visit::walk_crate(&mut visitor, krate, ());
     }
 
-    fn check_for_item_unused_imports(&self, vi: &ViewItem) {
+    fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
         // Ignore is_public import statements because there's no way to be sure
         // whether they're used or not. Also ignore imports with a dummy span
         // because this means that they were generated in some fashion by the
@@ -5448,29 +5484,73 @@ fn check_for_item_unused_imports(&self, vi: &ViewItem) {
             ViewItemUse(ref path) => {
                 for p in path.iter() {
                     match p.node {
-                        ViewPathSimple(_, _, id) | ViewPathGlob(_, id) => {
-                            if !self.used_imports.contains(&id) {
-                                self.session.add_lint(UnusedImports,
-                                                      id, p.span,
-                                                      ~"unused import");
-                            }
-                        }
-
+                        ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
                         ViewPathList(_, ref list, _) => {
                             for i in list.iter() {
-                                if !self.used_imports.contains(&i.node.id) {
-                                    self.session.add_lint(UnusedImports,
-                                                          i.node.id, i.span,
-                                                          ~"unused import");
-                                }
+                                self.finalize_import(i.node.id, i.span);
                             }
-                        }
+                        },
+                        ViewPathGlob(_, id) => {
+                            if !self.used_imports.contains(&(id, TypeNS)) &&
+                               !self.used_imports.contains(&(id, ValueNS)) {
+                                self.session.add_lint(UnusedImports, id, p.span, ~"unused import");
+                            }
+                        },
                     }
                 }
             }
         }
     }
 
+    // We have information about whether `use` (import) directives are actually used now.
+    // If an import is not used at all, we signal a lint error. If an import is only used
+    // for a single namespace, we remove the other namespace from the recorded privacy
+    // information. That means in privacy.rs, we will only check imports and namespaces
+    // which are used. In particular, this means that if an import could name either a
+    // public or private item, we will check the correct thing, dependent on how the import
+    // is used.
+    fn finalize_import(&mut self, id: NodeId, span: Span) {
+        debug!("finalizing import uses for {}", self.session.codemap.span_to_snippet(span));
+
+        if !self.used_imports.contains(&(id, TypeNS)) &&
+           !self.used_imports.contains(&(id, ValueNS)) {
+            self.session.add_lint(UnusedImports, id, span, ~"unused import");
+        }
+
+        let (v_priv, t_priv) = match self.last_private.find(&id) {
+            Some(&LastImport{value_priv: v,
+                             value_used: _,
+                             type_priv: t,
+                             type_used: _}) => (v, t),
+            Some(_) => fail!("We should only have LastImport for `use` directives"),
+            _ => return,
+        };
+
+        let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
+            Used
+        } else {
+            Unused
+        };
+        let t_used = if self.used_imports.contains(&(id, TypeNS)) {
+            Used
+        } else {
+            Unused
+        };
+
+        match (v_priv, t_priv) {
+            // Since some items may be both in the value _and_ type namespaces (e.g., structs)
+            // we might have two LastPrivates pointing at the same thing. There is no point
+            // checking both, so lets not check the value one.
+            (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
+            _ => {},
+        }
+
+        self.last_private.insert(id, LastImport{value_priv: v_priv,
+                                                value_used: v_used,
+                                                type_priv: t_priv,
+                                                type_used: t_used});
+    }
+
     //
     // Diagnostics
     //
index 22f9d2f9843b9ce0efb0a12c06ee90982f38930c..586323358c241234494ea2560f6e0954957208e5 100644 (file)
@@ -25,7 +25,6 @@
 use rustc::metadata::decoder;
 
 use std;
-use std::hashmap::HashMap;
 
 use doctree;
 use visit_ast;
@@ -68,7 +67,7 @@ fn clean(&self) -> ~[U] {
 pub struct Crate {
     name: ~str,
     module: Option<Item>,
-    externs: HashMap<ast::CrateNum, ExternalCrate>,
+    externs: ~[(ast::CrateNum, ExternalCrate)],
 }
 
 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
@@ -76,9 +75,9 @@ fn clean(&self) -> Crate {
         use syntax::attr::find_crateid;
         let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
 
-        let mut externs = HashMap::new();
+        let mut externs = ~[];
         cx.sess.cstore.iter_crate_data(|n, meta| {
-            externs.insert(n, meta.clean());
+            externs.push((n, meta.clean()));
         });
 
         Crate {
@@ -181,6 +180,7 @@ pub enum ItemEnum {
     VariantItem(Variant),
     ForeignFunctionItem(Function),
     ForeignStaticItem(Static),
+    MacroItem(Macro),
 }
 
 #[deriving(Clone, Encodable, Decodable)]
@@ -206,7 +206,8 @@ fn clean(&self) -> Item {
                        self.fns.clean(), self.foreigns.clean().concat_vec(),
                        self.mods.clean(), self.typedefs.clean(),
                        self.statics.clean(), self.traits.clean(),
-                       self.impls.clean(), self.view_items.clean()].concat_vec()
+                       self.impls.clean(), self.view_items.clean(),
+                       self.macros.clean()].concat_vec()
             })
         }
     }
@@ -1263,3 +1264,23 @@ fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
         None => None
     }
 }
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Macro {
+    source: ~str,
+}
+
+impl Clean<Item> for doctree::Macro {
+    fn clean(&self) -> Item {
+        Item {
+            name: Some(self.name.clean()),
+            attrs: self.attrs.clean(),
+            source: self.where.clean(),
+            visibility: ast::Public.clean(),
+            id: self.id,
+            inner: MacroItem(Macro {
+                source: self.where.to_src(),
+            }),
+        }
+    }
+}
index f1bd3a62e01623ad7f8107ac4e75b88cbd18b269..03186c16733a52273061767e5ca381466f994891 100644 (file)
@@ -32,6 +32,7 @@ pub struct Module {
     impls: ~[Impl],
     foreigns: ~[ast::ForeignMod],
     view_items: ~[ast::ViewItem],
+    macros: ~[Macro],
 }
 
 impl Module {
@@ -52,6 +53,7 @@ pub fn new(name: Option<Ident>) -> Module {
             impls      : ~[],
             view_items : ~[],
             foreigns   : ~[],
+            macros     : ~[],
         }
     }
 }
@@ -157,6 +159,13 @@ pub struct Impl {
     id: ast::NodeId,
 }
 
+pub struct Macro {
+    name: Ident,
+    id: ast::NodeId,
+    attrs: ~[ast::Attribute],
+    where: Span,
+}
+
 pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {
     if sd.ctor_id.is_some() {
         // We are in a tuple-struct
index 11f801550856b019ee98b2d7b09b1ae4432726ff..649d5f592c5c58869b2a00dd6c11b77f959c4fe1 100644 (file)
@@ -157,6 +157,7 @@ pub struct Cache {
     priv parent_stack: ~[ast::NodeId],
     priv search_index: ~[IndexItem],
     priv privmod: bool,
+    priv public_items: HashSet<ast::NodeId>,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -231,18 +232,23 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     }
 
     // Crawl the crate to build various caches used for the output
-    let mut cache = Cache {
-        impls: HashMap::new(),
-        typarams: HashMap::new(),
-        paths: HashMap::new(),
-        traits: HashMap::new(),
-        implementors: HashMap::new(),
-        stack: ~[],
-        parent_stack: ~[],
-        search_index: ~[],
-        extern_locations: HashMap::new(),
-        privmod: false,
-    };
+    let mut cache = local_data::get(::analysiskey, |analysis| {
+        let public_items = analysis.map(|a| a.public_items.clone());
+        let public_items = public_items.unwrap_or(HashSet::new());
+        Cache {
+            impls: HashMap::new(),
+            typarams: HashMap::new(),
+            paths: HashMap::new(),
+            traits: HashMap::new(),
+            implementors: HashMap::new(),
+            stack: ~[],
+            parent_stack: ~[],
+            search_index: ~[],
+            extern_locations: HashMap::new(),
+            privmod: false,
+            public_items: public_items,
+        }
+    });
     cache.stack.push(krate.name.clone());
     krate = cache.fold_crate(krate);
 
@@ -305,7 +311,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
         krate = folder.fold_crate(krate);
     }
 
-    for (&n, e) in krate.externs.iter() {
+    for &(n, ref e) in krate.externs.iter() {
         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
     }
 
@@ -565,8 +571,24 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
             clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) | clean::VariantItem(..) => {
-                self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
+            clean::ForeignFunctionItem(..) => {
+                // Reexported items mean that the same id can show up twice in
+                // the rustdoc ast that we're looking at. We know, however, that
+                // a reexported item doesn't show up in the `public_items` map,
+                // so we can skip inserting into the paths map if there was
+                // already an entry present and we're not a public item.
+                if !self.paths.contains_key(&item.id) ||
+                   self.public_items.contains(&item.id) {
+                    self.paths.insert(item.id,
+                                      (self.stack.clone(), shortty(&item)));
+                }
+            }
+            // link variants to their parent enum because pages aren't emitted
+            // for each variant
+            clean::VariantItem(..) => {
+                let mut stack = self.stack.clone();
+                stack.pop();
+                self.paths.insert(item.id, (stack, "enum"));
             }
             _ => {}
         }
@@ -791,6 +813,7 @@ fn shortty(item: &clean::Item) -> &'static str {
         clean::VariantItem(..)         => "variant",
         clean::ForeignFunctionItem(..) => "ffi",
         clean::ForeignStaticItem(..)   => "ffs",
+        clean::MacroItem(..)           => "macro",
     }
 }
 
@@ -869,6 +892,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             clean::StructItem(ref s) => item_struct(fmt.buf, self.item, s),
             clean::EnumItem(ref e) => item_enum(fmt.buf, self.item, e),
             clean::TypedefItem(ref t) => item_typedef(fmt.buf, self.item, t),
+            clean::MacroItem(ref m) => item_macro(fmt.buf, self.item, m),
             _ => Ok(())
         }
     }
@@ -937,6 +961,8 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
             (_, &clean::ViewItemItem(..)) => Greater,
             (&clean::ModuleItem(..), _) => Less,
             (_, &clean::ModuleItem(..)) => Greater,
+            (&clean::MacroItem(..), _) => Less,
+            (_, &clean::MacroItem(..)) => Greater,
             (&clean::StructItem(..), _) => Less,
             (_, &clean::StructItem(..)) => Greater,
             (&clean::EnumItem(..), _) => Less,
@@ -987,6 +1013,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
                 clean::VariantItem(..)         => "Variants",
                 clean::ForeignFunctionItem(..) => "Foreign Functions",
                 clean::ForeignStaticItem(..)   => "Foreign Statics",
+                clean::MacroItem(..)           => "Macros",
             }));
         }
 
@@ -1099,7 +1126,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         if_ok!(write!(w, "\\{\n"));
         for m in required.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, ";\n"));
         }
         if required.len() > 0 && provided.len() > 0 {
@@ -1107,7 +1134,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         }
         for m in provided.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, " \\{ ... \\}\n"));
         }
         if_ok!(write!(w, "\\}"));
@@ -1121,7 +1148,7 @@ fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
         if_ok!(write!(w, "<h3 id='{}.{}' class='method'><code>",
                       shortty(m.item()),
                       *m.item().name.get_ref()));
-        if_ok!(render_method(w, m.item(), false));
+        if_ok!(render_method(w, m.item()));
         if_ok!(write!(w, "</code></h3>"));
         if_ok!(document(w, m.item()));
         Ok(())
@@ -1176,16 +1203,12 @@ fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
     })
 }
 
-fn render_method(w: &mut Writer, meth: &clean::Item,
-                 withlink: bool) -> fmt::Result {
+fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
     fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
-           g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
-           withlink: bool) -> fmt::Result {
-        write!(w, "{}fn {withlink, select,
-                            true{<a href='\\#{ty}.{name}'
-                                    class='fnname'>{name}</a>}
-                            other{<span class='fnname'>{name}</span>}
-                        }{generics}{decl}",
+           g: &clean::Generics, selfty: &clean::SelfTy,
+           d: &clean::FnDecl) -> fmt::Result {
+        write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
+                   {generics}{decl}",
                match purity {
                    ast::UnsafeFn => "unsafe ",
                    _ => "",
@@ -1193,15 +1216,14 @@ fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
                ty = shortty(it),
                name = it.name.get_ref().as_slice(),
                generics = *g,
-               decl = Method(selfty, d),
-               withlink = if withlink {"true"} else {"false"})
+               decl = Method(selfty, d))
     }
     match meth.inner {
         clean::TyMethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         clean::MethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         _ => unreachable!()
     }
@@ -1432,7 +1454,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
     fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult<bool> {
         if_ok!(write!(w, "<h4 id='method.{}' class='method'><code>",
                       *item.name.get_ref()));
-        if_ok!(render_method(w, item, false));
+        if_ok!(render_method(w, item));
         if_ok!(write!(w, "</code></h4>\n"));
         match item.doc_value() {
             Some(s) => {
@@ -1609,3 +1631,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         Ok(())
     }
 }
+
+fn item_macro(w: &mut Writer, it: &clean::Item,
+              t: &clean::Macro) -> fmt::Result {
+    if_ok!(write!(w, "<pre class='macro'>{}</pre>", t.source));
+    document(w, it)
+}
index e0f4a9c167d2a541d0599d42ea2817ec38be34c8..8e1876bad036804fc286fffb6ecace8dd8077494 100644 (file)
@@ -301,3 +301,5 @@ a {
 .stability.Stable { border-color: #AEC516; color: #7c8b10; }
 .stability.Frozen { border-color: #009431; color: #007726; }
 .stability.Locked { border-color: #0084B6; color: #00668c; }
+
+:target { background: #FDFFD3; }
index 2c4d553a39f6477fa26243dcd75436a9a02075f5..4194f5e47293628610fe8eaf809c49e42c96ece5 100644 (file)
@@ -344,7 +344,7 @@ fn json_output(krate: clean::Crate, res: ~[plugins::PluginJson],
     };
     let crate_json = match json::from_str(crate_json_str) {
         Ok(j) => j,
-        Err(_) => fail!("Rust generated JSON is invalid??")
+        Err(e) => fail!("Rust generated JSON is invalid: {:?}", e)
     };
 
     json.insert(~"crate", crate_json);
index 6ebaf6eece82d4b27a0ae056ee4d89a3eb2af702..2b8f01cfac8cacd57c1ff204310e0e698193b3d0 100644 (file)
@@ -150,8 +150,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             }
             clean::ImplItem(..) => {}
 
-            // tymethods have no control over privacy
-            clean::TyMethodItem(..) => {}
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
         }
 
         let fastreturn = match i.inner {
index 8b127b6079d9075f18110f41238e780dc3a3fc6d..db4842b79a04bbd23a7599d1f2b2755460418adf 100644 (file)
@@ -144,11 +144,13 @@ fn maketest(s: &str, cratename: &str) -> ~str {
 #[deny(warnings)];
 #[allow(unused_variable, dead_assignment, unused_mut, attribute_usage, dead_code)];
 ";
-    if s.contains("extra") {
-        prog.push_str("extern crate extra;\n");
-    }
-    if s.contains(cratename) {
-        prog.push_str(format!("extern crate {};\n", cratename));
+    if !s.contains("extern crate") {
+        if s.contains("extra") {
+            prog.push_str("extern crate extra;\n");
+        }
+        if s.contains(cratename) {
+            prog.push_str(format!("extern crate {};\n", cratename));
+        }
     }
     if s.contains("fn main") {
         prog.push_str(s);
index 5bf1aa3e91a6d4f67dc55ec7bf02b17f54366079..ef02d7345672154bb0951df944e363deb06db2da 100644 (file)
@@ -280,7 +280,14 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
             ast::ItemForeignMod(ref fm) => {
                 om.foreigns.push(fm.clone());
             }
-            _ => (),
+            ast::ItemMac(ref _m) => {
+                om.macros.push(Macro {
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    name: item.ident,
+                    where: item.span,
+                })
+            }
         }
     }
 }
index 4452482b7e8ceee4c6c3ced6498d055de746c9ee..d3ddd9ae78380dfad3298b40b75b0f40329b7a3a 100644 (file)
@@ -77,7 +77,7 @@
 #[cfg(test)] pub use ops = realstd::ops;
 #[cfg(test)] pub use cmp = realstd::cmp;
 
-mod macros;
+pub mod macros;
 
 mod rtdeps;
 
index 14ae7c9900c4693651ee87cefe8bba317d259e8d..34b33003786e73b050108f5e7d4aab8dec5ca321 100644 (file)
@@ -7,8 +7,29 @@
 // <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.
+
+//! Standard library macros
+//!
+//! This modules contains a set of macros which are exported from the standard
+//! library. Each macro is available for use when linking against the standard
+//! library.
+
 #[macro_escape];
 
+/// The standard logging macro
+///
+/// This macro will generically log over a provided level (of type u32) with a
+/// format!-based argument list. See documentation in `std::fmt` for details on
+/// how to use the syntax, and documentation in `std::logging` for info about
+/// logging macros.
+///
+/// # Example
+///
+/// ```
+/// log!(::std::logging::DEBUG, "this is a debug message");
+/// log!(::std::logging::WARN, "this is a warning {}", "message");
+/// log!(6, "this is a custom logging level: {level}", level=6);
+/// ```
 #[macro_export]
 macro_rules! log(
     ($lvl:expr, $($arg:tt)+) => ({
@@ -21,26 +42,73 @@ macro_rules! log(
     })
 )
 
+/// A convenience macro for logging at the error log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let error = 3;
+/// error!("the build has failed with error code: {}", error);
+/// ```
 #[macro_export]
 macro_rules! error(
     ($($arg:tt)*) => (log!(1u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the warning log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let code = 3;
+/// warn!("you may like to know that a process exited with: {}", code);
+/// ```
 #[macro_export]
 macro_rules! warn(
     ($($arg:tt)*) => (log!(2u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the info log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let ret = 3;
+/// info!("this function is about to return: {}", ret);
+/// ```
 #[macro_export]
 macro_rules! info(
     ($($arg:tt)*) => (log!(3u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the debug log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// debug!("x = {x}, y = {y}", x=10, y=20);
+/// ```
 #[macro_export]
 macro_rules! debug(
     ($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
 )
 
+/// A macro to test whether a log level is enabled for the current module.
+///
+/// # Example
+///
+/// ```
+/// # struct Point { x: int, y: int }
+/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
+/// if log_enabled!(std::logging::DEBUG) {
+///     let x = some_expensive_computation();
+///     debug!("x.x = {}, x.y = {}", x.x, x.y);
+/// }
+/// ```
 #[macro_export]
 macro_rules! log_enabled(
     ($lvl:expr) => ({
@@ -49,6 +117,25 @@ macro_rules! log_enabled(
     })
 )
 
+/// The entry point for failure of rust tasks.
+///
+/// This macro is used to inject failure into a rust task, causing the task to
+/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
+/// type, and the single-argument form of the `fail!` macro will be the value
+/// which is transmitted.
+///
+/// The multi-argument form of this macro fails with a string and has the
+/// `format!` sytnax for building a string.
+///
+/// # Example
+///
+/// ```should_fail
+/// # #[allow(unreachable_code)];
+/// fail!();
+/// fail!("this is a terrible mistake!");
+/// fail!(4); // fail with the value of 4 to be collected elsewhere
+/// fail!("this is a {} {message}", "fancy", message = "message");
+/// ```
 #[macro_export]
 macro_rules! fail(
     () => (
@@ -70,6 +157,26 @@ fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
     });
 )
 
+/// Ensure that a boolean expression is `true` at runtime.
+///
+/// This will invoke the `fail!` macro if the provided expression cannot be
+/// evaluated to `true` at runtime.
+///
+/// # Example
+///
+/// ```
+/// // the failure message for these assertions is the stringified value of the
+/// // expression given.
+/// assert!(true);
+/// # fn some_computation() -> bool { true }
+/// assert!(some_computation());
+///
+/// // assert with a custom message
+/// # let x = true;
+/// assert!(x, "x wasn't true!");
+/// # let a = 3; let b = 27;
+/// assert!(a + b == 30, "a = {}, b = {}", a, b);
+/// ```
 #[macro_export]
 macro_rules! assert(
     ($cond:expr) => (
@@ -89,6 +196,18 @@ macro_rules! assert(
     );
 )
 
+/// Asserts that two expressions are equal to each other, testing equality in
+/// both directions.
+///
+/// On failure, this macro will print the values of the expressions.
+///
+/// # Example
+///
+/// ```
+/// let a = 3;
+/// let b = 1 + 2;
+/// assert_eq!(a, b);
+/// ```
 #[macro_export]
 macro_rules! assert_eq(
     ($given:expr , $expected:expr) => ({
@@ -110,13 +229,15 @@ macro_rules! assert_eq(
 /// # Example
 ///
 /// ~~~rust
+/// struct Item { weight: uint }
+///
 /// fn choose_weighted_item(v: &[Item]) -> Item {
 ///     assert!(!v.is_empty());
 ///     let mut so_far = 0u;
 ///     for item in v.iter() {
 ///         so_far += item.weight;
 ///         if so_far > 100 {
-///             return item;
+///             return *item;
 ///         }
 ///     }
 ///     // The above loop always returns, so we must hint to the
@@ -136,6 +257,16 @@ macro_rules! unimplemented(
     () => (fail!("not yet implemented"))
 )
 
+/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// format!("test");
+/// format!("hello {}", "world!");
+/// format!("x = {}, y = {y}", 10, y = 30);
+/// ```
 #[macro_export]
 macro_rules! format(
     ($($arg:tt)*) => (
@@ -143,6 +274,19 @@ macro_rules! format(
     )
 )
 
+/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// # #[allow(unused_must_use)];
+/// use std::io::MemWriter;
+///
+/// let mut w = MemWriter::new();
+/// write!(&mut w, "test");
+/// write!(&mut w, "formatted {}", "arguments");
+/// ```
 #[macro_export]
 macro_rules! write(
     ($dst:expr, $($arg:tt)*) => ({
@@ -151,6 +295,8 @@ macro_rules! write(
     })
 )
 
+/// Equivalent to the `write!` macro, except that a newline is appended after
+/// the message is written.
 #[macro_export]
 macro_rules! writeln(
     ($dst:expr, $($arg:tt)*) => ({
@@ -159,16 +305,42 @@ macro_rules! writeln(
     })
 )
 
+/// Equivalent to the `println!` macro except that a newline is not printed at
+/// the end of the message.
 #[macro_export]
 macro_rules! print(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
 )
 
+/// Macro for printing to a task's stdout handle.
+///
+/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
+/// The syntax of this macro is the same as that used for `format!`. For more
+/// information, see `std::fmt` and `std::io::stdio`.
+///
+/// # Example
+///
+/// ```
+/// println!("hello there!");
+/// println!("format {} arguments", "some");
+/// ```
 #[macro_export]
 macro_rules! println(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
 )
 
+/// Declare a task-local key with a specific type.
+///
+/// # Example
+///
+/// ```
+/// use std::local_data;
+///
+/// local_data_key!(my_integer: int)
+///
+/// local_data::set(my_integer, 2);
+/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
+/// ```
 #[macro_export]
 macro_rules! local_data_key(
     ($name:ident: $ty:ty) => (
@@ -179,6 +351,9 @@ macro_rules! local_data_key(
     );
 )
 
+/// Helper macro for unwrapping `Result` values while returning early with an
+/// error if the value of the expression is `Err`. For more information, see
+/// `std::io`.
 #[macro_export]
 macro_rules! if_ok(
     ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
index 719ed62d03d0aaa65707319c5696db53680088d4..74e2fceb6cae6d7854a93db3eb2f36a91fd3f6a5 100644 (file)
@@ -88,7 +88,8 @@ pub fn getcwd() -> Path {
             fail!();
         }
     }
-    Path::new(str::from_utf16(buf))
+    Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
+              .expect("GetCurrentDirectoryW returned invalid UTF-16"))
 }
 
 #[cfg(windows)]
@@ -124,7 +125,12 @@ pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
                 }
                 if k != 0 && done {
                     let sub = buf.slice(0, k as uint);
-                    res = option::Some(str::from_utf16(sub));
+                    // We want to explicitly catch the case when the
+                    // closure returned invalid UTF-16, rather than
+                    // set `res` to None and continue.
+                    let s = str::from_utf16(sub)
+                        .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
+                    res = option::Some(s)
                 }
             }
             return res;
@@ -739,7 +745,8 @@ fn FormatMessageW(flags: DWORD,
                 fail!("[{}] FormatMessage failure", errno());
             }
 
-            str::from_utf16(buf)
+            str::from_utf16(str::truncate_utf16_at_nul(buf))
+                .expect("FormatMessageW returned invalid UTF-16")
         }
     }
 
@@ -828,8 +835,10 @@ fn real_args() -> ~[~str] {
             while *ptr.offset(len as int) != 0 { len += 1; }
 
             // Push it onto the list.
-            args.push(vec::raw::buf_as_slice(ptr, len,
-                                             str::from_utf16));
+            let opt_s = vec::raw::buf_as_slice(ptr, len, |buf| {
+                    str::from_utf16(str::truncate_utf16_at_nul(buf))
+                });
+            args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
         }
     }
 
index a780a912d4df3cfa1d954a84a265d6f0f1d2fa3a..2ac3a9817872e24b0b08452cd90e9d245cf45350 100644 (file)
@@ -830,60 +830,192 @@ fn first_non_utf8_index(v: &[u8]) -> Option<uint> {
 
 /// Determines if a vector of `u16` contains valid UTF-16
 pub fn is_utf16(v: &[u16]) -> bool {
-    let len = v.len();
-    let mut i = 0u;
-    while i < len {
-        let u = v[i];
+    let mut it = v.iter();
+    macro_rules! next ( ($ret:expr) => {
+            match it.next() { Some(u) => *u, None => return $ret }
+        }
+    )
+    loop {
+        let u = next!(true);
 
-        if  u <= 0xD7FF_u16 || u >= 0xE000_u16 {
-            i += 1u;
+        match char::from_u32(u as u32) {
+            Some(_) => {}
+            None => {
+                let u2 = next!(false);
+                if u < 0xD7FF || u > 0xDBFF ||
+                    u2 < 0xDC00 || u2 > 0xDFFF { return false; }
+            }
+        }
+    }
+}
+
+/// An iterator that decodes UTF-16 encoded codepoints from a vector
+/// of `u16`s.
+#[deriving(Clone)]
+pub struct UTF16Items<'a> {
+    priv iter: vec::Items<'a, u16>
+}
+/// The possibilities for values decoded from a `u16` stream.
+#[deriving(Eq, TotalEq, Clone)]
+pub enum UTF16Item {
+    /// A valid codepoint.
+    ScalarValue(char),
+    /// An invalid surrogate without its pair.
+    LoneSurrogate(u16)
+}
+
+impl UTF16Item {
+    /// Convert `self` to a `char`, taking `LoneSurrogate`s to the
+    /// replacement character (U+FFFD).
+    #[inline]
+    pub fn to_char_lossy(&self) -> char {
+        match *self {
+            ScalarValue(c) => c,
+            LoneSurrogate(_) => '\uFFFD'
+        }
+    }
+}
+
+impl<'a> Iterator<UTF16Item> for UTF16Items<'a> {
+    fn next(&mut self) -> Option<UTF16Item> {
+        let u = match self.iter.next() {
+            Some(u) => *u,
+            None => return None
+        };
 
+        if u < 0xD800 || 0xDFFF < u {
+            // not a surrogate
+            Some(ScalarValue(unsafe {cast::transmute(u as u32)}))
+        } else if u >= 0xDC00 {
+            // a trailing surrogate
+            Some(LoneSurrogate(u))
         } else {
-            if i+1u < len { return false; }
-            let u2 = v[i+1u];
-            if u < 0xD7FF_u16 || u > 0xDBFF_u16 { return false; }
-            if u2 < 0xDC00_u16 || u2 > 0xDFFF_u16 { return false; }
-            i += 2u;
+            // preserve state for rewinding.
+            let old = self.iter;
+
+            let u2 = match self.iter.next() {
+                Some(u2) => *u2,
+                // eof
+                None => return Some(LoneSurrogate(u))
+            };
+            if u2 < 0xDC00 || u2 > 0xDFFF {
+                // not a trailing surrogate so we're not a valid
+                // surrogate pair, so rewind to redecode u2 next time.
+                self.iter = old;
+                return Some(LoneSurrogate(u))
+            }
+
+            // all ok, so lets decode it.
+            let c = ((u - 0xD800) as u32 << 10 | (u2 - 0xDC00) as u32) + 0x1_0000;
+            Some(ScalarValue(unsafe {cast::transmute(c)}))
         }
     }
-    return true;
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let (low, high) = self.iter.size_hint();
+        // we could be entirely valid surrogates (2 elements per
+        // char), or entirely non-surrogates (1 element per char)
+        (low / 2, high)
+    }
 }
 
-/// Iterates over the utf-16 characters in the specified slice, yielding each
-/// decoded unicode character to the function provided.
+/// Create an iterator over the UTF-16 encoded codepoints in `v`,
+/// returning invalid surrogates as `LoneSurrogate`s.
 ///
-/// # Failures
+/// # Example
 ///
-/// * Fails on invalid utf-16 data
-pub fn utf16_chars(v: &[u16], f: |char|) {
-    let len = v.len();
-    let mut i = 0u;
-    while i < len && v[i] != 0u16 {
-        let u = v[i];
-
-        if  u <= 0xD7FF_u16 || u >= 0xE000_u16 {
-            f(unsafe { cast::transmute(u as u32) });
-            i += 1u;
+/// ```rust
+/// use std::str;
+/// use std::str::{ScalarValue, LoneSurrogate};
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///          0x0073, 0xDD1E, 0x0069, 0x0063,
+///          0xD834];
+///
+/// assert_eq!(str::utf16_items(v).to_owned_vec(),
+///            ~[ScalarValue('𝄞'),
+///              ScalarValue('m'), ScalarValue('u'), ScalarValue('s'),
+///              LoneSurrogate(0xDD1E),
+///              ScalarValue('i'), ScalarValue('c'),
+///              LoneSurrogate(0xD834)]);
+/// ```
+pub fn utf16_items<'a>(v: &'a [u16]) -> UTF16Items<'a> {
+    UTF16Items { iter : v.iter() }
+}
 
-        } else {
-            let u2 = v[i+1u];
-            assert!(u >= 0xD800_u16 && u <= 0xDBFF_u16);
-            assert!(u2 >= 0xDC00_u16 && u2 <= 0xDFFF_u16);
-            let mut c: u32 = (u - 0xD800_u16) as u32;
-            c = c << 10;
-            c |= (u2 - 0xDC00_u16) as u32;
-            c |= 0x1_0000_u32;
-            f(unsafe { cast::transmute(c) });
-            i += 2u;
+/// Return a slice of `v` ending at (and not including) the first NUL
+/// (0).
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // "abcd"
+/// let mut v = ['a' as u16, 'b' as u16, 'c' as u16, 'd' as u16];
+/// // no NULs so no change
+/// assert_eq!(str::truncate_utf16_at_nul(v), v.as_slice());
+///
+/// // "ab\0d"
+/// v[2] = 0;
+/// assert_eq!(str::truncate_utf16_at_nul(v),
+///            &['a' as u16, 'b' as u16]);
+/// ```
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+    match v.iter().position(|c| *c == 0) {
+        // don't include the 0
+        Some(i) => v.slice_to(i),
+        None => v
+    }
+}
+
+/// Decode a UTF-16 encoded vector `v` into a string, returning `None`
+/// if `v` contains any invalid data.
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞music
+/// let mut v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///              0x0073, 0x0069, 0x0063];
+/// assert_eq!(str::from_utf16(v), Some(~"𝄞music"));
+///
+/// // 𝄞mu<invalid>ic
+/// v[4] = 0xD800;
+/// assert_eq!(str::from_utf16(v), None);
+/// ```
+pub fn from_utf16(v: &[u16]) -> Option<~str> {
+    let mut s = with_capacity(v.len() / 2);
+    for c in utf16_items(v) {
+        match c {
+            ScalarValue(c) => s.push_char(c),
+            LoneSurrogate(_) => return None
         }
     }
+    Some(s)
 }
 
-/// Allocates a new string from the utf-16 slice provided
-pub fn from_utf16(v: &[u16]) -> ~str {
-    let mut buf = with_capacity(v.len());
-    utf16_chars(v, |ch| buf.push_char(ch));
-    buf
+/// Decode a UTF-16 encoded vector `v` into a string, replacing
+/// invalid data with the replacement character (U+FFFD).
+///
+/// # Example
+/// ```rust
+/// use std::str;
+///
+/// // 𝄞mus<invalid>ic<invalid>
+/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
+///          0x0073, 0xDD1E, 0x0069, 0x0063,
+///          0xD834];
+///
+/// assert_eq!(str::from_utf16_lossy(v),
+///            ~"𝄞mus\uFFFDic\uFFFD");
+/// ```
+pub fn from_utf16_lossy(v: &[u16]) -> ~str {
+    utf16_items(v).map(|c| c.to_char_lossy()).collect()
 }
 
 /// Allocates a new string with the specified capacity. The string returned is
@@ -3536,6 +3668,65 @@ fn test_is_utf8() {
         assert!(is_utf8([0xF4, 0x8F, 0xBF, 0xBF]));
     }
 
+    #[test]
+    fn test_is_utf16() {
+        macro_rules! pos ( ($($e:expr),*) => { { $(assert!(is_utf16($e));)* } });
+
+        // non-surrogates
+        pos!([0x0000],
+             [0x0001, 0x0002],
+             [0xD7FF],
+             [0xE000]);
+
+        // surrogate pairs (randomly generated with Python 3's
+        // .encode('utf-16be'))
+        pos!([0xdb54, 0xdf16, 0xd880, 0xdee0, 0xdb6a, 0xdd45],
+             [0xd91f, 0xdeb1, 0xdb31, 0xdd84, 0xd8e2, 0xde14],
+             [0xdb9f, 0xdc26, 0xdb6f, 0xde58, 0xd850, 0xdfae]);
+
+        // mixtures (also random)
+        pos!([0xd921, 0xdcc2, 0x002d, 0x004d, 0xdb32, 0xdf65],
+             [0xdb45, 0xdd2d, 0x006a, 0xdacd, 0xddfe, 0x0006],
+             [0x0067, 0xd8ff, 0xddb7, 0x000f, 0xd900, 0xdc80]);
+
+        // negative tests
+        macro_rules! neg ( ($($e:expr),*) => { { $(assert!(!is_utf16($e));)* } });
+
+        neg!(
+            // surrogate + regular unit
+            [0xdb45, 0x0000],
+            // surrogate + lead surrogate
+            [0xd900, 0xd900],
+            // unterminated surrogate
+            [0xd8ff],
+            // trail surrogate without a lead
+            [0xddb7]);
+
+        // random byte sequences that Python 3's .decode('utf-16be')
+        // failed on
+        neg!([0x5b3d, 0x0141, 0xde9e, 0x8fdc, 0xc6e7],
+             [0xdf5a, 0x82a5, 0x62b9, 0xb447, 0x92f3],
+             [0xda4e, 0x42bc, 0x4462, 0xee98, 0xc2ca],
+             [0xbe00, 0xb04a, 0x6ecb, 0xdd89, 0xe278],
+             [0x0465, 0xab56, 0xdbb6, 0xa893, 0x665e],
+             [0x6b7f, 0x0a19, 0x40f4, 0xa657, 0xdcc5],
+             [0x9b50, 0xda5e, 0x24ec, 0x03ad, 0x6dee],
+             [0x8d17, 0xcaa7, 0xf4ae, 0xdf6e, 0xbed7],
+             [0xdaee, 0x2584, 0x7d30, 0xa626, 0x121a],
+             [0xd956, 0x4b43, 0x7570, 0xccd6, 0x4f4a],
+             [0x9dcf, 0x1b49, 0x4ba5, 0xfce9, 0xdffe],
+             [0x6572, 0xce53, 0xb05a, 0xf6af, 0xdacf],
+             [0x1b90, 0x728c, 0x9906, 0xdb68, 0xf46e],
+             [0x1606, 0xbeca, 0xbe76, 0x860f, 0xdfa5],
+             [0x8b4f, 0xde7a, 0xd220, 0x9fac, 0x2b6f],
+             [0xb8fe, 0xebbe, 0xda32, 0x1a5f, 0x8b8b],
+             [0x934b, 0x8956, 0xc434, 0x1881, 0xddf7],
+             [0x5a95, 0x13fc, 0xf116, 0xd89b, 0x93f9],
+             [0xd640, 0x71f1, 0xdd7d, 0x77eb, 0x1cd8],
+             [0x348b, 0xaef0, 0xdb2c, 0xebf1, 0x1282],
+             [0x50d7, 0xd824, 0x5010, 0xb369, 0x22ea]);
+    }
+
     #[test]
     fn test_raw_from_c_str() {
         unsafe {
@@ -3687,17 +3878,72 @@ fn test_utf16() {
                 0xdc9c_u16, 0xd801_u16, 0xdc92_u16, 0xd801_u16,
                 0xdc96_u16, 0xd801_u16, 0xdc86_u16, 0x0020_u16,
                 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16,
-                0x000a_u16 ]) ];
+                0x000a_u16 ]),
+             // Issue #12318, even-numbered non-BMP planes
+             (~"\U00020000",
+              ~[0xD840, 0xDC00])];
 
         for p in pairs.iter() {
             let (s, u) = (*p).clone();
-            assert!(s.to_utf16() == u);
-            assert!(from_utf16(u) == s);
-            assert!(from_utf16(s.to_utf16()) == s);
-            assert!(from_utf16(u).to_utf16() == u);
+            assert!(is_utf16(u));
+            assert_eq!(s.to_utf16(), u);
+
+            assert_eq!(from_utf16(u).unwrap(), s);
+            assert_eq!(from_utf16_lossy(u), s);
+
+            assert_eq!(from_utf16(s.to_utf16()).unwrap(), s);
+            assert_eq!(from_utf16(u).unwrap().to_utf16(), u);
         }
     }
 
+    #[test]
+    fn test_utf16_invalid() {
+        // completely positive cases tested above.
+        // lead + eof
+        assert_eq!(from_utf16([0xD800]), None);
+        // lead + lead
+        assert_eq!(from_utf16([0xD800, 0xD800]), None);
+
+        // isolated trail
+        assert_eq!(from_utf16([0x0061, 0xDC00]), None);
+
+        // general
+        assert_eq!(from_utf16([0xD800, 0xd801, 0xdc8b, 0xD800]), None);
+    }
+
+    #[test]
+    fn test_utf16_lossy() {
+        // completely positive cases tested above.
+        // lead + eof
+        assert_eq!(from_utf16_lossy([0xD800]), ~"\uFFFD");
+        // lead + lead
+        assert_eq!(from_utf16_lossy([0xD800, 0xD800]), ~"\uFFFD\uFFFD");
+
+        // isolated trail
+        assert_eq!(from_utf16_lossy([0x0061, 0xDC00]), ~"a\uFFFD");
+
+        // general
+        assert_eq!(from_utf16_lossy([0xD800, 0xd801, 0xdc8b, 0xD800]), ~"\uFFFD𐒋\uFFFD");
+    }
+
+    #[test]
+    fn test_truncate_utf16_at_nul() {
+        let v = [];
+        assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+        let v = [0, 2, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[]);
+
+        let v = [1, 0, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[1]);
+
+        let v = [1, 2, 0];
+        assert_eq!(truncate_utf16_at_nul(v), &[1, 2]);
+
+        let v = [1, 2, 3];
+        assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]);
+    }
+
     #[test]
     fn test_char_at() {
         let s = ~"ศไทย中华Việt Nam";
index 4648f149a9fed92c287939d30f67c5e02cce9a5f..8818cb0d270b6cc2c4bbfbe3e4f339a7240b5747 100644 (file)
 
 //! Runtime calls emitted by the compiler.
 
-use c_str::ToCStr;
+use c_str::CString;
+use libc::c_char;
+use cast;
+use option::Some;
 
 #[cold]
 #[lang="fail_"]
@@ -23,7 +26,14 @@ pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
 pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
     let msg = format!("index out of bounds: the len is {} but the index is {}",
                       len as uint, index as uint);
-    msg.with_c_str(|buf| fail_(buf as *u8, file, line))
+
+    let file_str = match unsafe { CString::new(file as *c_char, false) }.as_str() {
+        // This transmute is safe because `file` is always stored in rodata.
+        Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
+        None    => "file wasn't UTF-8 safe"
+    };
+
+    ::rt::begin_unwind(msg, file_str, line)
 }
 
 #[lang="malloc"]
index 0e53ecd416a7ab4beab4e4e0b98452b6263b7f65..db4260a30ee113886ae7f9274520746eb590f524 100644 (file)
@@ -192,12 +192,6 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
      * other tasks wishing to access the data will block until the closure
      * finishes running.
      *
-     * The reason this function is 'unsafe' is because it is possible to
-     * construct a circular reference among multiple Arcs by mutating the
-     * underlying data. This creates potential for deadlock, but worse, this
-     * will guarantee a memory leak of all involved Arcs. Using MutexArcs
-     * inside of other Arcs is safe in absence of circular references.
-     *
      * If you wish to nest MutexArcs, one strategy for ensuring safety at
      * runtime is to add a "nesting level counter" inside the stored data, and
      * when traversing the arcs, assert that they monotonically decrease.
@@ -210,63 +204,33 @@ pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
      * blocked on the mutex) will also fail immediately.
      */
     #[inline]
-    pub unsafe fn unsafe_access<U>(&self, blk: |x: &mut T| -> U) -> U {
+    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
         let state = self.x.get();
-        // Borrowck would complain about this if the function were
-        // not already unsafe. See borrow_rwlock, far below.
-        (&(*state).lock).lock(|| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data)
-        })
+        unsafe {
+            // Borrowck would complain about this if the code were
+            // not already unsafe. See borrow_rwlock, far below.
+            (&(*state).lock).lock(|| {
+                check_poison(true, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data)
+            })
+        }
     }
 
-    /// As unsafe_access(), but with a condvar, as sync::mutex.lock_cond().
+    /// As access(), but with a condvar, as sync::mutex.lock_cond().
     #[inline]
-    pub unsafe fn unsafe_access_cond<U>(&self,
-                                        blk: |x: &mut T, c: &Condvar| -> U)
-                                        -> U {
+    pub fn access_cond<U>(&self, blk: |x: &mut T, c: &Condvar| -> U) -> U {
         let state = self.x.get();
-        (&(*state).lock).lock_cond(|cond| {
-            check_poison(true, (*state).failed);
-            let _z = PoisonOnFail::new(&mut (*state).failed);
-            blk(&mut (*state).data,
-                &Condvar {is_mutex: true,
-                          failed: &(*state).failed,
-                          cond: cond })
-        })
-    }
-}
-
-impl<T:Freeze + Send> MutexArc<T> {
-
-    /**
-     * As unsafe_access.
-     *
-     * The difference between access and unsafe_access is that the former
-     * forbids mutexes to be nested. While unsafe_access can be used on
-     * MutexArcs without freezable interiors, this safe version of access
-     * requires the Freeze bound, which prohibits access on MutexArcs which
-     * might contain nested MutexArcs inside.
-     *
-     * The purpose of this is to offer a safe implementation of MutexArc to be
-     * used instead of RWArc in cases where no readers are needed and slightly
-     * better performance is required.
-     *
-     * Both methods have the same failure behaviour as unsafe_access and
-     * unsafe_access_cond.
-     */
-    #[inline]
-    pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
-        unsafe { self.unsafe_access(blk) }
-    }
-
-    /// As unsafe_access_cond but safe and Freeze.
-    #[inline]
-    pub fn access_cond<U>(&self,
-                          blk: |x: &mut T, c: &Condvar| -> U)
-                          -> U {
-        unsafe { self.unsafe_access_cond(blk) }
+        unsafe {
+            (&(*state).lock).lock_cond(|cond| {
+                check_poison(true, (*state).failed);
+                let _z = PoisonOnFail::new(&mut (*state).failed);
+                blk(&mut (*state).data,
+                    &Condvar {is_mutex: true,
+                            failed: &(*state).failed,
+                            cond: cond })
+            })
+        }
     }
 }
 
@@ -590,7 +554,6 @@ pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
 
 impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
     /// Duplicate a Copy-on-write Arc. See arc::clone for more details.
-    #[inline]
     fn clone(&self) -> CowArc<T> {
         CowArc { x: self.x.clone() }
     }
@@ -692,20 +655,18 @@ fn test_mutex_arc_poison() {
     }
 
     #[test]
-    fn test_unsafe_mutex_arc_nested() {
-        unsafe {
-            // Tests nested mutexes and access
-            // to underlaying data.
-            let arc = ~MutexArc::new(1);
-            let arc2 = ~MutexArc::new(*arc);
-            task::spawn(proc() {
-                (*arc2).unsafe_access(|mutex| {
-                    (*mutex).access(|one| {
-                        assert!(*one == 1);
-                    })
+    fn test_mutex_arc_nested() {
+        // Tests nested mutexes and access
+        // to underlaying data.
+        let arc = ~MutexArc::new(1);
+        let arc2 = ~MutexArc::new(*arc);
+        task::spawn(proc() {
+            (*arc2).access(|mutex| {
+                (*mutex).access(|one| {
+                    assert!(*one == 1);
                 })
-            });
-        }
+            })
+        });
     }
 
     #[test]
diff --git a/src/test/compile-fail/mutex-arc-nested.rs b/src/test/compile-fail/mutex-arc-nested.rs
deleted file mode 100644 (file)
index 34c56f9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 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.
-
-extern crate sync;
-
-use std::task;
-use sync::MutexArc;
-
-fn test_mutex_arc_nested() {
-    let arc = ~MutexArc::new(1);
-    let arc2 = ~MutexArc::new(*arc);
-
-    task::spawn(proc() {
-        (*arc2).access(|mutex| { //~ ERROR instantiating a type parameter with an incompatible type
-        })
-    });
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs
new file mode 100644 (file)
index 0000000..541356f
--- /dev/null
@@ -0,0 +1,66 @@
+// 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    let _x: ~Bar;  //~ ERROR use of undeclared type name `Bar`
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+    let _x: ~Bar;  //~ ERROR  use of undeclared type name `Bar`
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs
new file mode 100644 (file)
index 0000000..e293153
--- /dev/null
@@ -0,0 +1,91 @@
+// 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_single1() {
+    // In an ideal world, these would be private instead of inaccessible.
+    use foo1::Bar;  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_single2() {
+    use foo2::Bar;  //~ ERROR `Bar` is private
+
+    let _x : ~Bar;
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    let _x: ~Bar;
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+}
+
+fn test_single3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-make/rustdoc-json/Makefile b/src/test/run-make/rustdoc-json/Makefile
new file mode 100644 (file)
index 0000000..5e6ab4b
--- /dev/null
@@ -0,0 +1,4 @@
+-include ../tools.mk
+all:
+       $(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
+       $(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
diff --git a/src/test/run-make/rustdoc-json/foo.rs b/src/test/run-make/rustdoc-json/foo.rs
new file mode 100644 (file)
index 0000000..818ec1e
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_id = "foo#0.1"];
+
+//! Very docs
+
+pub mod bar {
+
+    /// So correct
+    pub mod baz {
+        /// Much detail
+        pub fn baz() { }
+    }
+
+    /// *wow*
+    pub trait Doge { }
+}
diff --git a/src/test/run-pass/privacy-ns.rs b/src/test/run-pass/privacy-ns.rs
new file mode 100644 (file)
index 0000000..c933e5b
--- /dev/null
@@ -0,0 +1,124 @@
+// 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.
+
+// ignore-fast
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused1() {
+    use foo1::Bar;
+    use foo1::{Bar,Baz};
+    use foo1::*;
+}
+
+fn test_single1() {
+    use foo1::Bar;
+
+    let _x: ~Bar;
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};
+
+    let _x: ~Bar;
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    let _x: ~Bar;
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused2() {
+    use foo2::Bar;
+    use foo2::{Bar,Baz};
+    use foo2::*;
+}
+
+fn test_single2() {
+    use foo2::Bar;
+
+    Bar();
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};
+
+    Bar();
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    Bar();
+}
+
+// public type, public value
+pub mod foo3 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;
+    use foo3::{Bar,Baz};
+    use foo3::*;
+}
+
+fn test_single3() {
+    use foo3::Bar;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-pass/self-re-assign.rs b/src/test/run-pass/self-re-assign.rs
new file mode 100644 (file)
index 0000000..041c5cf
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure assigning an owned or managed variable to itself works. In particular,
+// that we do not glue_drop before we glue_take (#3290).
+
+use std::rc::Rc;
+
+pub fn main() {
+   let mut x = ~3;
+   x = x;
+   assert!(*x == 3);
+
+   let mut x = Rc::new(3);
+   x = x;
+   assert!(*x.borrow() == 3);
+}