#
# 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>
#
######################################################################
# $(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)
-Subproject commit d4606f1818dd8dfeaa3e509cd1cbac4482c3513e
+Subproject commit f4b221571ce6f05714c1f1c6fa48f1393499989c
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
> 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,
To encode using Encodable :
```rust
+extern crate extra;
extern crate serialize;
use extra::json;
use std::io;
```rust
+extern crate extra;
extern crate collections;
use extra::json;
To decode a JSON string using `Decodable` trait :
```rust
+extern crate extra;
extern crate serialize;
use serialize::Decodable;
using the serialization API, using the derived serialization code.
```rust
+extern crate extra;
extern crate serialize;
use extra::json;
use serialize::{Encodable, Decodable};
Example of `ToJson` trait implementation for TestStruct1.
```rust
+extern crate extra;
extern crate serialize;
extern crate collections;
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);
/// 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)
////////////////////////////////////////////////////////////////////////////////
}
}
- /// 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.
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"),
// 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"));
}
}
}
// 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};
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,
}
}
ArgumentIrrefutableMode,
}
-#[deriving(Eq)]
+#[deriving(Eq, IterBytes)]
enum Namespace {
TypeNS,
ValueNS
// so as to avoid printing duplicate errors
emit_errors: bool,
- used_imports: HashSet<NodeId>,
+ used_imports: HashSet<(NodeId, Namespace)>,
}
struct BuildReducedGraphVisitor<'a> {
}
-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, _: ()) {
// 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,
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.
//
// 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.
_ => {
}
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);
}
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();
}
}
// 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(..) => {}
_ => {
module);
type_result = BoundResult(containing_module,
name_bindings);
- used_public = true;
+ type_used_public = true;
}
}
}
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 => {
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 => {
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(
// 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(());
.get() {
Some(did) => {
closest_private =
- DependsOn(did);
+ LastMod(DependsOn(did));
}
None => {}
}
// 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
Success(containing_module) => {
search_module = containing_module;
start_index = 1;
- last_private = AllPublic;
+ last_private = LastMod(AllPublic);
}
}
}
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()));
}
}
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));
}
}
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));
}
}
// 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();
Some(&primitive_type) => {
result_def =
- Some((DefPrimTy(primitive_type), AllPublic));
+ Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
if path.segments
.iter()
// 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
// 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;
namespace,
span) {
Some(def) => {
- return Some((def, AllPublic));
+ return Some((def, LastMod(AllPublic)));
}
None => {
// Continue.
// 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);
}
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
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);
}
0,
path.span,
PathSearch,
- AllPublic) {
+ LastMod(AllPublic)) {
Failed => {
let msg = format!("use of undeclared module `::{}`",
self.idents_to_str(module_path_idents));
// 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)));
}
}
}
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,
};
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));
}
}
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| {
//
// 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
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
//
use rustc::metadata::decoder;
use std;
-use std::hashmap::HashMap;
use doctree;
use visit_ast;
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> {
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 {
VariantItem(Variant),
ForeignFunctionItem(Function),
ForeignStaticItem(Static),
+ MacroItem(Macro),
}
#[deriving(Clone, Encodable, Decodable)]
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()
})
}
}
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(),
+ }),
+ }
+ }
+}
impls: ~[Impl],
foreigns: ~[ast::ForeignMod],
view_items: ~[ast::ViewItem],
+ macros: ~[Macro],
}
impl Module {
impls : ~[],
view_items : ~[],
foreigns : ~[],
+ macros : ~[],
}
}
}
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
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
}
// 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);
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));
}
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"));
}
_ => {}
}
clean::VariantItem(..) => "variant",
clean::ForeignFunctionItem(..) => "ffi",
clean::ForeignStaticItem(..) => "ffs",
+ clean::MacroItem(..) => "macro",
}
}
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(())
}
}
(_, &clean::ViewItemItem(..)) => Greater,
(&clean::ModuleItem(..), _) => Less,
(_, &clean::ModuleItem(..)) => Greater,
+ (&clean::MacroItem(..), _) => Less,
+ (_, &clean::MacroItem(..)) => Greater,
(&clean::StructItem(..), _) => Less,
(_, &clean::StructItem(..)) => Greater,
(&clean::EnumItem(..), _) => Less,
clean::VariantItem(..) => "Variants",
clean::ForeignFunctionItem(..) => "Foreign Functions",
clean::ForeignStaticItem(..) => "Foreign Statics",
+ clean::MacroItem(..) => "Macros",
}));
}
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 {
}
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, "\\}"));
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(())
})
}
-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 ",
_ => "",
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!()
}
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) => {
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)
+}
.stability.Stable { border-color: #AEC516; color: #7c8b10; }
.stability.Frozen { border-color: #009431; color: #007726; }
.stability.Locked { border-color: #0084B6; color: #00668c; }
+
+:target { background: #FDFFD3; }
};
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);
}
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 {
#[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);
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,
+ })
+ }
}
}
}
#[cfg(test)] pub use ops = realstd::ops;
#[cfg(test)] pub use cmp = realstd::cmp;
-mod macros;
+pub mod macros;
mod rtdeps;
// <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)+) => ({
})
)
+/// 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) => ({
})
)
+/// 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(
() => (
});
)
+/// 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) => (
);
)
+/// 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) => ({
/// # 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
() => (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)*) => (
)
)
+/// 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)*) => ({
})
)
+/// 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)*) => ({
})
)
+/// 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) => (
);
)
+/// 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) })
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)]
}
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;
fail!("[{}] FormatMessage failure", errno());
}
- str::from_utf16(buf)
+ str::from_utf16(str::truncate_utf16_at_nul(buf))
+ .expect("FormatMessageW returned invalid UTF-16")
}
}
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"));
}
}
/// 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
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 {
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";
//! 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_"]
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"]
* 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.
* 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 })
+ })
+ }
}
}
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() }
}
}
#[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]
+++ /dev/null
-// 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() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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() {
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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() {
+}
+
--- /dev/null
+-include ../tools.mk
+all:
+ $(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
+ $(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_id = "foo#0.1"];
+
+//! Very docs
+
+pub mod bar {
+
+ /// So correct
+ pub mod baz {
+ /// Much detail
+ pub fn baz() { }
+ }
+
+ /// *wow*
+ pub trait Doge { }
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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() {
+}
+
--- /dev/null
+// 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);
+}