From f6efb54d4446313d6dba93dd6bde33cd79354543 Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Thu, 12 Jun 2014 22:54:27 +0200 Subject: [PATCH 01/55] Fix an ICE on a cast from an inferred nil to uint Fixes #10991. --- src/librustc/middle/typeck/check/mod.rs | 72 ++++++------------------- src/test/compile-fail/issue-10991.rs | 14 +++++ 2 files changed, 29 insertions(+), 57 deletions(-) create mode 100644 src/test/compile-fail/issue-10991.rs diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b24b32bc81fd3..993b88a6eeb4a 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3023,6 +3023,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ty::ty_trait(..) => (), _ => { + let t_1 = structurally_resolved_type(fcx, e.span, t_1); + let t_e = structurally_resolved_type(fcx, e.span, t_e); + if ty::type_is_nil(t_e) { fcx.type_error_message(expr.span, |actual| { format!("cast from nil: `{}` as `{}`", @@ -3037,21 +3040,14 @@ fn check_expr_with_unifier(fcx: &FnCtxt, }, t_e, None); } - let t1 = structurally_resolved_type(fcx, e.span, t_1); - let te = structurally_resolved_type(fcx, e.span, t_e); - let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1); - let t_1_is_char = type_is_char(fcx, expr.span, t_1); - let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1); - let t_1_is_float = type_is_floating_point(fcx, - expr.span, - t_1); + let t_1_is_scalar = ty::type_is_scalar(t_1); + let t_1_is_char = ty::type_is_char(t_1); + let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); + let t_1_is_float = ty::type_is_floating_point(t_1); // casts to scalars other than `char` and `bare fn` are trivial - let t_1_is_trivial = t_1_is_scalar && - !t_1_is_char && !t_1_is_bare_fn; - - if type_is_c_like_enum(fcx, expr.span, t_e) && - t_1_is_trivial { + let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; + if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial { if t_1_is_float { fcx.type_error_message(expr.span, |actual| { format!("illegal cast; cast through an \ @@ -3062,22 +3058,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } // casts from C-like enums are allowed } else if t_1_is_char { - let te = fcx.infcx().resolve_type_vars_if_possible(te); - if ty::get(te).sty != ty::ty_uint(ast::TyU8) { + let t_e = fcx.infcx().resolve_type_vars_if_possible(t_e); + if ty::get(t_e).sty != ty::ty_uint(ast::TyU8) { fcx.type_error_message(expr.span, |actual| { format!("only `u8` can be cast as \ `char`, not `{}`", actual) }, t_e, None); } - } else if ty::get(t1).sty == ty::ty_bool { + } else if ty::get(t_1).sty == ty::ty_bool { fcx.tcx() .sess .span_err(expr.span, "cannot cast as `bool`, compare with \ zero instead"); - } else if type_is_region_ptr(fcx, expr.span, t_e) && - type_is_unsafe_ptr(fcx, expr.span, t_1) { - + } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { fn is_vec(t: ty::t) -> bool { match ty::get(t).sty { ty::ty_vec(..) => true, @@ -3110,7 +3104,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, /* this cast is only allowed from &[T] to *T or &T to *T. */ - match (&ty::get(te).sty, &ty::get(t_1).sty) { + match (&ty::get(t_e).sty, &ty::get(t_1).sty) { (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable })) if types_compatible(fcx, e.span, mt1, mt2) => { @@ -3120,8 +3114,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, demand::coerce(fcx, e.span, t_1, &**e); } } - } else if !(type_is_scalar(fcx,expr.span,t_e) - && t_1_is_trivial) { + } else if !(ty::type_is_scalar(t_e) && t_1_is_trivial) { /* If more type combinations should be supported than are supported here, then file an enhancement issue and @@ -4203,41 +4196,6 @@ pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { return ty::type_is_uint(typ_s); } -pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_scalar(typ_s); -} - -pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_char(typ_s); -} - -pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_bare_fn(typ_s); -} - -pub fn type_is_floating_point(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_floating_point(typ_s); -} - -pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_unsafe_ptr(typ_s); -} - -pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_region_ptr(typ_s); -} - -pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { - let typ_s = structurally_resolved_type(fcx, sp, typ); - return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); -} - pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt, e: &ast::Expr, v: ast::ExprVstore, diff --git a/src/test/compile-fail/issue-10991.rs b/src/test/compile-fail/issue-10991.rs new file mode 100644 index 0000000000000..8f7e6470f9095 --- /dev/null +++ b/src/test/compile-fail/issue-10991.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let nil = (); + let _t = nil as uint; //~ ERROR: cast from nil: `()` as `uint` +} From 207bfee2140857ac5161686db97cef90f0e38907 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Wed, 4 Jun 2014 23:55:10 +0100 Subject: [PATCH 02/55] rustc: Add self/super hint for extern crate resolve errors. --- src/librustc/middle/resolve.rs | 82 +++++++++++++------ src/test/compile-fail/issue-1697.rs | 4 +- .../compile-fail/resolve_self_super_hint.rs | 32 ++++++++ src/test/compile-fail/unresolved-import.rs | 4 +- 4 files changed, 92 insertions(+), 30 deletions(-) create mode 100644 src/test/compile-fail/resolve_self_super_hint.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 53c09fcf28350..7710ef8d733b7 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1485,26 +1485,21 @@ impl<'a> Resolver<'a> { ViewItemExternCrate(name, _, node_id) => { // n.b. we don't need to look at the path option here, because cstore already did - match self.session.cstore.find_extern_mod_stmt_cnum(node_id) { - Some(crate_id) => { - let def_id = DefId { krate: crate_id, node: 0 }; - self.external_exports.insert(def_id); - let parent_link = ModuleParentLink - (parent.module().downgrade(), name); - let external_module = Rc::new(Module::new(parent_link, - Some(def_id), - NormalModuleKind, - false, - true)); - - parent.module().external_module_children - .borrow_mut().insert(name.name, - external_module.clone()); - - self.build_reduced_graph_for_external_crate( - external_module); - } - None => {} // Ignore. + for &crate_id in self.session.cstore.find_extern_mod_stmt_cnum(node_id).iter() { + let def_id = DefId { krate: crate_id, node: 0 }; + self.external_exports.insert(def_id); + let parent_link = ModuleParentLink(parent.module().downgrade(), name); + let external_module = Rc::new(Module::new(parent_link, + Some(def_id), + NormalModuleKind, + false, + true)); + debug!("(build reduced graph for item) found extern `{}`", + self.module_to_str(&*external_module)); + parent.module().external_module_children.borrow_mut() + .insert(name.name, + external_module.clone()); + self.build_reduced_graph_for_external_crate(external_module); } } } @@ -1997,7 +1992,9 @@ impl<'a> Resolver<'a> { fn resolve_imports_for_module_subtree(&mut self, module_: Rc) { debug!("(resolving imports for module subtree) resolving {}", self.module_to_str(&*module_)); + let orig_module = replace(&mut self.current_module, module_.clone()); self.resolve_imports_for_module(module_.clone()); + self.current_module = orig_module; self.populate_module_if_necessary(&module_); for (_, child_node) in module_.children.borrow().iter() { @@ -2611,6 +2608,22 @@ impl<'a> Resolver<'a> { name_search_type: NameSearchType, lp: LastPrivate) -> ResolveResult<(Rc, LastPrivate)> { + fn search_parent_externals(needle: Name, module: &Rc) + -> Option> { + module.external_module_children.borrow() + .find_copy(&needle) + .map(|_| module.clone()) + .or_else(|| { + match module.parent_link.clone() { + ModuleParentLink(parent, _) => { + search_parent_externals(needle, + &parent.upgrade().unwrap()) + } + _ => None + } + }) + } + let mut search_module = module_; let mut index = index; let module_path_len = module_path.len(); @@ -2635,11 +2648,28 @@ impl<'a> Resolver<'a> { hi: span.lo + Pos::from_uint(segment_name.get().len()), expn_info: span.expn_info, }; - self.resolve_error(span, - format!("unresolved import. maybe \ - a missing `extern crate \ - {}`?", - segment_name).as_slice()); + + match search_parent_externals(name.name, &self.current_module) { + Some(module) => { + let path_str = self.idents_to_str(module_path); + let target_mod_str = self.module_to_str(&*module); + let current_mod_str = self.module_to_str(&*self.current_module); + + let prefix = if target_mod_str == current_mod_str { + "self::".to_string() + } else { + format!("{}::", target_mod_str) + }; + + self.resolve_error(span, format!("unresolved import. Did you mean \ + `{}{}`?", + prefix, path_str).as_slice()); + }, + None => self.resolve_error(span, format!("unresolved import. Maybe a \ + missing `extern crate {}`?", + segment_name).as_slice()), + } + return Failed; } self.resolve_error(span, @@ -5480,7 +5510,7 @@ impl<'a> Resolver<'a> { // /// A somewhat inefficient routine to obtain the name of a module. - fn module_to_str(&mut self, module: &Module) -> String { + fn module_to_str(&self, module: &Module) -> String { let mut idents = Vec::new(); fn collect_mod(idents: &mut Vec, module: &Module) { diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index f79a8fffd922d..84ff07facee5a 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -12,7 +12,7 @@ #![feature(globs)] -use unresolved::*; //~ ERROR unresolved import. maybe a missing +use unresolved::*; //~ ERROR unresolved import. Maybe a missing //~^ ERROR failed to resolve import fn main() { diff --git a/src/test/compile-fail/resolve_self_super_hint.rs b/src/test/compile-fail/resolve_self_super_hint.rs new file mode 100644 index 0000000000000..f900d3a74ed90 --- /dev/null +++ b/src/test/compile-fail/resolve_self_super_hint.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod a { + extern crate collections; + use collections::HashMap; + //~^ ERROR unresolved import. Did you mean `self::collections`? + //~^^ ERROR failed to resolve import `collections::HashMap` + + mod b { + use collections::HashMap; +//~^ ERROR unresolved import. Did you mean `a::collections`? +//~^^ ERROR failed to resolve import `collections::HashMap` + mod c { + use collections::HashMap; +//~^ ERROR unresolved import. Did you mean `a::collections`? +//~^^ ERROR failed to resolve import `collections::HashMap` + mod d { + use collections::HashMap; +//~^ ERROR unresolved import. Did you mean `a::collections` +//~^^ ERROR failed to resolve import `collections::HashMap` + } + } + } +} diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index cb009163697f7..a614ed109d872 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use foo::bar; //~ ERROR unresolved import. maybe a missing `extern crate foo`? +use foo::bar; //~ ERROR unresolved import. Maybe a missing `extern crate foo`? //~^ ERROR failed to resolve import `foo::bar` use x = bar::baz; //~ ERROR unresolved import: there is no `baz` in `bar` //~^ ERROR failed to resolve import `bar::baz` From 91753262726ccce83cc1a9e08a817f18e770cd9d Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Tue, 17 Jun 2014 05:25:30 -0700 Subject: [PATCH 03/55] emacs: Don't overwrite font lock for attributes This addresses the font lock regression introduced by the earlier pull request #14818 - attributes are no longer be highligted inside of comments and strings. Also add some font lock test infrastructure and some tests for attribute font locking. --- src/etc/emacs/rust-mode-tests.el | 112 ++++++++++++++++++++++++------- src/etc/emacs/rust-mode.el | 2 +- 2 files changed, 87 insertions(+), 27 deletions(-) diff --git a/src/etc/emacs/rust-mode-tests.el b/src/etc/emacs/rust-mode-tests.el index a4e837958c91b..6a04352412323 100644 --- a/src/etc/emacs/rust-mode-tests.el +++ b/src/etc/emacs/rust-mode-tests.el @@ -12,7 +12,7 @@ (defun rust-test-explain-bad-manip (original point-pos manip-func expected got) (if (equal expected got) nil - (list + (list ;; The (goto-char) and (insert) business here is just for ;; convenience--after an error, you can copy-paste that into emacs eval to ;; insert the bare strings into a buffer @@ -66,13 +66,13 @@ Also, the result should be the same regardless of whether the code is at the beg do (rust-test-manip-code (concat padding-beginning unfilled padding-end) pos - (lambda () + (lambda () (let ((fill-column rust-test-fill-column)) (fill-paragraph))) (concat padding-beginning expected padding-end))))))) (ert-deftest fill-paragraph-top-level-multi-line-style-doc-comment-second-line () - (test-fill-paragraph + (test-fill-paragraph "/** * This is a very very very very very very very long string */" @@ -188,10 +188,10 @@ This is some more text. Fee fie fo fum. Humpty dumpty sat on a wall. (ert-deftest fill-paragraph-with-no-space-after-star-prefix () (test-fill-paragraph - "/** + "/** *This is a very very very very very very very long string */" - "/** + "/** *This is a very very very very *very very very long string */")) @@ -226,7 +226,7 @@ fn bar() { }" fn bar() { }" 14 67)) (defun test-auto-fill (initial position inserted expected) - (rust-test-manip-code + (rust-test-manip-code initial position (lambda () @@ -244,7 +244,7 @@ fn bar() { }" 14 67)) (ert-deftest auto-fill-multi-line-doc-comment () (test-auto-fill "/** - * + * */" 8 "This is a very very very very very very very long string" @@ -317,7 +317,7 @@ fn foo() { /*! * this is a nested doc comment */ - + //! And so is this }")) @@ -456,7 +456,7 @@ fn foo() { (test-indent " fn foo() { - let x = + let x = match blah { Pattern | Pattern2 => { @@ -473,7 +473,7 @@ fn foo() { (test-indent " fn foo() { - let x = + let x = foo(bar(|x| { only_one_indent_here(); })); @@ -572,7 +572,7 @@ fn indenting_middle_of_line() { } fn indented_already() { - + // The previous line already has its spaces } " @@ -654,91 +654,91 @@ All positions are position symbols found in `rust-test-positions-alist'." (rust-get-buffer-pos reg-end)))))) (ert-deftest rust-beginning-of-defun-from-middle-of-fn () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn1 'start-of-fn1 #'beginning-of-defun)) (ert-deftest rust-beginning-of-defun-from-end () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'end-of-fn1 'start-of-fn1 #'beginning-of-defun)) (ert-deftest rust-beginning-of-defun-before-open-brace () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'start-of-fn1-middle-of-line 'start-of-fn1 #'beginning-of-defun)) (ert-deftest rust-beginning-of-defun-between-fns () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'between-fn1-fn2 'start-of-fn1 #'beginning-of-defun)) (ert-deftest rust-beginning-of-defun-with-arg () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn2 'start-of-fn1 #'beginning-of-defun 2)) (ert-deftest rust-beginning-of-defun-with-negative-arg () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn1 'beginning-of-fn3 #'beginning-of-defun -2)) (ert-deftest rust-beginning-of-defun-pub-fn () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn3 'beginning-of-fn3 #'beginning-of-defun)) (ert-deftest rust-end-of-defun-from-middle-of-fn () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn1 'between-fn1-fn2 #'end-of-defun)) (ert-deftest rust-end-of-defun-from-beg () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'start-of-fn1 'between-fn1-fn2 #'end-of-defun)) (ert-deftest rust-end-of-defun-before-open-brace () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'start-of-fn1-middle-of-line 'between-fn1-fn2 #'end-of-defun)) (ert-deftest rust-end-of-defun-between-fns () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'between-fn1-fn2 'after-end-of-fn2 #'end-of-defun)) (ert-deftest rust-end-of-defun-with-arg () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn1 'after-end-of-fn2 #'end-of-defun 2)) (ert-deftest rust-end-of-defun-with-negative-arg () - (rust-test-motion + (rust-test-motion rust-test-motion-string 'middle-of-fn3 'between-fn1-fn2 @@ -752,14 +752,14 @@ All positions are position symbols found in `rust-test-positions-alist'." #'mark-defun)) (ert-deftest rust-mark-defun-from-end () - (rust-test-region + (rust-test-region rust-test-region-string 'end-of-fn1 'before-start-of-fn1 'between-fn1-fn2 #'mark-defun)) (ert-deftest rust-mark-defun-start-of-defun () - (rust-test-region + (rust-test-region rust-test-region-string 'start-of-fn2 'between-fn1-fn2 'after-end-of-fn2 @@ -834,3 +834,63 @@ All positions are position symbols found in `rust-test-positions-alist'." 'nonblank-line-indented-already-middle-start 'nonblank-line-indented-already-middle-target #'indent-for-tab-command)) + +(defun rust-test-fontify-string (str) + (with-temp-buffer + (rust-mode) + (insert str) + (font-lock-fontify-buffer) + (buffer-string))) + +(defun rust-test-group-str-by-face (str) + "Fontify `STR' in rust-mode and group it by face, returning a +list of substrings of `STR' each followed by its face." + (cl-loop with fontified = (rust-test-fontify-string str) + for start = 0 then end + while start + for end = (next-single-property-change start 'face fontified) + for prop = (get-text-property start 'face fontified) + for text = (substring-no-properties fontified start end) + if prop + append (list text prop))) + +(defun rust-test-font-lock (source face-groups) + "Test that `SOURCE' fontifies to the expected `FACE-GROUPS'" + (should (equal (rust-test-group-str-by-face source) + face-groups))) + +(ert-deftest font-lock-attribute-simple () + (rust-test-font-lock + "#[foo]" + '("#[foo]" font-lock-preprocessor-face))) + +(ert-deftest font-lock-attribute-inner () + (rust-test-font-lock + "#![foo]" + '("#![foo]" font-lock-preprocessor-face))) + +(ert-deftest font-lock-attribute-key-value () + (rust-test-font-lock + "#[foo = \"bar\"]" + '("#[foo = " font-lock-preprocessor-face + "\"bar\"" font-lock-string-face + "]" font-lock-preprocessor-face))) + +(ert-deftest font-lock-attribute-around-comment () + (rust-test-font-lock + "#[foo /* bar */]" + '("#[foo " font-lock-preprocessor-face + "/* " font-lock-comment-delimiter-face + "bar */" font-lock-comment-face + "]" font-lock-preprocessor-face))) + +(ert-deftest font-lock-attribute-inside-string () + (rust-test-font-lock + "\"#[foo]\"" + '("\"#[foo]\"" font-lock-string-face))) + +(ert-deftest font-lock-attribute-inside-comment () + (rust-test-font-lock + "/* #[foo] */" + '("/* " font-lock-comment-delimiter-face + "#[foo] */" font-lock-comment-face))) diff --git a/src/etc/emacs/rust-mode.el b/src/etc/emacs/rust-mode.el index 67f4951193f08..beb2e6510fd72 100644 --- a/src/etc/emacs/rust-mode.el +++ b/src/etc/emacs/rust-mode.el @@ -214,7 +214,7 @@ ;; Attributes like `#[bar(baz)]` or `#![bar(baz)]` or `#[bar = "baz"]` (,(rust-re-grab (concat "#\\!?\\[" rust-re-ident "[^]]*\\]")) - 1 font-lock-preprocessor-face t) + 1 font-lock-preprocessor-face keep) ;; Syntax extension invocations like `foo!`, highlight including the ! (,(concat (rust-re-grab (concat rust-re-ident "!")) "[({[:space:][]") From 77b874b68d8d42824e96fda2ebe92a4eb80177a0 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Tue, 17 Jun 2014 16:39:40 -0700 Subject: [PATCH 04/55] emacs: Add shebang to test script --- src/etc/emacs/run_rust_emacs_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etc/emacs/run_rust_emacs_tests.sh b/src/etc/emacs/run_rust_emacs_tests.sh index 770135c3d20e0..b35fcf870c4d3 100755 --- a/src/etc/emacs/run_rust_emacs_tests.sh +++ b/src/etc/emacs/run_rust_emacs_tests.sh @@ -1,3 +1,4 @@ +#!/bin/sh # 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. From 23a7d24dd70c3614952df695a5fe78fbcd7ac20b Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Tue, 17 Jun 2014 16:42:42 -0700 Subject: [PATCH 05/55] emacs: Remove outdated references to ~ in tests --- src/etc/emacs/rust-mode-tests.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/etc/emacs/rust-mode-tests.el b/src/etc/emacs/rust-mode-tests.el index 6a04352412323..85800a6965daf 100644 --- a/src/etc/emacs/rust-mode-tests.el +++ b/src/etc/emacs/rust-mode-tests.el @@ -301,7 +301,7 @@ struct Foo { bar: int, struct Blah {x:int, y:int, - z:~str}")) + z:String")) (ert-deftest indent-doc-comments () (test-indent @@ -331,7 +331,7 @@ struct foo { b:char } -fn bar(x:~int) { // comment here should not affect the next indent +fn bar(x:Box) { // comment here should not affect the next indent bla(); bla(); }")) @@ -387,7 +387,7 @@ fn baz( a:int, // shoudl work with a comment here " fn args_on_the_next_line( // with a comment a:int, - b:~str) { + b:String) { let aaaaaa = [ 1, 2, From 3791a8508750b48fa4e7e8a325284144877feb8c Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Thu, 5 Jun 2014 22:37:52 +0100 Subject: [PATCH 06/55] rustc: reduce redundant resolve errors. --- src/librustc/middle/resolve.rs | 254 +++++++++--------- .../phase-syntax-doesnt-resolve.rs | 5 +- src/test/compile-fail/import-from-missing.rs | 4 +- src/test/compile-fail/import.rs | 4 +- src/test/compile-fail/import2.rs | 6 +- src/test/compile-fail/issue-12612.rs | 3 +- src/test/compile-fail/issue-13404.rs | 3 +- src/test/compile-fail/issue-1697.rs | 6 +- src/test/compile-fail/issue-2123.rs | 11 +- src/test/compile-fail/issue-2937.rs | 11 +- .../compile-fail/macro-inner-attributes.rs | 5 +- src/test/compile-fail/privacy2.rs | 9 +- src/test/compile-fail/privacy3.rs | 6 +- .../compile-fail/resolve_self_super_hint.rs | 13 +- src/test/compile-fail/super-at-top-level.rs | 2 +- src/test/compile-fail/unresolved-import.rs | 7 +- src/test/compile-fail/use-from-trait-xc.rs | 12 +- src/test/compile-fail/use-from-trait.rs | 8 +- 18 files changed, 181 insertions(+), 188 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 7710ef8d733b7..5ce63b94b2499 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -206,10 +206,12 @@ impl ReducedGraphParent { } } +type ErrorMessage = Option<(Span, String)>; + enum ResolveResult { - Failed, // Failed to resolve the name. - Indeterminate, // Couldn't determine due to unresolved globs. - Success(T) // Successfully resolved the import. + Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message. + Indeterminate, // Couldn't determine due to unresolved globs. + Success(T) // Successfully resolved the import. } impl ResolveResult { @@ -1485,10 +1487,12 @@ impl<'a> Resolver<'a> { ViewItemExternCrate(name, _, node_id) => { // n.b. we don't need to look at the path option here, because cstore already did - for &crate_id in self.session.cstore.find_extern_mod_stmt_cnum(node_id).iter() { + for &crate_id in self.session.cstore + .find_extern_mod_stmt_cnum(node_id).iter() { let def_id = DefId { krate: crate_id, node: 0 }; self.external_exports.insert(def_id); - let parent_link = ModuleParentLink(parent.module().downgrade(), name); + let parent_link = + ModuleParentLink(parent.module().downgrade(), name); let external_module = Rc::new(Module::new(parent_link, Some(def_id), NormalModuleKind, @@ -1497,8 +1501,7 @@ impl<'a> Resolver<'a> { debug!("(build reduced graph for item) found extern `{}`", self.module_to_str(&*external_module)); parent.module().external_module_children.borrow_mut() - .insert(name.name, - external_module.clone()); + .insert(name.name, external_module.clone()); self.build_reduced_graph_for_external_crate(external_module); } } @@ -2029,22 +2032,21 @@ impl<'a> Resolver<'a> { let import_directive = imports.get(import_index); match self.resolve_import_for_module(module.clone(), import_directive) { - Failed => { - // We presumably emitted an error. Continue. - let msg = format!("failed to resolve import `{}`", - self.import_path_to_str( - import_directive.module_path - .as_slice(), - import_directive.subclass)); - self.resolve_error(import_directive.span, msg.as_slice()); - } - Indeterminate => { - // Bail out. We'll come around next time. - break; - } - Success(()) => { - // Good. Continue. + Failed(err) => { + let (span, help) = match err { + Some((span, msg)) => (span, format!(". {}", msg)), + None => (import_directive.span, String::new()) + }; + let msg = format!("unresolved import `{}`{}", + self.import_path_to_str( + import_directive.module_path + .as_slice(), + import_directive.subclass), + help); + self.resolve_error(span, msg.as_slice()); } + Indeterminate => break, // Bail out. We'll come around next time. + Success(()) => () // Good. Continue. } module.resolved_import_count @@ -2108,7 +2110,7 @@ impl<'a> Resolver<'a> { module_: Rc, import_directive: &ImportDirective) -> ResolveResult<()> { - let mut resolution_result = Failed; + let mut resolution_result = Failed(None); let module_path = &import_directive.module_path; debug!("(resolving import for module) resolving import `{}::...` in \ @@ -2126,8 +2128,10 @@ impl<'a> Resolver<'a> { DontUseLexicalScope, import_directive.span, ImportSearch) { - - Failed => None, + Failed(err) => { + resolution_result = Failed(err); + None + }, Indeterminate => { resolution_result = Indeterminate; None @@ -2405,12 +2409,10 @@ impl<'a> Resolver<'a> { } if value_result.is_unbound() && type_result.is_unbound() { - let msg = format!("unresolved import: there is no \ - `{}` in `{}`", + let msg = format!("There is no `{}` in `{}`", token::get_ident(source), self.module_to_str(&*containing_module)); - self.resolve_error(directive.span, msg.as_slice()); - return Failed; + return Failed(Some((directive.span, msg))); } let value_used_public = value_used_reexport || value_used_public; let type_used_public = type_used_reexport || type_used_public; @@ -2639,21 +2641,20 @@ impl<'a> Resolver<'a> { TypeNS, name_search_type, false) { - Failed => { + Failed(None) => { let segment_name = token::get_ident(name); let module_name = self.module_to_str(&*search_module); - if "???" == module_name.as_slice() { - let span = Span { - lo: span.lo, - hi: span.lo + Pos::from_uint(segment_name.get().len()), - expn_info: span.expn_info, - }; + let mut span = span; + let msg = if "???" == module_name.as_slice() { + span.hi = span.lo + Pos::from_uint(segment_name.get().len()); - match search_parent_externals(name.name, &self.current_module) { + match search_parent_externals(name.name, + &self.current_module) { Some(module) => { let path_str = self.idents_to_str(module_path); let target_mod_str = self.module_to_str(&*module); - let current_mod_str = self.module_to_str(&*self.current_module); + let current_mod_str = + self.module_to_str(&*self.current_module); let prefix = if target_mod_str == current_mod_str { "self::".to_string() @@ -2661,24 +2662,20 @@ impl<'a> Resolver<'a> { format!("{}::", target_mod_str) }; - self.resolve_error(span, format!("unresolved import. Did you mean \ - `{}{}`?", - prefix, path_str).as_slice()); + format!("Did you mean `{}{}`?", prefix, path_str) }, - None => self.resolve_error(span, format!("unresolved import. Maybe a \ - missing `extern crate {}`?", - segment_name).as_slice()), + None => format!("Maybe a missing `extern crate {}`?", + segment_name), } + } else { + format!("Could not find `{}` in `{}`.", + segment_name, + module_name) + }; - return Failed; - } - self.resolve_error(span, - format!("unresolved import: could not \ - find `{}` in `{}`.", - segment_name, - module_name).as_slice()); - return Failed; + return Failed(Some((span, msg))); } + Failed(err) => return Failed(err), Indeterminate => { debug!("(resolving module path for import) module \ resolution is indeterminate: {}", @@ -2692,13 +2689,10 @@ impl<'a> Resolver<'a> { Some(ref type_def) => { match type_def.module_def { None => { - // Not a module. - self.resolve_error( - span, - format!("not a module `{}`", - token::get_ident(name)) - .as_slice()); - return Failed; + let msg = format!("Not a module `{}`", + token::get_ident(name)); + + return Failed(Some((span, msg))); } Some(ref module_def) => { // If we're doing the search for an @@ -2708,11 +2702,10 @@ impl<'a> Resolver<'a> { module_def.kind.get()) { (ImportSearch, TraitModuleKind) | (ImportSearch, ImplModuleKind) => { - self.resolve_error( - span, - "cannot import from a trait \ - or type implementation"); - return Failed; + let msg = + "Cannot import from a trait or \ + type implementation".to_string(); + return Failed(Some((span, msg))); } (_, _) => { search_module = module_def.clone(); @@ -2738,11 +2731,9 @@ impl<'a> Resolver<'a> { } None => { // There are no type bindings at all. - self.resolve_error( - span, - format!("not a module `{}`", - token::get_ident(name)).as_slice()); - return Failed; + let msg = format!("Not a module `{}`", + token::get_ident(name)); + return Failed(Some((span, msg))); } } } @@ -2782,24 +2773,22 @@ impl<'a> Resolver<'a> { let start_index; let last_private; match module_prefix_result { - Failed => { + Failed(None) => { let mpath = self.idents_to_str(module_path); - match mpath.as_slice().rfind(':') { + let mpath = mpath.as_slice(); + match mpath.rfind(':') { Some(idx) => { - self.resolve_error( - span, - format!("unresolved import: could not find `{}` \ - in `{}`", - // idx +- 1 to account for the colons on \ - // either side - mpath.as_slice().slice_from(idx + 1), - mpath.as_slice() - .slice_to(idx - 1)).as_slice()); + let msg = format!("Could not find `{}` in `{}`", + // idx +- 1 to account for the + // colons on either side + mpath.slice_from(idx + 1), + mpath.slice_to(idx - 1)); + return Failed(Some((span, msg))); }, - None => (), - }; - return Failed; + None => return Failed(None), + } } + Failed(err) => return Failed(err), Indeterminate => { debug!("(resolving module path for import) indeterminate; \ bailing"); @@ -2821,14 +2810,10 @@ impl<'a> Resolver<'a> { // This is not a crate-relative path. We resolve the // first component of the path in the current lexical // scope and then proceed to resolve below that. - let result = self.resolve_module_in_lexical_scope( - module_, - module_path[0]); - match result { - Failed => { - self.resolve_error(span, "unresolved name"); - return Failed; - } + match self.resolve_module_in_lexical_scope( + module_, + module_path[0]) { + Failed(err) => return Failed(err), Indeterminate => { debug!("(resolving module path for import) \ indeterminate; bailing"); @@ -2935,7 +2920,7 @@ impl<'a> Resolver<'a> { // No more parents. This module was unresolved. debug!("(resolving item in lexical scope) unresolved \ module"); - return Failed; + return Failed(None); } ModuleParentLink(parent_module_node, _) => { match search_module.kind.get() { @@ -2945,7 +2930,7 @@ impl<'a> Resolver<'a> { scope) unresolved module: not \ searching through module \ parents"); - return Failed; + return Failed(None); } ExternModuleKind | TraitModuleKind | @@ -2966,9 +2951,10 @@ impl<'a> Resolver<'a> { namespace, PathSearch, true) { - Failed => { - // Continue up the search chain. - } + Failed(Some((span, msg))) => + self.resolve_error(span, format!("failed to resolve. {}", + msg)), + Failed(None) => (), // Continue up the search chain. Indeterminate => { // We couldn't see through the higher scope because of an // unresolved import higher up. Bail. @@ -3006,7 +2992,7 @@ impl<'a> Resolver<'a> { debug!("!!! (resolving module in lexical \ scope) module wasn't actually a \ module!"); - return Failed; + return Failed(None); } Some(ref module_def) => { return Success(module_def.clone()); @@ -3016,7 +3002,7 @@ impl<'a> Resolver<'a> { None => { debug!("!!! (resolving module in lexical scope) module wasn't actually a module!"); - return Failed; + return Failed(None); } } } @@ -3025,10 +3011,9 @@ impl<'a> Resolver<'a> { bailing"); return Indeterminate; } - Failed => { - debug!("(resolving module in lexical scope) failed to \ - resolve"); - return Failed; + Failed(err) => { + debug!("(resolving module in lexical scope) failed to resolve"); + return Failed(err); } } } @@ -3106,7 +3091,7 @@ impl<'a> Resolver<'a> { debug!("(resolving module prefix) resolving `super` at {}", self.module_to_str(&*containing_module)); match self.get_nearest_normal_module_parent(containing_module) { - None => return Failed, + None => return Failed(None), Some(new_module) => { containing_module = new_module; i += 1; @@ -3203,7 +3188,7 @@ impl<'a> Resolver<'a> { // We're out of luck. debug!("(resolving name in module) failed to resolve `{}`", token::get_name(name).get()); - return Failed; + return Failed(None); } fn report_unresolved_imports(&mut self, module_: Rc) { @@ -4561,8 +4546,15 @@ impl<'a> Resolver<'a> { Indeterminate => { fail!("unexpected indeterminate result"); } + Failed(err) => { + match err { + Some((span, msg)) => { + self.resolve_error(span, format!("failed to resolve: {}", + msg)); + } + None => () + } - Failed => { debug!("(resolve bare identifier pattern) failed to find {}", token::get_ident(name)); return BareIdentifierPatternUnresolved; @@ -4727,17 +4719,22 @@ impl<'a> Resolver<'a> { UseLexicalScope, path.span, PathSearch) { - Failed => { - let msg = format!("use of undeclared module `{}`", - self.idents_to_str(module_path_idents.as_slice())); - self.resolve_error(path.span, msg.as_slice()); - return None; - } + Failed(err) => { + let (span, msg) = match err { + Some((span, msg)) => (span, msg), + None => { + let msg = format!("Use of undeclared module `{}`", + self.idents_to_str( + module_path_idents.as_slice())); + (path.span, msg) + } + }; - Indeterminate => { - fail!("indeterminate unexpected"); + self.resolve_error(span, format!("failed to resolve. {}", + msg.as_slice())); + return None; } - + Indeterminate => fail!("indeterminate unexpected"), Success((resulting_module, resulting_last_private)) => { containing_module = resulting_module; last_private = resulting_last_private; @@ -4798,10 +4795,19 @@ impl<'a> Resolver<'a> { path.span, PathSearch, LastMod(AllPublic)) { - Failed => { - let msg = format!("use of undeclared module `::{}`", - self.idents_to_str(module_path_idents.as_slice())); - self.resolve_error(path.span, msg.as_slice()); + Failed(err) => { + let (span, msg) = match err { + Some((span, msg)) => (span, msg), + None => { + let msg = format!("Use of undeclared module `::{}`", + self.idents_to_str( + module_path_idents.as_slice())); + (path.span, msg) + } + }; + + self.resolve_error(span, format!("failed to resolve. {}", + msg.as_slice())); return None; } @@ -4894,7 +4900,13 @@ impl<'a> Resolver<'a> { Indeterminate => { fail!("unexpected indeterminate result"); } - Failed => { + Failed(err) => { + match err { + Some((span, msg)) => + self.resolve_error(span, format!("failed to resolve. {}", msg)), + None => () + } + debug!("(resolving item path by identifier in lexical scope) \ failed to resolve {}", token::get_ident(ident)); return None; @@ -4909,9 +4921,9 @@ impl<'a> Resolver<'a> { rs } - fn resolve_error(&self, span: Span, s: &str) { + fn resolve_error(&self, span: Span, s: T) { if self.emit_errors { - self.session.span_err(span, s); + self.session.span_err(span, s.as_slice()); } } diff --git a/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs index 274fbf797e1ef..3814656282585 100644 --- a/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs +++ b/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs @@ -19,7 +19,6 @@ extern crate macro_crate_test; fn main() { macro_crate_test::foo(); - //~^ ERROR unresolved name - //~^^ ERROR use of undeclared module `macro_crate_test` - //~^^^ ERROR unresolved name `macro_crate_test::foo`. + //~^ ERROR failed to resolve. Use of undeclared module `macro_crate_test` + //~^^ ERROR unresolved name `macro_crate_test::foo`. } diff --git a/src/test/compile-fail/import-from-missing.rs b/src/test/compile-fail/import-from-missing.rs index ecfec6c27d9a4..f393442de1011 100644 --- a/src/test/compile-fail/import-from-missing.rs +++ b/src/test/compile-fail/import-from-missing.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:failed to resolve import use spam::{ham, eggs}; +//~^ ERROR unresolved import `spam::eggs`. There is no `eggs` in `spam` mod spam { pub fn ham() { } diff --git a/src/test/compile-fail/import.rs b/src/test/compile-fail/import.rs index 1a6865c1ea722..844d527a54607 100644 --- a/src/test/compile-fail/import.rs +++ b/src/test/compile-fail/import.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:failed to resolve import use zed::bar; use zed::baz; +//~^ ERROR unresolved import `zed::baz`. There is no `baz` in `zed` mod zed { diff --git a/src/test/compile-fail/import2.rs b/src/test/compile-fail/import2.rs index 64b6b6c6f5849..f674d19ca5c9a 100644 --- a/src/test/compile-fail/import2.rs +++ b/src/test/compile-fail/import2.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use baz::zed::bar; //~ ERROR unresolved import -//~^ ERROR failed to resolve import +use baz::zed::bar; +//~^ ERROR unresolved import `baz::zed::bar`. Could not find `zed` in `baz`. mod baz {} diff --git a/src/test/compile-fail/issue-12612.rs b/src/test/compile-fail/issue-12612.rs index 9d6eb42567893..ee998e57c56c9 100644 --- a/src/test/compile-fail/issue-12612.rs +++ b/src/test/compile-fail/issue-12612.rs @@ -16,8 +16,7 @@ use foo::bar; mod test { use bar::foo; - //~^ ERROR: unresolved import - //~^^ ERROR: failed to resolve import + //~^ ERROR unresolved import `bar::foo`. Maybe a missing `extern crate bar`? } fn main() {} diff --git a/src/test/compile-fail/issue-13404.rs b/src/test/compile-fail/issue-13404.rs index 2ce502ee8dbb3..355be1562df2b 100644 --- a/src/test/compile-fail/issue-13404.rs +++ b/src/test/compile-fail/issue-13404.rs @@ -10,8 +10,7 @@ use a::f; use b::f; -//~^ ERROR: unresolved import -//~^^ ERROR: failed to resolve import +//~^ ERROR: unresolved import `b::f`. There is no `f` in `b` mod a { pub fn f() {} } mod b { } diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index 84ff07facee5a..46d9a558d9ea9 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -12,8 +12,6 @@ #![feature(globs)] -use unresolved::*; //~ ERROR unresolved import. Maybe a missing -//~^ ERROR failed to resolve import +use unresolved::*; //~ ERROR unresolved import `unresolved::*`. Maybe a missing `extern crate unres -fn main() { -} +fn main() {} diff --git a/src/test/compile-fail/issue-2123.rs b/src/test/compile-fail/issue-2123.rs index 6d617d338ed94..335012cedb84c 100644 --- a/src/test/compile-fail/issue-2123.rs +++ b/src/test/compile-fail/issue-2123.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use x = m::f; //~ ERROR failed to resolve import - //~^ unresolved import: there is no `f` in `m` +use x = m::f; //~ ERROR unresolved import `m::f`. There is no `f` in `m` -mod m { -} +mod m {} -fn main() { -} +fn main() {} diff --git a/src/test/compile-fail/issue-2937.rs b/src/test/compile-fail/issue-2937.rs index b225c5496e249..335012cedb84c 100644 --- a/src/test/compile-fail/issue-2937.rs +++ b/src/test/compile-fail/issue-2937.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use x = m::f; //~ ERROR failed to resolve import - //~^ ERROR unresolved import: there is no `f` in `m` +use x = m::f; //~ ERROR unresolved import `m::f`. There is no `f` in `m` -mod m { -} +mod m {} -fn main() { -} +fn main() {} diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs index ae804ea7ece40..3e731a2d2fed4 100644 --- a/src/test/compile-fail/macro-inner-attributes.rs +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -25,9 +25,8 @@ test!(b, #[qux] fn main() { a::bar(); - //~^ ERROR use of undeclared module `a` - //~^^ ERROR unresolved name - //~^^^ ERROR unresolved name `a::bar` + //~^ ERROR failed to resolve. Use of undeclared module `a` + //~^^ ERROR unresolved name `a::bar` b::bar(); } diff --git a/src/test/compile-fail/privacy2.rs b/src/test/compile-fail/privacy2.rs index df4e401dfa53f..5a5b6eb8436d7 100644 --- a/src/test/compile-fail/privacy2.rs +++ b/src/test/compile-fail/privacy2.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -24,14 +24,13 @@ mod bar { pub fn foo() {} fn test1() { - use bar::foo; //~ ERROR: unresolved import - //~^ ERROR: failed to resolve + use bar::foo; + //~^ ERROR unresolved import `bar::foo`. There is no `foo` in `bar` } fn test2() { use bar::glob::foo; - //~^ ERROR: there is no - //~^^ ERROR: failed to resolve + //~^ ERROR unresolved import `bar::glob::foo`. There is no `foo` in `bar::glob` } #[start] fn main(_: int, _: **u8) -> int { 3 } diff --git a/src/test/compile-fail/privacy3.rs b/src/test/compile-fail/privacy3.rs index f8d8ba2ab1aa3..6898a0cde17f5 100644 --- a/src/test/compile-fail/privacy3.rs +++ b/src/test/compile-fail/privacy3.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -25,8 +25,8 @@ mod bar { pub fn foo() {} fn test1() { - use bar::gpriv; //~ ERROR: unresolved import - //~^ ERROR: failed to resolve + use bar::gpriv; + //~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar` gpriv(); } diff --git a/src/test/compile-fail/resolve_self_super_hint.rs b/src/test/compile-fail/resolve_self_super_hint.rs index f900d3a74ed90..ed143fdff687f 100644 --- a/src/test/compile-fail/resolve_self_super_hint.rs +++ b/src/test/compile-fail/resolve_self_super_hint.rs @@ -11,21 +11,16 @@ mod a { extern crate collections; use collections::HashMap; - //~^ ERROR unresolved import. Did you mean `self::collections`? - //~^^ ERROR failed to resolve import `collections::HashMap` - +//~^ ERROR unresolved import `collections::HashMap`. Did you mean `self::collections`? mod b { use collections::HashMap; -//~^ ERROR unresolved import. Did you mean `a::collections`? -//~^^ ERROR failed to resolve import `collections::HashMap` +//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? mod c { use collections::HashMap; -//~^ ERROR unresolved import. Did you mean `a::collections`? -//~^^ ERROR failed to resolve import `collections::HashMap` +//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? mod d { use collections::HashMap; -//~^ ERROR unresolved import. Did you mean `a::collections` -//~^^ ERROR failed to resolve import `collections::HashMap` +//~^ ERROR unresolved import `collections::HashMap`. Did you mean `a::collections`? } } } diff --git a/src/test/compile-fail/super-at-top-level.rs b/src/test/compile-fail/super-at-top-level.rs index 7176d5f92f9a1..309b6773f604e 100644 --- a/src/test/compile-fail/super-at-top-level.rs +++ b/src/test/compile-fail/super-at-top-level.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::f; //~ ERROR failed to resolve import +use super::f; //~ ERROR unresolved import `super::f` fn main() { } diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index a614ed109d872..b5dcd5d165d4c 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use foo::bar; //~ ERROR unresolved import. Maybe a missing `extern crate foo`? - //~^ ERROR failed to resolve import `foo::bar` -use x = bar::baz; //~ ERROR unresolved import: there is no `baz` in `bar` - //~^ ERROR failed to resolve import `bar::baz` +use foo::bar; //~ ERROR unresolved import `foo::bar`. Maybe a missing `extern crate foo`? + +use x = bar::baz; //~ ERROR unresolved import `bar::baz`. There is no `baz` in `bar` mod bar { struct bar; diff --git a/src/test/compile-fail/use-from-trait-xc.rs b/src/test/compile-fail/use-from-trait-xc.rs index d45387ed1a25b..8e197b901e610 100644 --- a/src/test/compile-fail/use-from-trait-xc.rs +++ b/src/test/compile-fail/use-from-trait-xc.rs @@ -12,10 +12,10 @@ extern crate use_from_trait_xc; -use use_from_trait_xc::Trait::foo; //~ ERROR cannot import from a trait or type implementation -//~^ ERROR failed to resolve import -use use_from_trait_xc::Foo::new; //~ ERROR cannot import from a trait or type implementation -//~^ ERROR failed to resolve import +use use_from_trait_xc::Trait::foo; +//~^ ERROR unresolved import `use_from_trait_xc::Trait::foo`. Cannot import from a trait or type imp -fn main() { -} +use use_from_trait_xc::Foo::new; +//~^ ERROR unresolved import `use_from_trait_xc::Foo::new`. Cannot import from a trait or type imple + +fn main() {} diff --git a/src/test/compile-fail/use-from-trait.rs b/src/test/compile-fail/use-from-trait.rs index 8f8d96f8024e7..c9eea3c5df255 100644 --- a/src/test/compile-fail/use-from-trait.rs +++ b/src/test/compile-fail/use-from-trait.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use Trait::foo; //~ ERROR cannot import from a trait or type implementation -//~^ ERROR failed to resolve import -use Foo::new; //~ ERROR cannot import from a trait or type implementation -//~^ ERROR failed to resolve import +use Trait::foo; +//~^ ERROR unresolved import `Trait::foo`. Cannot import from a trait or type implementation +use Foo::new; +//~^ ERROR unresolved import `Foo::new`. Cannot import from a trait or type implementation pub trait Trait { fn foo(); From 4eb5d7baf928a922b30d71e64f7be258d1a82f2f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 11 Jun 2014 18:01:48 -0400 Subject: [PATCH 07/55] librustc: Don't overwrite vtables when coercing to trait object. --- src/librustc/middle/astencode.rs | 70 +++++++++++++------ src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 7 +- src/librustc/middle/trans/expr.rs | 34 ++++----- src/librustc/middle/trans/meth.rs | 10 ++- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 3 +- src/librustc/middle/typeck/check/regionck.rs | 2 +- src/librustc/middle/typeck/check/vtable.rs | 12 ++-- src/librustc/middle/typeck/check/writeback.rs | 6 +- src/librustc/middle/typeck/mod.rs | 36 ++++++++-- src/test/run-pass/deref-rc.rs | 16 +++++ src/test/run-pass/issue-14399.rs | 25 +++++++ 13 files changed, 164 insertions(+), 61 deletions(-) create mode 100644 src/test/run-pass/deref-rc.rs create mode 100644 src/test/run-pass/issue-14399.rs diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c7524c11188bc..8cb975182a033 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -552,16 +552,17 @@ impl tr for freevar_entry { // Encoding and decoding of MethodCallee trait read_method_callee_helper { - fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) -> (u32, MethodCallee); + fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) + -> (typeck::ExprAdjustment, MethodCallee); } fn encode_method_callee(ecx: &e::EncodeContext, ebml_w: &mut Encoder, - autoderef: u32, + adjustment: typeck::ExprAdjustment, method: &MethodCallee) { ebml_w.emit_struct("MethodCallee", 4, |ebml_w| { - ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| { - autoderef.encode(ebml_w) + ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| { + adjustment.encode(ebml_w) }); ebml_w.emit_struct_field("origin", 1u, |ebml_w| { method.origin.encode(ebml_w) @@ -576,12 +577,14 @@ fn encode_method_callee(ecx: &e::EncodeContext, } impl<'a> read_method_callee_helper for reader::Decoder<'a> { - fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) -> (u32, MethodCallee) { + fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) + -> (typeck::ExprAdjustment, MethodCallee) { + self.read_struct("MethodCallee", 4, |this| { - let autoderef = this.read_struct_field("autoderef", 0, |this| { + let adjustment = this.read_struct_field("adjustment", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((autoderef, MethodCallee { + Ok((adjustment, MethodCallee { origin: this.read_struct_field("origin", 1, |this| { let method_origin: MethodOrigin = Decodable::decode(this).unwrap(); @@ -627,11 +630,11 @@ impl tr for MethodOrigin { fn encode_vtable_res_with_key(ecx: &e::EncodeContext, ebml_w: &mut Encoder, - autoderef: u32, + adjustment: typeck::ExprAdjustment, dr: &typeck::vtable_res) { ebml_w.emit_struct("VtableWithKey", 2, |ebml_w| { - ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| { - autoderef.encode(ebml_w) + ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| { + adjustment.encode(ebml_w) }); ebml_w.emit_struct_field("vtable_res", 1u, |ebml_w| { Ok(encode_vtable_res(ecx, ebml_w, dr)) @@ -705,7 +708,7 @@ pub trait vtable_decoder_helpers { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt, cdata: &cstore::crate_metadata) - -> (u32, typeck::vtable_res); + -> (typeck::ExprAdjustment, typeck::vtable_res); fn read_vtable_res(&mut self, tcx: &ty::ctxt, cdata: &cstore::crate_metadata) -> typeck::vtable_res; @@ -731,12 +734,12 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt, cdata: &cstore::crate_metadata) - -> (u32, typeck::vtable_res) { + -> (typeck::ExprAdjustment, typeck::vtable_res) { self.read_struct("VtableWithKey", 2, |this| { - let autoderef = this.read_struct_field("autoderef", 0, |this| { + let adjustment = this.read_struct_field("adjustment", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| { + Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| { Ok(this.read_vtable_res(tcx, cdata)) }).unwrap())) }).unwrap() @@ -1050,7 +1053,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, ebml_w.tag(c::tag_table_method_map, |ebml_w| { ebml_w.id(id); ebml_w.tag(c::tag_table_val, |ebml_w| { - encode_method_callee(ecx, ebml_w, method_call.autoderef, method) + encode_method_callee(ecx, ebml_w, method_call.adjustment, method) }) }) } @@ -1059,7 +1062,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, ebml_w.tag(c::tag_table_vtable_map, |ebml_w| { ebml_w.id(id); ebml_w.tag(c::tag_table_val, |ebml_w| { - encode_vtable_res_with_key(ecx, ebml_w, method_call.autoderef, dr); + encode_vtable_res_with_key(ecx, ebml_w, method_call.adjustment, dr); }) }) } @@ -1068,12 +1071,13 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, match *adj { ty::AutoDerefRef(adj) => { for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(id, autoderef as u32); + let method_call = MethodCall::autoderef(id, autoderef); for &method in tcx.method_map.borrow().find(&method_call).iter() { ebml_w.tag(c::tag_table_method_map, |ebml_w| { ebml_w.id(id); ebml_w.tag(c::tag_table_val, |ebml_w| { - encode_method_callee(ecx, ebml_w, method_call.autoderef, method) + encode_method_callee(ecx, ebml_w, + method_call.adjustment, method) }) }) } @@ -1083,12 +1087,32 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, ebml_w.id(id); ebml_w.tag(c::tag_table_val, |ebml_w| { encode_vtable_res_with_key(ecx, ebml_w, - method_call.autoderef, dr); + method_call.adjustment, dr); }) }) } } } + ty::AutoObject(..) => { + let method_call = MethodCall::autoobject(id); + for &method in tcx.method_map.borrow().find(&method_call).iter() { + ebml_w.tag(c::tag_table_method_map, |ebml_w| { + ebml_w.id(id); + ebml_w.tag(c::tag_table_val, |ebml_w| { + encode_method_callee(ecx, ebml_w, method_call.adjustment, method) + }) + }) + } + + for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { + ebml_w.tag(c::tag_table_vtable_map, |ebml_w| { + ebml_w.id(id); + ebml_w.tag(c::tag_table_val, |ebml_w| { + encode_vtable_res_with_key(ecx, ebml_w, method_call.adjustment, dr); + }) + }) + } + } _ => {} } @@ -1393,20 +1417,20 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext, dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds); } c::tag_table_method_map => { - let (autoderef, method) = val_dsr.read_method_callee(xcx); + let (adjustment, method) = val_dsr.read_method_callee(xcx); let method_call = MethodCall { expr_id: id, - autoderef: autoderef + adjustment: adjustment }; dcx.tcx.method_map.borrow_mut().insert(method_call, method); } c::tag_table_vtable_map => { - let (autoderef, vtable_res) = + let (adjustment, vtable_res) = val_dsr.read_vtable_res_with_key(xcx.dcx.tcx, xcx.dcx.cdata); let vtable_key = MethodCall { expr_id: id, - autoderef: autoderef + adjustment: adjustment }; dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 86cd3c53804de..f70123313c47f 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -611,7 +611,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); for i in range(0, autoderefs) { - let deref_id = typeck::MethodCall::autoderef(expr.id, i as u32); + let deref_id = typeck::MethodCall::autoderef(expr.id, i); match self.typer.node_method_ty(deref_id) { None => {} Some(method_ty) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8224557f86007..ea083e410998c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -697,9 +697,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { base_cmt: cmt, deref_cnt: uint) -> cmt { + let adjustment = match self.typer.adjustments().borrow().find(&node.id()) { + Some(&ty::AutoObject(..)) => typeck::AutoObject, + _ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt), + _ => typeck::NoAdjustment + }; let method_call = typeck::MethodCall { expr_id: node.id(), - autoderef: deref_cnt as u32 + adjustment: adjustment }; let method_ty = self.typer.node_method_ty(method_call); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 42c7a71bab84d..8b9ed86b6776d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -65,8 +65,8 @@ use middle::ty::struct_fields; use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe}; use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef}; use middle::ty; -use middle::typeck::MethodCall; use middle::typeck; +use middle::typeck::MethodCall; use util::common::indenter; use util::ppaux::Repr; use util::nodemap::NodeMap; @@ -1178,7 +1178,7 @@ fn trans_unary<'a>(bcx: &'a Block<'a>, } ast::UnDeref => { let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); - deref_once(bcx, expr, datum, 0) + deref_once(bcx, expr, datum, method_call) } } } @@ -1487,7 +1487,7 @@ fn trans_overloaded_call<'a>( SaveIn(addr)) })); - let method_call = typeck::MethodCall::expr(expr.id); + let method_call = MethodCall::expr(expr.id); let method_type = bcx.tcx() .method_map .borrow() @@ -1737,8 +1737,9 @@ fn deref_multiple<'a>(bcx: &'a Block<'a>, -> DatumBlock<'a, Expr> { let mut bcx = bcx; let mut datum = datum; - for i in range(1, times+1) { - datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i)); + for i in range(0, times) { + let method_call = MethodCall::autoderef(expr.id, i); + datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call)); } DatumBlock { bcx: bcx, datum: datum } } @@ -1746,22 +1747,18 @@ fn deref_multiple<'a>(bcx: &'a Block<'a>, fn deref_once<'a>(bcx: &'a Block<'a>, expr: &ast::Expr, datum: Datum, - derefs: uint) + method_call: MethodCall) -> DatumBlock<'a, Expr> { let ccx = bcx.ccx(); - debug!("deref_once(expr={}, datum={}, derefs={})", + debug!("deref_once(expr={}, datum={}, method_call={})", expr.repr(bcx.tcx()), datum.to_str(ccx), - derefs); + method_call); let mut bcx = bcx; // Check for overloaded deref. - let method_call = MethodCall { - expr_id: expr.id, - autoderef: derefs as u32 - }; let method_ty = ccx.tcx.method_map.borrow() .find(&method_call).map(|method| method.ty); let datum = match method_ty { @@ -1771,11 +1768,10 @@ fn deref_once<'a>(bcx: &'a Block<'a>, // converts from the `Shaht` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. - let datum = if derefs == 0 { - datum - } else { - // Always perform an AutoPtr when applying an overloaded auto-deref. - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) + let datum = match method_call.adjustment { + // Always perform an AutoPtr when applying an overloaded auto-deref + typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), + _ => datum }; let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, datum, None, None)); @@ -1834,8 +1830,8 @@ fn deref_once<'a>(bcx: &'a Block<'a>, } }; - debug!("deref_once(expr={}, derefs={}, result={})", - expr.id, derefs, r.datum.to_str(ccx)); + debug!("deref_once(expr={}, method_call={}, result={})", + expr.id, method_call, r.datum.to_str(ccx)); return r; diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index bde48b94473e6..85660cd2eb540 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -538,9 +538,13 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, // Store the vtable into the second half of pair. let origins = { let vtable_map = ccx.tcx.vtable_map.borrow(); - resolve_param_vtables_under_param_substs(ccx.tcx(), - bcx.fcx.param_substs, - vtable_map.get(&MethodCall::expr(id)).get_self().unwrap()) + // This trait cast might be because of implicit coercion + let method_call = match ccx.tcx.adjustments.borrow().find(&id) { + Some(&ty::AutoObject(..)) => MethodCall::autoobject(id), + _ => MethodCall::expr(id) + }; + let vres = vtable_map.get(&method_call).get_self().unwrap(); + resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) }; let vtable = get_vtable(bcx, v_ty, origins); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ac1b6ca591bec..c4e48bea85e0a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2823,7 +2823,7 @@ pub fn adjust_ty(cx: &ctxt, if !ty::type_is_error(adjusted_ty) { for i in range(0, adj.autoderefs) { - let method_call = typeck::MethodCall::autoderef(expr_id, i as u32); + let method_call = typeck::MethodCall::autoderef(expr_id, i); match method_type(method_call) { Some(method_ty) => { adjusted_ty = ty_fn_ret(method_ty); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7d647dea32278..6016bc54e0121 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1331,8 +1331,7 @@ pub fn autoderef(fcx: &FnCtxt, sp: Span, base_ty: ty::t, let mt = match ty::deref(resolved_t, false) { Some(mt) => Some(mt), None => { - let method_call = - expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32)); + let method_call = expr_id.map(|id| MethodCall::autoderef(id, autoderefs)); try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) } }; diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 1069f0a67a290..4cd319af0d9d8 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -879,7 +879,7 @@ fn constrain_autoderefs(rcx: &mut Rcx, rcx.fcx.infcx().ty_to_str(derefd_ty), i, derefs); - let method_call = MethodCall::autoderef(deref_expr.id, i as u32); + let method_call = MethodCall::autoderef(deref_expr.id, i); derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) { Some(method) => { // Treat overloaded autoderefs as if an AutoRef adjustment diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index fe79dabc3f8de..6ac6cdce8590d 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -529,7 +529,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { let _indent = indenter(); let cx = fcx.ccx; - let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t| { + let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t, key: MethodCall| { // Look up vtables for the type we're casting to, // passing in the source and target type. The source // must be a pointer type suitable to the object sigil, @@ -596,7 +596,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { if !is_early { let mut r = VecPerParamSpace::empty(); r.push(subst::SelfSpace, vtables); - insert_vtables(fcx, MethodCall::expr(ex.id), r); + insert_vtables(fcx, key, r); } // Now, if this is &trait, we need to link the @@ -694,7 +694,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { ast::ExprCast(ref src, _) => { debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); let target_ty = fcx.expr_ty(ex); - resolve_object_cast(&**src, target_ty); + let key = MethodCall::expr(ex.id); + resolve_object_cast(&**src, target_ty, key); } _ => () } @@ -705,7 +706,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { match *adjustment { AutoDerefRef(adj) => { for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(ex.id, autoderef as u32); + let method_call = MethodCall::autoderef(ex.id, autoderef); match fcx.inh.method_map.borrow().find(&method_call) { Some(method) => { debug!("vtable resolution on parameter bounds for autoderef {}", @@ -745,7 +746,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { } }; - resolve_object_cast(ex, object_ty); + let key = MethodCall::autoobject(ex.id); + resolve_object_cast(ex, object_ty, key); } AutoAddEnv(..) => {} } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index db9e90ecd509d..8e3e8e6091b2e 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -248,7 +248,7 @@ impl<'cx> WritebackCx<'cx> { ty::AutoDerefRef(adj) => { for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(id, autoderef as u32); + let method_call = MethodCall::autoderef(id, autoderef); self.visit_method_map_entry(reason, method_call); self.visit_vtable_map_entry(reason, method_call); } @@ -260,6 +260,10 @@ impl<'cx> WritebackCx<'cx> { } ty::AutoObject(trait_store, bb, def_id, substs) => { + let method_call = MethodCall::autoobject(id); + self.visit_method_map_entry(reason, method_call); + self.visit_vtable_map_entry(reason, method_call); + ty::AutoObject( self.resolve(&trait_store, reason), self.resolve(&bb, reason), diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index b5c103b84812a..bc2768ce214eb 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -149,24 +149,52 @@ pub struct MethodCallee { pub substs: subst::Substs } +/** + * With method calls, we store some extra information in + * side tables (i.e method_map, vtable_map). We use + * MethodCall as a key to index into these tables instead of + * just directly using the expression's NodeId. The reason + * for this being that we may apply adjustments (coercions) + * with the resulting expression also needing to use the + * side tables. The problem with this is that we don't + * assign a separate NodeId to this new expression + * and so it would clash with the base expression if both + * needed to add to the side tables. Thus to disambiguate + * we also keep track of whether there's an adjustment in + * our key. + */ #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct MethodCall { pub expr_id: ast::NodeId, - pub autoderef: u32 + pub adjustment: ExprAdjustment +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)] +pub enum ExprAdjustment { + NoAdjustment, + AutoDeref(uint), + AutoObject } impl MethodCall { pub fn expr(id: ast::NodeId) -> MethodCall { MethodCall { expr_id: id, - autoderef: 0 + adjustment: NoAdjustment + } + } + + pub fn autoobject(id: ast::NodeId) -> MethodCall { + MethodCall { + expr_id: id, + adjustment: AutoObject } } - pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall { + pub fn autoderef(expr_id: ast::NodeId, autoderef: uint) -> MethodCall { MethodCall { expr_id: expr_id, - autoderef: 1 + autoderef + adjustment: AutoDeref(1 + autoderef) } } } diff --git a/src/test/run-pass/deref-rc.rs b/src/test/run-pass/deref-rc.rs new file mode 100644 index 0000000000000..fbb8a3a1720f9 --- /dev/null +++ b/src/test/run-pass/deref-rc.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::rc::Rc; + +fn main() { + let x = Rc::new([1, 2, 3, 4]); + assert!(*x == [1, 2, 3, 4]); +} diff --git a/src/test/run-pass/issue-14399.rs b/src/test/run-pass/issue-14399.rs new file mode 100644 index 0000000000000..4c84d0fcaf089 --- /dev/null +++ b/src/test/run-pass/issue-14399.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// #14399 +// We'd previously ICE if we had a method call whose return +// value was coerced to a trait object. (v.clone() returns Box +// which is coerced to Box). + +#[deriving(Clone)] +struct B1; + +trait A {} +impl A for B1 {} + +fn main() { + let v = box B1; + let _c: Box = v.clone(); +} From 77657baf2c1174fc8e22ac11c0ff737c8e9a3ad7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 17 Jun 2014 22:13:36 -0700 Subject: [PATCH 08/55] Mark all crates except std as experimental --- src/liballoc/lib.rs | 1 + src/libarena/lib.rs | 1 + src/libcollections/lib.rs | 1 + src/libcore/lib.rs | 1 + src/libdebug/lib.rs | 1 + src/libflate/lib.rs | 1 + src/libfmt_macros/lib.rs | 2 +- src/libfourcc/lib.rs | 1 + src/libgetopts/lib.rs | 1 + src/libglob/lib.rs | 1 + src/libgraphviz/lib.rs | 1 + src/libgreen/lib.rs | 1 + src/libhexfloat/lib.rs | 1 + src/liblog/lib.rs | 1 + src/libnative/lib.rs | 1 + src/libnum/lib.rs | 1 + src/librustc/lib.rs | 1 + src/librustdoc/lib.rs | 1 + src/librustuv/lib.rs | 1 + src/libsemver/lib.rs | 1 + src/libserialize/lib.rs | 1 + src/libsync/lib.rs | 1 + src/libsyntax/lib.rs | 1 + src/libterm/lib.rs | 1 + src/libtest/lib.rs | 1 + src/libtime/lib.rs | 1 + src/liburl/lib.rs | 1 + src/libuuid/lib.rs | 1 + 28 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index a947378f768c9..e578346861e24 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -61,6 +61,7 @@ //! the system malloc/free. #![crate_id = "alloc#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 34264aa1b8145..86babb7a3d2e7 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -20,6 +20,7 @@ //! more complex, slower Arena which can hold objects of any type. #![crate_id = "arena#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index fde8dcd0ef5f8..3abecc3fc8622 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -13,6 +13,7 @@ */ #![crate_id = "collections#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![license = "MIT/ASL2"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5c7b588a9c9a5..62c34912f66ad 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -46,6 +46,7 @@ //! #![crate_id = "core#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libdebug/lib.rs b/src/libdebug/lib.rs index 452c3d2937cc5..5056c40a2de55 100644 --- a/src/libdebug/lib.rs +++ b/src/libdebug/lib.rs @@ -17,6 +17,7 @@ //! will persist into the future. #![crate_id = "debug#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index c9617f0da1bd7..188596891be59 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -19,6 +19,7 @@ Simple [DEFLATE][def]-based compression. This is a wrapper around the */ #![crate_id = "flate#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index aa221bde101e5..90023ab0fc505 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -15,11 +15,11 @@ //! generated instead. #![crate_id = "fmt_macros#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![feature(macro_rules, globs)] -#![experimental] use std::char; use std::str; diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs index 2d760bbad7728..a5880f3247242 100644 --- a/src/libfourcc/lib.rs +++ b/src/libfourcc/lib.rs @@ -40,6 +40,7 @@ fn main() { */ #![crate_id = "fourcc#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index e127000eb0719..0981820533ddf 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -79,6 +79,7 @@ //! ~~~ #![crate_id = "getopts#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs index a2c2706b4c2f7..495acdbab6260 100644 --- a/src/libglob/lib.rs +++ b/src/libglob/lib.rs @@ -24,6 +24,7 @@ */ #![crate_id = "glob#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index e5fb200a1c417..13342633f4c23 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -267,6 +267,7 @@ pub fn main() { */ #![crate_id = "graphviz#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs index 6c3ad8a6ef961..8024b5b75e744 100644 --- a/src/libgreen/lib.rs +++ b/src/libgreen/lib.rs @@ -198,6 +198,7 @@ //! ``` #![crate_id = "green#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs index 5451e4fc18cfe..f0f05baa28293 100644 --- a/src/libhexfloat/lib.rs +++ b/src/libhexfloat/lib.rs @@ -37,6 +37,7 @@ fn main() { */ #![crate_id = "hexfloat#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 90a186f59d2d8..ddc2872b7aec8 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -106,6 +106,7 @@ if logging is disabled, none of the components of the log will be executed. */ #![crate_id = "log#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index f04dfac80ccfe..e72d5c3b87564 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -42,6 +42,7 @@ //! ``` #![crate_id = "native#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs index 27ccc528c940d..6803b91143e44 100644 --- a/src/libnum/lib.rs +++ b/src/libnum/lib.rs @@ -45,6 +45,7 @@ #![feature(macro_rules)] #![crate_id = "num#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 680bd667c3f0d..86529cf198797 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -19,6 +19,7 @@ This API is completely unstable and subject to change. */ #![crate_id = "rustc#0.11.0-pre"] +#![experimental] #![comment = "The Rust compiler"] #![license = "MIT/ASL2"] #![crate_type = "dylib"] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c141e322fbe17..fdf38dc335ce1 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,6 +9,7 @@ // except according to those terms. #![crate_id = "rustdoc#0.11.0-pre"] +#![experimental] #![desc = "rustdoc, the Rust documentation extractor"] #![license = "MIT/ASL2"] #![crate_type = "dylib"] diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 78c2c5ff63057..dae94acb6f0af 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -35,6 +35,7 @@ via `close` and `delete` methods. */ #![crate_id = "rustuv#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/libsemver/lib.rs b/src/libsemver/lib.rs index 2ad69dad8d2c9..054a97315add0 100644 --- a/src/libsemver/lib.rs +++ b/src/libsemver/lib.rs @@ -29,6 +29,7 @@ //! `0.8.1-rc.3.0+20130922.linux`. #![crate_id = "semver#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ad622eace97b3..275e5e242d665 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -15,6 +15,7 @@ Core encoding and decoding interfaces. */ #![crate_id = "serialize#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs index 4e8617e48c339..1336ea48d3150 100644 --- a/src/libsync/lib.rs +++ b/src/libsync/lib.rs @@ -18,6 +18,7 @@ //! through `std::sync`. #![crate_id = "sync#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 8a66f0e6846e2..b18e3a221f9f3 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -19,6 +19,7 @@ This API is completely unstable and subject to change. */ #![crate_id = "syntax#0.11.0-pre"] +#![experimental] #![license = "MIT/ASL2"] #![crate_type = "dylib"] #![crate_type = "rlib"] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 4725017548598..80ece06df3add 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -39,6 +39,7 @@ //! [ti]: https://en.wikipedia.org/wiki/Terminfo #![crate_id = "term#0.11.0-pre"] +#![experimental] #![comment = "Simple ANSI color library"] #![license = "MIT/ASL2"] #![crate_type = "rlib"] diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index e7c35fb59eee5..0415c20425be1 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -24,6 +24,7 @@ // build off of. #![crate_id = "test#0.11.0-pre"] +#![experimental] #![comment = "Rust internal test library only used by rustc"] #![license = "MIT/ASL2"] #![crate_type = "rlib"] diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 79f8cd3379a9d..94a7acaf0765a 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -11,6 +11,7 @@ //! Simple time handling. #![crate_id = "time#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs index a3329a90e9b22..566602b409104 100644 --- a/src/liburl/lib.rs +++ b/src/liburl/lib.rs @@ -11,6 +11,7 @@ //! Types/fns concerning URLs (see RFC 3986) #![crate_id = "url#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index bace30e3f6ffd..e65eeb824672c 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -55,6 +55,7 @@ Examples of string representations: */ #![crate_id = "uuid#0.11.0-pre"] +#![experimental] #![crate_type = "rlib"] #![crate_type = "dylib"] #![license = "MIT/ASL2"] From bb0a42745f7a951c298b7bc2e07f7ba1fee14100 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 17 Jun 2014 17:14:55 -0400 Subject: [PATCH 09/55] fix signatures of mmap-related functions from libc --- src/libgreen/stack.rs | 2 +- src/liblibc/lib.rs | 20 ++++++++++---------- src/libstd/os.rs | 11 +++++------ 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/libgreen/stack.rs b/src/libgreen/stack.rs index 2e385f75e1d3e..526ce66b1ead8 100644 --- a/src/libgreen/stack.rs +++ b/src/libgreen/stack.rs @@ -96,7 +96,7 @@ fn protect_last_page(stack: &MemoryMap) -> bool { // This may seem backwards: the start of the segment is the last page? // Yes! The stack grows from higher addresses (the end of the allocated // block) to lower addresses (the start of the allocated block). - let last_page = stack.data as *libc::c_void; + let last_page = stack.data as *mut libc::c_void; libc::mprotect(last_page, page_size() as libc::size_t, libc::PROT_NONE) != -1 } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 05d9988a13965..2a464d82fd979 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -2057,7 +2057,7 @@ pub mod consts { pub static MAP_FIXED : c_int = 0x0010; pub static MAP_ANON : c_int = 0x0020; - pub static MAP_FAILED : *c_void = -1 as *c_void; + pub static MAP_FAILED : *mut c_void = -1 as *mut c_void; pub static MCL_CURRENT : c_int = 0x0001; pub static MCL_FUTURE : c_int = 0x0002; @@ -2268,7 +2268,7 @@ pub mod consts { pub static MAP_FIXED : c_int = 0x0010; pub static MAP_ANON : c_int = 0x0800; - pub static MAP_FAILED : *c_void = -1 as *c_void; + pub static MAP_FAILED : *mut c_void = -1 as *mut c_void; pub static MCL_CURRENT : c_int = 0x0001; pub static MCL_FUTURE : c_int = 0x0002; @@ -2804,7 +2804,7 @@ pub mod consts { pub static MAP_FIXED : c_int = 0x0010; pub static MAP_ANON : c_int = 0x1000; - pub static MAP_FAILED : *c_void = -1 as *c_void; + pub static MAP_FAILED : *mut c_void = -1 as *mut c_void; pub static MCL_CURRENT : c_int = 0x0001; pub static MCL_FUTURE : c_int = 0x0002; @@ -3192,7 +3192,7 @@ pub mod consts { pub static MAP_FIXED : c_int = 0x0010; pub static MAP_ANON : c_int = 0x1000; - pub static MAP_FAILED : *c_void = -1 as *c_void; + pub static MAP_FAILED : *mut c_void = -1 as *mut c_void; pub static MCL_CURRENT : c_int = 0x0001; pub static MCL_FUTURE : c_int = 0x0002; @@ -3951,19 +3951,19 @@ pub mod funcs { pub fn mlockall(flags: c_int) -> c_int; pub fn munlockall() -> c_int; - pub fn mmap(addr: *c_void, + pub fn mmap(addr: *mut c_void, len: size_t, prot: c_int, flags: c_int, fd: c_int, offset: off_t) -> *mut c_void; - pub fn munmap(addr: *c_void, len: size_t) -> c_int; + pub fn munmap(addr: *mut c_void, len: size_t) -> c_int; - pub fn mprotect(addr: *c_void, len: size_t, prot: c_int) + pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int; - pub fn msync(addr: *c_void, len: size_t, flags: c_int) + pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int; pub fn shm_open(name: *c_char, oflag: c_int, mode: mode_t) -> c_int; @@ -4208,9 +4208,9 @@ pub mod funcs { extern { pub fn getdtablesize() -> c_int; - pub fn madvise(addr: *c_void, len: size_t, advice: c_int) + pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int; - pub fn mincore(addr: *c_void, len: size_t, vec: *c_uchar) + pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int; } } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index dfbf61cc890b7..4d58d4674bf9a 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1338,7 +1338,6 @@ impl MemoryMap { /// `ErrZeroLength`. pub fn new(min_len: uint, options: &[MapOption]) -> Result { use libc::off_t; - use cmp::Equiv; if min_len == 0 { return Err(ErrZeroLength) @@ -1371,10 +1370,10 @@ impl MemoryMap { if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; } let r = unsafe { - libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd, - offset) + libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags, + fd, offset) }; - if r.equiv(&libc::MAP_FAILED) { + if r == libc::MAP_FAILED { Err(match errno() as c_int { libc::EACCES => ErrFdNotAvail, libc::EBADF => ErrInvalidFd, @@ -1410,8 +1409,8 @@ impl Drop for MemoryMap { if self.len == 0 { /* workaround for dummy_stack */ return; } unsafe { - // FIXME: what to do if this fails? - let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t); + // `munmap` only fails due to logic errors + libc::munmap(self.data as *mut c_void, self.len as libc::size_t); } } } From 19260b043b84dd44e2be26a66771ad621dbf1a59 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jun 2014 01:04:35 -0700 Subject: [PATCH 10/55] rustdoc: Fix testing indented code blocks The collapse/unindent passes were run in the wrong order, generating different markdown for indented tests. --- src/liballoc/owned.rs | 8 ++++++-- src/libcore/failure.rs | 4 +++- src/librustdoc/test.rs | 2 +- src/libsync/deque.rs | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/liballoc/owned.rs b/src/liballoc/owned.rs index 9377c96827261..fa7a8df5035f4 100644 --- a/src/liballoc/owned.rs +++ b/src/liballoc/owned.rs @@ -25,8 +25,12 @@ use core::result::{Ok, Err, Result}; /// /// The following two examples are equivalent: /// -/// let foo = box(HEAP) Bar::new(...); -/// let foo = box Bar::new(...); +/// use std::owned::HEAP; +/// +/// # struct Bar; +/// # impl Bar { fn new(_a: int) { } } +/// let foo = box(HEAP) Bar::new(2); +/// let foo = box Bar::new(2); #[lang="exchange_heap"] pub static HEAP: () = (); diff --git a/src/libcore/failure.rs b/src/libcore/failure.rs index 763ca843c11e9..c64bd6201faf3 100644 --- a/src/libcore/failure.rs +++ b/src/libcore/failure.rs @@ -15,7 +15,9 @@ //! useful an upstream crate must define failure for libcore to use. The current //! interface for failure is: //! -//! fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> !; +//! ```ignore +//! fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> !; +//! ``` //! //! This definition allows for failing with any general message, but it does not //! allow for failing with a `~Any` value. The reason for this is that libcore diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 907d9fc7561d4..1a24c0863a186 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -86,8 +86,8 @@ pub fn run(input: &str, let mut v = RustdocVisitor::new(&*ctx, None); v.visit(&ctx.krate); let krate = v.clean(); - let (krate, _) = passes::unindent_comments(krate); let (krate, _) = passes::collapse_docs(krate); + let (krate, _) = passes::unindent_comments(krate); let mut collector = Collector::new(krate.name.to_string(), libs, diff --git a/src/libsync/deque.rs b/src/libsync/deque.rs index 36ccf2d51782b..f0184dc816417 100644 --- a/src/libsync/deque.rs +++ b/src/libsync/deque.rs @@ -24,7 +24,7 @@ //! //! # Example //! -//! use std::rt::deque::BufferPool; +//! use std::sync::deque::BufferPool; //! //! let mut pool = BufferPool::new(); //! let (mut worker, mut stealer) = pool.deque(); From 72c08a4f8f52da100d1c3e7ffe06e9ad4f3a0e28 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jun 2014 01:07:59 -0700 Subject: [PATCH 11/55] rustdoc: Don't inject `extern crate std`. No need to duplicate the compiler's work! Closes #14999 --- src/librustdoc/test.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1a24c0863a186..02890cb6d7841 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -209,7 +209,9 @@ pub fn maketest(s: &str, cratename: Option<&str>, lints: bool) -> String { "); } - if !s.contains("extern crate") { + // Don't inject `extern crate std` because it's already injected by the + // compiler. + if !s.contains("extern crate") && cratename != Some("std") { match cratename { Some(cratename) => { if s.contains(cratename) { From e710653a3b2f0c9f7555c0a4fc01d083c7a4ce91 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jun 2014 01:13:53 -0700 Subject: [PATCH 12/55] std: Remove dual export of `Show` Closes #14996 --- src/libstd/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index af76defc8f610..7236b52783106 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -420,7 +420,7 @@ use str; use string; use slice::Vector; -pub use core::fmt::{Formatter, Result, FormatWriter, Show, rt}; +pub use core::fmt::{Formatter, Result, FormatWriter, rt}; pub use core::fmt::{Show, Bool, Char, Signed, Unsigned, Octal, Binary}; pub use core::fmt::{LowerHex, UpperHex, String, Pointer}; pub use core::fmt::{Float, LowerExp, UpperExp}; From be9c2d13815eb9aa1b6213a46542aa4262127643 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 20 May 2014 18:49:19 +0200 Subject: [PATCH 13/55] Bug fixes for flowgraph construction. 1. After recursively processing an ExprWhile, need to pop loop_scopes the same way we do for ExprLoop. 2. Proposed fix for flowgraph handling of ExprInlineAsm: we need to represent the flow into the subexpressions of an `asm!` block. --- src/librustc/middle/cfg/construct.rs | 38 ++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index f855ca37597a3..0d8729071ef6b 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -254,6 +254,7 @@ impl<'a> CFGBuilder<'a> { }); let body_exit = self.block(&**body, cond_exit); // 4 self.add_contained_edge(body_exit, loopback); // 5 + self.loop_scopes.pop(); expr_exit } @@ -427,8 +428,22 @@ impl<'a> CFGBuilder<'a> { self.straightline(expr, pred, [e]) } + ast::ExprInlineAsm(ref inline_asm) => { + let inputs = inline_asm.inputs.iter(); + let outputs = inline_asm.outputs.iter(); + fn extract_expr(&(_, expr): &(A, Gc)) -> Gc { expr } + let post_inputs = self.exprs(inputs.map(|a| { + debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a); + extract_expr(a) + }), pred); + let post_outputs = self.exprs(outputs.map(|a| { + debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a); + extract_expr(a) + }), post_inputs); + self.add_node(expr.id, [post_outputs]) + } + ast::ExprMac(..) | - ast::ExprInlineAsm(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprLit(..) | @@ -444,15 +459,22 @@ impl<'a> CFGBuilder<'a> { func_or_rcvr: Gc, args: &[Gc]) -> CFGIndex { let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); - self.straightline(call_expr, func_or_rcvr_exit, args) + let ret = self.straightline(call_expr, func_or_rcvr_exit, args); + + let return_ty = ty::node_id_to_type(self.tcx, call_expr.id); + let fails = ty::type_is_bot(return_ty); + if fails { + self.add_node(ast::DUMMY_NODE_ID, []) + } else { + ret + } } - fn exprs(&mut self, - exprs: &[Gc], - pred: CFGIndex) -> CFGIndex { + fn exprs>>(&mut self, + mut exprs: I, + pred: CFGIndex) -> CFGIndex { //! Constructs graph for `exprs` evaluated in order - - exprs.iter().fold(pred, |p, &e| self.expr(e, p)) + exprs.fold(pred, |p, e| self.expr(e, p)) } fn opt_expr(&mut self, @@ -469,7 +491,7 @@ impl<'a> CFGBuilder<'a> { subexprs: &[Gc]) -> CFGIndex { //! Handles case of an expression that evaluates `subexprs` in order - let subexprs_exit = self.exprs(subexprs, pred); + let subexprs_exit = self.exprs(subexprs.iter().map(|&e|e), pred); self.add_node(expr.id, [subexprs_exit]) } From fef63e2f237ea016b367c97dca50f35ab68c5164 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 21 May 2014 14:48:03 +0200 Subject: [PATCH 14/55] NodeIndex should derive `Show`. --- src/librustc/middle/graph.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index e3a89fe2525d2..3d5e4b167a330 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -55,7 +55,7 @@ pub struct Edge { pub data: E, } -#[deriving(PartialEq)] +#[deriving(PartialEq, Show)] pub struct NodeIndex(pub uint); pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX); From 75340f41763c4166172af24c8db676c1da97910d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 21 May 2014 14:49:16 +0200 Subject: [PATCH 15/55] Revise dataflow to do a cfg-driven walk. Fix #6298. This is instead of the prior approach of emulating cfg traversal privately by traversing AST in same way). Of special note, this removes a special case handling of `ExprParen` that was actually injecting a bug (since it was acting like an expression like `(*func)()` was consuming `*func` *twice*: once from `(*func)` and again from `*func`). nikomatsakis was the first one to point out that it might suffice to simply have the outer `ExprParen` do the consumption of the contents (alone). (This version has been updated to incorporate feedback from Niko's review of PR 14873.) --- src/librustc/middle/borrowck/mod.rs | 24 +- src/librustc/middle/borrowck/move_data.rs | 31 +- src/librustc/middle/dataflow.rs | 872 ++++++++-------------- src/librustc/middle/expr_use_visitor.rs | 19 +- src/librustc/middle/graph.rs | 2 +- 5 files changed, 340 insertions(+), 608 deletions(-) diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 18cd0b1326d96..98edc6365cf32 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -12,7 +12,9 @@ #![allow(non_camel_case_types)] +use middle::cfg; use middle::dataflow::DataFlowContext; +use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use middle::def; use euv = middle::expr_use_visitor; @@ -126,8 +128,13 @@ fn borrowck_fn(this: &mut BorrowckCtxt, let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id); let (all_loans, move_data) = gather_loans::gather_loans_in_fn(this, decl, body); + let cfg = cfg::CFG::new(this.tcx, body); + let mut loan_dfcx = DataFlowContext::new(this.tcx, + "borrowck", + Some(decl), + &cfg, LoanDataFlowOperator, id_range, all_loans.len()); @@ -135,11 +142,14 @@ fn borrowck_fn(this: &mut BorrowckCtxt, loan_dfcx.add_gen(loan.gen_scope, loan_idx); loan_dfcx.add_kill(loan.kill_scope, loan_idx); } - loan_dfcx.propagate(body); + loan_dfcx.add_kills_from_flow_exits(&cfg); + loan_dfcx.propagate(&cfg, body); let flowed_moves = move_data::FlowedMoveData::new(move_data, this.tcx, + &cfg, id_range, + decl, body); check_loans::check_loans(this, &loan_dfcx, flowed_moves, @@ -753,15 +763,17 @@ fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool { } } -impl DataFlowOperator for LoanDataFlowOperator { +impl BitwiseOperator for LoanDataFlowOperator { #[inline] - fn initial_value(&self) -> bool { - false // no loans in scope by default + fn join(&self, succ: uint, pred: uint) -> uint { + succ | pred // loans from both preds are in scope } +} +impl DataFlowOperator for LoanDataFlowOperator { #[inline] - fn join(&self, succ: uint, pred: uint) -> uint { - succ | pred // loans from both preds are in scope + fn initial_value(&self) -> bool { + false // no loans in scope by default } } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index f7c2629233484..3e2f763a84bc2 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -20,7 +20,9 @@ use std::rc::Rc; use std::uint; use std::collections::{HashMap, HashSet}; use middle::borrowck::*; +use middle::cfg; use middle::dataflow::DataFlowContext; +use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use euv = middle::expr_use_visitor; use middle::ty; @@ -499,22 +501,33 @@ impl MoveData { impl<'a> FlowedMoveData<'a> { pub fn new(move_data: MoveData, tcx: &'a ty::ctxt, + cfg: &'a cfg::CFG, id_range: ast_util::IdRange, + decl: &ast::FnDecl, body: &ast::Block) -> FlowedMoveData<'a> { let mut dfcx_moves = DataFlowContext::new(tcx, + "flowed_move_data_moves", + Some(decl), + cfg, MoveDataFlowOperator, id_range, move_data.moves.borrow().len()); let mut dfcx_assign = DataFlowContext::new(tcx, + "flowed_move_data_assigns", + Some(decl), + cfg, AssignDataFlowOperator, id_range, move_data.var_assignments.borrow().len()); move_data.add_gen_kills(tcx, &mut dfcx_moves, &mut dfcx_assign); - dfcx_moves.propagate(body); - dfcx_assign.propagate(body); + dfcx_moves.add_kills_from_flow_exits(cfg); + dfcx_assign.add_kills_from_flow_exits(cfg); + dfcx_moves.propagate(cfg, body); + dfcx_assign.propagate(cfg, body); + FlowedMoveData { move_data: move_data, dfcx_moves: dfcx_moves, @@ -659,12 +672,21 @@ impl<'a> FlowedMoveData<'a> { } } +impl BitwiseOperator for MoveDataFlowOperator { + #[inline] + fn join(&self, succ: uint, pred: uint) -> uint { + succ | pred // moves from both preds are in scope + } +} + impl DataFlowOperator for MoveDataFlowOperator { #[inline] fn initial_value(&self) -> bool { false // no loans in scope by default } +} +impl BitwiseOperator for AssignDataFlowOperator { #[inline] fn join(&self, succ: uint, pred: uint) -> uint { succ | pred // moves from both preds are in scope @@ -676,9 +698,4 @@ impl DataFlowOperator for AssignDataFlowOperator { fn initial_value(&self) -> bool { false // no assignments in scope by default } - - #[inline] - fn join(&self, succ: uint, pred: uint) -> uint { - succ | pred // moves from both preds are in scope - } } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index bc083dac6ac75..872a0878e3792 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -17,23 +17,24 @@ */ -use middle::def; +use middle::cfg; +use middle::cfg::CFGIndex; use middle::ty; -use middle::typeck; use std::io; -use std::gc::Gc; use std::uint; use syntax::ast; -use syntax::ast_util; use syntax::ast_util::IdRange; +use syntax::visit; use syntax::print::{pp, pprust}; -use util::ppaux::Repr; use util::nodemap::NodeMap; #[deriving(Clone)] pub struct DataFlowContext<'a, O> { tcx: &'a ty::ctxt, + /// a name for the analysis using this dataflow instance + analysis_name: &'static str, + /// the data flow operator oper: O, @@ -44,33 +45,39 @@ pub struct DataFlowContext<'a, O> { /// equal to bits_per_id/uint::BITS rounded up. words_per_id: uint, - // mapping from node to bitset index. - nodeid_to_bitset: NodeMap, + // mapping from cfg node index to bitset index. + index_to_bitset: Vec>, + + // mapping from node to cfg node index + // FIXME (#6298): Shouldn't this go with CFG? + nodeid_to_index: NodeMap, - // Bit sets per id. The following three fields (`gens`, `kills`, + // Bit sets per cfg node. The following three fields (`gens`, `kills`, // and `on_entry`) all have the same structure. For each id in // `id_range`, there is a range of words equal to `words_per_id`. // So, to access the bits for any given id, you take a slice of // the full vector (see the method `compute_id_range()`). - /// bits generated as we exit the scope `id`. Updated by `add_gen()`. + /// bits generated as we exit the cfg node. Updated by `add_gen()`. gens: Vec, - /// bits killed as we exit the scope `id`. Updated by `add_kill()`. + /// bits killed as we exit the cfg node. Updated by `add_kill()`. kills: Vec, - /// bits that are valid on entry to the scope `id`. Updated by + /// bits that are valid on entry to the cfg node. Updated by /// `propagate()`. on_entry: Vec, } +pub trait BitwiseOperator { + /// Joins two predecessor bits together, typically either `|` or `&` + fn join(&self, succ: uint, pred: uint) -> uint; +} + /// Parameterization for the precise form of data flow that is used. -pub trait DataFlowOperator { +pub trait DataFlowOperator : BitwiseOperator { /// Specifies the initial value for each bit in the `on_entry` set fn initial_value(&self) -> bool; - - /// Joins two predecessor bits together, typically either `|` or `&` - fn join(&self, succ: uint, pred: uint) -> uint; } struct PropagationContext<'a, 'b, O> { @@ -78,9 +85,68 @@ struct PropagationContext<'a, 'b, O> { changed: bool } -struct LoopScope<'a> { - loop_id: ast::NodeId, - break_bits: Vec +fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap) -> CFGIndex { + let opt_cfgindex = index.find(&id).map(|&i|i); + opt_cfgindex.unwrap_or_else(|| { + fail!("nodeid_to_index does not have entry for NodeId {}", id); + }) +} + +impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { + fn has_bitset(&self, n: ast::NodeId) -> bool { + assert!(n != ast::DUMMY_NODE_ID); + match self.nodeid_to_index.find(&n) { + None => false, + Some(&cfgidx) => { + let node_id = cfgidx.node_id(); + node_id < self.index_to_bitset.len() && + self.index_to_bitset.get(node_id).is_some() + } + } + } + fn get_bitset_index(&self, cfgidx: CFGIndex) -> uint { + let node_id = cfgidx.node_id(); + self.index_to_bitset.get(node_id).unwrap() + } + fn get_or_create_bitset_index(&mut self, cfgidx: CFGIndex) -> uint { + assert!(self.words_per_id > 0); + let len = self.gens.len() / self.words_per_id; + let expanded; + let n; + if self.index_to_bitset.len() <= cfgidx.node_id() { + self.index_to_bitset.grow_set(cfgidx.node_id(), &None, Some(len)); + expanded = true; + n = len; + } else { + let entry = self.index_to_bitset.get_mut(cfgidx.node_id()); + match *entry { + None => { + *entry = Some(len); + expanded = true; + n = len; + } + Some(bitidx) => { + expanded = false; + n = bitidx; + } + } + } + if expanded { + let entry = if self.oper.initial_value() { uint::MAX } else {0}; + for _ in range(0, self.words_per_id) { + self.gens.push(0); + self.kills.push(0); + self.on_entry.push(entry); + } + } + + let start = n * self.words_per_id; + let end = start + self.words_per_id; + let len = self.gens.len(); + assert!(start < len); + assert!(end <= len); + n + } } impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> { @@ -94,8 +160,9 @@ impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> { pprust::NodePat(pat) => pat.id }; - if self.nodeid_to_bitset.contains_key(&id) { - let (start, end) = self.compute_id_range_frozen(id); + if self.has_bitset(id) { + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range_frozen(cfgidx); let on_entry = self.on_entry.slice(start, end); let entry_str = bits_to_str(on_entry); @@ -121,24 +188,74 @@ impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> { } } +fn build_nodeid_to_index(decl: Option<&ast::FnDecl>, + cfg: &cfg::CFG) -> NodeMap { + let mut index = NodeMap::new(); + + // FIXME (#6298): Would it be better to fold formals from decl + // into cfg itself? i.e. introduce a fn-based flow-graph in + // addition to the current block-based flow-graph, rather than + // have to put traversals like this here? + match decl { + None => {} + Some(decl) => add_entries_from_fn_decl(&mut index, decl, cfg.entry) + } + + cfg.graph.each_node(|node_idx, node| { + if node.data.id != ast::DUMMY_NODE_ID { + index.insert(node.data.id, node_idx); + } + true + }); + + return index; + + fn add_entries_from_fn_decl(index: &mut NodeMap, + decl: &ast::FnDecl, + entry: CFGIndex) { + //! add mappings from the ast nodes for the formal bindings to + //! the entry-node in the graph. + struct Formals<'a> { + entry: CFGIndex, + index: &'a mut NodeMap, + } + let mut formals = Formals { entry: entry, index: index }; + visit::walk_fn_decl(&mut formals, decl, ()); + impl<'a> visit::Visitor<()> for Formals<'a> { + fn visit_pat(&mut self, p: &ast::Pat, e: ()) { + self.index.insert(p.id, self.entry); + visit::walk_pat(self, p, e) + } + } + } +} + impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { pub fn new(tcx: &'a ty::ctxt, + analysis_name: &'static str, + decl: Option<&ast::FnDecl>, + cfg: &cfg::CFG, oper: O, id_range: IdRange, bits_per_id: uint) -> DataFlowContext<'a, O> { let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS; - debug!("DataFlowContext::new(id_range={:?}, bits_per_id={:?}, words_per_id={:?})", - id_range, bits_per_id, words_per_id); + debug!("DataFlowContext::new(analysis_name: {:s}, id_range={:?}, \ + bits_per_id={:?}, words_per_id={:?})", + analysis_name, id_range, bits_per_id, words_per_id); let gens = Vec::new(); let kills = Vec::new(); let on_entry = Vec::new(); + let nodeid_to_index = build_nodeid_to_index(decl, cfg); + DataFlowContext { tcx: tcx, + analysis_name: analysis_name, words_per_id: words_per_id, - nodeid_to_bitset: NodeMap::new(), + index_to_bitset: Vec::new(), + nodeid_to_index: nodeid_to_index, bits_per_id: bits_per_id, oper: oper, gens: gens, @@ -149,74 +266,60 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { pub fn add_gen(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` generates `bit` - - debug!("add_gen(id={:?}, bit={:?})", id, bit); - let (start, end) = self.compute_id_range(id); - { - let gens = self.gens.mut_slice(start, end); - set_bit(gens, bit); + if self.nodeid_to_index.contains_key(&id) { + debug!("add_gen(id={:?}, bit={:?})", id, bit); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range(cfgidx); + { + let gens = self.gens.mut_slice(start, end); + set_bit(gens, bit); + } + } else { + debug!("{:s} add_gen skip (id={:?}, bit={:?}); id not in current fn", + self.analysis_name, id, bit); } } pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` kills `bit` - - debug!("add_kill(id={:?}, bit={:?})", id, bit); - let (start, end) = self.compute_id_range(id); - { - let kills = self.kills.mut_slice(start, end); - set_bit(kills, bit); + if self.nodeid_to_index.contains_key(&id) { + debug!("add_kill(id={:?}, bit={:?})", id, bit); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range(cfgidx); + { + let kills = self.kills.mut_slice(start, end); + set_bit(kills, bit); + } + } else { + debug!("{:s} add_kill skip (id={:?}, bit={:?}); id not in current fn", + self.analysis_name, id, bit); } } - fn apply_gen_kill(&mut self, id: ast::NodeId, bits: &mut [uint]) { + fn apply_gen_kill(&mut self, cfgidx: CFGIndex, bits: &mut [uint]) { //! Applies the gen and kill sets for `id` to `bits` - - debug!("apply_gen_kill(id={:?}, bits={}) [before]", - id, mut_bits_to_str(bits)); - let (start, end) = self.compute_id_range(id); + debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]", + self.analysis_name, cfgidx, mut_bits_to_str(bits)); + let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.slice(start, end); - bitwise(bits, gens, |a, b| a | b); + bitwise(bits, gens, &Union); let kills = self.kills.slice(start, end); - bitwise(bits, kills, |a, b| a & !b); - - debug!("apply_gen_kill(id={:?}, bits={}) [after]", - id, mut_bits_to_str(bits)); - } + bitwise(bits, kills, &Subtract); - fn apply_kill(&mut self, id: ast::NodeId, bits: &mut [uint]) { - debug!("apply_kill(id={:?}, bits={}) [before]", - id, mut_bits_to_str(bits)); - let (start, end) = self.compute_id_range(id); - let kills = self.kills.slice(start, end); - bitwise(bits, kills, |a, b| a & !b); - debug!("apply_kill(id={:?}, bits={}) [after]", - id, mut_bits_to_str(bits)); + debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [after]", + self.analysis_name, cfgidx, mut_bits_to_str(bits)); } - fn compute_id_range_frozen(&self, id: ast::NodeId) -> (uint, uint) { - let n = *self.nodeid_to_bitset.get(&id); + fn compute_id_range_frozen(&self, cfgidx: CFGIndex) -> (uint, uint) { + let n = self.get_bitset_index(cfgidx); let start = n * self.words_per_id; let end = start + self.words_per_id; (start, end) } - fn compute_id_range(&mut self, id: ast::NodeId) -> (uint, uint) { - let mut expanded = false; - let len = self.nodeid_to_bitset.len(); - let n = self.nodeid_to_bitset.find_or_insert_with(id, |_| { - expanded = true; - len - }); - if expanded { - let entry = if self.oper.initial_value() { uint::MAX } else {0}; - for _ in range(0, self.words_per_id) { - self.gens.push(0); - self.kills.push(0); - self.on_entry.push(entry); - } - } - let start = *n * self.words_per_id; + fn compute_id_range(&mut self, cfgidx: CFGIndex) -> (uint, uint) { + let n = self.get_or_create_bitset_index(cfgidx); + let start = n * self.words_per_id; let end = start + self.words_per_id; assert!(start < self.gens.len()); @@ -234,26 +337,28 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { -> bool { //! Iterates through each bit that is set on entry to `id`. //! Only useful after `propagate()` has been called. - if !self.nodeid_to_bitset.contains_key(&id) { + if !self.has_bitset(id) { return true; } - let (start, end) = self.compute_id_range_frozen(id); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range_frozen(cfgidx); let on_entry = self.on_entry.slice(start, end); - debug!("each_bit_on_entry_frozen(id={:?}, on_entry={})", - id, bits_to_str(on_entry)); + debug!("{:s} each_bit_on_entry_frozen(id={:?}, on_entry={})", + self.analysis_name, id, bits_to_str(on_entry)); self.each_bit(on_entry, f) } pub fn each_gen_bit_frozen(&self, id: ast::NodeId, f: |uint| -> bool) -> bool { //! Iterates through each bit in the gen set for `id`. - if !self.nodeid_to_bitset.contains_key(&id) { + if !self.has_bitset(id) { return true; } - let (start, end) = self.compute_id_range_frozen(id); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range_frozen(cfgidx); let gens = self.gens.slice(start, end); - debug!("each_gen_bit(id={:?}, gens={})", - id, bits_to_str(gens)); + debug!("{:s} each_gen_bit(id={:?}, gens={})", + self.analysis_name, id, bits_to_str(gens)); self.each_bit(gens, f) } @@ -287,11 +392,63 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { } return true; } + + pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) { + //! Whenever you have a `break` or `continue` statement, flow + //! exits through any number of enclosing scopes on its way to + //! the new destination. This function infers the kill bits of + //! those control operators based on the kill bits associated + //! with those scopes. + //! + //! This is usually called (if it is called at all), after + //! all add_gen and add_kill calls, but before propagate. + + debug!("{:s} add_kills_from_flow_exits", self.analysis_name); + if self.bits_per_id == 0 { + // Skip the surprisingly common degenerate case. (Note + // compute_id_range requires self.words_per_id > 0.) + return; + } + cfg.graph.each_edge(|_edge_index, edge| { + let flow_exit = edge.source(); + let (start, end) = self.compute_id_range(flow_exit); + let mut orig_kills = self.kills.slice(start, end).to_owned(); + + let mut changed = false; + for &node_id in edge.data.exiting_scopes.iter() { + let opt_cfg_idx = self.nodeid_to_index.find(&node_id).map(|&i|i); + match opt_cfg_idx { + Some(cfg_idx) => { + let (start, end) = self.compute_id_range(cfg_idx); + let kills = self.kills.slice(start, end); + if bitwise(orig_kills.as_mut_slice(), kills, &Union) { + changed = true; + } + } + None => { + debug!("{:s} add_kills_from_flow_exits flow_exit={} \ + no cfg_idx for exiting_scope={:?}", + self.analysis_name, flow_exit, node_id); + } + } + } + + if changed { + let bits = self.kills.mut_slice(start, end); + debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [before]", + self.analysis_name, flow_exit, mut_bits_to_str(bits)); + bits.copy_from(orig_kills.as_slice()); + debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [after]", + self.analysis_name, flow_exit, mut_bits_to_str(bits)); + } + true + }); + } } impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> { // ^^^^^^^^^^^^^ only needed for pretty printing - pub fn propagate(&mut self, blk: &ast::Block) { + pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &ast::Block) { //! Performs the data flow analysis. if self.bits_per_id == 0 { @@ -307,16 +464,14 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> { }; let mut temp = Vec::from_elem(words_per_id, 0u); - let mut loop_scopes = Vec::new(); - while propcx.changed { propcx.changed = false; propcx.reset(temp.as_mut_slice()); - propcx.walk_block(blk, temp.as_mut_slice(), &mut loop_scopes); + propcx.walk_cfg(cfg, temp.as_mut_slice()); } } - debug!("Dataflow result:"); + debug!("Dataflow result for {:s}:", self.analysis_name); debug!("{}", { self.pretty_print_to(box io::stderr(), blk).unwrap(); "" @@ -334,462 +489,30 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> { } impl<'a, 'b, O:DataFlowOperator> PropagationContext<'a, 'b, O> { - fn tcx(&self) -> &'b ty::ctxt { - self.dfcx.tcx - } - - fn walk_block(&mut self, - blk: &ast::Block, - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - debug!("DataFlowContext::walk_block(blk.id={}, in_out={})", - blk.id, bits_to_str(in_out)); - - self.merge_with_entry_set(blk.id, in_out); - - for stmt in blk.stmts.iter() { - self.walk_stmt(stmt.clone(), in_out, loop_scopes); - } - - self.walk_opt_expr(blk.expr, in_out, loop_scopes); - - self.dfcx.apply_gen_kill(blk.id, in_out); - } - - fn walk_stmt(&mut self, - stmt: Gc, - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - match stmt.node { - ast::StmtDecl(ref decl, _) => { - self.walk_decl(decl.clone(), in_out, loop_scopes); - } - - ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => { - self.walk_expr(&**expr, in_out, loop_scopes); - } - - ast::StmtMac(..) => { - self.tcx().sess.span_bug(stmt.span, "unexpanded macro"); - } - } - } - - fn walk_decl(&mut self, - decl: Gc, - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - match decl.node { - ast::DeclLocal(ref local) => { - self.walk_opt_expr(local.init, in_out, loop_scopes); - self.walk_pat(local.pat, in_out, loop_scopes); - } - - ast::DeclItem(_) => {} - } - } - - fn walk_expr(&mut self, - expr: &ast::Expr, - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - debug!("DataFlowContext::walk_expr(expr={}, in_out={})", - expr.repr(self.dfcx.tcx), bits_to_str(in_out)); - - self.merge_with_entry_set(expr.id, in_out); - - match expr.node { - ast::ExprFnBlock(..) | ast::ExprProc(..) => { - } - - ast::ExprIf(cond, then, els) => { - // - // (cond) - // | - // v - // ( ) - // / \ - // | | - // v v - // (then)(els) - // | | - // v v - // ( succ ) - // - self.walk_expr(&*cond, in_out, loop_scopes); - - let mut then_bits = in_out.to_owned(); - self.walk_block(&*then, then_bits.as_mut_slice(), loop_scopes); - - self.walk_opt_expr(els, in_out, loop_scopes); - join_bits(&self.dfcx.oper, then_bits.as_slice(), in_out); - } - - ast::ExprWhile(cond, blk) => { - // - // (expr) <--+ - // | | - // v | - // +--(cond) | - // | | | - // | v | - // v (blk) ----+ - // | - // <--+ (break) - // - - self.walk_expr(&*cond, in_out, loop_scopes); - - let mut body_bits = in_out.to_owned(); - loop_scopes.push(LoopScope { - loop_id: expr.id, - break_bits: Vec::from_slice(in_out) - }); - self.walk_block(&*blk, body_bits.as_mut_slice(), loop_scopes); - self.add_to_entry_set(expr.id, body_bits.as_slice()); - let new_loop_scope = loop_scopes.pop().unwrap(); - copy_bits(new_loop_scope.break_bits.as_slice(), in_out); - } - - ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"), - - ast::ExprLoop(ref blk, _) => { - // - // (expr) <--+ - // | | - // v | - // (blk) ----+ - // | - // <--+ (break) - // - - let mut body_bits = in_out.to_owned(); - self.reset(in_out); - loop_scopes.push(LoopScope { - loop_id: expr.id, - break_bits: Vec::from_slice(in_out) - }); - self.walk_block(&**blk, body_bits.as_mut_slice(), loop_scopes); - self.add_to_entry_set(expr.id, body_bits.as_slice()); - - let new_loop_scope = loop_scopes.pop().unwrap(); - assert_eq!(new_loop_scope.loop_id, expr.id); - copy_bits(new_loop_scope.break_bits.as_slice(), in_out); - } - - ast::ExprMatch(ref discr, ref arms) => { - // - // (discr) - // / | \ - // | | | - // v v v - // (..arms..) - // | | | - // v v v - // ( succ ) - // - // - self.walk_expr(&**discr, in_out, loop_scopes); - - let mut guards = in_out.to_owned(); - - // We know that exactly one arm will be taken, so we - // can start out with a blank slate and just union - // together the bits from each arm: - self.reset(in_out); - - for arm in arms.iter() { - // in_out reflects the discr and all guards to date - self.walk_opt_expr(arm.guard, guards.as_mut_slice(), - loop_scopes); - - // determine the bits for the body and then union - // them into `in_out`, which reflects all bodies to date - let mut body = guards.to_owned(); - self.walk_pat_alternatives(arm.pats.as_slice(), - body.as_mut_slice(), - loop_scopes); - self.walk_expr(&*arm.body, body.as_mut_slice(), loop_scopes); - join_bits(&self.dfcx.oper, body.as_slice(), in_out); - } - } - - ast::ExprRet(o_e) => { - self.walk_opt_expr(o_e, in_out, loop_scopes); - self.reset(in_out); - } - - ast::ExprBreak(label) => { - let scope = self.find_scope(expr, label, loop_scopes); - self.break_from_to(expr, scope, in_out); - self.reset(in_out); - } - - ast::ExprAgain(label) => { - let scope = self.find_scope(expr, label, loop_scopes); - self.pop_scopes(expr, scope, in_out); - self.add_to_entry_set(scope.loop_id, in_out); - self.reset(in_out); - } - - ast::ExprAssign(ref l, ref r) | - ast::ExprAssignOp(_, ref l, ref r) => { - self.walk_expr(&**r, in_out, loop_scopes); - self.walk_expr(&**l, in_out, loop_scopes); - } - - ast::ExprVec(ref exprs) => { - self.walk_exprs(exprs.as_slice(), in_out, loop_scopes) - } - - ast::ExprRepeat(ref l, ref r) => { - self.walk_expr(&**l, in_out, loop_scopes); - self.walk_expr(&**r, in_out, loop_scopes); - } - - ast::ExprStruct(_, ref fields, with_expr) => { - for field in fields.iter() { - self.walk_expr(&*field.expr, in_out, loop_scopes); - } - self.walk_opt_expr(with_expr, in_out, loop_scopes); - } - - ast::ExprCall(ref f, ref args) => { - self.walk_expr(&**f, in_out, loop_scopes); - self.walk_call(expr.id, args.as_slice(), in_out, loop_scopes); - } - - ast::ExprMethodCall(_, _, ref args) => { - self.walk_call(expr.id, args.as_slice(), in_out, loop_scopes); - } - - ast::ExprIndex(l, r) | - ast::ExprBinary(_, l, r) if self.is_method_call(expr) => { - self.walk_call(expr.id, [l, r], in_out, loop_scopes); - } - - ast::ExprUnary(_, e) if self.is_method_call(expr) => { - self.walk_call(expr.id, [e], in_out, loop_scopes); - } - - ast::ExprTup(ref exprs) => { - self.walk_exprs(exprs.as_slice(), in_out, loop_scopes); - } - - ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op) => { - self.walk_expr(&**l, in_out, loop_scopes); - let temp = in_out.to_owned(); - self.walk_expr(&**r, in_out, loop_scopes); - join_bits(&self.dfcx.oper, temp.as_slice(), in_out); - } - - ast::ExprIndex(l, r) | - ast::ExprBinary(_, l, r) => { - self.walk_exprs([l, r], in_out, loop_scopes); - } - - ast::ExprLit(..) | - ast::ExprPath(..) => {} - - ast::ExprAddrOf(_, ref e) | - ast::ExprCast(ref e, _) | - ast::ExprUnary(_, ref e) | - ast::ExprParen(ref e) | - ast::ExprVstore(ref e, _) | - ast::ExprField(ref e, _, _) => { - self.walk_expr(&**e, in_out, loop_scopes); - } - - ast::ExprBox(ref s, ref e) => { - self.walk_expr(&**s, in_out, loop_scopes); - self.walk_expr(&**e, in_out, loop_scopes); - } - - ast::ExprInlineAsm(ref inline_asm) => { - for &(_, ref expr) in inline_asm.inputs.iter() { - self.walk_expr(&**expr, in_out, loop_scopes); - } - for &(_, ref expr) in inline_asm.outputs.iter() { - self.walk_expr(&**expr, in_out, loop_scopes); - } - } - - ast::ExprBlock(ref blk) => { - self.walk_block(&**blk, in_out, loop_scopes); - } - - ast::ExprMac(..) => { - self.tcx().sess.span_bug(expr.span, "unexpanded macro"); - } - } - - self.dfcx.apply_gen_kill(expr.id, in_out); - } - - fn pop_scopes(&mut self, - from_expr: &ast::Expr, - to_scope: &mut LoopScope, - in_out: &mut [uint]) { - //! Whenever you have a `break` or a `loop` statement, flow - //! exits through any number of enclosing scopes on its - //! way to the new destination. This function applies the kill - //! sets of those enclosing scopes to `in_out` (those kill sets - //! concern items that are going out of scope). - - let tcx = self.tcx(); - - debug!("pop_scopes(from_expr={}, to_scope={:?}, in_out={})", - from_expr.repr(tcx), to_scope.loop_id, - bits_to_str(in_out)); - - let mut id = from_expr.id; - while id != to_scope.loop_id { - self.dfcx.apply_kill(id, in_out); - - match tcx.region_maps.opt_encl_scope(id) { - Some(i) => { id = i; } - None => { - tcx.sess.span_bug( - from_expr.span, - format!("pop_scopes(from_expr={}, to_scope={:?}) \ - to_scope does not enclose from_expr", - from_expr.repr(tcx), - to_scope.loop_id).as_slice()); - } - } - } - } - - fn break_from_to(&mut self, - from_expr: &ast::Expr, - to_scope: &mut LoopScope, - in_out: &mut [uint]) { - self.pop_scopes(from_expr, to_scope, in_out); - self.dfcx.apply_kill(from_expr.id, in_out); - join_bits(&self.dfcx.oper, - in_out, - to_scope.break_bits.as_mut_slice()); - debug!("break_from_to(from_expr={}, to_scope={}) final break_bits={}", - from_expr.repr(self.tcx()), - to_scope.loop_id, - bits_to_str(in_out)); - } - - fn walk_exprs(&mut self, - exprs: &[Gc], - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - for expr in exprs.iter() { - self.walk_expr(&**expr, in_out, loop_scopes); - } - } - - fn walk_opt_expr(&mut self, - opt_expr: Option>, - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - for expr in opt_expr.iter() { - self.walk_expr(&**expr, in_out, loop_scopes); - } - } - - fn walk_call(&mut self, - call_id: ast::NodeId, - args: &[Gc], - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - self.walk_exprs(args, in_out, loop_scopes); - - // FIXME(#6268) nested method calls - // self.merge_with_entry_set(in_out); - // self.dfcx.apply_gen_kill(in_out); - - let return_ty = ty::node_id_to_type(self.tcx(), call_id); - let fails = ty::type_is_bot(return_ty); - if fails { - self.reset(in_out); - } - } - - fn walk_pat(&mut self, - pat: Gc, - in_out: &mut [uint], - _loop_scopes: &mut Vec ) { - debug!("DataFlowContext::walk_pat(pat={}, in_out={})", - pat.repr(self.dfcx.tcx), bits_to_str(in_out)); - - ast_util::walk_pat(&*pat, |p| { - debug!(" p.id={} in_out={}", p.id, bits_to_str(in_out)); - self.merge_with_entry_set(p.id, in_out); - self.dfcx.apply_gen_kill(p.id, in_out); - true + fn walk_cfg(&mut self, + cfg: &cfg::CFG, + in_out: &mut [uint]) { + debug!("DataFlowContext::walk_cfg(in_out={}) {:s}", + bits_to_str(in_out), self.dfcx.analysis_name); + cfg.graph.each_node(|node_index, node| { + debug!("DataFlowContext::walk_cfg idx={} id={} begin in_out={}", + node_index, node.data.id, bits_to_str(in_out)); + + let (start, end) = self.dfcx.compute_id_range(node_index); + + // Initialize local bitvector with state on-entry. + in_out.copy_from(self.dfcx.on_entry.slice(start, end)); + + // Compute state on-exit by applying transfer function to + // state on-entry. + self.dfcx.apply_gen_kill(node_index, in_out); + + // Propagate state on-exit from node into its successors. + self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index); + true // continue to next node }); } - fn walk_pat_alternatives(&mut self, - pats: &[Gc], - in_out: &mut [uint], - loop_scopes: &mut Vec ) { - if pats.len() == 1 { - // Common special case: - return self.walk_pat(pats[0], in_out, loop_scopes); - } - - // In the general case, the patterns in `pats` are - // alternatives, so we must treat this like an N-way select - // statement. - let initial_state = in_out.to_owned(); - for &pat in pats.iter() { - let mut temp = initial_state.clone(); - self.walk_pat(pat, temp.as_mut_slice(), loop_scopes); - join_bits(&self.dfcx.oper, temp.as_slice(), in_out); - } - } - - fn find_scope<'a,'b>( - &self, - expr: &ast::Expr, - label: Option, - loop_scopes: &'a mut Vec>) - -> &'a mut LoopScope<'b> { - let index = match label { - None => { - let len = loop_scopes.len(); - len - 1 - } - - Some(_) => { - match self.tcx().def_map.borrow().find(&expr.id) { - Some(&def::DefLabel(loop_id)) => { - match loop_scopes.iter().position(|l| l.loop_id == loop_id) { - Some(i) => i, - None => { - self.tcx().sess.span_bug( - expr.span, - format!("no loop scope for id {:?}", - loop_id).as_slice()); - } - } - } - - r => { - self.tcx().sess.span_bug( - expr.span, - format!("bad entry `{:?}` in def_map for label", - r).as_slice()); - } - } - } - }; - - loop_scopes.get_mut(index) - } - - fn is_method_call(&self, expr: &ast::Expr) -> bool { - let method_call = typeck::MethodCall::expr(expr.id); - self.dfcx.tcx.method_map.borrow().contains_key(&method_call) - } - fn reset(&mut self, bits: &mut [uint]) { let e = if self.dfcx.oper.initial_value() {uint::MAX} else {0}; for b in bits.mut_iter() { @@ -797,36 +520,33 @@ impl<'a, 'b, O:DataFlowOperator> PropagationContext<'a, 'b, O> { } } - fn add_to_entry_set(&mut self, id: ast::NodeId, pred_bits: &[uint]) { - debug!("add_to_entry_set(id={:?}, pred_bits={})", - id, bits_to_str(pred_bits)); - let (start, end) = self.dfcx.compute_id_range(id); - let changed = { // FIXME(#5074) awkward construction - let on_entry = self.dfcx.on_entry.mut_slice(start, end); - join_bits(&self.dfcx.oper, pred_bits, on_entry) - }; - if changed { - debug!("changed entry set for {:?} to {}", - id, bits_to_str(self.dfcx.on_entry.slice(start, end))); - self.changed = true; - } + fn propagate_bits_into_graph_successors_of(&mut self, + pred_bits: &[uint], + cfg: &cfg::CFG, + cfgidx: CFGIndex) { + cfg.graph.each_outgoing_edge(cfgidx, |_e_idx, edge| { + self.propagate_bits_into_entry_set_for(pred_bits, edge); + true + }); } - fn merge_with_entry_set(&mut self, - id: ast::NodeId, - pred_bits: &mut [uint]) { - debug!("merge_with_entry_set(id={:?}, pred_bits={})", - id, mut_bits_to_str(pred_bits)); - let (start, end) = self.dfcx.compute_id_range(id); - let changed = { // FIXME(#5074) awkward construction + fn propagate_bits_into_entry_set_for(&mut self, + pred_bits: &[uint], + edge: &cfg::CFGEdge) { + let source = edge.source(); + let cfgidx = edge.target(); + debug!("{:s} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", + self.dfcx.analysis_name, bits_to_str(pred_bits), source, cfgidx); + let (start, end) = self.dfcx.compute_id_range(cfgidx); + let changed = { + // (scoping mutable borrow of self.dfcx.on_entry) let on_entry = self.dfcx.on_entry.mut_slice(start, end); - let changed = join_bits(&self.dfcx.oper, pred_bits, on_entry); - copy_bits(on_entry, pred_bits); - changed + bitwise(on_entry, pred_bits, &self.dfcx.oper) }; if changed { - debug!("changed entry set for {:?} to {}", - id, bits_to_str(self.dfcx.on_entry.slice(start, end))); + debug!("{:s} changed entry set for {:?} to {}", + self.dfcx.analysis_name, cfgidx, + bits_to_str(self.dfcx.on_entry.slice(start, end))); self.changed = true; } } @@ -855,24 +575,15 @@ fn bits_to_str(words: &[uint]) -> String { return result } -fn copy_bits(in_vec: &[uint], out_vec: &mut [uint]) -> bool { - bitwise(out_vec, in_vec, |_, b| b) -} - -fn join_bits(oper: &O, - in_vec: &[uint], - out_vec: &mut [uint]) -> bool { - bitwise(out_vec, in_vec, |a, b| oper.join(a, b)) -} - #[inline] -fn bitwise(out_vec: &mut [uint], in_vec: &[uint], op: |uint, uint| -> uint) - -> bool { +fn bitwise(out_vec: &mut [uint], + in_vec: &[uint], + op: &Op) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) { let old_val = *out_elt; - let new_val = op(old_val, *in_elt); + let new_val = op.join(old_val, *in_elt); *out_elt = new_val; changed |= old_val != new_val; } @@ -897,3 +608,12 @@ fn bit_str(bit: uint) -> String { let lobits = 1 << (bit & 0xFF); format!("[{}:{}-{:02x}]", bit, byte, lobits) } + +struct Union; +impl BitwiseOperator for Union { + fn join(&self, a: uint, b: uint) -> uint { a | b } +} +struct Subtract; +impl BitwiseOperator for Subtract { + fn join(&self, a: uint, b: uint) -> uint { a & !b } +} diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 86cd3c53804de..ad058ab6b5f1d 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -186,24 +186,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { let cmt = return_if_err!(self.mc.cat_expr(expr)); self.delegate_consume(expr.id, expr.span, cmt); - - match expr.node { - ast::ExprParen(ref subexpr) => { - // Argh but is ExprParen horrible. So, if we consume - // `(x)`, that generally is also consuming `x`, UNLESS - // there are adjustments on the `(x)` expression - // (e.g., autoderefs and autorefs). - if self.typer.adjustments().borrow().contains_key(&expr.id) { - self.walk_expr(expr); - } else { - self.consume_expr(&**subexpr); - } - } - - _ => { - self.walk_expr(expr) - } - } + self.walk_expr(expr); } fn mutate_expr(&mut self, diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 3d5e4b167a330..b1f9b0bff9fd2 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -55,7 +55,7 @@ pub struct Edge { pub data: E, } -#[deriving(PartialEq, Show)] +#[deriving(Clone, PartialEq, Show)] pub struct NodeIndex(pub uint); pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX); From 4d82456f69d858bb8ebd7bfc508365cf983eea54 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 21 May 2014 14:48:33 +0200 Subject: [PATCH 16/55] middle::cfg code cleanup. Namely: 1. Now that cfg mod is used for dataflow, we do not need to turn on the `allow(deadcode)` to placate the linter. 2. remove dead struct defn. --- src/librustc/middle/cfg/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index f0b912fb87bbf..bb758ec7c38b7 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -15,8 +15,6 @@ Uses `Graph` as the underlying representation. */ -#![allow(dead_code)] // still a WIP, #6298 - use middle::graph; use middle::ty; use syntax::ast; @@ -48,11 +46,6 @@ pub type CFGNode = graph::Node; pub type CFGEdge = graph::Edge; -pub struct CFGIndices { - entry: CFGIndex, - exit: CFGIndex, -} - impl CFG { pub fn new(tcx: &ty::ctxt, blk: &ast::Block) -> CFG { From 263a433f1901592f91e6433ccc79539e619cd95f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 13 Jun 2014 17:19:29 +0200 Subject: [PATCH 17/55] Ensure dataflow of a proc never looks at blocks from closed-over context. Details: in a program like: ``` type T = proc(int) -> int; /* 4 */ pub fn outer(captured /* pat 16 */: T) -> T { (proc(x /* pat 23 */) { ((captured /* 29 */).foo((x /* 30 */)) /* 28 */) } /* block 27 */ /* 20 */) } /* block 19 */ /* 12 */ ``` the `captured` arg is moved from the outer fn into the inner proc (id=20). The old dataflow analysis for flowed_move_data_moves, when looking at the inner proc, would attempt to add a kill bit for `captured` at the end of its scope; the problem is that it thought the end of the `captured` arg's scope was the outer fn (id=12), even though at that point in the analysis, the `captured` arg's scope should now be restricted to the proc itself (id=20). This patch fixes handling of upvars so that dataflow of a fn/proc should never attempts to add a gen or kill bit to any NodeId outside of the current fn/proc. It accomplishes this by adding an `LpUpvar` variant to `borrowck::LoanPath`, so for cases like `captured` above will carry both their original `var_id`, as before, as well as the `NodeId` for the closure that is capturing them. As a drive-by fix to another occurrence of a similar bug that nikomatsakis pointed out to me earlier, this also fixes `gather_loans::compute_kill_scope` so that it computes the kill scope of the `captured` arg to be block 27; that is, the block for the proc itself (id=20). (This is an updated version that generalizes the new loan path variant to cover all upvars, and thus renamed the variant from `LpCopiedUpvar` to just `LpUpvar`.) --- src/librustc/middle/borrowck/check_loans.rs | 4 +- .../middle/borrowck/gather_loans/mod.rs | 5 ++- .../borrowck/gather_loans/restrictions.rs | 17 ++++++-- src/librustc/middle/borrowck/mod.rs | 42 +++++++++++++++---- src/librustc/middle/borrowck/move_data.rs | 13 +++++- src/librustc/middle/dataflow.rs | 38 +++++++---------- src/librustc/middle/mem_categorization.rs | 5 ++- 7 files changed, 82 insertions(+), 42 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 166d069880f9f..df208b9cdc133 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -242,7 +242,7 @@ impl<'a> CheckLoanCtxt<'a> { let mut loan_path = loan_path; loop { match *loan_path { - LpVar(_) => { + LpVar(_) | LpUpvar(_) => { break; } LpExtend(ref lp_base, _, _) => { @@ -632,7 +632,7 @@ impl<'a> CheckLoanCtxt<'a> { */ match **lp { - LpVar(_) => { + LpVar(_) | LpUpvar(_) => { // assigning to `x` does not require that `x` is initialized } LpExtend(ref lp_base, _, LpInterior(_)) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 89f304513ffb3..454c3dcd5d3ca 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -395,7 +395,8 @@ impl<'a> GatherLoanCtxt<'a> { //! from a local variable, mark the mutability decl as necessary. match *loan_path { - LpVar(local_id) => { + LpVar(local_id) | + LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => { self.tcx().used_mut_nodes.borrow_mut().insert(local_id); } LpExtend(ref base, mc::McInherited, _) => { @@ -445,8 +446,8 @@ impl<'a> GatherLoanCtxt<'a> { //! with immutable `&` pointers, because borrows of such pointers //! do not require restrictions and hence do not cause a loan. + let lexical_scope = lp.kill_scope(self.bccx.tcx); let rm = &self.bccx.tcx.region_maps; - let lexical_scope = rm.var_scope(lp.node_id()); if rm.is_subscope_of(lexical_scope, loan_scope) { lexical_scope } else { diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 5b3e1ac0b2c74..d131b6f7eda29 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -67,13 +67,23 @@ impl<'a> RestrictionsContext<'a> { } mc::cat_local(local_id) | - mc::cat_arg(local_id) | - mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => { - // R-Variable + mc::cat_arg(local_id) => { + // R-Variable, locally declared let lp = Rc::new(LpVar(local_id)); SafeIf(lp.clone(), vec!(lp)) } + mc::cat_upvar(upvar_id, _) => { + // R-Variable, captured into closure + let lp = Rc::new(LpUpvar(upvar_id)); + SafeIf(lp.clone(), vec!(lp)) + } + + mc::cat_copied_upvar(..) => { + // FIXME(#2152) allow mutation of upvars + Safe + } + mc::cat_downcast(cmt_base) => { // When we borrow the interior of an enum, we have to // ensure the enum itself is not mutated, because that @@ -107,7 +117,6 @@ impl<'a> RestrictionsContext<'a> { self.extend(result, cmt.mutbl, LpDeref(pk)) } - mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars mc::cat_static_item(..) => { Safe } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 98edc6365cf32..0c77e63779074 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -201,6 +201,7 @@ pub struct Loan { #[deriving(PartialEq, Eq, Hash)] pub enum LoanPath { LpVar(ast::NodeId), // `x` in doc.rs + LpUpvar(ty::UpvarId), // `x` captured by-value into closure LpExtend(Rc, mc::MutabilityCategory, LoanPathElem) } @@ -210,11 +211,25 @@ pub enum LoanPathElem { LpInterior(mc::InteriorKind) // `LV.f` in doc.rs } +pub fn closure_to_block(closure_id: ast::NodeId, + tcx: &ty::ctxt) -> ast::NodeId { + match tcx.map.get(closure_id) { + ast_map::NodeExpr(expr) => match expr.node { + ast::ExprProc(_decl, block) | + ast::ExprFnBlock(_decl, block) => { block.id } + _ => fail!("encountered non-closure id: {}", closure_id) + }, + _ => fail!("encountered non-expr id: {}", closure_id) + } +} + impl LoanPath { - pub fn node_id(&self) -> ast::NodeId { + pub fn kill_scope(&self, tcx: &ty::ctxt) -> ast::NodeId { match *self { - LpVar(local_id) => local_id, - LpExtend(ref base, _, _) => base.node_id() + LpVar(local_id) => tcx.region_maps.var_scope(local_id), + LpUpvar(upvar_id) => + closure_to_block(upvar_id.closure_expr_id, tcx), + LpExtend(ref base, _, _) => base.kill_scope(tcx), } } } @@ -234,12 +249,18 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option> { } mc::cat_local(id) | - mc::cat_arg(id) | - mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, .. }) | - mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => { + mc::cat_arg(id) => { Some(Rc::new(LpVar(id))) } + mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) | + mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, + onceness: _, + capturing_proc: proc_id }) => { + let upvar_id = ty::UpvarId{ var_id: id, closure_expr_id: proc_id }; + Some(Rc::new(LpUpvar(upvar_id))) + } + mc::cat_deref(ref cmt_base, _, pk) => { opt_loan_path(cmt_base).map(|lp| { Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk))) @@ -693,6 +714,7 @@ impl<'a> BorrowckCtxt<'a> { loan_path: &LoanPath, out: &mut String) { match *loan_path { + LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) | LpVar(id) => { out.push_str(ty::local_var_name_str(self.tcx, id).get()); } @@ -734,7 +756,7 @@ impl<'a> BorrowckCtxt<'a> { self.append_autoderefd_loan_path_to_str(&**lp_base, out) } - LpVar(..) | LpExtend(_, _, LpInterior(..)) => { + LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => { self.append_loan_path_to_str(loan_path, out) } } @@ -796,6 +818,12 @@ impl Repr for LoanPath { (format!("$({})", tcx.map.node_to_str(id))).to_string() } + &LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => { + let s = tcx.map.node_to_str(var_id); + let s = format!("$({} captured by id={})", s, closure_expr_id); + s.to_string() + } + &LpExtend(ref lp, _, LpDeref(_)) => { (format!("{}.*", lp.repr(tcx))).to_string() } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 3e2f763a84bc2..bb92043b1ea6a 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -231,7 +231,7 @@ impl MoveData { } let index = match *lp { - LpVar(..) => { + LpVar(..) | LpUpvar(..) => { let index = MovePathIndex(self.paths.borrow().len()); self.paths.borrow_mut().push(MovePath { @@ -302,7 +302,7 @@ impl MoveData { } None => { match **lp { - LpVar(..) => { } + LpVar(..) | LpUpvar(..) => { } LpExtend(ref b, _, _) => { self.add_existing_base_paths(b, result); } @@ -418,6 +418,11 @@ impl MoveData { let path = *self.path_map.borrow().get(&path.loan_path); self.kill_moves(path, kill_id, dfcx_moves); } + LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => { + let kill_id = closure_to_block(closure_expr_id, tcx); + let path = *self.path_map.borrow().get(&path.loan_path); + self.kill_moves(path, kill_id, dfcx_moves); + } LpExtend(..) => {} } } @@ -430,6 +435,10 @@ impl MoveData { let kill_id = tcx.region_maps.var_scope(id); dfcx_assign.add_kill(kill_id, assignment_index); } + LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => { + let kill_id = closure_to_block(closure_expr_id, tcx); + dfcx_assign.add_kill(kill_id, assignment_index); + } LpExtend(..) => { tcx.sess.bug("var assignment for non var path"); } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 872a0878e3792..7a26d2104826f 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -266,34 +266,24 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { pub fn add_gen(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` generates `bit` - if self.nodeid_to_index.contains_key(&id) { - debug!("add_gen(id={:?}, bit={:?})", id, bit); - let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); - let (start, end) = self.compute_id_range(cfgidx); - { - let gens = self.gens.mut_slice(start, end); - set_bit(gens, bit); - } - } else { - debug!("{:s} add_gen skip (id={:?}, bit={:?}); id not in current fn", - self.analysis_name, id, bit); - } + debug!("{:s} add_gen(id={:?}, bit={:?})", + self.analysis_name, id, bit); + assert!(self.nodeid_to_index.contains_key(&id)); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range(cfgidx); + let gens = self.gens.mut_slice(start, end); + set_bit(gens, bit); } pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` kills `bit` - if self.nodeid_to_index.contains_key(&id) { - debug!("add_kill(id={:?}, bit={:?})", id, bit); - let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); - let (start, end) = self.compute_id_range(cfgidx); - { - let kills = self.kills.mut_slice(start, end); - set_bit(kills, bit); - } - } else { - debug!("{:s} add_kill skip (id={:?}, bit={:?}); id not in current fn", - self.analysis_name, id, bit); - } + debug!("{:s} add_kill(id={:?}, bit={:?})", + self.analysis_name, id, bit); + assert!(self.nodeid_to_index.contains_key(&id)); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); + let (start, end) = self.compute_id_range(cfgidx); + let kills = self.kills.mut_slice(start, end); + set_bit(kills, bit); } fn apply_gen_kill(&mut self, cfgidx: CFGIndex, bits: &mut [uint]) { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8224557f86007..03c9c56c78701 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -97,6 +97,7 @@ pub enum categorization { pub struct CopiedUpvar { pub upvar_id: ast::NodeId, pub onceness: ast::Onceness, + pub capturing_proc: ast::NodeId, } // different kinds of pointers: @@ -559,7 +560,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { span:span, cat:cat_copied_upvar(CopiedUpvar { upvar_id: var_id, - onceness: closure_ty.onceness}), + onceness: closure_ty.onceness, + capturing_proc: fn_node_id, + }), mutbl:McImmutable, ty:expr_ty })) From 95fdbeee48163691cf66de4a53fdc108157babcf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 10 Jun 2014 14:22:48 +0200 Subject: [PATCH 18/55] fix typo in borrowck doc. --- src/librustc/middle/borrowck/doc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs index 2427df463bfe4..9fc291d397191 100644 --- a/src/librustc/middle/borrowck/doc.rs +++ b/src/librustc/middle/borrowck/doc.rs @@ -948,7 +948,7 @@ The borrow checker is also in charge of ensuring that: These are two separate dataflow analyses built on the same framework. Let's look at checking that memory is initialized first; -the checking of immutable local variabe assignments works in a very +the checking of immutable local variable assignments works in a very similar way. To track the initialization of memory, we actually track all the From 373b0fc56905c17d14438446e16712bf714c6f08 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 Jun 2014 14:52:11 +0200 Subject: [PATCH 19/55] some extra test cases to cover in the borrow checker. --- .../loop-no-reinit-needed-post-bot.rs | 41 +++++++++++++++++++ src/test/run-pass/struct-partial-move-1.rs | 30 ++++++++++++++ src/test/run-pass/struct-partial-move-2.rs | 37 +++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/test/run-pass/loop-no-reinit-needed-post-bot.rs create mode 100644 src/test/run-pass/struct-partial-move-1.rs create mode 100644 src/test/run-pass/struct-partial-move-2.rs diff --git a/src/test/run-pass/loop-no-reinit-needed-post-bot.rs b/src/test/run-pass/loop-no-reinit-needed-post-bot.rs new file mode 100644 index 0000000000000..8b77500225022 --- /dev/null +++ b/src/test/run-pass/loop-no-reinit-needed-post-bot.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; +// Ensure S is moved, not copied, on assignment. +impl Drop for S { fn drop(&mut self) { } } + +// user-defined function "returning" bottom (i.e. no return at all). +fn my_fail() -> ! { loop {} } + +pub fn step(f: bool) { + let mut g = S; + let mut i = 0; + loop + { + if i > 10 { break; } else { i += 1; } + + let _g = g; + + if f { + // re-initialize g, but only before restarting loop. + g = S; + continue; + } + + my_fail(); + + // we never get here, so we do not need to re-initialize g. + } +} + +pub fn main() { + step(true); +} diff --git a/src/test/run-pass/struct-partial-move-1.rs b/src/test/run-pass/struct-partial-move-1.rs new file mode 100644 index 0000000000000..7e02d10208182 --- /dev/null +++ b/src/test/run-pass/struct-partial-move-1.rs @@ -0,0 +1,30 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(PartialEq, Show)] +struct Partial { x: T, y: T } + +#[deriving(PartialEq, Show)] +struct S { val: int } +impl S { fn new(v: int) -> S { S { val: v } } } +impl Drop for S { fn drop(&mut self) { } } + +pub fn f((b1, b2): (T, T), f: |T| -> T) -> Partial { + let p = Partial { x: b1, y: b2 }; + + // Move of `p` is legal even though we are also moving `p.y`; the + // `..p` moves all fields *except* `p.y` in this context. + Partial { y: f(p.y), ..p } +} + +pub fn main() { + let p = f((S::new(3), S::new(4)), |S { val: z }| S::new(z+1)); + assert_eq!(p, Partial { x: S::new(3), y: S::new(5) }); +} diff --git a/src/test/run-pass/struct-partial-move-2.rs b/src/test/run-pass/struct-partial-move-2.rs new file mode 100644 index 0000000000000..fe5e1eaaa1af5 --- /dev/null +++ b/src/test/run-pass/struct-partial-move-2.rs @@ -0,0 +1,37 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(PartialEq, Show)] +struct Partial { x: T, y: T } + +#[deriving(PartialEq, Show)] +struct S { val: int } +impl S { fn new(v: int) -> S { S { val: v } } } +impl Drop for S { fn drop(&mut self) { } } + +type Two = (Partial, Partial); + +pub fn f((b1, b2): (T, T), (b3, b4): (T, T), f: |T| -> T) -> Two { + let p = Partial { x: b1, y: b2 }; + let q = Partial { x: b3, y: b4 }; + + // Move of `q` is legal even though we have already moved `q.y`; + // the `..q` moves all fields *except* `q.y` in this context. + // Likewise, the move of `p.x` is legal for similar reasons. + (Partial { x: f(q.y), ..p }, Partial { y: f(p.x), ..q }) +} + +pub fn main() { + let two = f((S::new(1), S::new(3)), + (S::new(5), S::new(7)), + |S { val: z }| S::new(z+1)); + assert_eq!(two, (Partial { x: S::new(8), y: S::new(3) }, + Partial { x: S::new(5), y: S::new(2) })); +} From 3ddb987f45c9126009b1c20cd1cc108b9de9c734 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 Jun 2014 15:38:50 +0200 Subject: [PATCH 20/55] Regression tests for flowgraph construction bug on ExprWhile. --- src/test/run-make/graphviz-flowgraph/Makefile | 3 +- .../graphviz-flowgraph/f23.dot-expected.dot | 93 +++++++++++++ src/test/run-make/graphviz-flowgraph/f23.rs | 31 +++++ .../graphviz-flowgraph/f24.dot-expected.dot | 123 ++++++++++++++++++ src/test/run-make/graphviz-flowgraph/f24.rs | 36 +++++ .../graphviz-flowgraph/f25.dot-expected.dot | 123 ++++++++++++++++++ src/test/run-make/graphviz-flowgraph/f25.rs | 36 +++++ 7 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f23.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f24.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f25.rs diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile index fedcc89cd429f..09440949177dd 100644 --- a/src/test/run-make/graphviz-flowgraph/Makefile +++ b/src/test/run-make/graphviz-flowgraph/Makefile @@ -2,7 +2,8 @@ FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \ f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \ - f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs + f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs f23.rs \ + f24.rs f25.rs # all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES)) diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot new file mode 100644 index 0000000000000..876957a0689d6 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot @@ -0,0 +1,93 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 23"]; + N3[label="local mut x"]; + N4[label="expr 23"]; + N5[label="local mut y"]; + N6[label="expr 23"]; + N7[label="local mut z"]; + N8[label="(dummy_node)"]; + N9[label="expr x"]; + N10[label="expr 0"]; + N11[label="expr x > 0"]; + N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N13[label="expr 1"]; + N14[label="expr x"]; + N15[label="expr x -= 1"]; + N16[label="(dummy_node)"]; + N17[label="expr y"]; + N18[label="expr 0"]; + N19[label="expr y > 0"]; + N20[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; + N21[label="expr 1"]; + N22[label="expr y"]; + N23[label="expr y -= 1"]; + N24[label="(dummy_node)"]; + N25[label="expr z"]; + N26[label="expr 0"]; + N27[label="expr z > 0"]; + N28[label="expr while z > 0 { z -= 1; }"]; + N29[label="expr 1"]; + N30[label="expr z"]; + N31[label="expr z -= 1"]; + N32[label="block { z -= 1; }"]; + N33[label="expr x"]; + N34[label="expr 10"]; + N35[label="expr x > 10"]; + N36[label="expr return"]; + N37[label="(dummy_node)"]; + N38[label="expr \"unreachable\""]; + N39[label="block { return; \"unreachable\"; }"]; + N40[label="expr if x > 10 { return; \"unreachable\"; }"]; + N41[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; + N42[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N43[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N11 -> N13; + N13 -> N14; + N14 -> N15; + N15 -> N16; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N19 -> N21; + N21 -> N22; + N22 -> N23; + N23 -> N24; + N24 -> N25; + N25 -> N26; + N26 -> N27; + N27 -> N28; + N27 -> N29; + N29 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N24; + N28 -> N33; + N33 -> N34; + N34 -> N35; + N35 -> N36; + N36 -> N1[label="exiting scope_0 expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N37 -> N38; + N38 -> N39; + N35 -> N40; + N39 -> N40; + N40 -> N41; + N41 -> N16; + N20 -> N42; + N42 -> N8; + N12 -> N43; + N43 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f23.rs b/src/test/run-make/graphviz-flowgraph/f23.rs new file mode 100644 index 0000000000000..52341a3fbd408 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f23.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(unreachable_code)] +pub fn expr_while_23() { + let mut x = 23; + let mut y = 23; + let mut z = 23; + + while x > 0 { + x -= 1; + + while y > 0 { + y -= 1; + + while z > 0 { z -= 1; } + + if x > 10 { + return; + "unreachable"; + } + } + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot new file mode 100644 index 0000000000000..2558998be6e1f --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -0,0 +1,123 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 24"]; + N3[label="local mut x"]; + N4[label="expr 24"]; + N5[label="local mut y"]; + N6[label="expr 24"]; + N7[label="local mut z"]; + N8[label="(dummy_node)"]; + N9[label="expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N10[label="expr x"]; + N11[label="expr 0"]; + N12[label="expr x == 0"]; + N13[label="expr break"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { break ; \"unreachable\"; }"]; + N17[label="expr if x == 0 { break ; \"unreachable\"; }"]; + N18[label="expr 1"]; + N19[label="expr x"]; + N20[label="expr x -= 1"]; + N21[label="(dummy_node)"]; + N22[label="expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; + N23[label="expr y"]; + N24[label="expr 0"]; + N25[label="expr y == 0"]; + N26[label="expr break"]; + N27[label="(dummy_node)"]; + N28[label="expr \"unreachable\""]; + N29[label="block { break ; \"unreachable\"; }"]; + N30[label="expr if y == 0 { break ; \"unreachable\"; }"]; + N31[label="expr 1"]; + N32[label="expr y"]; + N33[label="expr y -= 1"]; + N34[label="(dummy_node)"]; + N35[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N36[label="expr z"]; + N37[label="expr 0"]; + N38[label="expr z == 0"]; + N39[label="expr break"]; + N40[label="(dummy_node)"]; + N41[label="expr \"unreachable\""]; + N42[label="block { break ; \"unreachable\"; }"]; + N43[label="expr if z == 0 { break ; \"unreachable\"; }"]; + N44[label="expr 1"]; + N45[label="expr z"]; + N46[label="expr z -= 1"]; + N47[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N48[label="expr x"]; + N49[label="expr 10"]; + N50[label="expr x > 10"]; + N51[label="expr return"]; + N52[label="(dummy_node)"]; + N53[label="expr \"unreachable\""]; + N54[label="block { return; \"unreachable\"; }"]; + N55[label="expr if x > 10 { return; \"unreachable\"; }"]; + N56[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; + N57[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N58[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N23; + N23 -> N24; + N24 -> N25; + N25 -> N26; + N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; + N27 -> N28; + N28 -> N29; + N25 -> N30; + N29 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N33; + N33 -> N34; + N34 -> N36; + N36 -> N37; + N37 -> N38; + N38 -> N39; + N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0 { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N40 -> N41; + N41 -> N42; + N38 -> N43; + N42 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N47; + N47 -> N34; + N35 -> N48; + N48 -> N49; + N49 -> N50; + N50 -> N51; + N51 -> N1[label="exiting scope_0 expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; + N52 -> N53; + N53 -> N54; + N50 -> N55; + N54 -> N55; + N55 -> N56; + N56 -> N21; + N22 -> N57; + N57 -> N8; + N9 -> N58; + N58 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f24.rs b/src/test/run-make/graphviz-flowgraph/f24.rs new file mode 100644 index 0000000000000..f796d660a1856 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f24.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(unreachable_code)] +pub fn expr_while_24() { + let mut x = 24; + let mut y = 24; + let mut z = 24; + + loop { + if x == 0 { break; "unreachable"; } + x -= 1; + + loop { + if y == 0 { break; "unreachable"; } + y -= 1; + + loop { + if z == 0 { break; "unreachable"; } + z -= 1; + } + + if x > 10 { + return; + "unreachable"; + } + } + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot new file mode 100644 index 0000000000000..c393b63546c70 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -0,0 +1,123 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 25"]; + N3[label="local mut x"]; + N4[label="expr 25"]; + N5[label="local mut y"]; + N6[label="expr 25"]; + N7[label="local mut z"]; + N8[label="(dummy_node)"]; + N9[label="expr \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l"]; + N10[label="expr x"]; + N11[label="expr 0"]; + N12[label="expr x == 0"]; + N13[label="expr break"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { break ; \"unreachable\"; }"]; + N17[label="expr if x == 0 { break ; \"unreachable\"; }"]; + N18[label="expr 1"]; + N19[label="expr x"]; + N20[label="expr x -= 1"]; + N21[label="(dummy_node)"]; + N22[label="expr \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l"]; + N23[label="expr y"]; + N24[label="expr 0"]; + N25[label="expr y == 0"]; + N26[label="expr break"]; + N27[label="(dummy_node)"]; + N28[label="expr \"unreachable\""]; + N29[label="block { break ; \"unreachable\"; }"]; + N30[label="expr if y == 0 { break ; \"unreachable\"; }"]; + N31[label="expr 1"]; + N32[label="expr y"]; + N33[label="expr y -= 1"]; + N34[label="(dummy_node)"]; + N35[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N36[label="expr z"]; + N37[label="expr 0"]; + N38[label="expr z == 0"]; + N39[label="expr break"]; + N40[label="(dummy_node)"]; + N41[label="expr \"unreachable\""]; + N42[label="block { break ; \"unreachable\"; }"]; + N43[label="expr if z == 0 { break ; \"unreachable\"; }"]; + N44[label="expr 1"]; + N45[label="expr z"]; + N46[label="expr z -= 1"]; + N47[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N48[label="expr x"]; + N49[label="expr 10"]; + N50[label="expr x > 10"]; + N51[label="expr continue \'a"]; + N52[label="(dummy_node)"]; + N53[label="expr \"unreachable\""]; + N54[label="block { continue \'a ; \"unreachable\"; }"]; + N55[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"]; + N56[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; + N57[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; + N58[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N23; + N23 -> N24; + N24 -> N25; + N25 -> N26; + N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; + N27 -> N28; + N28 -> N29; + N25 -> N30; + N29 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N33; + N33 -> N34; + N34 -> N36; + N36 -> N37; + N37 -> N38; + N38 -> N39; + N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0 { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"]; + N40 -> N41; + N41 -> N42; + N38 -> N43; + N42 -> N43; + N43 -> N44; + N44 -> N45; + N45 -> N46; + N46 -> N47; + N47 -> N34; + N35 -> N48; + N48 -> N49; + N49 -> N50; + N50 -> N51; + N51 -> N21[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10 { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; + N52 -> N53; + N53 -> N54; + N50 -> N55; + N54 -> N55; + N55 -> N56; + N56 -> N21; + N22 -> N57; + N57 -> N8; + N9 -> N58; + N58 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f25.rs b/src/test/run-make/graphviz-flowgraph/f25.rs new file mode 100644 index 0000000000000..2ee2e48fd10e0 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f25.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(unreachable_code)] +pub fn expr_while_25() { + let mut x = 25; + let mut y = 25; + let mut z = 25; + + 'a: loop { + if x == 0 { break; "unreachable"; } + x -= 1; + + 'a: loop { + if y == 0 { break; "unreachable"; } + y -= 1; + + 'a: loop { + if z == 0 { break; "unreachable"; } + z -= 1; + } + + if x > 10 { + continue 'a; + "unreachable"; + } + } + } +} From 4c2a8bbc097b4ba0c317c07a095238aed128899d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 18 Jun 2014 15:27:49 +0200 Subject: [PATCH 21/55] Adapt test case to match current set of emitted warnings. (or lack thereof.) PR 14739 injected the new message that this removes from one test case: borrowck-vec-pattern-loan-from-mut.rs When reviewing the test case, I was not able to convince myself that the error message was a legitimate thing to start emitting. Niko did not see an obvious reason for it either, so I am going to remove it and wait for someone (maybe Cameron Zwarich) to explain to me why we should be emitting it. --- src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs index ff029ce624c9b..393ec8b0b1b3b 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -12,7 +12,7 @@ fn a() { let mut v = vec!(1, 2, 3); let vb: &mut [int] = v.as_mut_slice(); match vb { - [_a, ..tail] => { //~ ERROR cannot use `vb[..]` because it was mutably borrowed + [_a, ..tail] => { v.push(tail[0] + tail[1]); //~ ERROR cannot borrow } _ => {} From 0f481db211dd03b0d8aad4ce29e211f78de340d4 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 23 May 2014 21:41:59 -0700 Subject: [PATCH 22/55] Fix spans for doc comments --- src/libsyntax/parse/lexer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 9039f346edb52..4ea47eb0a3db9 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -304,7 +304,7 @@ impl<'a> StringReader<'a> { if !is_line_non_doc_comment(string) { Some(TokenAndSpan{ tok: token::DOC_COMMENT(str_to_ident(string)), - sp: codemap::mk_sp(start_bpos, self.pos) + sp: codemap::mk_sp(start_bpos, self.last_pos) }) } else { None @@ -358,7 +358,7 @@ impl<'a> StringReader<'a> { fn consume_block_comment(&mut self) -> Option { // block comments starting with "/**" or "/*!" are doc-comments let is_doc_comment = self.curr_is('*') || self.curr_is('!'); - let start_bpos = self.pos - BytePos(if is_doc_comment {3} else {2}); + let start_bpos = self.last_pos - BytePos(2); let mut level: int = 1; while level > 0 { @@ -389,7 +389,7 @@ impl<'a> StringReader<'a> { if !is_block_non_doc_comment(string) { Some(TokenAndSpan{ tok: token::DOC_COMMENT(str_to_ident(string)), - sp: codemap::mk_sp(start_bpos, self.pos) + sp: codemap::mk_sp(start_bpos, self.last_pos) }) } else { None From 80d8214f95d3ad3f947a905b49c3de084e684e45 Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Wed, 18 Jun 2014 19:12:30 +0200 Subject: [PATCH 23/55] Remove obsolete test This test was added long time ago and marked as ignored. The same test was added later in #8485 as run-fail/issue-3907.rs, but the old one was not deleted. --- src/test/auxiliary/trait_typedef_cc.rs | 13 ----------- src/test/run-pass/trait-typedef-cc.rs | 30 -------------------------- 2 files changed, 43 deletions(-) delete mode 100644 src/test/auxiliary/trait_typedef_cc.rs delete mode 100644 src/test/run-pass/trait-typedef-cc.rs diff --git a/src/test/auxiliary/trait_typedef_cc.rs b/src/test/auxiliary/trait_typedef_cc.rs deleted file mode 100644 index 7290fe97a911e..0000000000000 --- a/src/test/auxiliary/trait_typedef_cc.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub trait Foo { - fn bar(); -} diff --git a/src/test/run-pass/trait-typedef-cc.rs b/src/test/run-pass/trait-typedef-cc.rs deleted file mode 100644 index 62cda8ed82d75..0000000000000 --- a/src/test/run-pass/trait-typedef-cc.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-test FIXME: #3907 -// aux-build:trait_typedef_cc.rs -extern crate trait_typedef_cc; - -type Foo = trait_typedef_cc::Foo; - -struct S { - name: int -} - -impl Foo for S { - fn bar() { } -} - -pub fn main() { - let s = S { - name: 0 - }; - s.bar(); -} From d41058ed39fcd7e15ce9d0e7705643da85c94271 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sat, 24 May 2014 01:12:22 -0700 Subject: [PATCH 24/55] Don't require mutable StringReader to emit lexer errors Teach StringReader how to emit errors for arbitrary spans, so we don't need to modify peek_span. This allows for emitting errors without having a &mut borrow of the StringReader. --- src/libsyntax/parse/lexer/mod.rs | 94 ++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 4ea47eb0a3db9..348445149a415 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -70,10 +70,10 @@ impl<'a> Reader for StringReader<'a> { ret_val } fn fatal(&self, m: &str) -> ! { - self.span_diagnostic.span_fatal(self.peek_span, m) + self.fatal_span(self.peek_span, m) } fn err(&self, m: &str) { - self.span_diagnostic.span_err(self.peek_span, m) + self.err_span(self.peek_span, m) } fn peek(&self) -> TokenAndSpan { // FIXME(pcwalton): Bad copy! @@ -137,43 +137,52 @@ impl<'a> StringReader<'a> { self.curr == Some(c) } - /// Report a lexical error spanning [`from_pos`, `to_pos`) - fn fatal_span(&mut self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! { - self.peek_span = codemap::mk_sp(from_pos, to_pos); - self.fatal(m); + /// Report a fatal lexical error with a given span. + pub fn fatal_span(&self, sp: Span, m: &str) -> ! { + self.span_diagnostic.span_fatal(sp, m) } - fn err_span(&mut self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.peek_span = codemap::mk_sp(from_pos, to_pos); - self.err(m); + /// Report a lexical error with a given span. + pub fn err_span(&self, sp: Span, m: &str) { + self.span_diagnostic.span_err(sp, m) + } + + /// Report a fatal error spanning [`from_pos`, `to_pos`). + fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! { + self.fatal_span(codemap::mk_sp(from_pos, to_pos), m) + } + + /// Report a lexical error spanning [`from_pos`, `to_pos`). + fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { + self.err_span(codemap::mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message - fn fatal_span_char(&mut self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> ! { + fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> ! { let mut m = m.to_string(); m.push_str(": "); char::escape_default(c, |c| m.push_char(c)); - self.fatal_span(from_pos, to_pos, m.as_slice()); + self.fatal_span_(from_pos, to_pos, m.as_slice()); } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message - fn err_span_char(&mut self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) { + fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) { let mut m = m.to_string(); m.push_str(": "); char::escape_default(c, |c| m.push_char(c)); - self.err_span(from_pos, to_pos, m.as_slice()); + self.err_span_(from_pos, to_pos, m.as_slice()); } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the /// offending string to the error message - fn fatal_span_verbose(&mut self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> ! { + fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> ! { m.push_str(": "); let from = self.byte_offset(from_pos).to_uint(); let to = self.byte_offset(to_pos).to_uint(); m.push_str(self.filemap.src.as_slice().slice(from, to)); - self.fatal_span(from_pos, to_pos, m.as_slice()); + self.fatal_span_(from_pos, to_pos, m.as_slice()); } /// Advance peek_tok and peek_span to refer to the next token, and @@ -369,7 +378,7 @@ impl<'a> StringReader<'a> { "unterminated block comment" }; let last_bpos = self.last_pos; - self.fatal_span(start_bpos, last_bpos, msg); + self.fatal_span_(start_bpos, last_bpos, msg); } else if self.curr_is('/') && self.nextch_is('*') { level += 1; self.bump(); @@ -421,7 +430,7 @@ impl<'a> StringReader<'a> { return Some(rslt); } else { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "scan_exponent: bad fp literal"); + self.err_span_(start_bpos, last_bpos, "scan_exponent: bad fp literal"); rslt.push_str("1"); // arbitrary placeholder exponent return Some(rslt); } @@ -447,9 +456,10 @@ impl<'a> StringReader<'a> { fn check_float_base(&mut self, start_bpos: BytePos, last_bpos: BytePos, base: uint) { match base { - 16u => self.err_span(start_bpos, last_bpos, "hexadecimal float literal is not supported"), - 8u => self.err_span(start_bpos, last_bpos, "octal float literal is not supported"), - 2u => self.err_span(start_bpos, last_bpos, "binary float literal is not supported"), + 16u => self.err_span_(start_bpos, last_bpos, + "hexadecimal float literal is not supported"), + 8u => self.err_span_(start_bpos, last_bpos, "octal float literal is not supported"), + 2u => self.err_span_(start_bpos, last_bpos, "binary float literal is not supported"), _ => () } } @@ -509,7 +519,7 @@ impl<'a> StringReader<'a> { } if num_str.len() == 0u { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "no valid digits found for number"); + self.err_span_(start_bpos, last_bpos, "no valid digits found for number"); num_str = "1".to_string(); } let parsed = match from_str_radix::(num_str.as_slice(), @@ -517,7 +527,7 @@ impl<'a> StringReader<'a> { Some(p) => p, None => { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "int literal is too large"); + self.err_span_(start_bpos, last_bpos, "int literal is too large"); 1 } }; @@ -573,7 +583,7 @@ impl<'a> StringReader<'a> { return token::LIT_FLOAT(str_to_ident(num_str.as_slice()), ast::TyF128); } let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "expected `f32`, `f64` or `f128` suffix"); + self.err_span_(start_bpos, last_bpos, "expected `f32`, `f64` or `f128` suffix"); } if is_float { let last_bpos = self.last_pos; @@ -583,7 +593,7 @@ impl<'a> StringReader<'a> { } else { if num_str.len() == 0u { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "no valid digits found for number"); + self.err_span_(start_bpos, last_bpos, "no valid digits found for number"); num_str = "1".to_string(); } let parsed = match from_str_radix::(num_str.as_slice(), @@ -591,7 +601,7 @@ impl<'a> StringReader<'a> { Some(p) => p, None => { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "int literal is too large"); + self.err_span_(start_bpos, last_bpos, "int literal is too large"); 1 } }; @@ -609,11 +619,11 @@ impl<'a> StringReader<'a> { for _ in range(0, n_hex_digits) { if self.is_eof() { let last_bpos = self.last_pos; - self.fatal_span(start_bpos, last_bpos, "unterminated numeric character escape"); + self.fatal_span_(start_bpos, last_bpos, "unterminated numeric character escape"); } if self.curr_is(delim) { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "numeric character escape is too short"); + self.err_span_(start_bpos, last_bpos, "numeric character escape is too short"); break; } let c = self.curr.unwrap_or('\x00'); @@ -630,7 +640,7 @@ impl<'a> StringReader<'a> { Some(x) => x, None => { let last_bpos = self.last_pos; - self.err_span(start_bpos, last_bpos, "illegal numeric character escape"); + self.err_span_(start_bpos, last_bpos, "illegal numeric character escape"); '?' } } @@ -856,16 +866,16 @@ impl<'a> StringReader<'a> { let last_bpos = self.last_pos; if token::is_keyword(token::keywords::Self, keyword_checking_token) { - self.err_span(start, - last_bpos, - "invalid lifetime name: 'self \ - is no longer a special lifetime"); + self.err_span_(start, + last_bpos, + "invalid lifetime name: 'self \ + is no longer a special lifetime"); } else if token::is_any_keyword(keyword_checking_token) && !token::is_keyword(token::keywords::Static, keyword_checking_token) { - self.err_span(start, - last_bpos, - "invalid lifetime name"); + self.err_span_(start, + last_bpos, + "invalid lifetime name"); } return token::LIFETIME(ident); } @@ -922,8 +932,8 @@ impl<'a> StringReader<'a> { while !self_.curr_is('"') { if self_.is_eof() { let last_pos = self_.last_pos; - self_.fatal_span(start, last_pos, - "unterminated double quote byte string"); + self_.fatal_span_(start, last_pos, + "unterminated double quote byte string"); } let ch_start = self_.last_pos; @@ -947,7 +957,7 @@ impl<'a> StringReader<'a> { if self_.is_eof() { let last_pos = self_.last_pos; - self_.fatal_span(start_bpos, last_pos, "unterminated raw string"); + self_.fatal_span_(start_bpos, last_pos, "unterminated raw string"); } else if !self_.curr_is('"') { let last_pos = self_.last_pos; let ch = self_.curr.unwrap(); @@ -963,7 +973,7 @@ impl<'a> StringReader<'a> { match self_.curr { None => { let last_pos = self_.last_pos; - self_.fatal_span(start_bpos, last_pos, "unterminated raw string") + self_.fatal_span_(start_bpos, last_pos, "unterminated raw string") }, Some('"') => { content_end_bpos = self_.last_pos; @@ -997,7 +1007,7 @@ impl<'a> StringReader<'a> { while !self.curr_is('"') { if self.is_eof() { let last_bpos = self.last_pos; - self.fatal_span(start_bpos, last_bpos, "unterminated double quote string"); + self.fatal_span_(start_bpos, last_bpos, "unterminated double quote string"); } let ch_start = self.last_pos; @@ -1020,7 +1030,7 @@ impl<'a> StringReader<'a> { if self.is_eof() { let last_bpos = self.last_pos; - self.fatal_span(start_bpos, last_bpos, "unterminated raw string"); + self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"); } else if !self.curr_is('"') { let last_bpos = self.last_pos; let curr_char = self.curr.unwrap(); @@ -1035,7 +1045,7 @@ impl<'a> StringReader<'a> { 'outer: loop { if self.is_eof() { let last_bpos = self.last_pos; - self.fatal_span(start_bpos, last_bpos, "unterminated raw string"); + self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"); } if self.curr_is('"') { content_end_bpos = self.last_pos; From 91c7687f03fd01c61fc7594e6ff8f3cc0f6363a4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jun 2014 08:47:44 -0700 Subject: [PATCH 25/55] test: Attempt to fix nightly-linux The nightly builds on linux have been failing over the past few days due to a malformed LD_LIBRARY_PATH. It appears that the underlying cause is that one of the tests, dep-info-custom, recursively invokes make but the RUSTC variable passed down has the string "$LD_LIBRARY_PATH". This is intended to read the host's original LD_LIBRARY_PATH, but it appears that the makefile is eagerly expanding the "$L" to nothing, causing the original host's LD_LIBRARY_PATH to be ignored. This fix removes passing the string "$LD_LIBRARY_PATH" and rather expands it eagerly to ensure that escaping doesn't happen at a later stage. I'm still not entirely sure why the makefile is interpreting the dollar as a variable, but this seems to fix the issue. --- src/test/run-make/tools.mk | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 483a5db877846..d4862e1570434 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -1,12 +1,9 @@ -export LD_LIBRARY_PATH:=$(TMPDIR):$(LD_LIBRARY_PATH) -export DYLD_LIBRARY_PATH:=$(TMPDIR):$(DYLD_LIBRARY_PATH) - # These deliberately use `=` and not `:=` so that client makefiles can # augment HOST_RPATH_DIR / TARGET_RPATH_DIR. HOST_RPATH_ENV = \ - $(LD_LIB_PATH_ENVVAR)=$(HOST_RPATH_DIR):$$$(LD_LIB_PATH_ENVVAR) + $(LD_LIB_PATH_ENVVAR)="$(HOST_RPATH_DIR):$($(LD_LIB_PATH_ENVVAR))" TARGET_RPATH_ENV = \ - $(LD_LIB_PATH_ENVVAR)=$(TARGET_RPATH_DIR):$$$(LD_LIB_PATH_ENVVAR) + $(LD_LIB_PATH_ENVVAR)="$(TARGET_RPATH_DIR):$($(LD_LIB_PATH_ENVVAR))" RUSTC := $(HOST_RPATH_ENV) $(RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) CC := $(CC) -L $(TMPDIR) @@ -43,7 +40,6 @@ DYLIB_GLOB = $(1)*.dll DYLIB = $(TMPDIR)/$(1).dll BIN = $(1).exe RPATH_LINK_SEARCH = -RUSTC := PATH="$(PATH):$(LD_LIBRARY_PATH)" $(RUSTC) else RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0 From 303cadfbb3addd30dafdc2bcb5db994ab3bb30ab Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Tue, 27 May 2014 15:00:22 -0700 Subject: [PATCH 26/55] vim: Add :Run and :Expand commands Define a command :Run to compile and run the current file. This supports unnamed buffers (by writing to a temporary file). See the comment above the command definition for notes on usage. Define and mappings for :Run to make it easier to invoke in MacVim. Define a command :Expand to display the --pretty expanded output for the current file. This can be configured to use different pretty types. See the comment above the command definition for notes on usage. Create an autoload file and put function definitions there to speed up load time. --- src/etc/vim/autoload/rust.vim | 192 ++++++++++++++++++++++++++++++++++ src/etc/vim/ftplugin/rust.vim | 110 ++++++++++++------- 2 files changed, 265 insertions(+), 37 deletions(-) create mode 100644 src/etc/vim/autoload/rust.vim diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim new file mode 100644 index 0000000000000..688c1f690eb56 --- /dev/null +++ b/src/etc/vim/autoload/rust.vim @@ -0,0 +1,192 @@ +" Author: Kevin Ballard +" Description: Helper functions for Rust commands/mappings +" Last Modified: May 27, 2014 + +" Jump {{{1 + +function! rust#Jump(mode, function) range + let cnt = v:count1 + normal! m' + if a:mode ==# 'v' + norm! gv + endif + let foldenable = &foldenable + set nofoldenable + while cnt > 0 + execute "call Jump_" . a:function . "()" + let cnt = cnt - 1 + endwhile + let &foldenable = foldenable +endfunction + +function! s:Jump_Back() + call search('{', 'b') + keepjumps normal! w99[{ +endfunction + +function! s:Jump_Forward() + normal! j0 + call search('{', 'b') + keepjumps normal! w99[{% + call search('{') +endfunction + +" Run {{{1 + +function! rust#Run(bang, args) + if a:bang + let idx = index(a:args, '--') + if idx != -1 + let rustc_args = idx == 0 ? [] : a:args[:idx-1] + let args = a:args[idx+1:] + else + let rustc_args = a:args + let args = [] + endif + else + let rustc_args = [] + let args = a:args + endif + + let b:rust_last_rustc_args = rustc_args + let b:rust_last_args = args + + call s:WithPath(function("s:Run"), rustc_args, args) +endfunction + +function! s:Run(path, rustc_args, args) + try + let exepath = tempname() + if has('win32') + let exepath .= '.exe' + endif + + let rustc_args = [a:path, '-o', exepath] + a:rustc_args + + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + let output = system(shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) + if output != '' + echohl WarningMsg + echo output + echohl None + endif + if !v:shell_error + exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) + endif + finally + if exists("exepath") + silent! call delete(exepath) + endif + endtry +endfunction + +" Expand {{{1 + +function! rust#Expand(bang, args) + if a:bang && !empty(a:args) + let pretty = a:args[0] + let args = a:args[1:] + else + let pretty = "expanded" + let args = a:args + endif + call s:WithPath(function("s:Expand"), pretty, args) +endfunction + +function! s:Expand(path, pretty, args) + try + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + let args = [a:path, '--pretty', a:pretty] + a:args + let output = system(shellescape(rustc) . " " . join(map(args, "shellescape(v:val)"))) + if v:shell_error + echohl WarningMsg + echo output + echohl None + else + new + silent put =output + 1 + d + setl filetype=rust + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + endif + endtry +endfunction + +function! rust#CompleteExpand(lead, line, pos) + if a:line[: a:pos-1] =~ '^Expand!\s*\S*$' + " first argument and it has a ! + let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph="] + if !empty(a:lead) + call filter(list, "v:val[:len(a:lead)-1] == a:lead") + endif + return list + endif + + return glob(escape(a:lead, "*?[") . '*', 0, 1) +endfunction + +" Utility functions {{{1 + +function! s:WithPath(func, ...) + try + let save_write = &write + set write + let path = expand('%') + let pathisempty = empty(path) + if pathisempty || !save_write + " use a temporary file named 'unnamed.rs' inside a temporary + " directory. This produces better error messages + let tmpdir = tempname() + call mkdir(tmpdir) + + let save_cwd = getcwd() + silent exe 'lcd' tmpdir + + let path = 'unnamed.rs' + + let save_mod = &mod + set nomod + + silent exe 'keepalt write! ' . path + if pathisempty + silent keepalt 0file + endif + else + update + endif + + call call(a:func, [path] + a:000) + finally + if exists("save_mod") | let &mod = save_mod | endif + if exists("save_write") | let &write = save_write | endif + if exists("save_cwd") | silent exe 'lcd' save_cwd | endif + if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif + endtry +endfunction + +function! rust#AppendCmdLine(text) + call setcmdpos(getcmdpos()) + let cmd = getcmdline() . a:text + return cmd +endfunction + +function! s:RmDir(path) + " sanity check; make sure it's not empty, /, or $HOME + if empty(a:path) + echoerr 'Attempted to delete empty path' + return 0 + elseif a:path == '/' || a:path == $HOME + echoerr 'Attempted to delete protected path: ' . a:path + return 0 + endif + silent exe "!rm -rf " . shellescape(a:path) +endfunction + +" }}}1 + +" vim: set noet sw=4 ts=4: diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim index b70cda9b998c4..fee59b5868766 100644 --- a/src/etc/vim/ftplugin/rust.vim +++ b/src/etc/vim/ftplugin/rust.vim @@ -1,13 +1,19 @@ -" Vim syntax file " Language: Rust +" Description: Vim syntax file for Rust " Maintainer: Chris Morgan -" Last Change: 2014 Feb 27 +" Maintainer: Kevin Ballard +" Last Change: May 27, 2014 if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 +let s:save_cpo = &cpo +set cpo&vim + +" Variables {{{1 + " The rust source code at present seems to typically omit a leader on /*! " comments, so we'll use that as our default, but make it easy to switch. " This does not affect indentation at all (I tested it with and without @@ -42,22 +48,74 @@ if exists("g:loaded_delimitMate") let b:delimitMate_excluded_regions = delimitMate#Get("excluded_regions") . ',rustLifetimeCandidate,rustGenericLifetimeCandidate' endif +" Motion Commands {{{1 + " Bind motion commands to support hanging indents -nnoremap [[ :call Rust_Jump('n', 'Back') -nnoremap ]] :call Rust_Jump('n', 'Forward') -xnoremap [[ :call Rust_Jump('v', 'Back') -xnoremap ]] :call Rust_Jump('v', 'Forward') -onoremap [[ :call Rust_Jump('o', 'Back') -onoremap ]] :call Rust_Jump('o', 'Forward') +nnoremap [[ :call rust#Jump('n', 'Back') +nnoremap ]] :call rust#Jump('n', 'Forward') +xnoremap [[ :call rust#Jump('v', 'Back') +xnoremap ]] :call rust#Jump('v', 'Forward') +onoremap [[ :call rust#Jump('o', 'Back') +onoremap ]] :call rust#Jump('o', 'Forward') + +" Commands {{{1 + +" :Run will compile and run the current file. If it has unsaved changes, they +" will be saved first. If it has no path, it will be written to a temporary +" file first. The generated binary is always placed in a temporary directory, +" but run from the current directory. +" +" The arguments passed to :Run will be passed to the generated binary. +" +" If ! is specified, the arguments are given to rustc as well. A -- argument +" separates rustc args from the args passed to the binary. +" +" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is +" assumed that rustc is in $PATH. +command! -nargs=* -complete=file -bang -bar -buffer Run call rust#Run(0, []) + +" :Expand will expand the current file using --pretty. +" +" Any arguments given to :Expand will be passed to rustc. This is largely so +" you can pass various --cfg configurations. +" +" If ! is specified, the first argument will be interpreted as the --pretty +" type. Otherwise it will default to 'expanded'. +" +" If the current file has unsaved changes, it will be saved first. If it's an +" unnamed buffer, it will be written to a temporary file. +" +" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is +" assumed that rustc is in $PATH. +command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer Expand call rust#Expand(0, []) + +" Mappings {{{1 + +" Bind ⌘R in MacVim to :Run +nnoremap :Run +" Bind ⌘⇧R in MacVim to :Run! pre-filled with the last args +nnoremap :Run! =join(b:rust_last_rustc_args)erust#AppendCmdLine(' -- ' . join(b:rust_last_args)) + +if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") + let b:rust_last_rustc_args = [] + let b:rust_last_args = [] +endif + +" Cleanup {{{1 let b:undo_ftplugin = " \setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< \|if exists('b:rust_original_delimitMate_excluded_regions') \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions \|unlet b:rust_original_delimitMate_excluded_regions - \|elseif exists('b:delimitMate_excluded_regions') - \|unlet b:delimitMate_excluded_regions + \|else + \|unlet! b:delimitMate_excluded_regions \|endif + \|unlet! b:rust_last_rustc_args b:rust_last_args + \|delcommand Run + \|delcommand Expand + \|nunmap + \|nunmap \|nunmap [[ \|nunmap ]] \|xunmap [[ @@ -66,31 +124,9 @@ let b:undo_ftplugin = " \|ounmap ]] \" -if exists('*Rust_Jump') | finish | endif +" }}}1 -function! Rust_Jump(mode, function) range - let cnt = v:count1 - normal! m' - if a:mode ==# 'v' - norm! gv - endif - let foldenable = &foldenable - set nofoldenable - while cnt > 0 - execute "call Rust_Jump_" . a:function . "()" - let cnt = cnt - 1 - endwhile - let &foldenable = foldenable -endfunction - -function! Rust_Jump_Back() - call search('{', 'b') - keepjumps normal! w99[{ -endfunction - -function! Rust_Jump_Forward() - normal! j0 - call search('{', 'b') - keepjumps normal! w99[{% - call search('{') -endfunction +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set noet sw=4 ts=4: From bd3bebcf60793477da390471d6d00a5523d716b4 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Thu, 29 May 2014 23:43:52 -0700 Subject: [PATCH 27/55] Rename :Run and :Expand to :RustRun and :RustExpand --- src/etc/vim/autoload/rust.vim | 2 +- src/etc/vim/ftplugin/rust.vim | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim index 688c1f690eb56..c5bf0c10751b2 100644 --- a/src/etc/vim/autoload/rust.vim +++ b/src/etc/vim/autoload/rust.vim @@ -118,7 +118,7 @@ function! s:Expand(path, pretty, args) endfunction function! rust#CompleteExpand(lead, line, pos) - if a:line[: a:pos-1] =~ '^Expand!\s*\S*$' + if a:line[: a:pos-1] =~ '^RustExpand!\s*\S*$' " first argument and it has a ! let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph="] if !empty(a:lead) diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim index fee59b5868766..6e373b2ddc471 100644 --- a/src/etc/vim/ftplugin/rust.vim +++ b/src/etc/vim/ftplugin/rust.vim @@ -60,24 +60,24 @@ onoremap ]] :call rust#Jump('o', 'Forward') " Commands {{{1 -" :Run will compile and run the current file. If it has unsaved changes, they -" will be saved first. If it has no path, it will be written to a temporary -" file first. The generated binary is always placed in a temporary directory, -" but run from the current directory. +" :RustRun will compile and run the current file. If it has unsaved changes, +" they will be saved first. If it has no path, it will be written to a +" temporary file first. The generated binary is always placed in a temporary +" directory, but run from the current directory. " -" The arguments passed to :Run will be passed to the generated binary. +" The arguments passed to :RustRun will be passed to the generated binary. " " If ! is specified, the arguments are given to rustc as well. A -- argument " separates rustc args from the args passed to the binary. " " If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is " assumed that rustc is in $PATH. -command! -nargs=* -complete=file -bang -bar -buffer Run call rust#Run(0, []) +command! -nargs=* -complete=file -bang -bar -buffer RustRun call rust#Run(0, []) -" :Expand will expand the current file using --pretty. +" :RustExpand will expand the current file using --pretty. " -" Any arguments given to :Expand will be passed to rustc. This is largely so -" you can pass various --cfg configurations. +" Any arguments given to :RustExpand will be passed to rustc. This is largely +" so you can pass various --cfg configurations. " " If ! is specified, the first argument will be interpreted as the --pretty " type. Otherwise it will default to 'expanded'. @@ -87,14 +87,14 @@ command! -nargs=* -complete=file -bang -bar -buffer Run call rust#Run(0, [ " " If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is " assumed that rustc is in $PATH. -command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer Expand call rust#Expand(0, []) +command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer RustExpand call rust#Expand(0, []) " Mappings {{{1 -" Bind ⌘R in MacVim to :Run -nnoremap :Run -" Bind ⌘⇧R in MacVim to :Run! pre-filled with the last args -nnoremap :Run! =join(b:rust_last_rustc_args)erust#AppendCmdLine(' -- ' . join(b:rust_last_args)) +" Bind ⌘R in MacVim to :RustRun +nnoremap :RustRun +" Bind ⌘⇧R in MacVim to :RustRun! pre-filled with the last args +nnoremap :RustRun! =join(b:rust_last_rustc_args)erust#AppendCmdLine(' -- ' . join(b:rust_last_args)) if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") let b:rust_last_rustc_args = [] @@ -112,8 +112,8 @@ let b:undo_ftplugin = " \|unlet! b:delimitMate_excluded_regions \|endif \|unlet! b:rust_last_rustc_args b:rust_last_args - \|delcommand Run - \|delcommand Expand + \|delcommand RustRun + \|delcommand RustExpand \|nunmap \|nunmap \|nunmap [[ From 918eda59bee9a627919d11b7bc9f909d7a9676ff Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 30 May 2014 00:06:52 -0700 Subject: [PATCH 28/55] Write documentation for the Rust vim plugin --- src/etc/vim/doc/rust.txt | 129 ++++++++++++++++++++++++++++++++++ src/etc/vim/ftplugin/rust.vim | 27 +------ 2 files changed, 131 insertions(+), 25 deletions(-) create mode 100644 src/etc/vim/doc/rust.txt diff --git a/src/etc/vim/doc/rust.txt b/src/etc/vim/doc/rust.txt new file mode 100644 index 0000000000000..e0a647225a9e5 --- /dev/null +++ b/src/etc/vim/doc/rust.txt @@ -0,0 +1,129 @@ +*rust.txt* Filetype plugin for Rust + +============================================================================== +CONTENTS *rust* + +1. Introduction |rust-intro| +2. Settings |rust-settings| +3. Commands |rust-commands| +4. Mappings |rust-mappings| + +============================================================================== +INTRODUCTION *rust-intro* + +This plugin provides syntax and supporting functionality for the Rust +filetype. + +============================================================================== +SETTINGS *rust-settings* + +This plugin has a few variables you can define in your vimrc that change the +behavior of the plugin. + + *g:rustc_path* +g:rustc_path~ + Set this option to the path to rustc for use in the |:RustRun| and + |:RustExpand| commands. If unset, "rustc" will be located in $PATH: > + let g:rustc_path = $HOME."/bin/rustc" +< + + *g:rustc_makeprg_no_percent* +g:rustc_makeprg_no_percent~ + Set this option to 1 to have 'makeprg' default to "rustc" instead of + "rustc %": > + let g:rustc_makeprg_no_percent = 1 +< + + *g:rust_conceal* +g:rust_conceal~ + Set this option to turn on the basic |conceal| support: > + let g:rust_conceal = 1 +< + + *g:rust_conceal_mod_path* +g:rust_conceal_mod_path~ + Set this option to turn on |conceal| for the path connecting token + "::": > + let g:rust_conceal_mod_path = 1 +< + + *g:rust_conceal_pub* +g:rust_conceal_pub~ + Set this option to turn on |conceal| for the "pub" token: > + let g:rust_conceal_pub = 1 +< + + *g:rust_bang_comment_leader* +g:rust_bang_comment_leader~ + Set this option to 1 to preserve the leader on multi-line doc comments + using the /*! syntax: > + let g:rust_bang_comment_leader = 1 +< + + *g:ftplugin_rust_source_path* +g:ftplugin_rust_source_path~ + Set this option to a path that should be prepended to 'path' for Rust + source files: > + let g:ftplugin_rust_source_path = $HOME.'/dev/rust' +< + +============================================================================== +COMMANDS *rust-commands* + +:RustRun [args] *:RustRun* +:RustRun! [rustc-args] [--] [args] + Compiles and runs the current file. If it has unsaved changes, + it will be saved first using |:update|. If the current file is + an unnamed buffer, it will be written to a temporary file + first. The compiled binary is always placed in a temporary + directory, but is run from the current directory. + + The arguments given to |:RustRun| will be passed to the + compiled binary. + + If ! is specified, the arguments are passed to rustc instead. + A "--" argument will separate the rustc arguments from the + arguments passed to the binary. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +:RustExpand [args] *:RustExpand* +:RustExpand! [TYPE] [args] + Expands the current file using --pretty and displays the + results in a new split. If the current file has unsaved + changes, it will be saved first using |:update|. If the + current file is an unnamed buffer, it will be written to a + temporary file first. + + The arguments given to |:RustExpand| will be passed to rustc. + This is largely intended for specifying various --cfg + configurations. + + If ! is specified, the first argument is the expansion type to + pass to rustc --pretty. Otherwise it will default to + "expanded". + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + + +============================================================================== +MAPPINGS *rust-mappings* + +This plugin defines mappings for |[[| and |]]| to support hanging indents. + +It also has a few other mappings: + + *rust_* + Executes |:RustRun| with no arguments. + Note: This binding is only available in MacVim. + + *rust_* + Populates the command line with |:RustRun|! using the + arguments given to the last invocation, but does not + execute it. + Note: This binding is only available in MacVim. + +============================================================================== + vim:tw=78:sw=4:noet:ts=8:ft=help:norl: diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim index 6e373b2ddc471..ed5d721de0859 100644 --- a/src/etc/vim/ftplugin/rust.vim +++ b/src/etc/vim/ftplugin/rust.vim @@ -60,33 +60,10 @@ onoremap ]] :call rust#Jump('o', 'Forward') " Commands {{{1 -" :RustRun will compile and run the current file. If it has unsaved changes, -" they will be saved first. If it has no path, it will be written to a -" temporary file first. The generated binary is always placed in a temporary -" directory, but run from the current directory. -" -" The arguments passed to :RustRun will be passed to the generated binary. -" -" If ! is specified, the arguments are given to rustc as well. A -- argument -" separates rustc args from the args passed to the binary. -" -" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is -" assumed that rustc is in $PATH. +" See |:RustRun| for docs command! -nargs=* -complete=file -bang -bar -buffer RustRun call rust#Run(0, []) -" :RustExpand will expand the current file using --pretty. -" -" Any arguments given to :RustExpand will be passed to rustc. This is largely -" so you can pass various --cfg configurations. -" -" If ! is specified, the first argument will be interpreted as the --pretty -" type. Otherwise it will default to 'expanded'. -" -" If the current file has unsaved changes, it will be saved first. If it's an -" unnamed buffer, it will be written to a temporary file. -" -" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is -" assumed that rustc is in $PATH. +" See |:RustExpand| for docs command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer RustExpand call rust#Expand(0, []) " Mappings {{{1 From 1273f94cbb19608e6a4e02c54d8543f6fe648a47 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Fri, 30 May 2014 16:35:10 -0700 Subject: [PATCH 29/55] Add commands :RustEmitIr and :RustEmitAsm --- src/etc/vim/autoload/rust.vim | 33 +++++++++++++++++++++++++++++++++ src/etc/vim/doc/rust.txt | 21 +++++++++++++++++++++ src/etc/vim/ftplugin/rust.vim | 8 ++++++++ 3 files changed, 62 insertions(+) diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim index c5bf0c10751b2..c6b9b314da5c4 100644 --- a/src/etc/vim/autoload/rust.vim +++ b/src/etc/vim/autoload/rust.vim @@ -130,6 +130,39 @@ function! rust#CompleteExpand(lead, line, pos) return glob(escape(a:lead, "*?[") . '*', 0, 1) endfunction +" Emit {{{1 + +function! rust#Emit(type, args) + call s:WithPath(function("s:Emit"), a:type, a:args) +endfunction + +function! s:Emit(path, type, args) + try + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + + let args = [a:path, '--emit', a:type, '-o', '-'] + a:args + let output = system(shellescape(rustc) . " " . join(map(args, "shellescape(v:val)"))) + if v:shell_error + echohl WarningMsg + echo output + echohl None + else + new + silent put =output + 1 + d + if a:type == "ir" + setl filetype=llvm + elseif a:type == "asm" + setl filetype=asm + endif + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + endif + endtry +endfunction + " Utility functions {{{1 function! s:WithPath(func, ...) diff --git a/src/etc/vim/doc/rust.txt b/src/etc/vim/doc/rust.txt index e0a647225a9e5..96ed69db63529 100644 --- a/src/etc/vim/doc/rust.txt +++ b/src/etc/vim/doc/rust.txt @@ -107,6 +107,27 @@ COMMANDS *rust-commands* If |g:rustc_path| is defined, it is used as the path to rustc. Otherwise it is assumed rustc can be found in $PATH. +:RustEmitIr [args] *:RustEmitIr* + Compiles the current file to LLVM IR and displays the results + in a new split. If the current file has unsaved changes, it + will be saved first using |:update|. If the current file is an + unnamed buffer, it will be written to a temporary file first. + + The arguments given to |:RustEmitIr| will be passed to rustc. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +:RustEmitAsm [args] *:RustEmitAsm* + Compiles the current file to assembly and displays the results + in a new split. If the current file has unsaved changes, it + will be saved first using |:update|. If the current file is an + unnamed buffer, it will be written to a temporary file first. + + The arguments given to |:RustEmitAsm| will be passed to rustc. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. ============================================================================== MAPPINGS *rust-mappings* diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim index ed5d721de0859..65f9f4105ad8f 100644 --- a/src/etc/vim/ftplugin/rust.vim +++ b/src/etc/vim/ftplugin/rust.vim @@ -66,6 +66,12 @@ command! -nargs=* -complete=file -bang -bar -buffer RustRun call rust#Run( " See |:RustExpand| for docs command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer RustExpand call rust#Expand(0, []) +" See |:RustEmitIr| for docs +command! -nargs=* -bar -buffer RustEmitIr call rust#Emit("ir", []) + +" See |:RustEmitAsm| for docs +command! -nargs=* -bar -buffer RustEmitAsm call rust#Emit("asm", []) + " Mappings {{{1 " Bind ⌘R in MacVim to :RustRun @@ -91,6 +97,8 @@ let b:undo_ftplugin = " \|unlet! b:rust_last_rustc_args b:rust_last_args \|delcommand RustRun \|delcommand RustExpand + \|delcommand RustEmitIr + \|delcommand RustEmitAsm \|nunmap \|nunmap \|nunmap [[ From 87c529c43a41e0c04a468cd2b301013df629b040 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 14 Jun 2014 22:53:55 -0700 Subject: [PATCH 30/55] Add a ByteOrder trait for abstracting over endian conversions The `Bitwise::swap_bytes` method was also moved into the `ByteOrder` trait. This was because it works on the byte level rather than the bit level. --- src/libcore/mem.rs | 336 +++++++++++++++++++++++---------- src/libcore/num/int_macros.rs | 11 -- src/libcore/num/mod.rs | 72 +++---- src/libcore/num/uint_macros.rs | 11 -- 4 files changed, 263 insertions(+), 167 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 237efcd0096d0..6b08a32944c96 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -13,6 +13,7 @@ //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. +use clone::Clone; use ptr; use intrinsics; use intrinsics::{bswap16, bswap32, bswap64}; @@ -169,151 +170,238 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { ptr::write(dst, src) } -/// Convert an u16 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: u16) -> u16 { x } +/// A type that can have its bytes re-ordered. +pub trait ByteOrder: Clone { + /// Reverses the byte order of the value. + /// + /// # Example + /// + /// ```rust + /// use std::mem::ByteOrder; + /// + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0xEFCDAB8967452301u64; + /// + /// assert_eq!(n.swap_bytes(), m); + /// ``` + fn swap_bytes(&self) -> Self; + + /// Convert a value from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// use std::mem::ByteOrder; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(ByteOrder::from_big_endian(n), n) + /// } else { + /// assert_eq!(ByteOrder::from_big_endian(n), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn from_big_endian(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } -/// Convert an u16 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le16(x: u16) -> u16 { unsafe { bswap16(x) } } + /// Convert a value from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// use std::mem::ByteOrder; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(ByteOrder::from_little_endian(n), n) + /// } else { + /// assert_eq!(ByteOrder::from_little_endian(n), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn from_little_endian(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } -/// Convert an u32 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_le32(x: u32) -> u32 { x } + /// Convert the value to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// use std::mem::ByteOrder; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_big_endian(), n) + /// } else { + /// assert_eq!(n.to_big_endian(), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn to_big_endian(&self) -> Self { + if cfg!(target_endian = "big") { self.clone() } else { self.swap_bytes() } + } -/// Convert an u32 to little endian from the target's endianness. + /// Convert the value to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// use std::mem::ByteOrder; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_little_endian(), n) + /// } else { + /// assert_eq!(n.to_little_endian(), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn to_little_endian(&self) -> Self { + if cfg!(target_endian = "little") { self.clone() } else { self.swap_bytes() } + } +} + +impl ByteOrder for u8 { + #[inline] + fn swap_bytes(&self) -> u8 { + *self // swapping a single byte does nothing + } +} + +impl ByteOrder for u16 { + #[inline] + fn swap_bytes(&self) -> u16 { + unsafe { intrinsics::bswap16(*self) } + } +} + +impl ByteOrder for u32 { + #[inline] + fn swap_bytes(&self) -> u32 { + unsafe { intrinsics::bswap32(*self) } + } +} + +impl ByteOrder for u64 { + #[inline] + fn swap_bytes(&self) -> u64 { + unsafe { intrinsics::bswap64(*self) } + } +} + +#[cfg(target_word_size = "32")] +impl ByteOrder for uint { + #[inline] + fn swap_bytes(&self) -> uint { + (*self as u32).swap_bytes() as uint + } +} + +#[cfg(target_word_size = "64")] +impl ByteOrder for uint { + #[inline] + fn swap_bytes(&self) -> uint { + (*self as u64).swap_bytes() as uint + } +} + +/// Convert an u16 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[inline] +#[stable] +pub fn to_le16(x: u16) -> u16 { x.to_little_endian() } -/// Convert an u64 to little endian from the target's endianness. +/// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_le64(x: u64) -> u64 { x } +#[inline] +#[stable] +pub fn to_le32(x: u32) -> u32 { x.to_little_endian() } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le64(x: u64) -> u64 { unsafe { bswap64(x) } } - - -/// Convert an u16 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[inline] +#[stable] +pub fn to_le64(x: u64) -> u64 { x.to_little_endian() } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be16(x: u16) -> u16 { x } - -/// Convert an u32 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[inline] +#[stable] +pub fn to_be16(x: u16) -> u16 { x.to_big_endian() } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be32(x: u32) -> u32 { x } - -/// Convert an u64 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[inline] +#[stable] +pub fn to_be32(x: u32) -> u32 { x.to_big_endian() } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be64(x: u64) -> u64 { x } - - -/// Convert an u16 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le16(x: u16) -> u16 { x } +#[inline] +#[stable] +pub fn to_be64(x: u64) -> u64 { x.to_big_endian() } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le16(x: u16) -> u16 { unsafe { bswap16(x) } } - -/// Convert an u32 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le32(x: u32) -> u32 { x } +#[inline] +#[stable] +pub fn from_le16(x: u16) -> u16 { ByteOrder::from_little_endian(x) } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le32(x: u32) -> u32 { unsafe { bswap32(x) } } - -/// Convert an u64 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le64(x: u64) -> u64 { x } +#[inline] +#[stable] +pub fn from_le32(x: u32) -> u32 { ByteOrder::from_little_endian(x) } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le64(x: u64) -> u64 { unsafe { bswap64(x) } } - - -/// Convert an u16 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[inline] +#[stable] +pub fn from_le64(x: u64) -> u64 { ByteOrder::from_little_endian(x) } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be16(x: u16) -> u16 { x } - -/// Convert an u32 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[inline] +#[stable] +pub fn from_be16(x: u16) -> u16 { ByteOrder::from_big_endian(x) } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be32(x: u32) -> u32 { x } - -/// Convert an u64 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[inline] +#[stable] +pub fn from_be32(x: u32) -> u32 { ByteOrder::from_big_endian(x) } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be64(x: u64) -> u64 { x } +#[inline] +#[stable] +pub fn from_be64(x: u64) -> u64 { ByteOrder::from_big_endian(x) } /** * Swap the values at two mutable locations of the same type, without @@ -558,6 +646,60 @@ mod tests { assert!(Vec::from_slice([76u8]) == transmute("L".to_string())); } } + + macro_rules! test_byte_order { + ($T:ident) => { + mod $T { + use mem::ByteOrder; + + static A: $T = 0b0101100; + static B: $T = 0b0100001; + static C: $T = 0b1111001; + + static _0: $T = 0; + static _1: $T = !0; + + #[test] + fn test_swap_bytes() { + assert_eq!(A.swap_bytes().swap_bytes(), A); + assert_eq!(B.swap_bytes().swap_bytes(), B); + assert_eq!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq!(_0.swap_bytes(), _0); + assert_eq!(_1.swap_bytes(), _1); + } + + #[test] + fn test_little_endian() { + assert_eq!(ByteOrder::from_little_endian(A.to_little_endian()), A); + assert_eq!(ByteOrder::from_little_endian(B.to_little_endian()), B); + assert_eq!(ByteOrder::from_little_endian(C.to_little_endian()), C); + assert_eq!(ByteOrder::from_little_endian(_0), _0); + assert_eq!(ByteOrder::from_little_endian(_1), _1); + assert_eq!(_0.to_little_endian(), _0); + assert_eq!(_1.to_little_endian(), _1); + } + + #[test] + fn test_big_endian() { + assert_eq!(ByteOrder::from_big_endian(A.to_big_endian()), A); + assert_eq!(ByteOrder::from_big_endian(B.to_big_endian()), B); + assert_eq!(ByteOrder::from_big_endian(C.to_big_endian()), C); + assert_eq!(ByteOrder::from_big_endian(_0), _0); + assert_eq!(ByteOrder::from_big_endian(_1), _1); + assert_eq!(_0.to_big_endian(), _0); + assert_eq!(_1.to_big_endian(), _1); + } + } + } + } + + test_byte_order!(u8) + test_byte_order!(u16) + test_byte_order!(u32) + test_byte_order!(u64) + test_byte_order!(uint) } // FIXME #13642 (these benchmarks should be in another place) diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 20bb12db694c0..8a1bd66aa1acc 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -113,17 +113,6 @@ mod tests { assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); } - #[test] - fn test_swap_bytes() { - let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n); - - // Swapping these should make no difference - let n: $T = 0; assert_eq!(n.swap_bytes(), n); - let n: $T = -1; assert_eq!(n.swap_bytes(), n); - } - #[test] fn test_rotate() { let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index eaa632be6d04c..696abc05ed275 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -437,19 +437,6 @@ pub trait Bitwise: Bounded /// ``` fn trailing_zeros(&self) -> Self; - /// Reverses the byte order of a binary number. - /// - /// # Example - /// - /// ```rust - /// use std::num::Bitwise; - /// - /// let n = 0x0123456789ABCDEFu64; - /// let m = 0xEFCDAB8967452301u64; - /// assert_eq!(n.swap_bytes(), m); - /// ``` - fn swap_bytes(&self) -> Self; - /// Shifts the bits to the left by a specified amount amount, `r`, wrapping /// the truncated bits to the end of the resulting value. /// @@ -479,25 +466,17 @@ pub trait Bitwise: Bounded fn rotate_right(&self, r: uint) -> Self; } -/// Swapping a single byte does nothing. This is unsafe to be consistent with -/// the other `bswap` intrinsics. -#[inline] -unsafe fn bswap8(x: u8) -> u8 { x } - -macro_rules! bitwise_impl( - ($t:ty, $bits:expr, $co:ident, $lz:ident, $tz:ident, $bs:path) => { +macro_rules! bitwise_impl { + ($t:ty, $bits:expr, $co:path, $lz:path, $tz:path) => { impl Bitwise for $t { #[inline] - fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self) } } - - #[inline] - fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self) } } + fn count_ones(&self) -> $t { unsafe { $co(*self) } } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self) } } + fn leading_zeros(&self) -> $t { unsafe { $lz(*self) } } #[inline] - fn swap_bytes(&self) -> $t { unsafe { $bs(*self) } } + fn trailing_zeros(&self) -> $t { unsafe { $tz(*self) } } #[inline] fn rotate_left(&self, r: uint) -> $t { @@ -514,22 +493,19 @@ macro_rules! bitwise_impl( } } } -) +} -macro_rules! bitwise_cast_impl( - ($t:ty, $t_cast:ty, $bits:expr, $co:ident, $lz:ident, $tz:ident, $bs:path) => { +macro_rules! bitwise_cast_impl { + ($t:ty, $t_cast:ty, $bits:expr, $co:path, $lz:path, $tz:path) => { impl Bitwise for $t { #[inline] - fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self as $t_cast) as $t } } + fn count_ones(&self) -> $t { unsafe { $co(*self as $t_cast) as $t } } #[inline] - fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self as $t_cast) as $t } } + fn leading_zeros(&self) -> $t { unsafe { $lz(*self as $t_cast) as $t } } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self as $t_cast) as $t } } - - #[inline] - fn swap_bytes(&self) -> $t { unsafe { $bs(*self as $t_cast) as $t } } + fn trailing_zeros(&self) -> $t { unsafe { $tz(*self as $t_cast) as $t } } #[inline] fn rotate_left(&self, r: uint) -> $t { @@ -544,27 +520,27 @@ macro_rules! bitwise_cast_impl( } } } -) +} #[cfg(target_word_size = "32")] -bitwise_cast_impl!(uint, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) +bitwise_cast_impl!(uint, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) #[cfg(target_word_size = "64")] -bitwise_cast_impl!(uint, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) +bitwise_cast_impl!(uint, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) -bitwise_impl!(u8, 8, ctpop8, ctlz8, cttz8, bswap8) -bitwise_impl!(u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16) -bitwise_impl!(u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -bitwise_impl!(u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) +bitwise_impl!(u8, 8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8) +bitwise_impl!(u16, 16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16) +bitwise_impl!(u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) +bitwise_impl!(u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) #[cfg(target_word_size = "32")] -bitwise_cast_impl!(int, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) +bitwise_cast_impl!(int, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) #[cfg(target_word_size = "64")] -bitwise_cast_impl!(int, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) +bitwise_cast_impl!(int, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) -bitwise_cast_impl!(i8, u8, 8, ctpop8, ctlz8, cttz8, bswap8) -bitwise_cast_impl!(i16, u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16) -bitwise_cast_impl!(i32, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -bitwise_cast_impl!(i64, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) +bitwise_cast_impl!(i8, u8, 8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8) +bitwise_cast_impl!(i16, u16, 16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16) +bitwise_cast_impl!(i32, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) +bitwise_cast_impl!(i64, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) /// Specifies the available operations common to all of Rust's core numeric primitives. /// These may not always make sense from a purely mathematical point of view, but diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 8e4ba10154244..8548b14105394 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -64,17 +64,6 @@ mod tests { assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); } - #[test] - fn test_swap_bytes() { - let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n); - - // Swapping these should make no difference - let n: $T = 0; assert_eq!(n.swap_bytes(), n); - let n: $T = MAX; assert_eq!(n.swap_bytes(), n); - } - #[test] fn test_rotate() { let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); From b84d17d4d77b04e1b7784d95e0c3cb2dca16f344 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 14 Jun 2014 23:11:33 -0700 Subject: [PATCH 31/55] Use ByteOrder methods instead of free-standing functions --- src/libcollections/hash/mod.rs | 61 +++++++++++++--------------------- src/libnative/io/net.rs | 9 ++--- src/librustuv/net.rs | 10 +++--- src/libserialize/ebml.rs | 4 +-- src/libuuid/lib.rs | 16 ++++----- 5 files changed, 44 insertions(+), 56 deletions(-) diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index bd7bab456ba01..80417e2a57986 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -98,46 +98,31 @@ pub trait Writer { ////////////////////////////////////////////////////////////////////////////// -fn id(t: T) -> T { t } - -macro_rules! impl_hash( - ( $($ty:ident, $uty:ident, $f:path;)* ) => ( - $( - impl Hash for $ty { - #[inline] - fn hash(&self, state: &mut S) { - let a: [u8, ..::core::$ty::BYTES] = unsafe { - mem::transmute($f(*self as $uty) as $ty) - }; - state.write(a.as_slice()) - } +macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl Hash for $ty { + #[inline] + fn hash(&self, state: &mut S) { + use core::mem::ByteOrder; + let a: [u8, ..::core::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_little_endian() as $ty) + }; + state.write(a.as_slice()) } - )* - ) -) - -impl_hash!( - u8, u8, id; - u16, u16, mem::to_le16; - u32, u32, mem::to_le32; - u64, u64, mem::to_le64; - i8, u8, id; - i16, u16, mem::to_le16; - i32, u32, mem::to_le32; - i64, u64, mem::to_le64; -) - -#[cfg(target_word_size = "32")] -impl_hash!( - uint, u32, mem::to_le32; - int, u32, mem::to_le32; -) + } + } +} -#[cfg(target_word_size = "64")] -impl_hash!( - uint, u64, mem::to_le64; - int, u64, mem::to_le64; -) +impl_hash!(u8, u8) +impl_hash!(u16, u16) +impl_hash!(u32, u32) +impl_hash!(u64, u64) +impl_hash!(uint, uint) +impl_hash!(i8, u8) +impl_hash!(i16, u16) +impl_hash!(i32, u32) +impl_hash!(i64, u64) +impl_hash!(int, uint) impl Hash for bool { #[inline] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 8cf0c3bf0620f..f0cd2d966cb36 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -11,6 +11,7 @@ use alloc::arc::Arc; use libc; use std::mem; +use std::mem::ByteOrder; use std::rt::mutex; use std::rt::rtio; use std::rt::rtio::{IoResult, IoError}; @@ -27,10 +28,10 @@ use super::util; #[cfg(unix)] pub type sock_t = super::file::fd_t; pub fn htons(u: u16) -> u16 { - mem::to_be16(u) + u.to_big_endian() } pub fn ntohs(u: u16) -> u16 { - mem::from_be16(u) + ByteOrder::from_big_endian(u) } enum InAddr { @@ -46,7 +47,7 @@ fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr { (c as u32 << 8) | (d as u32 << 0); InAddr(libc::in_addr { - s_addr: mem::from_be32(ip) + s_addr: ByteOrder::from_big_endian(ip) }) } rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -180,7 +181,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = mem::to_be32(storage.sin_addr.s_addr as u32); + let ip = (storage.sin_addr.s_addr as u32).to_big_endian(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index c8fb0f496dcb7..83beeceb8de3e 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -11,6 +11,7 @@ use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use libc; use std::mem; +use std::mem::ByteOrder; use std::ptr; use std::rt::rtio; use std::rt::rtio::IoError; @@ -30,8 +31,8 @@ use uvll; /// Generic functions related to dealing with sockaddr things //////////////////////////////////////////////////////////////////////////////// -pub fn htons(u: u16) -> u16 { mem::to_be16(u) } -pub fn ntohs(u: u16) -> u16 { mem::from_be16(u) } +pub fn htons(u: u16) -> u16 { u.to_big_endian() } +pub fn ntohs(u: u16) -> u16 { ByteOrder::from_big_endian(u) } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: uint) -> rtio::SocketAddr { @@ -41,7 +42,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = mem::to_be32(storage.sin_addr.s_addr as u32); + let ip = (storage.sin_addr.s_addr as u32).to_big_endian(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; @@ -89,7 +90,8 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { (*storage).sin_family = libc::AF_INET as libc::sa_family_t; (*storage).sin_port = htons(addr.port); (*storage).sin_addr = libc::in_addr { - s_addr: mem::from_be32(ip) + s_addr: ByteOrder::from_big_endian(ip), + }; mem::size_of::() } diff --git a/src/libserialize/ebml.rs b/src/libserialize/ebml.rs index 9ba2c2cd258ed..a1c79bc0b757c 100644 --- a/src/libserialize/ebml.rs +++ b/src/libserialize/ebml.rs @@ -154,7 +154,7 @@ pub mod reader { } pub fn vuint_at(data: &[u8], start: uint) -> DecodeResult { - use std::mem::from_be32; + use std::mem::ByteOrder; if data.len() - start < 4 { return vuint_at_slow(data, start); @@ -185,7 +185,7 @@ pub mod reader { unsafe { let ptr = data.as_ptr().offset(start as int) as *u32; - let val = from_be32(*ptr); + let val = ByteOrder::from_big_endian(*ptr); let i = (val >> 28u) as uint; let (shift, mask) = SHIFT_MASK_TABLE[i]; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index bace30e3f6ffd..1140f023d43fd 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -209,7 +209,7 @@ impl Uuid { /// * `d3` A 16-bit word /// * `d4` Array of 8 octets pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid { - use std::mem::{to_be16, to_be32}; + use std::mem::ByteOrder; // First construct a temporary field-based struct let mut fields = UuidFields { @@ -219,9 +219,9 @@ impl Uuid { data4: [0, ..8] }; - fields.data1 = to_be32(d1); - fields.data2 = to_be16(d2); - fields.data3 = to_be16(d3); + fields.data1 = d1.to_big_endian(); + fields.data2 = d2.to_big_endian(); + fields.data3 = d3.to_big_endian(); slice::bytes::copy_memory(fields.data4, d4); unsafe { @@ -335,16 +335,16 @@ impl Uuid { /// /// Example: `550e8400-e29b-41d4-a716-446655440000` pub fn to_hyphenated_str(&self) -> String { - use std::mem::{to_be16, to_be32}; + use std::mem::ByteOrder; // Convert to field-based struct as it matches groups in output. // Ensure fields are in network byte order, as per RFC. let mut uf: UuidFields; unsafe { uf = transmute_copy(&self.bytes); } - uf.data1 = to_be32(uf.data1); - uf.data2 = to_be16(uf.data2); - uf.data3 = to_be16(uf.data3); + uf.data1 = uf.data1.to_big_endian(); + uf.data2 = uf.data2.to_big_endian(); + uf.data3 = uf.data3.to_big_endian(); let s = format!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}-\ {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", uf.data1, From 4c0f8f49f6fe860efa268efa2f4fa0b5f00a4b07 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 16 Jun 2014 00:22:51 -0700 Subject: [PATCH 32/55] Fix comment formatting --- src/libcore/mem.rs | 76 ++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 6b08a32944c96..b64ee9bf4f702 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -403,10 +403,8 @@ pub fn from_be32(x: u32) -> u32 { ByteOrder::from_big_endian(x) } #[stable] pub fn from_be64(x: u64) -> u64 { ByteOrder::from_big_endian(x) } -/** - * Swap the values at two mutable locations of the same type, without - * deinitialising or copying either one. - */ +/// Swap the values at two mutable locations of the same type, without +/// deinitialising or copying either one. #[inline] #[stable] pub fn swap(x: &mut T, y: &mut T) { @@ -425,42 +423,40 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/** - * Replace the value at a mutable location with a new one, returning the old - * value, without deinitialising or copying either one. - * - * This is primarily used for transferring and swapping ownership of a value - * in a mutable location. For example, this function allows consumption of - * one field of a struct by replacing it with another value. The normal approach - * doesn't always work: - * - * ```rust,ignore - * struct Buffer { buf: Vec } - * - * impl Buffer { - * fn get_and_reset(&mut self) -> Vec { - * // error: cannot move out of dereference of `&mut`-pointer - * let buf = self.buf; - * self.buf = Vec::new(); - * buf - * } - * } - * ``` - * - * Note that `T` does not necessarily implement `Clone`, so it can't even - * clone and reset `self.buf`. But `replace` can be used to disassociate - * the original value of `self.buf` from `self`, allowing it to be returned: - * - * ```rust - * # struct Buffer { buf: Vec } - * impl Buffer { - * fn get_and_reset(&mut self) -> Vec { - * use std::mem::replace; - * replace(&mut self.buf, Vec::new()) - * } - * } - * ``` - */ +/// Replace the value at a mutable location with a new one, returning the old +/// value, without deinitialising or copying either one. +/// +/// This is primarily used for transferring and swapping ownership of a value +/// in a mutable location. For example, this function allows consumption of +/// one field of a struct by replacing it with another value. The normal approach +/// doesn't always work: +/// +/// ```rust,ignore +/// struct Buffer { buf: Vec } +/// +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// // error: cannot move out of dereference of `&mut`-pointer +/// let buf = self.buf; +/// self.buf = Vec::new(); +/// buf +/// } +/// } +/// ``` +/// +/// Note that `T` does not necessarily implement `Clone`, so it can't even +/// clone and reset `self.buf`. But `replace` can be used to disassociate +/// the original value of `self.buf` from `self`, allowing it to be returned: +/// +/// ```rust +/// # struct Buffer { buf: Vec } +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// use std::mem::replace; +/// replace(&mut self.buf, Vec::new()) +/// } +/// } +/// ``` #[inline] #[stable] pub fn replace(dest: &mut T, mut src: T) -> T { From ff9f92ce5224f5e27b8dc39ffc02eb9481f7cff1 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 16 Jun 2014 11:25:47 -0700 Subject: [PATCH 33/55] Merge the Bitwise and ByteOrder traits into the Int trait This reduces the complexity of the trait hierarchy. --- src/libcollections/enum_set.rs | 2 - src/libcollections/hash/mod.rs | 1 - src/libcore/mem.rs | 220 +--------------------- src/libcore/num/int_macros.rs | 69 +++++-- src/libcore/num/mod.rs | 305 ++++++++++++++++++++----------- src/libcore/num/uint_macros.rs | 69 +++++-- src/libnative/io/net.rs | 5 +- src/libnum/bigint.rs | 2 +- src/librustc/middle/trans/adt.rs | 1 - src/librustuv/net.rs | 5 +- src/libserialize/ebml.rs | 4 +- src/libstd/num/mod.rs | 2 +- src/libuuid/lib.rs | 3 - src/test/bench/sudoku.rs | 1 - 14 files changed, 325 insertions(+), 364 deletions(-) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 34514fde9dbd1..1360b412c2370 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -15,8 +15,6 @@ use core::prelude::*; -use core::num::Bitwise; - #[deriving(Clone, PartialEq, Eq, Hash, Show)] /// A specialized Set implementation to use enum types. pub struct EnumSet { diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index 80417e2a57986..07c768d0c7916 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -103,7 +103,6 @@ macro_rules! impl_hash { impl Hash for $ty { #[inline] fn hash(&self, state: &mut S) { - use core::mem::ByteOrder; let a: [u8, ..::core::$ty::BYTES] = unsafe { mem::transmute((*self as $uty).to_little_endian() as $ty) }; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b64ee9bf4f702..eab344ac7a701 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -13,10 +13,9 @@ //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. -use clone::Clone; -use ptr; use intrinsics; -use intrinsics::{bswap16, bswap32, bswap64}; +use num::Int; +use ptr; pub use intrinsics::transmute; @@ -170,155 +169,6 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { ptr::write(dst, src) } -/// A type that can have its bytes re-ordered. -pub trait ByteOrder: Clone { - /// Reverses the byte order of the value. - /// - /// # Example - /// - /// ```rust - /// use std::mem::ByteOrder; - /// - /// let n = 0x0123456789ABCDEFu64; - /// let m = 0xEFCDAB8967452301u64; - /// - /// assert_eq!(n.swap_bytes(), m); - /// ``` - fn swap_bytes(&self) -> Self; - - /// Convert a value from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are swapped. - /// - /// # Example - /// - /// ```rust - /// use std::mem::ByteOrder; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(ByteOrder::from_big_endian(n), n) - /// } else { - /// assert_eq!(ByteOrder::from_big_endian(n), n.swap_bytes()) - /// } - /// ``` - #[inline] - fn from_big_endian(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - - /// Convert a value from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are swapped. - /// - /// # Example - /// - /// ```rust - /// use std::mem::ByteOrder; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(ByteOrder::from_little_endian(n), n) - /// } else { - /// assert_eq!(ByteOrder::from_little_endian(n), n.swap_bytes()) - /// } - /// ``` - #[inline] - fn from_little_endian(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - - /// Convert the value to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are swapped. - /// - /// # Example - /// - /// ```rust - /// use std::mem::ByteOrder; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_big_endian(), n) - /// } else { - /// assert_eq!(n.to_big_endian(), n.swap_bytes()) - /// } - /// ``` - #[inline] - fn to_big_endian(&self) -> Self { - if cfg!(target_endian = "big") { self.clone() } else { self.swap_bytes() } - } - - /// Convert the value to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are swapped. - /// - /// # Example - /// - /// ```rust - /// use std::mem::ByteOrder; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_little_endian(), n) - /// } else { - /// assert_eq!(n.to_little_endian(), n.swap_bytes()) - /// } - /// ``` - #[inline] - fn to_little_endian(&self) -> Self { - if cfg!(target_endian = "little") { self.clone() } else { self.swap_bytes() } - } -} - -impl ByteOrder for u8 { - #[inline] - fn swap_bytes(&self) -> u8 { - *self // swapping a single byte does nothing - } -} - -impl ByteOrder for u16 { - #[inline] - fn swap_bytes(&self) -> u16 { - unsafe { intrinsics::bswap16(*self) } - } -} - -impl ByteOrder for u32 { - #[inline] - fn swap_bytes(&self) -> u32 { - unsafe { intrinsics::bswap32(*self) } - } -} - -impl ByteOrder for u64 { - #[inline] - fn swap_bytes(&self) -> u64 { - unsafe { intrinsics::bswap64(*self) } - } -} - -#[cfg(target_word_size = "32")] -impl ByteOrder for uint { - #[inline] - fn swap_bytes(&self) -> uint { - (*self as u32).swap_bytes() as uint - } -} - -#[cfg(target_word_size = "64")] -impl ByteOrder for uint { - #[inline] - fn swap_bytes(&self) -> uint { - (*self as u64).swap_bytes() as uint - } -} - /// Convert an u16 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. @@ -366,42 +216,42 @@ pub fn to_be64(x: u64) -> u64 { x.to_big_endian() } /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] #[stable] -pub fn from_le16(x: u16) -> u16 { ByteOrder::from_little_endian(x) } +pub fn from_le16(x: u16) -> u16 { Int::from_little_endian(x) } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] #[stable] -pub fn from_le32(x: u32) -> u32 { ByteOrder::from_little_endian(x) } +pub fn from_le32(x: u32) -> u32 { Int::from_little_endian(x) } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] #[stable] -pub fn from_le64(x: u64) -> u64 { ByteOrder::from_little_endian(x) } +pub fn from_le64(x: u64) -> u64 { Int::from_little_endian(x) } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] #[stable] -pub fn from_be16(x: u16) -> u16 { ByteOrder::from_big_endian(x) } +pub fn from_be16(x: u16) -> u16 { Int::from_big_endian(x) } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] #[stable] -pub fn from_be32(x: u32) -> u32 { ByteOrder::from_big_endian(x) } +pub fn from_be32(x: u32) -> u32 { Int::from_big_endian(x) } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] #[stable] -pub fn from_be64(x: u64) -> u64 { ByteOrder::from_big_endian(x) } +pub fn from_be64(x: u64) -> u64 { Int::from_big_endian(x) } /// Swap the values at two mutable locations of the same type, without /// deinitialising or copying either one. @@ -642,60 +492,6 @@ mod tests { assert!(Vec::from_slice([76u8]) == transmute("L".to_string())); } } - - macro_rules! test_byte_order { - ($T:ident) => { - mod $T { - use mem::ByteOrder; - - static A: $T = 0b0101100; - static B: $T = 0b0100001; - static C: $T = 0b1111001; - - static _0: $T = 0; - static _1: $T = !0; - - #[test] - fn test_swap_bytes() { - assert_eq!(A.swap_bytes().swap_bytes(), A); - assert_eq!(B.swap_bytes().swap_bytes(), B); - assert_eq!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq!(_0.swap_bytes(), _0); - assert_eq!(_1.swap_bytes(), _1); - } - - #[test] - fn test_little_endian() { - assert_eq!(ByteOrder::from_little_endian(A.to_little_endian()), A); - assert_eq!(ByteOrder::from_little_endian(B.to_little_endian()), B); - assert_eq!(ByteOrder::from_little_endian(C.to_little_endian()), C); - assert_eq!(ByteOrder::from_little_endian(_0), _0); - assert_eq!(ByteOrder::from_little_endian(_1), _1); - assert_eq!(_0.to_little_endian(), _0); - assert_eq!(_1.to_little_endian(), _1); - } - - #[test] - fn test_big_endian() { - assert_eq!(ByteOrder::from_big_endian(A.to_big_endian()), A); - assert_eq!(ByteOrder::from_big_endian(B.to_big_endian()), B); - assert_eq!(ByteOrder::from_big_endian(C.to_big_endian()), C); - assert_eq!(ByteOrder::from_big_endian(_0), _0); - assert_eq!(ByteOrder::from_big_endian(_1), _1); - assert_eq!(_0.to_big_endian(), _0); - assert_eq!(_1.to_big_endian(), _1); - } - } - } - } - - test_byte_order!(u8) - test_byte_order!(u16) - test_byte_order!(u32) - test_byte_order!(u64) - test_byte_order!(uint) } // FIXME #13642 (these benchmarks should be in another place) diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 8a1bd66aa1acc..84744b3f5d701 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -35,7 +35,6 @@ mod tests { use int; use num; - use num::Bitwise; use num::CheckedDiv; #[test] @@ -90,7 +89,7 @@ mod tests { } #[test] - fn test_bitwise() { + fn test_bitwise_operators() { assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); @@ -99,34 +98,74 @@ mod tests { assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not()); } + static A: $T = 0b0101100; + static B: $T = 0b0100001; + static C: $T = 0b1111001; + + static _0: $T = 0; + static _1: $T = !0; + #[test] fn test_count_ones() { - assert!((0b0101100 as $T).count_ones() == 3); - assert!((0b0100001 as $T).count_ones() == 2); - assert!((0b1111001 as $T).count_ones() == 5); + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); } #[test] fn test_count_zeros() { - assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3); - assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2); - assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); + assert!(A.count_zeros() == BITS as $T - 3); + assert!(B.count_zeros() == BITS as $T - 2); + assert!(C.count_zeros() == BITS as $T - 5); } #[test] fn test_rotate() { - let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); - let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5), n); - let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); + assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do // not cause undefined behaviour. See #10183. - let n: $T = 0; assert_eq!(n.rotate_left(124), n); - let n: $T = -1; assert_eq!(n.rotate_left(124), n); - let n: $T = 0; assert_eq!(n.rotate_right(124), n); - let n: $T = -1; assert_eq!(n.rotate_right(124), n); + assert_eq!(_0.rotate_left(124), _0); + assert_eq!(_1.rotate_left(124), _1); + assert_eq!(_0.rotate_right(124), _0); + assert_eq!(_1.rotate_right(124), _1); + } + + #[test] + fn test_swap_bytes() { + assert_eq!(A.swap_bytes().swap_bytes(), A); + assert_eq!(B.swap_bytes().swap_bytes(), B); + assert_eq!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq!(_0.swap_bytes(), _0); + assert_eq!(_1.swap_bytes(), _1); + } + + #[test] + fn test_little_endian() { + assert_eq!(Int::from_little_endian(A.to_little_endian()), A); + assert_eq!(Int::from_little_endian(B.to_little_endian()), B); + assert_eq!(Int::from_little_endian(C.to_little_endian()), C); + assert_eq!(Int::from_little_endian(_0), _0); + assert_eq!(Int::from_little_endian(_1), _1); + assert_eq!(_0.to_little_endian(), _0); + assert_eq!(_1.to_little_endian(), _1); + } + + #[test] + fn test_big_endian() { + assert_eq!(Int::from_big_endian(A.to_big_endian()), A); + assert_eq!(Int::from_big_endian(B.to_big_endian()), B); + assert_eq!(Int::from_big_endian(C.to_big_endian()), C); + assert_eq!(Int::from_big_endian(_0), _0); + assert_eq!(Int::from_big_endian(_1), _1); + assert_eq!(_0.to_big_endian(), _0); + assert_eq!(_1.to_big_endian(), _1); } #[test] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 696abc05ed275..ed0c24e7fa008 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -376,193 +376,292 @@ bounded_impl!(i64, i64::MIN, i64::MAX) bounded_impl!(f32, f32::MIN_VALUE, f32::MAX_VALUE) bounded_impl!(f64, f64::MIN_VALUE, f64::MAX_VALUE) -/// Numbers with a fixed binary representation. -pub trait Bitwise: Bounded - + Not - + BitAnd - + BitOr - + BitXor - + Shl - + Shr { - /// Returns the number of ones in the binary representation of the number. +/// Specifies the available operations common to all of Rust's core numeric primitives. +/// These may not always make sense from a purely mathematical point of view, but +/// may be useful for systems programming. +pub trait Primitive: Copy + + Clone + + Num + + NumCast + + PartialOrd + + Bounded {} + +trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) + +/// A collection of traits relevant to primitive signed and unsigned integers +pub trait Int: Primitive + + CheckedAdd + + CheckedSub + + CheckedMul + + CheckedDiv + + Bounded + + Not + + BitAnd + + BitOr + + BitXor + + Shl + + Shr { + /// Returns the number of ones in the binary representation of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b01001100u8; + /// /// assert_eq!(n.count_ones(), 3); /// ``` - fn count_ones(&self) -> Self; + fn count_ones(self) -> Self; - /// Returns the number of zeros in the binary representation of the number. + /// Returns the number of zeros in the binary representation of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b01001100u8; + /// /// assert_eq!(n.count_zeros(), 5); /// ``` #[inline] - fn count_zeros(&self) -> Self { - (!*self).count_ones() + fn count_zeros(self) -> Self { + (!self).count_ones() } /// Returns the number of leading zeros in the in the binary representation - /// of the number. + /// of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b0101000u16; + /// /// assert_eq!(n.leading_zeros(), 10); /// ``` - fn leading_zeros(&self) -> Self; + fn leading_zeros(self) -> Self; /// Returns the number of trailing zeros in the in the binary representation - /// of the number. + /// of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b0101000u16; + /// /// assert_eq!(n.trailing_zeros(), 3); /// ``` - fn trailing_zeros(&self) -> Self; + fn trailing_zeros(self) -> Self; - /// Shifts the bits to the left by a specified amount amount, `r`, wrapping - /// the truncated bits to the end of the resulting value. + /// Shifts the bits to the left by a specified amount amount, `n`, wrapping + /// the truncated bits to the end of the resulting integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF012u64; + /// /// assert_eq!(n.rotate_left(12), m); /// ``` - fn rotate_left(&self, r: uint) -> Self; + fn rotate_left(self, n: uint) -> Self; - /// Shifts the bits to the right by a specified amount amount, `r`, wrapping - /// the truncated bits to the beginning of the resulting value. + /// Shifts the bits to the right by a specified amount amount, `n`, wrapping + /// the truncated bits to the beginning of the resulting integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xDEF0123456789ABCu64; + /// /// assert_eq!(n.rotate_right(12), m); /// ``` - fn rotate_right(&self, r: uint) -> Self; + fn rotate_right(self, n: uint) -> Self; + + /// Reverses the byte order of the integer. + /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0xEFCDAB8967452301u64; + /// + /// assert_eq!(n.swap_bytes(), m); + /// ``` + fn swap_bytes(self) -> Self; + + /// Convert a integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(Int::from_big_endian(n), n) + /// } else { + /// assert_eq!(Int::from_big_endian(n), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn from_big_endian(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } + + /// Convert a integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(Int::from_little_endian(n), n) + /// } else { + /// assert_eq!(Int::from_little_endian(n), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn from_little_endian(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } + + /// Convert the integer to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_big_endian(), n) + /// } else { + /// assert_eq!(n.to_big_endian(), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn to_big_endian(self) -> Self { + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } + + /// Convert the integer to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_little_endian(), n) + /// } else { + /// assert_eq!(n.to_little_endian(), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn to_little_endian(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } } -macro_rules! bitwise_impl { - ($t:ty, $bits:expr, $co:path, $lz:path, $tz:path) => { - impl Bitwise for $t { +macro_rules! int_impl { + ($T:ty, $BITS:expr, $ctpop:path, $ctlz:path, $cttz:path, $bswap:path) => { + impl Int for $T { #[inline] - fn count_ones(&self) -> $t { unsafe { $co(*self) } } + fn count_ones(self) -> $T { unsafe { $ctpop(self) } } #[inline] - fn leading_zeros(&self) -> $t { unsafe { $lz(*self) } } + fn leading_zeros(self) -> $T { unsafe { $ctlz(self) } } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { $tz(*self) } } + fn trailing_zeros(self) -> $T { unsafe { $cttz(self) } } #[inline] - fn rotate_left(&self, r: uint) -> $t { - // Protect against undefined behaviour for overlong bit shifts - let r = r % $bits; - (*self << r) | (*self >> ($bits - r)) + fn rotate_left(self, n: uint) -> $T { + // Protect against undefined behaviour for over-long bit shifts + let n = n % $BITS; + (self << n) | (self >> ($BITS - n)) } #[inline] - fn rotate_right(&self, r: uint) -> $t { - // Protect against undefined behaviour for overlong bit shifts - let r = r % $bits; - (*self >> r) | (*self << ($bits - r)) + fn rotate_right(self, n: uint) -> $T { + // Protect against undefined behaviour for over-long bit shifts + let n = n % $BITS; + (self >> n) | (self << ($BITS - n)) } + + #[inline] + fn swap_bytes(self) -> $T { unsafe { $bswap(self) } } } } } -macro_rules! bitwise_cast_impl { - ($t:ty, $t_cast:ty, $bits:expr, $co:path, $lz:path, $tz:path) => { - impl Bitwise for $t { +/// Swapping a single byte is a no-op. This is marked as `unsafe` for +/// consistency with the other `bswap` intrinsics. +unsafe fn bswap8(x: u8) -> u8 { x } + +int_impl!(u8, 8, + intrinsics::ctpop8, + intrinsics::ctlz8, + intrinsics::cttz8, + bswap8) + +int_impl!(u16, 16, + intrinsics::ctpop16, + intrinsics::ctlz16, + intrinsics::cttz16, + intrinsics::bswap16) + +int_impl!(u32, 32, + intrinsics::ctpop32, + intrinsics::ctlz32, + intrinsics::cttz32, + intrinsics::bswap32) + +int_impl!(u64, 64, + intrinsics::ctpop64, + intrinsics::ctlz64, + intrinsics::cttz64, + intrinsics::bswap64) + +macro_rules! int_cast_impl { + ($T:ty, $U:ty) => { + impl Int for $T { #[inline] - fn count_ones(&self) -> $t { unsafe { $co(*self as $t_cast) as $t } } + fn count_ones(self) -> $T { (self as $U).count_ones() as $T } #[inline] - fn leading_zeros(&self) -> $t { unsafe { $lz(*self as $t_cast) as $t } } + fn leading_zeros(self) -> $T { (self as $U).leading_zeros() as $T } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { $tz(*self as $t_cast) as $t } } + fn trailing_zeros(self) -> $T { (self as $U).trailing_zeros() as $T } #[inline] - fn rotate_left(&self, r: uint) -> $t { - // cast to prevent the sign bit from being corrupted - (*self as $t_cast).rotate_left(r) as $t - } + fn rotate_left(self, n: uint) -> $T { (self as $U).rotate_left(n) as $T } #[inline] - fn rotate_right(&self, r: uint) -> $t { - // cast to prevent the sign bit from being corrupted - (*self as $t_cast).rotate_right(r) as $t - } + fn rotate_right(self, n: uint) -> $T { (self as $U).rotate_right(n) as $T } + + #[inline] + fn swap_bytes(self) -> $T { (self as $U).swap_bytes() as $T } } } } -#[cfg(target_word_size = "32")] -bitwise_cast_impl!(uint, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) -#[cfg(target_word_size = "64")] -bitwise_cast_impl!(uint, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) - -bitwise_impl!(u8, 8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8) -bitwise_impl!(u16, 16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16) -bitwise_impl!(u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) -bitwise_impl!(u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) - -#[cfg(target_word_size = "32")] -bitwise_cast_impl!(int, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) -#[cfg(target_word_size = "64")] -bitwise_cast_impl!(int, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) - -bitwise_cast_impl!(i8, u8, 8, intrinsics::ctpop8, intrinsics::ctlz8, intrinsics::cttz8) -bitwise_cast_impl!(i16, u16, 16, intrinsics::ctpop16, intrinsics::ctlz16, intrinsics::cttz16) -bitwise_cast_impl!(i32, u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, intrinsics::cttz32) -bitwise_cast_impl!(i64, u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, intrinsics::cttz64) - -/// Specifies the available operations common to all of Rust's core numeric primitives. -/// These may not always make sense from a purely mathematical point of view, but -/// may be useful for systems programming. -pub trait Primitive: Copy - + Clone - + Num - + NumCast - + PartialOrd - + Bounded {} - -trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) - -/// A collection of traits relevant to primitive signed and unsigned integers -pub trait Int: Primitive - + Bitwise - + CheckedAdd - + CheckedSub - + CheckedMul - + CheckedDiv {} +int_cast_impl!(i8, u8) +int_cast_impl!(i16, u16) +int_cast_impl!(i32, u32) +int_cast_impl!(i64, u64) -trait_impl!(Int for uint u8 u16 u32 u64 int i8 i16 i32 i64) +#[cfg(target_word_size = "32")] int_cast_impl!(uint, u32) +#[cfg(target_word_size = "64")] int_cast_impl!(uint, u64) +#[cfg(target_word_size = "32")] int_cast_impl!(int, u32) +#[cfg(target_word_size = "64")] int_cast_impl!(int, u64) /// Returns the smallest power of 2 greater than or equal to `n`. #[inline] diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 8548b14105394..1fe3c4cf1f1cf 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -26,7 +26,6 @@ mod tests { use num; use num::CheckedDiv; - use num::Bitwise; #[test] fn test_overflows() { @@ -41,7 +40,7 @@ mod tests { } #[test] - fn test_bitwise() { + fn test_bitwise_operators() { assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); @@ -50,34 +49,74 @@ mod tests { assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); } + static A: $T = 0b0101100; + static B: $T = 0b0100001; + static C: $T = 0b1111001; + + static _0: $T = 0; + static _1: $T = !0; + #[test] fn test_count_ones() { - assert!((0b0101100 as $T).count_ones() == 3); - assert!((0b0100001 as $T).count_ones() == 2); - assert!((0b1111001 as $T).count_ones() == 5); + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); } #[test] fn test_count_zeros() { - assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3); - assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2); - assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); + assert!(A.count_zeros() == BITS as $T - 3); + assert!(B.count_zeros() == BITS as $T - 2); + assert!(C.count_zeros() == BITS as $T - 5); } #[test] fn test_rotate() { - let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); - let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5), n); - let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); + assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); // Rotating these should make no difference // // We test using 124 bits because to ensure that overlong bit shifts do // not cause undefined behaviour. See #10183. - let n: $T = 0; assert_eq!(n.rotate_left(124), n); - let n: $T = MAX; assert_eq!(n.rotate_left(124), n); - let n: $T = 0; assert_eq!(n.rotate_right(124), n); - let n: $T = MAX; assert_eq!(n.rotate_right(124), n); + assert_eq!(_0.rotate_left(124), _0); + assert_eq!(_1.rotate_left(124), _1); + assert_eq!(_0.rotate_right(124), _0); + assert_eq!(_1.rotate_right(124), _1); + } + + #[test] + fn test_swap_bytes() { + assert_eq!(A.swap_bytes().swap_bytes(), A); + assert_eq!(B.swap_bytes().swap_bytes(), B); + assert_eq!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq!(_0.swap_bytes(), _0); + assert_eq!(_1.swap_bytes(), _1); + } + + #[test] + fn test_little_endian() { + assert_eq!(Int::from_little_endian(A.to_little_endian()), A); + assert_eq!(Int::from_little_endian(B.to_little_endian()), B); + assert_eq!(Int::from_little_endian(C.to_little_endian()), C); + assert_eq!(Int::from_little_endian(_0), _0); + assert_eq!(Int::from_little_endian(_1), _1); + assert_eq!(_0.to_little_endian(), _0); + assert_eq!(_1.to_little_endian(), _1); + } + + #[test] + fn test_big_endian() { + assert_eq!(Int::from_big_endian(A.to_big_endian()), A); + assert_eq!(Int::from_big_endian(B.to_big_endian()), B); + assert_eq!(Int::from_big_endian(C.to_big_endian()), C); + assert_eq!(Int::from_big_endian(_0), _0); + assert_eq!(Int::from_big_endian(_1), _1); + assert_eq!(_0.to_big_endian(), _0); + assert_eq!(_1.to_big_endian(), _1); } #[test] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index f0cd2d966cb36..23fd607aafeef 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -11,7 +11,6 @@ use alloc::arc::Arc; use libc; use std::mem; -use std::mem::ByteOrder; use std::rt::mutex; use std::rt::rtio; use std::rt::rtio::{IoResult, IoError}; @@ -31,7 +30,7 @@ pub fn htons(u: u16) -> u16 { u.to_big_endian() } pub fn ntohs(u: u16) -> u16 { - ByteOrder::from_big_endian(u) + Int::from_big_endian(u) } enum InAddr { @@ -47,7 +46,7 @@ fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr { (c as u32 << 8) | (d as u32 << 0); InAddr(libc::in_addr { - s_addr: ByteOrder::from_big_endian(ip) + s_addr: Int::from_big_endian(ip) }) } rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 0933301970d19..e9153f89e04ee 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -23,7 +23,7 @@ use std::{cmp, fmt}; use std::default::Default; use std::from_str::FromStr; use std::num::CheckedDiv; -use std::num::{Bitwise, ToPrimitive, FromPrimitive}; +use std::num::{ToPrimitive, FromPrimitive}; use std::num::{Zero, One, ToStrRadix, FromStrRadix}; use std::string::String; use std::{uint, i64, u64}; diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 9f4b11116dbb7..e4b28dc7aa7c2 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -46,7 +46,6 @@ #![allow(unsigned_negate)] use libc::c_ulonglong; -use std::num::{Bitwise}; use std::rc::Rc; use lib::llvm::{ValueRef, True, IntEQ, IntNE}; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 83beeceb8de3e..aa7fab2565d8c 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -11,7 +11,6 @@ use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use libc; use std::mem; -use std::mem::ByteOrder; use std::ptr; use std::rt::rtio; use std::rt::rtio::IoError; @@ -32,7 +31,7 @@ use uvll; //////////////////////////////////////////////////////////////////////////////// pub fn htons(u: u16) -> u16 { u.to_big_endian() } -pub fn ntohs(u: u16) -> u16 { ByteOrder::from_big_endian(u) } +pub fn ntohs(u: u16) -> u16 { Int::from_big_endian(u) } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: uint) -> rtio::SocketAddr { @@ -90,7 +89,7 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { (*storage).sin_family = libc::AF_INET as libc::sa_family_t; (*storage).sin_port = htons(addr.port); (*storage).sin_addr = libc::in_addr { - s_addr: ByteOrder::from_big_endian(ip), + s_addr: Int::from_big_endian(ip), }; mem::size_of::() diff --git a/src/libserialize/ebml.rs b/src/libserialize/ebml.rs index a1c79bc0b757c..7d0c82fc9a2d5 100644 --- a/src/libserialize/ebml.rs +++ b/src/libserialize/ebml.rs @@ -154,8 +154,6 @@ pub mod reader { } pub fn vuint_at(data: &[u8], start: uint) -> DecodeResult { - use std::mem::ByteOrder; - if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -185,7 +183,7 @@ pub mod reader { unsafe { let ptr = data.as_ptr().offset(start as int) as *u32; - let val = ByteOrder::from_big_endian(*ptr); + let val = Int::from_big_endian(*ptr); let i = (val >> 28u) as uint; let (shift, mask) = SHIFT_MASK_TABLE[i]; diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 602a2240f3908..7301f9b08e9dc 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -22,7 +22,7 @@ use string::String; pub use core::num::{Num, div_rem, Zero, zero, One, one}; pub use core::num::{Signed, abs, abs_sub, signum}; -pub use core::num::{Unsigned, pow, Bounded, Bitwise}; +pub use core::num::{Unsigned, pow, Bounded}; pub use core::num::{Primitive, Int, Saturating}; pub use core::num::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 1140f023d43fd..bbd461e3dde0d 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -209,8 +209,6 @@ impl Uuid { /// * `d3` A 16-bit word /// * `d4` Array of 8 octets pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid { - use std::mem::ByteOrder; - // First construct a temporary field-based struct let mut fields = UuidFields { data1: 0, @@ -335,7 +333,6 @@ impl Uuid { /// /// Example: `550e8400-e29b-41d4-a716-446655440000` pub fn to_hyphenated_str(&self) -> String { - use std::mem::ByteOrder; // Convert to field-based struct as it matches groups in output. // Ensure fields are in network byte order, as per RFC. let mut uf: UuidFields; diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index c0ea6f8617d87..af51157bba564 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -16,7 +16,6 @@ use std::io; use std::io::stdio::StdReader; use std::io::BufferedReader; -use std::num::Bitwise; use std::os; // Computes a single solution to a given 9x9 sudoku From 779ca97525176bc1d764f1b88906363290fcf851 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 16 Jun 2014 14:33:45 -0700 Subject: [PATCH 34/55] Remove `#[stable]` attribute from free-standing endian conversions and mark them as deprecated --- src/libcore/mem.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index eab344ac7a701..1032b820b2751 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -173,84 +173,84 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_little_endian` instead"] pub fn to_le16(x: u16) -> u16 { x.to_little_endian() } /// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_little_endian` instead"] pub fn to_le32(x: u32) -> u32 { x.to_little_endian() } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_little_endian` instead"] pub fn to_le64(x: u64) -> u64 { x.to_little_endian() } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_big_endian` instead"] pub fn to_be16(x: u16) -> u16 { x.to_big_endian() } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_big_endian` instead"] pub fn to_be32(x: u32) -> u32 { x.to_big_endian() } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::to_big_endian` instead"] pub fn to_be64(x: u64) -> u64 { x.to_big_endian() } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_little_endian` instead"] pub fn from_le16(x: u16) -> u16 { Int::from_little_endian(x) } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_little_endian` instead"] pub fn from_le32(x: u32) -> u32 { Int::from_little_endian(x) } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_little_endian` instead"] pub fn from_le64(x: u64) -> u64 { Int::from_little_endian(x) } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_big_endian` instead"] pub fn from_be16(x: u16) -> u16 { Int::from_big_endian(x) } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_big_endian` instead"] pub fn from_be32(x: u32) -> u32 { Int::from_big_endian(x) } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[stable] +#[deprecated = "use `Int::from_big_endian` instead"] pub fn from_be64(x: u64) -> u64 { Int::from_big_endian(x) } /// Swap the values at two mutable locations of the same type, without From cb8ca2dafdbcdedcaeb2573dccd3b3e4a26cae44 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 17 Jun 2014 15:47:31 -0700 Subject: [PATCH 35/55] Shorten endian conversion method names The consensus on #14917 was that the proposed names were too long. --- src/libcollections/hash/mod.rs | 2 +- src/libcore/mem.rs | 48 +++++++++++++++++----------------- src/libcore/num/int_macros.rs | 32 +++++++++++------------ src/libcore/num/mod.rs | 24 ++++++++--------- src/libcore/num/uint_macros.rs | 32 +++++++++++------------ src/libnative/io/net.rs | 8 +++--- src/librustuv/net.rs | 8 +++--- src/libserialize/ebml.rs | 2 +- src/libuuid/lib.rs | 12 ++++----- 9 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index 07c768d0c7916..a0c0c9f973578 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -104,7 +104,7 @@ macro_rules! impl_hash { #[inline] fn hash(&self, state: &mut S) { let a: [u8, ..::core::$ty::BYTES] = unsafe { - mem::transmute((*self as $uty).to_little_endian() as $ty) + mem::transmute((*self as $uty).to_le() as $ty) }; state.write(a.as_slice()) } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1032b820b2751..5280ac0d64fb2 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -173,85 +173,85 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_little_endian` instead"] -pub fn to_le16(x: u16) -> u16 { x.to_little_endian() } +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le16(x: u16) -> u16 { x.to_le() } /// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_little_endian` instead"] -pub fn to_le32(x: u32) -> u32 { x.to_little_endian() } +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le32(x: u32) -> u32 { x.to_le() } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_little_endian` instead"] -pub fn to_le64(x: u64) -> u64 { x.to_little_endian() } +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le64(x: u64) -> u64 { x.to_le() } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_big_endian` instead"] -pub fn to_be16(x: u16) -> u16 { x.to_big_endian() } +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be16(x: u16) -> u16 { x.to_be() } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_big_endian` instead"] -pub fn to_be32(x: u32) -> u32 { x.to_big_endian() } +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be32(x: u32) -> u32 { x.to_be() } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::to_big_endian` instead"] -pub fn to_be64(x: u64) -> u64 { x.to_big_endian() } +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be64(x: u64) -> u64 { x.to_be() } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_little_endian` instead"] -pub fn from_le16(x: u16) -> u16 { Int::from_little_endian(x) } +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le16(x: u16) -> u16 { Int::from_le(x) } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_little_endian` instead"] -pub fn from_le32(x: u32) -> u32 { Int::from_little_endian(x) } +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le32(x: u32) -> u32 { Int::from_le(x) } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_little_endian` instead"] -pub fn from_le64(x: u64) -> u64 { Int::from_little_endian(x) } +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le64(x: u64) -> u64 { Int::from_le(x) } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_big_endian` instead"] -pub fn from_be16(x: u16) -> u16 { Int::from_big_endian(x) } +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be16(x: u16) -> u16 { Int::from_be(x) } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_big_endian` instead"] -pub fn from_be32(x: u32) -> u32 { Int::from_big_endian(x) } +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be32(x: u32) -> u32 { Int::from_be(x) } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. #[inline] -#[deprecated = "use `Int::from_big_endian` instead"] -pub fn from_be64(x: u64) -> u64 { Int::from_big_endian(x) } +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be64(x: u64) -> u64 { Int::from_be(x) } /// Swap the values at two mutable locations of the same type, without /// deinitialising or copying either one. diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 84744b3f5d701..79734324706b2 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -147,25 +147,25 @@ mod tests { } #[test] - fn test_little_endian() { - assert_eq!(Int::from_little_endian(A.to_little_endian()), A); - assert_eq!(Int::from_little_endian(B.to_little_endian()), B); - assert_eq!(Int::from_little_endian(C.to_little_endian()), C); - assert_eq!(Int::from_little_endian(_0), _0); - assert_eq!(Int::from_little_endian(_1), _1); - assert_eq!(_0.to_little_endian(), _0); - assert_eq!(_1.to_little_endian(), _1); + fn test_le() { + assert_eq!(Int::from_le(A.to_le()), A); + assert_eq!(Int::from_le(B.to_le()), B); + assert_eq!(Int::from_le(C.to_le()), C); + assert_eq!(Int::from_le(_0), _0); + assert_eq!(Int::from_le(_1), _1); + assert_eq!(_0.to_le(), _0); + assert_eq!(_1.to_le(), _1); } #[test] - fn test_big_endian() { - assert_eq!(Int::from_big_endian(A.to_big_endian()), A); - assert_eq!(Int::from_big_endian(B.to_big_endian()), B); - assert_eq!(Int::from_big_endian(C.to_big_endian()), C); - assert_eq!(Int::from_big_endian(_0), _0); - assert_eq!(Int::from_big_endian(_1), _1); - assert_eq!(_0.to_big_endian(), _0); - assert_eq!(_1.to_big_endian(), _1); + fn test_be() { + assert_eq!(Int::from_be(A.to_be()), A); + assert_eq!(Int::from_be(B.to_be()), B); + assert_eq!(Int::from_be(C.to_be()), C); + assert_eq!(Int::from_be(_0), _0); + assert_eq!(Int::from_be(_1), _1); + assert_eq!(_0.to_be(), _0); + assert_eq!(_1.to_be(), _1); } #[test] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ed0c24e7fa008..dd32a6da1063b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -498,13 +498,13 @@ pub trait Int: Primitive /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { - /// assert_eq!(Int::from_big_endian(n), n) + /// assert_eq!(Int::from_be(n), n) /// } else { - /// assert_eq!(Int::from_big_endian(n), n.swap_bytes()) + /// assert_eq!(Int::from_be(n), n.swap_bytes()) /// } /// ``` #[inline] - fn from_big_endian(x: Self) -> Self { + fn from_be(x: Self) -> Self { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } @@ -518,13 +518,13 @@ pub trait Int: Primitive /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { - /// assert_eq!(Int::from_little_endian(n), n) + /// assert_eq!(Int::from_le(n), n) /// } else { - /// assert_eq!(Int::from_little_endian(n), n.swap_bytes()) + /// assert_eq!(Int::from_le(n), n.swap_bytes()) /// } /// ``` #[inline] - fn from_little_endian(x: Self) -> Self { + fn from_le(x: Self) -> Self { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } @@ -538,13 +538,13 @@ pub trait Int: Primitive /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_big_endian(), n) + /// assert_eq!(n.to_be(), n) /// } else { - /// assert_eq!(n.to_big_endian(), n.swap_bytes()) + /// assert_eq!(n.to_be(), n.swap_bytes()) /// } /// ``` #[inline] - fn to_big_endian(self) -> Self { + fn to_be(self) -> Self { // or not to be? if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } @@ -558,13 +558,13 @@ pub trait Int: Primitive /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_little_endian(), n) + /// assert_eq!(n.to_le(), n) /// } else { - /// assert_eq!(n.to_little_endian(), n.swap_bytes()) + /// assert_eq!(n.to_le(), n.swap_bytes()) /// } /// ``` #[inline] - fn to_little_endian(self) -> Self { + fn to_le(self) -> Self { if cfg!(target_endian = "little") { self } else { self.swap_bytes() } } } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 1fe3c4cf1f1cf..be1f960bcc3df 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -98,25 +98,25 @@ mod tests { } #[test] - fn test_little_endian() { - assert_eq!(Int::from_little_endian(A.to_little_endian()), A); - assert_eq!(Int::from_little_endian(B.to_little_endian()), B); - assert_eq!(Int::from_little_endian(C.to_little_endian()), C); - assert_eq!(Int::from_little_endian(_0), _0); - assert_eq!(Int::from_little_endian(_1), _1); - assert_eq!(_0.to_little_endian(), _0); - assert_eq!(_1.to_little_endian(), _1); + fn test_le() { + assert_eq!(Int::from_le(A.to_le()), A); + assert_eq!(Int::from_le(B.to_le()), B); + assert_eq!(Int::from_le(C.to_le()), C); + assert_eq!(Int::from_le(_0), _0); + assert_eq!(Int::from_le(_1), _1); + assert_eq!(_0.to_le(), _0); + assert_eq!(_1.to_le(), _1); } #[test] - fn test_big_endian() { - assert_eq!(Int::from_big_endian(A.to_big_endian()), A); - assert_eq!(Int::from_big_endian(B.to_big_endian()), B); - assert_eq!(Int::from_big_endian(C.to_big_endian()), C); - assert_eq!(Int::from_big_endian(_0), _0); - assert_eq!(Int::from_big_endian(_1), _1); - assert_eq!(_0.to_big_endian(), _0); - assert_eq!(_1.to_big_endian(), _1); + fn test_be() { + assert_eq!(Int::from_be(A.to_be()), A); + assert_eq!(Int::from_be(B.to_be()), B); + assert_eq!(Int::from_be(C.to_be()), C); + assert_eq!(Int::from_be(_0), _0); + assert_eq!(Int::from_be(_1), _1); + assert_eq!(_0.to_be(), _0); + assert_eq!(_1.to_be(), _1); } #[test] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 23fd607aafeef..5dfae8d9efe64 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -27,10 +27,10 @@ use super::util; #[cfg(unix)] pub type sock_t = super::file::fd_t; pub fn htons(u: u16) -> u16 { - u.to_big_endian() + u.to_be() } pub fn ntohs(u: u16) -> u16 { - Int::from_big_endian(u) + Int::from_be(u) } enum InAddr { @@ -46,7 +46,7 @@ fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr { (c as u32 << 8) | (d as u32 << 0); InAddr(libc::in_addr { - s_addr: Int::from_big_endian(ip) + s_addr: Int::from_be(ip) }) } rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -180,7 +180,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = (storage.sin_addr.s_addr as u32).to_big_endian(); + let ip = (storage.sin_addr.s_addr as u32).to_be(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index aa7fab2565d8c..82693acb1e9dc 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -30,8 +30,8 @@ use uvll; /// Generic functions related to dealing with sockaddr things //////////////////////////////////////////////////////////////////////////////// -pub fn htons(u: u16) -> u16 { u.to_big_endian() } -pub fn ntohs(u: u16) -> u16 { Int::from_big_endian(u) } +pub fn htons(u: u16) -> u16 { u.to_be() } +pub fn ntohs(u: u16) -> u16 { Int::from_be(u) } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: uint) -> rtio::SocketAddr { @@ -41,7 +41,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = (storage.sin_addr.s_addr as u32).to_big_endian(); + let ip = (storage.sin_addr.s_addr as u32).to_be(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; @@ -89,7 +89,7 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { (*storage).sin_family = libc::AF_INET as libc::sa_family_t; (*storage).sin_port = htons(addr.port); (*storage).sin_addr = libc::in_addr { - s_addr: Int::from_big_endian(ip), + s_addr: Int::from_be(ip), }; mem::size_of::() diff --git a/src/libserialize/ebml.rs b/src/libserialize/ebml.rs index 7d0c82fc9a2d5..12c5a3493c17b 100644 --- a/src/libserialize/ebml.rs +++ b/src/libserialize/ebml.rs @@ -183,7 +183,7 @@ pub mod reader { unsafe { let ptr = data.as_ptr().offset(start as int) as *u32; - let val = Int::from_big_endian(*ptr); + let val = Int::from_be(*ptr); let i = (val >> 28u) as uint; let (shift, mask) = SHIFT_MASK_TABLE[i]; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index bbd461e3dde0d..b68b435da4bb0 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -217,9 +217,9 @@ impl Uuid { data4: [0, ..8] }; - fields.data1 = d1.to_big_endian(); - fields.data2 = d2.to_big_endian(); - fields.data3 = d3.to_big_endian(); + fields.data1 = d1.to_be(); + fields.data2 = d2.to_be(); + fields.data3 = d3.to_be(); slice::bytes::copy_memory(fields.data4, d4); unsafe { @@ -339,9 +339,9 @@ impl Uuid { unsafe { uf = transmute_copy(&self.bytes); } - uf.data1 = uf.data1.to_big_endian(); - uf.data2 = uf.data2.to_big_endian(); - uf.data3 = uf.data3.to_big_endian(); + uf.data1 = uf.data1.to_be(); + uf.data2 = uf.data2.to_be(); + uf.data3 = uf.data3.to_be(); let s = format!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}-\ {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", uf.data1, From ae7006e373e458eaf0464761a6b492181c47100e Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 17 Jun 2014 11:09:20 -0700 Subject: [PATCH 36/55] Update doc comment for Int trait --- src/libcore/num/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dd32a6da1063b..573470c29bcf4 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -388,7 +388,8 @@ pub trait Primitive: Copy trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) -/// A collection of traits relevant to primitive signed and unsigned integers +/// A primitive signed or unsigned integer equipped with various bitwise +/// operators, bit counting methods, and endian conversion functions. pub trait Int: Primitive + CheckedAdd + CheckedSub From 8e9e17d188c2b59813b5a7d8f6ebb0c22e26ce93 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 17 Jun 2014 15:21:28 -0400 Subject: [PATCH 37/55] librustc: Use expr_ty_adjusted in trans_overloaded_call. --- src/librustc/middle/trans/expr.rs | 2 +- src/test/run-pass/issue-14958.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-14958.rs diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 42c7a71bab84d..599b45aafe20d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1463,7 +1463,7 @@ fn trans_overloaded_call<'a>( // Evaluate and tuple the arguments. let tuple_type = ty::mk_tup(bcx.tcx(), args.iter() - .map(|e| expr_ty(bcx, &**e)) + .map(|e| ty::expr_ty_adjusted(bcx.tcx(), &**e)) .collect()); let repr = adt::represent_type(bcx.ccx(), tuple_type); let numbered_fields: Vec<(uint, Gc)> = diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs new file mode 100644 index 0000000000000..045d3cc0458f7 --- /dev/null +++ b/src/test/run-pass/issue-14958.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(overloaded_calls)] + +trait Foo {} + +struct Bar; + +impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar { + fn call(&self, _: (&'a Foo,)) {} +} + +struct Baz; + +impl Foo for Baz {} + +fn main() { + let bar = Bar; + let baz = &Baz; + bar(baz); +} From a23511a65de7cce47aa12541de60df72b10eb2eb Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 17 Jun 2014 14:48:54 -0700 Subject: [PATCH 38/55] Revamp TaskBuilder API This patch consolidates and cleans up the task spawning APIs: * Removes the problematic `future_result` method from `std::task::TaskBuilder`, and adds a `try_future` that both spawns the task and returns a future representing its eventual result (or failure). * Removes the public `opts` field from `TaskBuilder`, instead adding appropriate builder methods to configure the task. * Adds extension traits to libgreen and libnative that add methods to `TaskBuilder` for spawning the task as a green or native thread. Previously, there was no way to benefit from the `TaskBuilder` functionality and also set the scheduler to spawn within. With this change, all task spawning scenarios are supported through the `TaskBuilder` interface. Closes #3725. [breaking-change] --- src/libgreen/lib.rs | 78 ++- src/libnative/lib.rs | 10 +- src/libnative/task.rs | 34 +- src/libstd/task.rs | 841 +++++++++++++++++-------------- src/test/run-pass/task-stderr.rs | 26 + 5 files changed, 594 insertions(+), 395 deletions(-) create mode 100644 src/test/run-pass/task-stderr.rs diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs index 6c3ad8a6ef961..ee25d19e324cc 100644 --- a/src/libgreen/lib.rs +++ b/src/libgreen/lib.rs @@ -159,16 +159,19 @@ //! //! # Using a scheduler pool //! +//! This library adds a `GreenTaskBuilder` trait that extends the methods +//! available on `std::task::TaskBuilder` to allow spawning a green task, +//! possibly pinned to a particular scheduler thread: +//! //! ```rust -//! use std::rt::task::TaskOpts; -//! use green::{SchedPool, PoolConfig}; -//! use green::sched::{PinnedTask, TaskFromFriend}; +//! use std::task::TaskBuilder; +//! use green::{SchedPool, PoolConfig, GreenTaskBuilder}; //! //! let config = PoolConfig::new(); //! let mut pool = SchedPool::new(config); //! //! // Spawn tasks into the pool of schedulers -//! pool.spawn(TaskOpts::new(), proc() { +//! TaskBuilder::new().green(&mut pool).spawn(proc() { //! // this code is running inside the pool of schedulers //! //! spawn(proc() { @@ -181,12 +184,9 @@ //! let mut handle = pool.spawn_sched(); //! //! // Pin a task to the spawned scheduler -//! let task = pool.task(TaskOpts::new(), proc() { /* ... */ }); -//! handle.send(PinnedTask(task)); -//! -//! // Schedule a task on this new scheduler -//! let task = pool.task(TaskOpts::new(), proc() { /* ... */ }); -//! handle.send(TaskFromFriend(task)); +//! TaskBuilder::new().green_pinned(&mut pool, &mut handle).spawn(proc() { +//! /* ... */ +//! }); //! //! // Handles keep schedulers alive, so be sure to drop all handles before //! // destroying the sched pool @@ -209,6 +209,8 @@ // NB this does *not* include globs, please keep it that way. #![feature(macro_rules, phase)] #![allow(visible_private_types)] +#![allow(deprecated)] +#![feature(default_type_params)] #[cfg(test)] #[phase(plugin, link)] extern crate log; #[cfg(test)] extern crate rustuv; @@ -224,8 +226,9 @@ use std::rt::task::TaskOpts; use std::rt; use std::sync::atomics::{SeqCst, AtomicUint, INIT_ATOMIC_UINT}; use std::sync::deque; +use std::task::{TaskBuilder, Spawner}; -use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, NewNeighbor}; +use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, PinnedTask, NewNeighbor}; use sleeper_list::SleeperList; use stack::StackPool; use task::GreenTask; @@ -444,6 +447,7 @@ impl SchedPool { /// This is useful to create a task which can then be sent to a specific /// scheduler created by `spawn_sched` (and possibly pin it to that /// scheduler). + #[deprecated = "use the green and green_pinned methods of GreenTaskBuilder instead"] pub fn task(&mut self, opts: TaskOpts, f: proc():Send) -> Box { GreenTask::configure(&mut self.stack_pool, opts, f) } @@ -454,6 +458,7 @@ impl SchedPool { /// New tasks are spawned in a round-robin fashion to the schedulers in this /// pool, but tasks can certainly migrate among schedulers once they're in /// the pool. + #[deprecated = "use the green and green_pinned methods of GreenTaskBuilder instead"] pub fn spawn(&mut self, opts: TaskOpts, f: proc():Send) { let task = self.task(opts, f); @@ -563,3 +568,54 @@ impl Drop for SchedPool { } } } + +/// A spawner for green tasks +pub struct GreenSpawner<'a>{ + pool: &'a mut SchedPool, + handle: Option<&'a mut SchedHandle> +} + +impl<'a> Spawner for GreenSpawner<'a> { + #[inline] + fn spawn(self, opts: TaskOpts, f: proc():Send) { + let GreenSpawner { pool, handle } = self; + match handle { + None => pool.spawn(opts, f), + Some(h) => h.send(PinnedTask(pool.task(opts, f))) + } + } +} + +/// An extension trait adding `green` configuration methods to `TaskBuilder`. +pub trait GreenTaskBuilder { + fn green<'a>(self, &'a mut SchedPool) -> TaskBuilder>; + fn green_pinned<'a>(self, &'a mut SchedPool, &'a mut SchedHandle) + -> TaskBuilder>; +} + +impl GreenTaskBuilder for TaskBuilder { + fn green<'a>(self, pool: &'a mut SchedPool) -> TaskBuilder> { + self.spawner(GreenSpawner {pool: pool, handle: None}) + } + + fn green_pinned<'a>(self, pool: &'a mut SchedPool, handle: &'a mut SchedHandle) + -> TaskBuilder> { + self.spawner(GreenSpawner {pool: pool, handle: Some(handle)}) + } +} + +#[cfg(test)] +mod test { + use std::task::TaskBuilder; + use super::{SchedPool, PoolConfig, GreenTaskBuilder}; + + #[test] + fn test_green_builder() { + let mut pool = SchedPool::new(PoolConfig::new()); + let res = TaskBuilder::new().green(&mut pool).try(proc() { + "Success!".to_string() + }); + assert_eq!(res.ok().unwrap(), "Success!".to_string()); + pool.shutdown(); + } +} diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index f04dfac80ccfe..40b99c5bbdb1d 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -32,10 +32,13 @@ //! ```rust //! extern crate native; //! +//! use std::task::TaskBuilder; +//! use native::NativeTaskBuilder; +//! //! fn main() { //! // We're not sure whether this main function is run in 1:1 or M:N mode. //! -//! native::task::spawn(proc() { +//! TaskBuilder::new().native().spawn(proc() { //! // this code is guaranteed to be run on a native thread //! }); //! } @@ -50,7 +53,8 @@ html_root_url = "http://doc.rust-lang.org/")] #![deny(unused_result, unused_must_use)] #![allow(non_camel_case_types)] -#![feature(macro_rules)] +#![allow(deprecated)] +#![feature(default_type_params)] // NB this crate explicitly does *not* allow glob imports, please seriously // consider whether they're needed before adding that feature here (the @@ -65,6 +69,8 @@ use std::os; use std::rt; use std::str; +pub use task::NativeTaskBuilder; + pub mod io; pub mod task; diff --git a/src/libnative/task.rs b/src/libnative/task.rs index b073c2c7fbf02..88e581a479136 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -27,6 +27,7 @@ use std::rt; use io; use task; +use std::task::{TaskBuilder, Spawner}; /// Creates a new Task which is ready to execute as a 1:1 task. pub fn new(stack_bounds: (uint, uint)) -> Box { @@ -48,12 +49,14 @@ fn ops() -> Box { } /// Spawns a function with the default configuration +#[deprecated = "use the native method of NativeTaskBuilder instead"] pub fn spawn(f: proc():Send) { spawn_opts(TaskOpts { name: None, stack_size: None, on_exit: None }, f) } /// Spawns a new task given the configuration options and a procedure to run /// inside the task. +#[deprecated = "use the native method of NativeTaskBuilder instead"] pub fn spawn_opts(opts: TaskOpts, f: proc():Send) { let TaskOpts { name, stack_size, on_exit } = opts; @@ -95,6 +98,26 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) { }) } +/// A spawner for native tasks +pub struct NativeSpawner; + +impl Spawner for NativeSpawner { + fn spawn(self, opts: TaskOpts, f: proc():Send) { + spawn_opts(opts, f) + } +} + +/// An extension trait adding a `native` configuration method to `TaskBuilder`. +pub trait NativeTaskBuilder { + fn native(self) -> TaskBuilder; +} + +impl NativeTaskBuilder for TaskBuilder { + fn native(self) -> TaskBuilder { + self.spawner(NativeSpawner) + } +} + // This structure is the glue between channels and the 1:1 scheduling mode. This // structure is allocated once per task. struct Ops { @@ -259,7 +282,8 @@ mod tests { use std::rt::local::Local; use std::rt::task::{Task, TaskOpts}; use std::task; - use super::{spawn, spawn_opts, Ops}; + use std::task::TaskBuilder; + use super::{spawn, spawn_opts, Ops, NativeTaskBuilder}; #[test] fn smoke() { @@ -347,4 +371,12 @@ mod tests { }); rx.recv(); } + + #[test] + fn test_native_builder() { + let res = TaskBuilder::new().native().try(proc() { + "Success!".to_string() + }); + assert_eq!(res.ok().unwrap(), "Success!".to_string()); + } } diff --git a/src/libstd/task.rs b/src/libstd/task.rs index f543188af4295..0ead8fa6c0c83 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -8,71 +8,110 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - * Utilities for managing and scheduling tasks - * - * An executing Rust program consists of a collection of tasks, each with their - * own stack, and sole ownership of their allocated heap data. Tasks communicate - * with each other using channels (see `std::comm` for more info about how - * communication works). - * - * Failure in one task does not propagate to any others (not to parent, not to - * child). Failure propagation is instead handled by using the channel send() - * and recv() methods which will fail if the other end has hung up already. - * - * Task Scheduling: - * - * By default, every task is created with the same "flavor" as the calling task. - * This flavor refers to the scheduling mode, with two possibilities currently - * being 1:1 and M:N modes. Green (M:N) tasks are cooperatively scheduled and - * native (1:1) tasks are scheduled by the OS kernel. - * - * # Example - * - * ```rust - * spawn(proc() { - * println!("Hello, World!"); - * }) - * ``` - */ +//! Utilities for managing and scheduling tasks +//! +//! An executing Rust program consists of a collection of lightweight tasks, +//! each with their own stack. Tasks communicate with each other using channels +//! (see `std::comm`) or other forms of synchronization (see `std::sync`) that +//! ensure data-race freedom. +//! +//! Failure in one task does immediately propagate to any others (not to parent, +//! not to child). Failure propagation is instead handled as part of task +//! synchronization. For example, the channel `send()` and `recv()` methods will +//! fail if the other end has hung up already. +//! +//! # Basic task scheduling +//! +//! By default, every task is created with the same "flavor" as the calling task. +//! This flavor refers to the scheduling mode, with two possibilities currently +//! being 1:1 and M:N modes. Green (M:N) tasks are cooperatively scheduled and +//! native (1:1) tasks are scheduled by the OS kernel. +//! +//! ## Example +//! +//! ```rust +//! spawn(proc() { +//! println!("Hello, World!"); +//! }) +//! ``` +//! +//! # Advanced task scheduling +//! +//! Task spawning can also be configured to use a particular scheduler, to +//! redirect the new task's output, or to yield a `future` representing the +//! task's final result. The configuration is established using the +//! `TaskBuilder` API: +//! +//! ## Example +//! +//! ```rust +//! extern crate green; +//! extern crate native; +//! +//! use std::task::TaskBuilder; +//! use green::{SchedPool, PoolConfig, GreenTaskBuilder}; +//! use native::NativeTaskBuilder; +//! +//! # fn main() { +//! // Create a green scheduler pool with the default configuration +//! let mut pool = SchedPool::new(PoolConfig::new()); +//! +//! // Spawn a task in the green pool +//! let mut fut_green = TaskBuilder::new().green(&mut pool).try_future(proc() { +//! /* ... */ +//! }); +//! +//! // Spawn a native task +//! let mut fut_native = TaskBuilder::new().native().try_future(proc() { +//! /* ... */ +//! }); +//! +//! // Wait for both tasks to finish, recording their outcome +//! let res_green = fut_green.unwrap(); +//! let res_native = fut_native.unwrap(); +//! +//! // Shut down the green scheduler pool +//! pool.shutdown(); +//! # } +//! ``` use any::Any; -use comm::{Sender, Receiver, channel}; +use comm::channel; use io::{Writer, stdio}; use kinds::{Send, marker}; use option::{None, Some, Option}; use owned::Box; -use result::{Result, Ok, Err}; +use result::Result; use rt::local::Local; use rt::task; use rt::task::Task; use str::{Str, SendStr, IntoMaybeOwned}; +use sync::Future; -#[cfg(test)] use any::AnyRefExt; -#[cfg(test)] use owned::AnyOwnExt; -#[cfg(test)] use result; -#[cfg(test)] use str::StrAllocating; -#[cfg(test)] use string::String; - -/// Task configuration options -pub struct TaskOpts { - /// Enable lifecycle notifications on the given channel - pub notify_chan: Option>, - /// A name for the task-to-be, for identification in failure messages - pub name: Option, - /// The size of the stack for the spawned task - pub stack_size: Option, - /// Task-local stdout - pub stdout: Option>, - /// Task-local stderr - pub stderr: Option>, +/// A means of spawning a task +pub trait Spawner { + /// Spawn a task, given low-level task options. + fn spawn(self, opts: task::TaskOpts, f: proc():Send); } -/** - * The task builder type. - * - * Provides detailed control over the properties and behavior of new tasks. - */ +/// The default task spawner, which spawns siblings to the current task. +pub struct SiblingSpawner; + +impl Spawner for SiblingSpawner { + fn spawn(self, opts: task::TaskOpts, f: proc():Send) { + // bind tb to provide type annotation + let tb: Option> = Local::try_take(); + match tb { + Some(t) => t.spawn_sibling(opts, f), + None => fail!("need a local task to spawn a sibling task"), + }; + } +} + +/// The task builder type. +/// +/// Provides detailed control over the properties and behavior of new tasks. + // NB: Builders are designed to be single-use because they do stateful // things that get weird when reusing - e.g. if you create a result future // it only applies to a single task, so then you have to maintain Some @@ -80,75 +119,102 @@ pub struct TaskOpts { // when you try to reuse the builder to spawn a new task. We'll just // sidestep that whole issue by making builders uncopyable and making // the run function move them in. -pub struct TaskBuilder { - /// Options to spawn the new task with - pub opts: TaskOpts, - gen_body: Option proc(): Send>, +pub struct TaskBuilder { + // A name for the task-to-be, for identification in failure messages + name: Option, + // The size of the stack for the spawned task + stack_size: Option, + // Task-local stdout + stdout: Option>, + // Task-local stderr + stderr: Option>, + // The mechanics of actually spawning the task (i.e.: green or native) + spawner: S, + // Optionally wrap the eventual task body + gen_body: Option proc():Send>, nocopy: marker::NoCopy, } -impl TaskBuilder { - /// Generate the base configuration for spawning a task, off of which more - /// configuration methods can be chained. - pub fn new() -> TaskBuilder { +impl TaskBuilder { + /// Generate the base configuration for spawning a task, off of which more + /// configuration methods can be chained. + pub fn new() -> TaskBuilder { TaskBuilder { - opts: TaskOpts::new(), + name: None, + stack_size: None, + stdout: None, + stderr: None, + spawner: SiblingSpawner, gen_body: None, nocopy: marker::NoCopy, } } +} - /// Get a future representing the exit status of the task. - /// - /// Taking the value of the future will block until the child task - /// terminates. The future result return value will be created *before* the task is - /// spawned; as such, do not invoke .get() on it directly; - /// rather, store it in an outer variable/list for later use. - /// - /// # Failure - /// Fails if a future_result was already set for this task. - pub fn future_result(&mut self) -> Receiver { - // FIXME (#3725): Once linked failure and notification are - // handled in the library, I can imagine implementing this by just - // registering an arbitrary number of task::on_exit handlers and - // sending out messages. - - if self.opts.notify_chan.is_some() { - fail!("Can't set multiple future_results for one task!"); - } - - // Construct the future and give it to the caller. - let (tx, rx) = channel(); +impl TaskBuilder { + /// Name the task-to-be. Currently the name is used for identification + /// only in failure messages. + pub fn named>(mut self, name: T) -> TaskBuilder { + self.name = Some(name.into_maybe_owned()); + self + } - // Reconfigure self to use a notify channel. - self.opts.notify_chan = Some(tx); + /// Set the size of the stack for the new task. + pub fn stack_size(mut self, size: uint) -> TaskBuilder { + self.stack_size = Some(size); + self + } - rx + /// Redirect task-local stdout. + pub fn stdout(mut self, stdout: Box) -> TaskBuilder { + self.stdout = Some(stdout); + self } - /// Name the task-to-be. Currently the name is used for identification - /// only in failure messages. - pub fn named>(mut self, name: S) -> TaskBuilder { - self.opts.name = Some(name.into_maybe_owned()); + /// Redirect task-local stderr. + pub fn stderr(mut self, stderr: Box) -> TaskBuilder { + self.stderr = Some(stderr); self } - /** - * Add a wrapper to the body of the spawned task. - * - * Before the task is spawned it is passed through a 'body generator' - * function that may perform local setup operations as well as wrap - * the task body in remote setup operations. With this the behavior - * of tasks can be extended in simple ways. - * - * This function augments the current body generator with a new body - * generator by applying the task body which results from the - * existing body generator to the new body generator. - */ - pub fn with_wrapper(mut self, - wrapper: proc(v: proc(): Send): Send -> proc(): Send) - -> TaskBuilder - { + /// Set the spawning mechanism for the task. + /// + /// The `TaskBuilder` API configures a task to be spawned, but defers to the + /// "spawner" to actually create and spawn the task. The `spawner` method + /// should not be called directly by `TaskBuiler` clients. It is intended + /// for use by downstream crates (like `native` and `green`) that implement + /// tasks. These downstream crates then add extension methods to the + /// builder, like `.native()` and `.green(pool)`, that actually set the + /// spawner. + pub fn spawner(self, spawner: T) -> TaskBuilder { + // repackage the entire TaskBuilder since its type is changing. + let TaskBuilder { + name, stack_size, stdout, stderr, spawner: _, gen_body, nocopy + } = self; + TaskBuilder { + name: name, + stack_size: stack_size, + stdout: stdout, + stderr: stderr, + spawner: spawner, + gen_body: gen_body, + nocopy: nocopy, + } + } + + /// Add a wrapper to the body of the spawned task. + /// + /// Before the task is spawned it is passed through a 'body generator' + /// function that may perform local setup operations as well as wrap + /// the task body in remote setup operations. With this the behavior + /// of tasks can be extended in simple ways. + /// + /// This function augments the current body generator with a new body + /// generator by applying the task body which results from the + /// existing body generator to the new body generator. + #[deprecated = "this function will be removed soon"] + pub fn with_wrapper(mut self, wrapper: proc(v: proc():Send):Send -> proc():Send) + -> TaskBuilder { self.gen_body = match self.gen_body.take() { Some(prev) => Some(proc(body) { wrapper(prev(body)) }), None => Some(wrapper) @@ -156,90 +222,80 @@ impl TaskBuilder { self } - /** - * Creates and executes a new child task - * - * Sets up a new task with its own call stack and schedules it to run - * the provided unique closure. The task has the properties and behavior - * specified by the task_builder. - */ - pub fn spawn(mut self, f: proc(): Send) { - let gen_body = self.gen_body.take(); - let f = match gen_body { + // Where spawning actually happens (whether yielding a future or not) + fn spawn_internal(self, f: proc():Send, + on_exit: Option>):Send>) { + let TaskBuilder { + name, stack_size, stdout, stderr, spawner, mut gen_body, nocopy: _ + } = self; + let f = match gen_body.take() { Some(gen) => gen(f), None => f }; - let t: Box = match Local::try_take() { - Some(t) => t, - None => fail!("need a local task to spawn a new task"), - }; - let TaskOpts { notify_chan, name, stack_size, stdout, stderr } = self.opts; - let opts = task::TaskOpts { - on_exit: notify_chan.map(|c| proc(r) c.send(r)), + on_exit: on_exit, name: name, stack_size: stack_size, }; if stdout.is_some() || stderr.is_some() { - t.spawn_sibling(opts, proc() { + spawner.spawn(opts, proc() { let _ = stdout.map(stdio::set_stdout); let _ = stderr.map(stdio::set_stderr); f(); - }); + }) } else { - t.spawn_sibling(opts, f); + spawner.spawn(opts, f) } } - /** - * Execute a function in another task and return either the return value - * of the function or result::err. - * - * # Return value - * - * If the function executed successfully then try returns result::ok - * containing the value returned by the function. If the function fails - * then try returns result::err containing nil. - * - * # Failure - * Fails if a future_result was already set for this task. - */ - pub fn try(mut self, f: proc(): Send -> T) - -> Result> { - let (tx, rx) = channel(); - - let result = self.future_result(); - - self.spawn(proc() { - tx.send(f()); - }); - - match result.recv() { - Ok(()) => Ok(rx.recv()), - Err(cause) => Err(cause) - } + /// Creates and executes a new child task. + /// + /// Sets up a new task with its own call stack and schedules it to run + /// the provided proc. The task has the properties and behavior + /// specified by the `TaskBuilder`. + pub fn spawn(self, f: proc():Send) { + self.spawn_internal(f, None) } -} - -/* Task construction */ -impl TaskOpts { - pub fn new() -> TaskOpts { - /*! - * The default task options - */ + /// Execute a proc in a newly-spawned task and return a future representing + /// the task's result. The task has the properties and behavior + /// specified by the `TaskBuilder`. + /// + /// Taking the value of the future will block until the child task + /// terminates. + /// + /// # Return value + /// + /// If the child task executes successfully (without failing) then the + /// future returns `result::Ok` containing the value returned by the + /// function. If the child task fails then the future returns `result::Err` + /// containing the argument to `fail!(...)` as an `Any` trait object. + pub fn try_future(self, f: proc():Send -> T) + -> Future>> { + // currently, the on_exit proc provided by librustrt only works for unit + // results, so we use an additional side-channel to communicate the + // result. + + let (tx_done, rx_done) = channel(); // signal that task has exited + let (tx_retv, rx_retv) = channel(); // return value from task + + let on_exit = proc(res) { tx_done.send(res) }; + self.spawn_internal(proc() { tx_retv.send(f()) }, + Some(on_exit)); + + Future::from_fn(proc() { + rx_done.recv().map(|_| rx_retv.recv()) + }) + } - TaskOpts { - notify_chan: None, - name: None, - stack_size: None, - stdout: None, - stderr: None, - } + /// Execute a function in a newly-spawnedtask and block until the task + /// completes or fails. Equivalent to `.try_future(f).unwrap()`. + pub fn try(self, f: proc():Send -> T) -> Result> { + self.try_future(f).unwrap() } } -/* Spawn convenience functions */ +/* Convenience functions */ /// Creates and executes a new child task /// @@ -251,14 +307,22 @@ pub fn spawn(f: proc(): Send) { TaskBuilder::new().spawn(f) } -/// Execute a function in another task and return either the return value of -/// the function or an error if the task failed +/// Execute a function in a newly-spawned task and return either the return +/// value of the function or an error if the task failed. /// -/// This is equivalent to TaskBuilder::new().try +/// This is equivalent to `TaskBuilder::new().try`. pub fn try(f: proc(): Send -> T) -> Result> { TaskBuilder::new().try(f) } +/// Execute a function in another task and return a future representing the +/// task's result. +/// +/// This is equivalent to `TaskBuilder::new().try_future`. +pub fn try_future(f: proc():Send -> T) -> Future>> { + TaskBuilder::new().try_future(f) +} + /* Lifecycle functions */ @@ -273,9 +337,8 @@ pub fn with_task_name(blk: |Option<&str>| -> U) -> U { } } +/// Yield control to the task scheduler. pub fn deschedule() { - //! Yield control to the task scheduler - use rt::local::Local; // FIXME(#7544): Optimize this, since we know we won't block. @@ -283,266 +346,282 @@ pub fn deschedule() { task.yield_now(); } +/// True if the running task is currently failing (e.g. will return `true` inside a +/// destructor that is run while unwinding the stack after a call to `fail!()`). pub fn failing() -> bool { - //! True if the running task has failed use rt::task::Task; Local::borrow(None::).unwinder.unwinding() } -// The following 8 tests test the following 2^3 combinations: -// {un,}linked {un,}supervised failure propagation {up,down}wards. - -// !!! These tests are dangerous. If Something is buggy, they will hang, !!! -// !!! instead of exiting cleanly. This might wedge the buildbots. !!! - -#[test] -fn test_unnamed_task() { - spawn(proc() { - with_task_name(|name| { - assert!(name.is_none()); +#[cfg(test)] +mod test { + use any::{Any, AnyRefExt}; + use owned::AnyOwnExt; + use result; + use result::{Ok, Err}; + use str::StrAllocating; + use string::String; + use std::io::{ChanReader, ChanWriter}; + use prelude::*; + use super::*; + + // !!! These tests are dangerous. If something is buggy, they will hang, !!! + // !!! instead of exiting cleanly. This might wedge the buildbots. !!! + + #[test] + fn test_unnamed_task() { + spawn(proc() { + with_task_name(|name| { + assert!(name.is_none()); + }) }) - }) -} + } -#[test] -fn test_owned_named_task() { - TaskBuilder::new().named("ada lovelace".to_string()).spawn(proc() { - with_task_name(|name| { - assert!(name.unwrap() == "ada lovelace"); + #[test] + fn test_owned_named_task() { + TaskBuilder::new().named("ada lovelace".to_string()).spawn(proc() { + with_task_name(|name| { + assert!(name.unwrap() == "ada lovelace"); + }) }) - }) -} + } -#[test] -fn test_static_named_task() { - TaskBuilder::new().named("ada lovelace").spawn(proc() { - with_task_name(|name| { - assert!(name.unwrap() == "ada lovelace"); + #[test] + fn test_static_named_task() { + TaskBuilder::new().named("ada lovelace").spawn(proc() { + with_task_name(|name| { + assert!(name.unwrap() == "ada lovelace"); + }) }) - }) -} + } -#[test] -fn test_send_named_task() { - TaskBuilder::new().named("ada lovelace".into_maybe_owned()).spawn(proc() { - with_task_name(|name| { - assert!(name.unwrap() == "ada lovelace"); + #[test] + fn test_send_named_task() { + TaskBuilder::new().named("ada lovelace".into_maybe_owned()).spawn(proc() { + with_task_name(|name| { + assert!(name.unwrap() == "ada lovelace"); + }) }) - }) -} - -#[test] -fn test_run_basic() { - let (tx, rx) = channel(); - TaskBuilder::new().spawn(proc() { - tx.send(()); - }); - rx.recv(); -} + } -#[test] -fn test_with_wrapper() { - let (tx, rx) = channel(); - TaskBuilder::new().with_wrapper(proc(body) { - let result: proc(): Send = proc() { - body(); + #[test] + fn test_run_basic() { + let (tx, rx) = channel(); + TaskBuilder::new().spawn(proc() { tx.send(()); - }; - result - }).spawn(proc() { }); - rx.recv(); -} + }); + rx.recv(); + } -#[test] -fn test_future_result() { - let mut builder = TaskBuilder::new(); - let result = builder.future_result(); - builder.spawn(proc() {}); - assert!(result.recv().is_ok()); - - let mut builder = TaskBuilder::new(); - let result = builder.future_result(); - builder.spawn(proc() { - fail!(); - }); - assert!(result.recv().is_err()); -} + #[test] + fn test_with_wrapper() { + let (tx, rx) = channel(); + TaskBuilder::new().with_wrapper(proc(body) { + let result: proc():Send = proc() { + body(); + tx.send(()); + }; + result + }).spawn(proc() { }); + rx.recv(); + } -#[test] #[should_fail] -fn test_back_to_the_future_result() { - let mut builder = TaskBuilder::new(); - builder.future_result(); - builder.future_result(); -} + #[test] + fn test_try_future() { + let result = TaskBuilder::new().try_future(proc() {}); + assert!(result.unwrap().is_ok()); -#[test] -fn test_try_success() { - match try(proc() { - "Success!".to_string() - }).as_ref().map(|s| s.as_slice()) { - result::Ok("Success!") => (), - _ => fail!() + let result = TaskBuilder::new().try_future(proc() -> () { + fail!(); + }); + assert!(result.unwrap().is_err()); } -} -#[test] -fn test_try_fail() { - match try(proc() { - fail!() - }) { - result::Err(_) => (), - result::Ok(()) => fail!() + #[test] + fn test_try_success() { + match try(proc() { + "Success!".to_string() + }).as_ref().map(|s| s.as_slice()) { + result::Ok("Success!") => (), + _ => fail!() + } } -} -#[test] -fn test_spawn_sched() { - use clone::Clone; + #[test] + fn test_try_fail() { + match try(proc() { + fail!() + }) { + result::Err(_) => (), + result::Ok(()) => fail!() + } + } - let (tx, rx) = channel(); + #[test] + fn test_spawn_sched() { + use clone::Clone; - fn f(i: int, tx: Sender<()>) { - let tx = tx.clone(); - spawn(proc() { - if i == 0 { - tx.send(()); - } else { - f(i - 1, tx); - } - }); + let (tx, rx) = channel(); + fn f(i: int, tx: Sender<()>) { + let tx = tx.clone(); + spawn(proc() { + if i == 0 { + tx.send(()); + } else { + f(i - 1, tx); + } + }); + + } + f(10, tx); + rx.recv(); } - f(10, tx); - rx.recv(); -} -#[test] -fn test_spawn_sched_childs_on_default_sched() { - let (tx, rx) = channel(); + #[test] + fn test_spawn_sched_childs_on_default_sched() { + let (tx, rx) = channel(); - spawn(proc() { spawn(proc() { - tx.send(()); + spawn(proc() { + tx.send(()); + }); }); - }); - rx.recv(); -} + rx.recv(); + } -#[cfg(test)] -fn avoid_copying_the_body(spawnfn: |v: proc(): Send|) { - let (tx, rx) = channel::(); + fn avoid_copying_the_body(spawnfn: |v: proc():Send|) { + let (tx, rx) = channel::(); - let x = box 1; - let x_in_parent = (&*x) as *int as uint; + let x = box 1; + let x_in_parent = (&*x) as *int as uint; - spawnfn(proc() { - let x_in_child = (&*x) as *int as uint; - tx.send(x_in_child); - }); + spawnfn(proc() { + let x_in_child = (&*x) as *int as uint; + tx.send(x_in_child); + }); - let x_in_child = rx.recv(); - assert_eq!(x_in_parent, x_in_child); -} + let x_in_child = rx.recv(); + assert_eq!(x_in_parent, x_in_child); + } -#[test] -fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(spawn); -} + #[test] + fn test_avoid_copying_the_body_spawn() { + avoid_copying_the_body(spawn); + } -#[test] -fn test_avoid_copying_the_body_task_spawn() { - avoid_copying_the_body(|f| { - let builder = TaskBuilder::new(); - builder.spawn(proc() { - f(); - }); - }) -} + #[test] + fn test_avoid_copying_the_body_task_spawn() { + avoid_copying_the_body(|f| { + let builder = TaskBuilder::new(); + builder.spawn(proc() { + f(); + }); + }) + } -#[test] -fn test_avoid_copying_the_body_try() { - avoid_copying_the_body(|f| { - let _ = try(proc() { - f() - }); - }) -} + #[test] + fn test_avoid_copying_the_body_try() { + avoid_copying_the_body(|f| { + let _ = try(proc() { + f() + }); + }) + } -#[test] -fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent task, this will stack overflow when - // climbing the task tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - static generations: uint = 16; - fn child_no(x: uint) -> proc(): Send { - return proc() { - if x < generations { - TaskBuilder::new().spawn(child_no(x+1)); + #[test] + fn test_child_doesnt_ref_parent() { + // If the child refcounts the parent task, this will stack overflow when + // climbing the task tree to dereference each ancestor. (See #1789) + // (well, it would if the constant were 8000+ - I lowered it to be more + // valgrind-friendly. try this at home, instead..!) + static generations: uint = 16; + fn child_no(x: uint) -> proc(): Send { + return proc() { + if x < generations { + TaskBuilder::new().spawn(child_no(x+1)); + } } } + TaskBuilder::new().spawn(child_no(0)); } - TaskBuilder::new().spawn(child_no(0)); -} -#[test] -fn test_simple_newsched_spawn() { - spawn(proc()()) -} + #[test] + fn test_simple_newsched_spawn() { + spawn(proc()()) + } -#[test] -fn test_try_fail_message_static_str() { - match try(proc() { - fail!("static string"); - }) { - Err(e) => { - type T = &'static str; - assert!(e.is::()); - assert_eq!(*e.move::().unwrap(), "static string"); + #[test] + fn test_try_fail_message_static_str() { + match try(proc() { + fail!("static string"); + }) { + Err(e) => { + type T = &'static str; + assert!(e.is::()); + assert_eq!(*e.move::().unwrap(), "static string"); + } + Ok(()) => fail!() } - Ok(()) => fail!() } -} -#[test] -fn test_try_fail_message_owned_str() { - match try(proc() { - fail!("owned string".to_string()); - }) { - Err(e) => { - type T = String; - assert!(e.is::()); - assert_eq!(*e.move::().unwrap(), "owned string".to_string()); + #[test] + fn test_try_fail_message_owned_str() { + match try(proc() { + fail!("owned string".to_string()); + }) { + Err(e) => { + type T = String; + assert!(e.is::()); + assert_eq!(*e.move::().unwrap(), "owned string".to_string()); + } + Ok(()) => fail!() } - Ok(()) => fail!() } -} -#[test] -fn test_try_fail_message_any() { - match try(proc() { - fail!(box 413u16 as Box); - }) { - Err(e) => { - type T = Box; - assert!(e.is::()); - let any = e.move::().unwrap(); - assert!(any.is::()); - assert_eq!(*any.move::().unwrap(), 413u16); + #[test] + fn test_try_fail_message_any() { + match try(proc() { + fail!(box 413u16 as Box); + }) { + Err(e) => { + type T = Box; + assert!(e.is::()); + let any = e.move::().unwrap(); + assert!(any.is::()); + assert_eq!(*any.move::().unwrap(), 413u16); + } + Ok(()) => fail!() } - Ok(()) => fail!() } -} -#[test] -fn test_try_fail_message_unit_struct() { - struct Juju; + #[test] + fn test_try_fail_message_unit_struct() { + struct Juju; + + match try(proc() { + fail!(Juju) + }) { + Err(ref e) if e.is::() => {} + Err(_) | Ok(()) => fail!() + } + } + + #[test] + fn test_stdout() { + let (tx, rx) = channel(); + let mut reader = ChanReader::new(rx); + let stdout = ChanWriter::new(tx); + + TaskBuilder::new().stdout(box stdout as Box).try(proc() { + print!("Hello, world!"); + }).unwrap(); - match try(proc() { - fail!(Juju) - }) { - Err(ref e) if e.is::() => {} - Err(_) | Ok(()) => fail!() + let output = reader.read_to_str().unwrap(); + assert_eq!(output, "Hello, world!".to_string()); } + + // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due + // to the test harness apparently interfering with stderr configuration. } diff --git a/src/test/run-pass/task-stderr.rs b/src/test/run-pass/task-stderr.rs new file mode 100644 index 0000000000000..b3cbdb3c4c382 --- /dev/null +++ b/src/test/run-pass/task-stderr.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::io::{ChanReader, ChanWriter}; +use std::task::build; + +fn main() { + let (tx, rx) = channel(); + let mut reader = ChanReader::new(rx); + let stderr = ChanWriter::new(tx); + + let res = build().stderr(box stderr as Box).try(proc() -> () { + fail!("Hello, world!") + }); + assert!(res.is_err()); + + let output = reader.read_to_str().unwrap(); + assert!(output.as_slice().contains("Hello, world!")); +} From f99349556014f9f2cb86814477248d46931b3048 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 16 Jun 2014 16:17:59 -0700 Subject: [PATCH 39/55] Fallout from TaskBuilder changes This commit brings code downstream of libstd up to date with the new TaskBuilder API. --- src/librustc/driver/mod.rs | 17 +++++++---------- src/libsync/lock.rs | 10 ++++------ src/libtest/lib.rs | 9 ++++----- src/test/bench/msgsend-pipes-shared.rs | 11 ++++------- src/test/bench/msgsend-pipes.rs | 17 ++++++----------- src/test/bench/shootout-pfib.rs | 11 ++++------- src/test/run-pass/issue-2190-1.rs | 4 +--- src/test/run-pass/task-comm-12.rs | 7 ++----- src/test/run-pass/task-comm-3.rs | 10 ++++------ src/test/run-pass/task-comm-9.rs | 8 +++----- src/test/run-pass/task-stderr.rs | 4 ++-- src/test/run-pass/tcp-stress.rs | 4 +--- src/test/run-pass/yield.rs | 7 ++----- src/test/run-pass/yield1.rs | 7 ++----- 14 files changed, 46 insertions(+), 80 deletions(-) diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index ada65394e1923..f55fd78762c5d 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -366,22 +366,19 @@ fn monitor(f: proc():Send) { #[cfg(not(rtopt))] static STACK_SIZE: uint = 20000000; // 20MB - let mut task_builder = TaskBuilder::new().named("rustc"); + let (tx, rx) = channel(); + let w = io::ChanWriter::new(tx); + let mut r = io::ChanReader::new(rx); + + let mut task = TaskBuilder::new().named("rustc").stderr(box w); // FIXME: Hacks on hacks. If the env is trying to override the stack size // then *don't* set it explicitly. if os::getenv("RUST_MIN_STACK").is_none() { - task_builder.opts.stack_size = Some(STACK_SIZE); + task = task.stack_size(STACK_SIZE); } - let (tx, rx) = channel(); - let w = io::ChanWriter::new(tx); - let mut r = io::ChanReader::new(rx); - - match task_builder.try(proc() { - io::stdio::set_stderr(box w); - f() - }) { + match task.try(f) { Ok(()) => { /* fallthrough */ } Err(value) => { // Task failed without emitting a fatal diagnostic diff --git a/src/libsync/lock.rs b/src/libsync/lock.rs index d7990068d5eb7..1fe8e8fc0db34 100644 --- a/src/libsync/lock.rs +++ b/src/libsync/lock.rs @@ -459,7 +459,7 @@ mod tests { use std::prelude::*; use std::comm::Empty; use std::task; - use std::task::TaskBuilder; + use std::task::try_future; use Arc; use super::{Mutex, Barrier, RWLock}; @@ -629,17 +629,15 @@ mod tests { let mut children = Vec::new(); for _ in range(0, 5) { let arc3 = arc.clone(); - let mut builder = TaskBuilder::new(); - children.push(builder.future_result()); - builder.spawn(proc() { + children.push(try_future(proc() { let lock = arc3.read(); assert!(*lock >= 0); - }); + })); } // Wait for children to pass their asserts for r in children.mut_iter() { - assert!(r.recv().is_ok()); + assert!(r.get_ref().is_ok()); } // Wait for writer to finish diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index e7c35fb59eee5..112ffd7c1a4a4 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1049,14 +1049,13 @@ pub fn run_test(opts: &TestOpts, if nocapture { drop((stdout, stderr)); } else { - task.opts.stdout = Some(box stdout as Box); - task.opts.stderr = Some(box stderr as Box); + task = task.stdout(box stdout as Box); + task = task.stderr(box stderr as Box); } - let result_future = task.future_result(); - task.spawn(testfn); + let result_future = task.try_future(testfn); let stdout = reader.read_to_end().unwrap().move_iter().collect(); - let task_result = result_future.recv(); + let task_result = result_future.unwrap(); let test_result = calc_result(&desc, task_result.is_ok()); monitor_ch.send((desc.clone(), test_result, stdout)); }) diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 03d91cf3aaa7a..14155d54d73cc 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -24,7 +24,6 @@ extern crate debug; use std::comm; use std::os; use std::task; -use std::task::TaskBuilder; use std::uint; fn move_out(_x: T) {} @@ -64,22 +63,20 @@ fn run(args: &[String]) { let mut worker_results = Vec::new(); for _ in range(0u, workers) { let to_child = to_child.clone(); - let mut builder = TaskBuilder::new(); - worker_results.push(builder.future_result()); - builder.spawn(proc() { + worker_results.push(task::try_future(proc() { for _ in range(0u, size / workers) { //println!("worker {:?}: sending {:?} bytes", i, num_bytes); to_child.send(bytes(num_bytes)); } //println!("worker {:?} exiting", i); - }); + })); } task::spawn(proc() { server(&from_parent, &to_parent); }); - for r in worker_results.iter() { - r.recv(); + for r in worker_results.move_iter() { + r.unwrap(); } //println!("sending stop message"); diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index 4de51c3ab4b8e..7ec2796b230a7 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -19,7 +19,6 @@ extern crate debug; use std::os; use std::task; -use std::task::TaskBuilder; use std::uint; fn move_out(_x: T) {} @@ -58,29 +57,25 @@ fn run(args: &[String]) { let mut worker_results = Vec::new(); let from_parent = if workers == 1 { let (to_child, from_parent) = channel(); - let mut builder = TaskBuilder::new(); - worker_results.push(builder.future_result()); - builder.spawn(proc() { + worker_results.push(task::try_future(proc() { for _ in range(0u, size / workers) { //println!("worker {:?}: sending {:?} bytes", i, num_bytes); to_child.send(bytes(num_bytes)); } //println!("worker {:?} exiting", i); - }); + })); from_parent } else { let (to_child, from_parent) = channel(); for _ in range(0u, workers) { let to_child = to_child.clone(); - let mut builder = TaskBuilder::new(); - worker_results.push(builder.future_result()); - builder.spawn(proc() { + worker_results.push(task::try_future(proc() { for _ in range(0u, size / workers) { //println!("worker {:?}: sending {:?} bytes", i, num_bytes); to_child.send(bytes(num_bytes)); } //println!("worker {:?} exiting", i); - }); + })); } from_parent }; @@ -88,8 +83,8 @@ fn run(args: &[String]) { server(&from_parent, &to_parent); }); - for r in worker_results.iter() { - r.recv(); + for r in worker_results.move_iter() { + r.unwrap(); } //println!("sending stop message"); diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 33853a91b7608..57a6d0e7c523d 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -24,7 +24,6 @@ extern crate time; use std::os; use std::result::{Ok, Err}; use std::task; -use std::task::TaskBuilder; use std::uint; fn fib(n: int) -> int { @@ -79,14 +78,12 @@ fn stress_task(id: int) { fn stress(num_tasks: int) { let mut results = Vec::new(); for i in range(0, num_tasks) { - let mut builder = TaskBuilder::new(); - results.push(builder.future_result()); - builder.spawn(proc() { + results.push(task::try_future(proc() { stress_task(i); - }); + })); } - for r in results.iter() { - r.recv(); + for r in results.move_iter() { + r.unwrap(); } } diff --git a/src/test/run-pass/issue-2190-1.rs b/src/test/run-pass/issue-2190-1.rs index f1217be3484fe..4ff735708b5ab 100644 --- a/src/test/run-pass/issue-2190-1.rs +++ b/src/test/run-pass/issue-2190-1.rs @@ -13,9 +13,7 @@ use std::task::TaskBuilder; static generations: uint = 1024+256+128+49; fn spawn(f: proc():Send) { - let mut t = TaskBuilder::new(); - t.opts.stack_size = Some(32 * 1024); - t.spawn(f); + TaskBuilder::new().stack_size(32 * 1024).spawn(f) } fn child_no(x: uint) -> proc():Send { diff --git a/src/test/run-pass/task-comm-12.rs b/src/test/run-pass/task-comm-12.rs index a78bbefed44db..851f87adfc20d 100644 --- a/src/test/run-pass/task-comm-12.rs +++ b/src/test/run-pass/task-comm-12.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::task; -use std::task::TaskBuilder; pub fn main() { test00(); } @@ -17,9 +16,7 @@ fn start(_task_number: int) { println!("Started / Finished task."); } fn test00() { let i: int = 0; - let mut builder = TaskBuilder::new(); - let mut result = builder.future_result(); - builder.spawn(proc() { + let mut result = task::try_future(proc() { start(i) }); @@ -31,7 +28,7 @@ fn test00() { } // Try joining tasks that have already finished. - result.recv(); + result.unwrap(); println!("Joined task."); } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 217bab5c1dea6..cd31d15db1092 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -10,7 +10,7 @@ extern crate debug; -use std::task::TaskBuilder; +use std::task; pub fn main() { println!("===== WITHOUT THREADS ====="); test00(); } @@ -39,14 +39,12 @@ fn test00() { let mut results = Vec::new(); while i < number_of_tasks { let tx = tx.clone(); - let mut builder = TaskBuilder::new(); - results.push(builder.future_result()); - builder.spawn({ + results.push(task::try_future({ let i = i; proc() { test00_start(&tx, i, number_of_messages) } - }); + })); i = i + 1; } @@ -62,7 +60,7 @@ fn test00() { } // Join spawned tasks... - for r in results.iter() { r.recv(); } + for r in results.mut_iter() { r.get_ref(); } println!("Completed: Final number is: "); println!("{:?}", sum); diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index ab6498c00279b..a46b4513c5dee 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -10,7 +10,7 @@ extern crate debug; -use std::task::TaskBuilder; +use std::task; pub fn main() { test00(); } @@ -25,9 +25,7 @@ fn test00() { let (tx, rx) = channel(); let number_of_messages: int = 10; - let mut builder = TaskBuilder::new(); - let result = builder.future_result(); - builder.spawn(proc() { + let result = task::try_future(proc() { test00_start(&tx, number_of_messages); }); @@ -38,7 +36,7 @@ fn test00() { i += 1; } - result.recv(); + result.unwrap(); assert_eq!(sum, number_of_messages * (number_of_messages - 1) / 2); } diff --git a/src/test/run-pass/task-stderr.rs b/src/test/run-pass/task-stderr.rs index b3cbdb3c4c382..6a71f9df6e45e 100644 --- a/src/test/run-pass/task-stderr.rs +++ b/src/test/run-pass/task-stderr.rs @@ -9,14 +9,14 @@ // except according to those terms. use std::io::{ChanReader, ChanWriter}; -use std::task::build; +use std::task::TaskBuilder; fn main() { let (tx, rx) = channel(); let mut reader = ChanReader::new(rx); let stderr = ChanWriter::new(tx); - let res = build().stderr(box stderr as Box).try(proc() -> () { + let res = TaskBuilder::new().stderr(box stderr as Box).try(proc() -> () { fail!("Hello, world!") }); assert!(res.is_err()); diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index 9c4716e5f4d38..99bf247229e05 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -60,9 +60,7 @@ fn main() { let (tx, rx) = channel(); for _ in range(0, 1000) { let tx = tx.clone(); - let mut builder = TaskBuilder::new(); - builder.opts.stack_size = Some(64 * 1024); - builder.spawn(proc() { + TaskBuilder::new().stack_size(64 * 1024).spawn(proc() { let host = addr.ip.to_str(); let port = addr.port; match TcpStream::connect(host.as_slice(), port) { diff --git a/src/test/run-pass/yield.rs b/src/test/run-pass/yield.rs index 2662a6c6568b9..89d204dcecbdb 100644 --- a/src/test/run-pass/yield.rs +++ b/src/test/run-pass/yield.rs @@ -9,18 +9,15 @@ // except according to those terms. use std::task; -use std::task::TaskBuilder; pub fn main() { - let mut builder = TaskBuilder::new(); - let mut result = builder.future_result(); - builder.spawn(child); + let mut result = task::try_future(child); println!("1"); task::deschedule(); println!("2"); task::deschedule(); println!("3"); - result.recv(); + result.unwrap(); } fn child() { diff --git a/src/test/run-pass/yield1.rs b/src/test/run-pass/yield1.rs index 8c5504725bb48..d882b1abd295d 100644 --- a/src/test/run-pass/yield1.rs +++ b/src/test/run-pass/yield1.rs @@ -9,15 +9,12 @@ // except according to those terms. use std::task; -use std::task::TaskBuilder; pub fn main() { - let mut builder = TaskBuilder::new(); - let mut result = builder.future_result(); - builder.spawn(child); + let mut result = task::try_future(child); println!("1"); task::deschedule(); - result.recv(); + result.unwrap(); } fn child() { println!("2"); } From 90f7e3a644c9795d9a7dce87d8c6b0cf369a7503 Mon Sep 17 00:00:00 2001 From: Cameron Zwarich Date: Wed, 18 Jun 2014 00:06:39 -0700 Subject: [PATCH 40/55] Reject double moves out of array elements Fixes #14986. --- src/librustc/middle/borrowck/move_data.rs | 32 ++++++++++++++++--- .../borrowck-array-double-move.rs | 21 ++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/borrowck-array-double-move.rs diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index bb92043b1ea6a..9c2194c74f4a4 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -25,6 +25,7 @@ use middle::dataflow::DataFlowContext; use middle::dataflow::BitwiseOperator; use middle::dataflow::DataFlowOperator; use euv = middle::expr_use_visitor; +use mc = middle::mem_categorization; use middle::ty; use syntax::ast; use syntax::ast_util; @@ -160,6 +161,22 @@ pub struct AssignDataFlowOperator; pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>; +fn loan_path_is_precise(loan_path: &LoanPath) -> bool { + match *loan_path { + LpVar(_) => { + true + } + LpExtend(_, _, LpInterior(mc::InteriorElement(_))) => { + // Paths involving element accesses do not refer to a unique + // location, as there is no accurate tracking of the indices. + false + } + LpExtend(ref lp_base, _, _) => { + loan_path_is_precise(&**lp_base) + } + } +} + impl MoveData { pub fn new() -> MoveData { MoveData { @@ -500,10 +517,17 @@ impl MoveData { path: MovePathIndex, kill_id: ast::NodeId, dfcx_moves: &mut MoveDataFlow) { - self.each_applicable_move(path, |move_index| { - dfcx_moves.add_kill(kill_id, move_index.get()); - true - }); + // We can only perform kills for paths that refer to a unique location, + // since otherwise we may kill a move from one location with an + // assignment referring to another location. + + let loan_path = self.path_loan_path(path); + if loan_path_is_precise(&*loan_path) { + self.each_applicable_move(path, |move_index| { + dfcx_moves.add_kill(kill_id, move_index.get()); + true + }); + } } } diff --git a/src/test/compile-fail/borrowck-array-double-move.rs b/src/test/compile-fail/borrowck-array-double-move.rs new file mode 100644 index 0000000000000..c7fb646f585b9 --- /dev/null +++ b/src/test/compile-fail/borrowck-array-double-move.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f() { + let mut a = [box 0, box 1]; + drop(a[0]); + a[1] = box 2; + drop(a[0]); //~ ERROR use of moved value: `a[..]` +} + +fn main() { + f(); +} + From 31dfcf9dc1e449fbf084485a1dc196695cab680e Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Wed, 18 Jun 2014 17:39:18 +1000 Subject: [PATCH 41/55] Vim: highlight escapes for byte literals. --- src/etc/vim/syntax/rust.vim | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 77348335eb346..b7901277ada17 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -145,11 +145,13 @@ syn match rustOperator display "&&\|||" syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustFail syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustFail -syn match rustSpecialError display contained /\\./ -syn match rustSpecial display contained /\\\([nrt0\\'"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)/ +syn match rustEscapeError display contained /\\./ +syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ +syn match rustEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/ syn match rustStringContinuation display contained /\\\n\s*/ -syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustSpecial,rustSpecialError,rustStringContinuation,@Spell -syn region rustString start='r\z(#*\)"' end='"\z1' contains=@Spell +syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation +syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell +syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDeriving syn region rustDeriving start="deriving(" end=")" contained contains=rustTrait @@ -177,7 +179,8 @@ syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[ "rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" -syn match rustCharacter /'\([^'\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'/ contains=rustSpecial,rustSpecialError +syn match rustCharacter /b'\([^'\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError +syn match rustCharacter /'\([^'\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell @@ -215,8 +218,9 @@ hi def link rustIdentifierPrime rustIdentifier hi def link rustTrait rustType hi def link rustSigil StorageClass -hi def link rustSpecial Special -hi def link rustSpecialError Error +hi def link rustEscape Special +hi def link rustEscapeUnicode rustEscape +hi def link rustEscapeError Error hi def link rustStringContinuation Special hi def link rustString String hi def link rustCharacter Character From b0dff7a19142b7d52d80ed62a14c1a6cb07cb647 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Wed, 18 Jun 2014 19:58:04 +1000 Subject: [PATCH 42/55] Vim: highlight invalid characters in char literals. --- src/etc/vim/syntax/rust.vim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index b7901277ada17..a0488cdb05ab4 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -179,8 +179,11 @@ syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[ "rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" -syn match rustCharacter /b'\([^'\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError -syn match rustCharacter /'\([^'\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError +syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/ +" The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII). +syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/ +syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode +syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell @@ -223,6 +226,8 @@ hi def link rustEscapeUnicode rustEscape hi def link rustEscapeError Error hi def link rustStringContinuation Special hi def link rustString String +hi def link rustCharacterInvalid Error +hi def link rustCharacterInvalidUnicode rustCharacterInvalid hi def link rustCharacter Character hi def link rustNumber Number hi def link rustBoolean Boolean From bde851e969d327397ac1ab4bca05692069ff62a5 Mon Sep 17 00:00:00 2001 From: Piotr Jawniak Date: Wed, 18 Jun 2014 11:40:41 +0200 Subject: [PATCH 43/55] Fix FIXME #5275 Issue #5275 was closed, but there still was a FIXME for it. --- src/librustc/middle/liveness.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index cd876113807a9..8cd840582ba99 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -701,17 +701,12 @@ impl<'a> Liveness<'a> { if self.loop_scope.len() == 0 { self.ir.tcx.sess.span_bug(sp, "break outside loop"); } else { - // FIXME(#5275): this shouldn't have to be a method... - self.last_loop_scope() + *self.loop_scope.last().unwrap() } } } } - fn last_loop_scope(&self) -> NodeId { - *self.loop_scope.last().unwrap() - } - #[allow(unused_must_use)] fn ln_str(&self, ln: LiveNode) -> String { let mut wr = io::MemWriter::new(); From b1df9aa16fe0f801f2f56afdddd6faa0461a3b0e Mon Sep 17 00:00:00 2001 From: Edward Wang Date: Wed, 18 Jun 2014 22:33:58 +0800 Subject: [PATCH 44/55] Fix #14865 Fixes a codegen bug which generates illegal non-terminated LLVM block when there are wildcard pattern with guard and enum patterns in a match expression. Also refactors the code a little. Closes #14865 --- src/librustc/middle/trans/_match.rs | 54 +++++++---------------------- src/test/run-pass/issue-14865.rs | 30 ++++++++++++++++ 2 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 src/test/run-pass/issue-14865.rs diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 808d894be4386..ffd29ffeb8fb4 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -518,8 +518,7 @@ fn enter_default<'a, 'b>( dm: &DefMap, m: &'a [Match<'a, 'b>], col: uint, - val: ValueRef, - chk: &FailureHandler) + val: ValueRef) -> Vec> { debug!("enter_default(bcx={}, m={}, col={}, val={})", bcx.to_str(), @@ -529,35 +528,13 @@ fn enter_default<'a, 'b>( let _indenter = indenter(); // Collect all of the matches that can match against anything. - let matches = enter_match(bcx, dm, m, col, val, |p| { + enter_match(bcx, dm, m, col, val, |p| { match p.node { ast::PatWild | ast::PatWildMulti => Some(Vec::new()), ast::PatIdent(_, _, None) if pat_is_binding(dm, &*p) => Some(Vec::new()), _ => None } - }); - - // Ok, now, this is pretty subtle. A "default" match is a match - // that needs to be considered if none of the actual checks on the - // value being considered succeed. The subtlety lies in that sometimes - // identifier/wildcard matches are *not* default matches. Consider: - // "match x { _ if something => foo, true => bar, false => baz }". - // There is a wildcard match, but it is *not* a default case. The boolean - // case on the value being considered is exhaustive. If the case is - // exhaustive, then there are no defaults. - // - // We detect whether the case is exhaustive in the following - // somewhat kludgy way: if the last wildcard/binding match has a - // guard, then by non-redundancy, we know that there aren't any - // non guarded matches, and thus by exhaustiveness, we know that - // we don't need any default cases. If the check *isn't* nonexhaustive - // (because chk is Some), then we need the defaults anyways. - let is_exhaustive = match matches.last() { - Some(m) if m.data.arm.guard.is_some() && chk.is_infallible() => true, - _ => false - }; - - if is_exhaustive { Vec::new() } else { matches } + }) } // nmatsakis: what does enter_opt do? @@ -1448,15 +1425,12 @@ fn compile_submatch<'a, 'b>( m.repr(bcx.tcx()), vec_map_to_str(vals, |v| bcx.val_to_str(*v))); let _indenter = indenter(); - - /* - For an empty match, a fall-through case must exist - */ - assert!((m.len() > 0u || chk.is_fallible())); let _icx = push_ctxt("match::compile_submatch"); let mut bcx = bcx; if m.len() == 0u { - Br(bcx, chk.handle_fail()); + if chk.is_fallible() { + Br(bcx, chk.handle_fail()); + } return; } if m[0].pats.len() == 0u { @@ -1658,7 +1632,7 @@ fn compile_submatch_continue<'a, 'b>( C_int(ccx, 0) // Placeholder for when not using a switch }; - let defaults = enter_default(else_cx, dm, m, col, val, chk); + let defaults = enter_default(else_cx, dm, m, col, val); let exhaustive = chk.is_infallible() && defaults.len() == 0u; let len = opts.len(); @@ -1947,18 +1921,14 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, // `compile_submatch` works one column of arm patterns a time and // then peels that column off. So as we progress, it may become - // impossible to know whether we have a genuine default arm, i.e. + // impossible to tell whether we have a genuine default arm, i.e. // `_ => foo` or not. Sometimes it is important to know that in order // to decide whether moving on to the next condition or falling back // to the default arm. - let has_default = arms.len() > 0 && { - let ref pats = arms.last().unwrap().pats; - - pats.len() == 1 - && match pats.last().unwrap().node { - ast::PatWild => true, _ => false - } - }; + let has_default = arms.last().map_or(false, |arm| { + arm.pats.len() == 1 + && arm.pats.last().unwrap().node == ast::PatWild + }); compile_submatch(bcx, matches.as_slice(), [discr_datum.val], &chk, has_default); diff --git a/src/test/run-pass/issue-14865.rs b/src/test/run-pass/issue-14865.rs new file mode 100644 index 0000000000000..7fa88a7653ac4 --- /dev/null +++ b/src/test/run-pass/issue-14865.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum X { + Foo(uint), + Bar(bool) +} + +fn main() { + let x = match Foo(42) { + Foo(..) => 1, + _ if true => 0, + Bar(..) => fail!("Oh dear") + }; + assert_eq!(x, 1); + + let x = match Foo(42) { + _ if true => 0, + Foo(..) => 1, + Bar(..) => fail!("Oh dear") + }; + assert_eq!(x, 0); +} From 7cfdfa6ef6d8d7bdf2cc942750cf55bb50b21148 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 18 Jun 2014 17:56:21 +0200 Subject: [PATCH 45/55] debuginfo: Add test case for issue 14411. --- src/test/debuginfo/issue14411.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/debuginfo/issue14411.rs diff --git a/src/test/debuginfo/issue14411.rs b/src/test/debuginfo/issue14411.rs new file mode 100644 index 0000000000000..16c7dcc34ff60 --- /dev/null +++ b/src/test/debuginfo/issue14411.rs @@ -0,0 +1,25 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-android: FIXME(#10381) + +// compile-flags:-g + +// No debugger interaction required: just make sure it compiles without +// crashing. + +fn test(a: &Vec) { + print!("{}", a.len()); +} + +pub fn main() { + let data = vec!(); + test(&data); +} From ba863c81672549693a863822bf2600e5362a2927 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 18 Jun 2014 11:25:04 -0700 Subject: [PATCH 46/55] (doc) Change search placeholder text. Update placeholder text to make keyboard shortcuts more apparent. --- src/librustdoc/html/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index f48a93574e7e7..0304a1d690ef5 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -63,7 +63,7 @@ r##"
From abf7e933df0c732f14b5b8906161e74e72cd26ca Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 18 Jun 2014 14:51:15 -0400 Subject: [PATCH 47/55] Update compiler-rt to work for non-v7 arm. --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index 7b97b8468f061..62a4ca6055ad6 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit 7b97b8468f0614072cf3299fa8c51e85f609316f +Subproject commit 62a4ca6055ad6fda8faf767b93b5736dcdfb7013 From 108b8b6dc707775bd54aeea7820e0d473f556718 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 18 Jun 2014 20:25:36 +0200 Subject: [PATCH 48/55] Deprecate the bytes!() macro. Replace its usage with byte string literals, except in `bytes!()` tests. Also add a new snapshot, to be able to use the new b"foo" syntax. The src/etc/2014-06-rewrite-bytes-macros.py script automatically rewrites `bytes!()` invocations into byte string literals. Pass it filenames as arguments to generate a diff that you can inspect, or `--apply` followed by filenames to apply the changes in place. Diffs can be piped into `tip` or `pygmentize -l diff` for coloring. --- src/compiletest/runtest.rs | 4 +- src/doc/complement-cheatsheet.md | 2 +- src/doc/rust.md | 13 + src/etc/2014-06-rewrite-bytes-macros.py | 138 +++++++++ src/libcollections/slice.rs | 32 +-- src/libcollections/str.rs | 52 ++-- src/libdebug/repr.rs | 6 +- src/libnative/io/file_unix.rs | 6 +- src/libnative/io/file_win32.rs | 2 +- src/librand/lib.rs | 6 +- src/librustc/metadata/filesearch.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustdoc/html/render.rs | 4 +- src/librustrt/args.rs | 4 +- src/librustrt/c_str.rs | 22 +- src/libserialize/base64.rs | 14 +- src/libserialize/hex.rs | 2 +- src/libstd/io/buffered.rs | 4 +- src/libstd/io/fs.rs | 30 +- src/libstd/io/mem.rs | 4 +- src/libstd/io/mod.rs | 28 +- src/libstd/io/pipe.rs | 2 +- src/libstd/io/stdio.rs | 2 +- src/libstd/macros.rs | 2 +- src/libstd/path/mod.rs | 4 +- src/libstd/path/posix.rs | 265 +++++++++--------- src/libstd/path/windows.rs | 107 +++---- src/libsyntax/ext/bytes.rs | 8 + src/libterm/terminfo/parm.rs | 54 ++-- src/libterm/terminfo/parser/compiled.rs | 8 +- src/snapshots.txt | 8 + .../compile-fail/macros-nonfatal-errors.rs | 3 +- ...-extension-bytes-non-ascii-char-literal.rs | 1 + .../syntax-extension-bytes-non-literal.rs | 1 + ...tension-bytes-too-large-integer-literal.rs | 1 + ...ax-extension-bytes-too-large-u8-literal.rs | 1 + ...tension-bytes-too-small-integer-literal.rs | 1 + ...ax-extension-bytes-too-small-u8-literal.rs | 1 + ...tax-extension-bytes-unsupported-literal.rs | 1 + src/test/run-pass/issue-4333.rs | 2 +- src/test/run-pass/tempfile.rs | 2 +- src/test/run-pass/trait-coercion.rs | 2 +- 42 files changed, 498 insertions(+), 355 deletions(-) create mode 100755 src/etc/2014-06-rewrite-bytes-macros.py diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 1e07068dd6f62..ce3c2d7de8095 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -1269,7 +1269,7 @@ fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> Path { fn aux_output_dir_name(config: &Config, testfile: &Path) -> Path { let mut f = output_base_name(config, testfile); - match f.filename().map(|s| Vec::from_slice(s).append(bytes!(".libaux"))) { + match f.filename().map(|s| Vec::from_slice(s).append(b".libaux")) { Some(v) => f.set_filename(v), None => () } @@ -1490,7 +1490,7 @@ fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path { (*p).clone() } else { let stem = p.filestem().unwrap(); - p.with_filename(Vec::from_slice(stem).append(bytes!("-")).append(suffix.as_bytes())) + p.with_filename(Vec::from_slice(stem).append(b"-").append(suffix.as_bytes())) } } diff --git a/src/doc/complement-cheatsheet.md b/src/doc/complement-cheatsheet.md index 9797284a65b7d..84fd140a23af4 100644 --- a/src/doc/complement-cheatsheet.md +++ b/src/doc/complement-cheatsheet.md @@ -76,7 +76,7 @@ character. ~~~ use std::str; -let x = bytes!(72u8,"ello ",0xF0,0x90,0x80,"World!"); +let x = b"Hello \xF0\x90\x80World!"; let y = str::from_utf8_lossy(x); ~~~ diff --git a/src/doc/rust.md b/src/doc/rust.md index cc41b8edfbf8d..7e5e5b2e67a43 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -378,6 +378,19 @@ the characters `U+0022` (double-quote) (except when followed by at least as many `U+0023` (`#`) characters as were used to start the raw string literal) or `U+005C` (`\`) do not have any special meaning. +Examples for byte string literals: + +~~~~ +b"foo"; br"foo"; // foo +b"\"foo\""; br#""foo""#; // "foo" + +b"foo #\"# bar"; +br##"foo #"# bar"##; // foo #"# bar + +b"\x52"; b"R"; br"R"; // R +b"\\x52"; br"\x52"; // \x52 +~~~~ + #### Number literals ~~~~ {.ebnf .gram} diff --git a/src/etc/2014-06-rewrite-bytes-macros.py b/src/etc/2014-06-rewrite-bytes-macros.py new file mode 100755 index 0000000000000..ceda4bf6fe253 --- /dev/null +++ b/src/etc/2014-06-rewrite-bytes-macros.py @@ -0,0 +1,138 @@ +#!/bin/env python +# +# 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 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +import sys +import subprocess +import re + + +def main(): + if len(sys.argv) <= 1: + print('Usage: %s [ --apply ] filename1.rs filename2.rs ...' + % sys.argv[0]) + elif sys.argv[1] == '--apply': + for filename in sys.argv[2:]: + patch(filename) + else: + for filename in sys.argv[1:]: + diff(filename) + + +def patch(filename): + source = read(filename) + rewritten = rewrite_bytes_macros(source) + if rewritten is not None and rewritten != source: + write(filename, rewritten) + + +def diff(filename): + rewritten = rewrite_bytes_macros(read(filename)) + if rewritten is not None: + p = subprocess.Popen(['diff', '-u', filename, '-'], + stdin=subprocess.PIPE) + p.stdin.write(rewritten) + p.stdin.close() + p.wait() + + +def read(filename): + with open(filename, 'rb') as f: + return f.read() + + +def write(filename, content): + with open(filename, 'wb') as f: + f.write(content) + + +def rewrite_bytes_macros(source): + rewritten, num_occurrences = BYTES_MACRO_RE.subn(rewrite_one_macro, source) + if num_occurrences > 0: + return rewritten + + +BYTES_MACRO_RE = re.compile(br'bytes!\( (?P [^)]* ) \)', re.VERBOSE) + + +def rewrite_one_macro(match): + try: + bytes = parse_bytes(split_args(match.group('args'))) + return b'b"' + b''.join(map(escape, bytes)) + b'"' + except SkipThisRewrite: + print('Skipped: %s' % match.group(0).decode('utf8', 'replace')) + return match.group(0) + + +class SkipThisRewrite(Exception): + pass + + +def split_args(args): + previous = b'' + for arg in args.split(b','): + if previous: + arg = previous + b',' + arg + if arg.count(b'"') % 2 == 0: + yield arg + previous = b'' + else: + previous = arg + if previous: + yield previous + + +def parse_bytes(args): + for arg in args: + arg = arg.strip() + if (arg.startswith(b'"') and arg.endswith(b'"')) or ( + arg.startswith(b"'") and arg.endswith(b"'")): + # Escaped newline means something different in Rust and Python. + if b'\\\n' in arg: + raise SkipThisRewrite + for byte in eval(b'u' + arg).encode('utf8'): + yield ord(byte) + else: + if arg.endswith(b'u8'): + arg = arg[:-2] + # Assume that all Rust integer literals + # are valid Python integer literals + value = int(eval(arg)) + assert value <= 0xFF + yield value + + +def escape(byte): + c = chr(byte) + escaped = { + b'\0': br'\0', + b'\t': br'\t', + b'\n': br'\n', + b'\r': br'\r', + b'\'': b'\\\'', + b'\\': br'\\', + }.get(c) + if escaped is not None: + return escaped + elif b' ' <= c <= b'~': + return chr(byte) + else: + return ('\\x%02X' % byte).encode('ascii') + + +if str is not bytes: + # Python 3.x + ord = lambda x: x + chr = lambda x: bytes([x]) + + +if __name__ == '__main__': + main() diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ff00ca58e8c76..f9826fcd2287f 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1957,30 +1957,30 @@ mod tests { #[test] fn test_starts_with() { - assert!(bytes!("foobar").starts_with(bytes!("foo"))); - assert!(!bytes!("foobar").starts_with(bytes!("oob"))); - assert!(!bytes!("foobar").starts_with(bytes!("bar"))); - assert!(!bytes!("foo").starts_with(bytes!("foobar"))); - assert!(!bytes!("bar").starts_with(bytes!("foobar"))); - assert!(bytes!("foobar").starts_with(bytes!("foobar"))); + assert!(b"foobar".starts_with(b"foo")); + assert!(!b"foobar".starts_with(b"oob")); + assert!(!b"foobar".starts_with(b"bar")); + assert!(!b"foo".starts_with(b"foobar")); + assert!(!b"bar".starts_with(b"foobar")); + assert!(b"foobar".starts_with(b"foobar")); let empty: &[u8] = []; assert!(empty.starts_with(empty)); - assert!(!empty.starts_with(bytes!("foo"))); - assert!(bytes!("foobar").starts_with(empty)); + assert!(!empty.starts_with(b"foo")); + assert!(b"foobar".starts_with(empty)); } #[test] fn test_ends_with() { - assert!(bytes!("foobar").ends_with(bytes!("bar"))); - assert!(!bytes!("foobar").ends_with(bytes!("oba"))); - assert!(!bytes!("foobar").ends_with(bytes!("foo"))); - assert!(!bytes!("foo").ends_with(bytes!("foobar"))); - assert!(!bytes!("bar").ends_with(bytes!("foobar"))); - assert!(bytes!("foobar").ends_with(bytes!("foobar"))); + assert!(b"foobar".ends_with(b"bar")); + assert!(!b"foobar".ends_with(b"oba")); + assert!(!b"foobar".ends_with(b"foo")); + assert!(!b"foo".ends_with(b"foobar")); + assert!(!b"bar".ends_with(b"foobar")); + assert!(b"foobar".ends_with(b"foobar")); let empty: &[u8] = []; assert!(empty.ends_with(empty)); - assert!(!empty.ends_with(bytes!("foo"))); - assert!(bytes!("foobar").ends_with(empty)); + assert!(!empty.ends_with(b"foo")); + assert!(b"foobar".ends_with(empty)); } #[test] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 83601be83dec0..642e7cfc9a36f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -382,7 +382,7 @@ static TAG_CONT_U8: u8 = 128u8; /// # Example /// /// ```rust -/// let input = bytes!("Hello ", 0xF0, 0x90, 0x80, "World"); +/// let input = b"Hello \xF0\x90\x80World"; /// let output = std::str::from_utf8_lossy(input); /// assert_eq!(output.as_slice(), "Hello \uFFFDWorld"); /// ``` @@ -391,7 +391,7 @@ pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> { return Slice(unsafe { mem::transmute(v) }) } - static REPLACEMENT: &'static [u8] = bytes!(0xEF, 0xBF, 0xBD); // U+FFFD in UTF-8 + static REPLACEMENT: &'static [u8] = b"\xEF\xBF\xBD"; // U+FFFD in UTF-8 let mut i = 0; let total = v.len(); fn unsafe_get(xs: &[u8], i: uint) -> u8 { @@ -994,7 +994,7 @@ mod tests { fn test_into_bytes() { let data = "asdf".to_string(); let buf = data.into_bytes(); - assert_eq!(bytes!("asdf"), buf.as_slice()); + assert_eq!(b"asdf", buf.as_slice()); } #[test] @@ -2050,58 +2050,58 @@ mod tests { #[test] fn test_str_from_utf8() { - let xs = bytes!("hello"); + let xs = b"hello"; assert_eq!(from_utf8(xs), Some("hello")); - let xs = bytes!("ศไทย中华Việt Nam"); + let xs = "ศไทย中华Việt Nam".as_bytes(); assert_eq!(from_utf8(xs), Some("ศไทย中华Việt Nam")); - let xs = bytes!("hello", 0xff); + let xs = b"hello\xFF"; assert_eq!(from_utf8(xs), None); } #[test] fn test_str_from_utf8_owned() { - let xs = Vec::from_slice(bytes!("hello")); + let xs = Vec::from_slice(b"hello"); assert_eq!(from_utf8_owned(xs), Ok("hello".to_string())); - let xs = Vec::from_slice(bytes!("ศไทย中华Việt Nam")); + let xs = Vec::from_slice("ศไทย中华Việt Nam".as_bytes()); assert_eq!(from_utf8_owned(xs), Ok("ศไทย中华Việt Nam".to_string())); - let xs = Vec::from_slice(bytes!("hello", 0xff)); + let xs = Vec::from_slice(b"hello\xFF"); assert_eq!(from_utf8_owned(xs), - Err(Vec::from_slice(bytes!("hello", 0xff)))); + Err(Vec::from_slice(b"hello\xFF"))); } #[test] fn test_str_from_utf8_lossy() { - let xs = bytes!("hello"); + let xs = b"hello"; assert_eq!(from_utf8_lossy(xs), Slice("hello")); - let xs = bytes!("ศไทย中华Việt Nam"); + let xs = "ศไทย中华Việt Nam".as_bytes(); assert_eq!(from_utf8_lossy(xs), Slice("ศไทย中华Việt Nam")); - let xs = bytes!("Hello", 0xC2, " There", 0xFF, " Goodbye"); + let xs = b"Hello\xC2 There\xFF Goodbye"; assert_eq!(from_utf8_lossy(xs), Owned("Hello\uFFFD There\uFFFD Goodbye".to_string())); - let xs = bytes!("Hello", 0xC0, 0x80, " There", 0xE6, 0x83, " Goodbye"); + let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; assert_eq!(from_utf8_lossy(xs), Owned("Hello\uFFFD\uFFFD There\uFFFD Goodbye".to_string())); - let xs = bytes!(0xF5, "foo", 0xF5, 0x80, "bar"); + let xs = b"\xF5foo\xF5\x80bar"; assert_eq!(from_utf8_lossy(xs), Owned("\uFFFDfoo\uFFFD\uFFFDbar".to_string())); - let xs = bytes!(0xF1, "foo", 0xF1, 0x80, "bar", 0xF1, 0x80, 0x80, "baz"); + let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; assert_eq!(from_utf8_lossy(xs), Owned("\uFFFDfoo\uFFFDbar\uFFFDbaz".to_string())); - let xs = bytes!(0xF4, "foo", 0xF4, 0x80, "bar", 0xF4, 0xBF, "baz"); + let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; assert_eq!(from_utf8_lossy(xs), Owned("\uFFFDfoo\uFFFDbar\uFFFD\uFFFDbaz".to_string())); - let xs = bytes!(0xF0, 0x80, 0x80, 0x80, "foo", 0xF0, 0x90, 0x80, 0x80, "bar"); + let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; assert_eq!(from_utf8_lossy(xs), Owned("\uFFFD\uFFFD\uFFFD\uFFFD\ foo\U00010000bar".to_string())); // surrogates - let xs = bytes!(0xED, 0xA0, 0x80, "foo", 0xED, 0xBF, 0xBF, "bar"); + let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; assert_eq!(from_utf8_lossy(xs), Owned("\uFFFD\uFFFD\uFFFDfoo\ \uFFFD\uFFFD\uFFFDbar".to_string())); } @@ -2298,8 +2298,8 @@ mod bench { #[bench] fn is_utf8_100_ascii(b: &mut Bencher) { - let s = bytes!("Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "); + let s = b"Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; assert_eq!(100, s.len()); b.iter(|| { @@ -2309,7 +2309,7 @@ mod bench { #[bench] fn is_utf8_100_multibyte(b: &mut Bencher) { - let s = bytes!("𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰"); + let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); assert_eq!(100, s.len()); b.iter(|| { is_utf8(s) @@ -2318,8 +2318,8 @@ mod bench { #[bench] fn from_utf8_lossy_100_ascii(b: &mut Bencher) { - let s = bytes!("Hello there, the quick brown fox jumped over the lazy dog! \ - Lorem ipsum dolor sit amet, consectetur. "); + let s = b"Hello there, the quick brown fox jumped over the lazy dog! \ + Lorem ipsum dolor sit amet, consectetur. "; assert_eq!(100, s.len()); b.iter(|| { @@ -2329,7 +2329,7 @@ mod bench { #[bench] fn from_utf8_lossy_100_multibyte(b: &mut Bencher) { - let s = bytes!("𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰"); + let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes(); assert_eq!(100, s.len()); b.iter(|| { let _ = from_utf8_lossy(s); @@ -2338,7 +2338,7 @@ mod bench { #[bench] fn from_utf8_lossy_invalid(b: &mut Bencher) { - let s = bytes!("Hello", 0xC0, 0x80, " There", 0xE6, 0x83, " Goodbye"); + let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; b.iter(|| { let _ = from_utf8_lossy(s); }); diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index d27b0f0de7e30..4744d92436f2b 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -75,13 +75,13 @@ macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty { fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> { let s = self.to_str(); writer.write(s.as_bytes()).and_then(|()| { - writer.write(bytes!($suffix)) + writer.write($suffix) }) } })) -num_repr!(f32, "f32") -num_repr!(f64, "f64") +num_repr!(f32, b"f32") +num_repr!(f64, b"f64") // New implementation using reflect::MovePtr diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index 93938e3d5b860..edf2becc77760 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -360,7 +360,7 @@ pub fn readdir(p: &CString) -> IoResult> { let root = Path::new(root); dirs.move_iter().filter(|path| { - path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") + path.as_vec() != b"." && path.as_vec() != b".." }).map(|path| root.join(path).to_c_str()).collect() } @@ -529,7 +529,7 @@ mod tests { let mut reader = FileDesc::new(reader, true); let mut writer = FileDesc::new(writer, true); - writer.inner_write(bytes!("test")).ok().unwrap(); + writer.inner_write(b"test").ok().unwrap(); let mut buf = [0u8, ..4]; match reader.inner_read(buf) { Ok(4) => { @@ -552,7 +552,7 @@ mod tests { assert!(!f.is_null()); let mut file = CFile::new(f); - file.write(bytes!("test")).ok().unwrap(); + file.write(b"test").ok().unwrap(); let mut buf = [0u8, ..4]; let _ = file.seek(0, SeekSet).ok().unwrap(); match file.read(buf) { diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 41ef5e31a91f6..cd9abc70a4ee8 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -351,7 +351,7 @@ pub fn readdir(p: &CString) -> IoResult> { let root = Path::new(root); dirs.move_iter().filter(|path| { - path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") + path.as_vec() != b"." && path.as_vec() != b".." }).map(|path| root.join(path).to_c_str()).collect() } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 5a9b949be251a..048e44cd55d78 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -292,9 +292,9 @@ pub struct AsciiGenerator<'a, R> { impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { fn next(&mut self) -> Option { static GEN_ASCII_STR_CHARSET: &'static [u8] = - bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"); + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; Some(*self.rng.choose(GEN_ASCII_STR_CHARSET).unwrap() as char) } } diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index ec46e7f8592d3..c15148f75df22 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -214,7 +214,7 @@ pub fn rust_path() -> Vec { env_rust_path.push(cwd.clone()); } loop { - if { let f = cwd.filename(); f.is_none() || f.unwrap() == bytes!("..") } { + if { let f = cwd.filename(); f.is_none() || f.unwrap() == b".." } { break } cwd.set_filename(".rust"); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 11166f92b1cc2..783fdfa4aaec9 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1411,7 +1411,7 @@ fn compile_unit_metadata(cx: &CrateContext) { match abs_path.path_relative_from(work_dir) { Some(ref p) if p.is_relative() => { // prepend "./" if necessary - let dotdot = bytes!(".."); + let dotdot = b".."; let prefix = &[dotdot[0], ::std::path::SEP_BYTE]; let mut path_bytes = Vec::from_slice(p.as_vec()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c6a6eb29addda..76e604ecfa287 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -602,7 +602,7 @@ fn mkdir(path: &Path) -> io::IoResult<()> { // FIXME (#9639): The closure should deal with &[u8] instead of &str fn clean_srcpath(src: &[u8], f: |&str|) { let p = Path::new(src); - if p.as_vec() != bytes!(".") { + if p.as_vec() != b"." { for c in p.str_components().map(|x|x.unwrap()) { if ".." == c { f("up"); @@ -714,7 +714,7 @@ impl<'a> SourceCollector<'a> { }); cur.push(Vec::from_slice(p.filename().expect("source has no filename")) - .append(bytes!(".html"))); + .append(b".html")); let mut w = BufferedWriter::new(try!(File::create(&cur))); let title = format!("{} -- source", cur.filename_display()); diff --git a/src/librustrt/args.rs b/src/librustrt/args.rs index d6d4b18051bf3..09ae2b31f6368 100644 --- a/src/librustrt/args.rs +++ b/src/librustrt/args.rs @@ -123,8 +123,8 @@ mod imp { let saved_value = take(); let expected = vec![ - Vec::from_slice(bytes!("happy")), - Vec::from_slice(bytes!("today?")), + Vec::from_slice(b"happy"), + Vec::from_slice(b"today?"), ]; put(expected.clone()); diff --git a/src/librustrt/c_str.rs b/src/librustrt/c_str.rs index b4d9ac7efbebc..4a7ac97beed8d 100644 --- a/src/librustrt/c_str.rs +++ b/src/librustrt/c_str.rs @@ -463,7 +463,7 @@ mod tests { #[test] fn test_str_multistring_parsing() { unsafe { - let input = bytes!("zero", "\x00", "one", "\x00", "\x00"); + let input = b"zero\0one\0\0"; let ptr = input.as_ptr(); let expected = ["zero", "one"]; let mut it = expected.iter(); @@ -505,7 +505,7 @@ mod tests { } }); - let _ = bytes!("hello").to_c_str().with_ref(|buf| { + let _ = b"hello".to_c_str().with_ref(|buf| { unsafe { assert_eq!(*buf.offset(0), 'h' as libc::c_char); assert_eq!(*buf.offset(1), 'e' as libc::c_char); @@ -516,7 +516,7 @@ mod tests { } }); - let _ = bytes!("foo", 0xff).to_c_str().with_ref(|buf| { + let _ = b"foo\xFF".to_c_str().with_ref(|buf| { unsafe { assert_eq!(*buf.offset(0), 'f' as libc::c_char); assert_eq!(*buf.offset(1), 'o' as libc::c_char); @@ -595,22 +595,22 @@ mod tests { #[test] fn test_as_bytes() { let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes(), bytes!("hello", 0)); + assert_eq!(c_str.as_bytes(), b"hello\0"); let c_str = "".to_c_str(); - assert_eq!(c_str.as_bytes(), bytes!(0)); - let c_str = bytes!("foo", 0xff).to_c_str(); - assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0)); + assert_eq!(c_str.as_bytes(), b"\0"); + let c_str = b"foo\xFF".to_c_str(); + assert_eq!(c_str.as_bytes(), b"foo\xFF\0"); } #[test] fn test_as_bytes_no_nul() { let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), bytes!("hello")); + assert_eq!(c_str.as_bytes_no_nul(), b"hello"); let c_str = "".to_c_str(); let exp: &[u8] = []; assert_eq!(c_str.as_bytes_no_nul(), exp); - let c_str = bytes!("foo", 0xff).to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), bytes!("foo", 0xff)); + let c_str = b"foo\xFF".to_c_str(); + assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); } #[test] @@ -633,7 +633,7 @@ mod tests { assert_eq!(c_str.as_str(), Some("hello")); let c_str = "".to_c_str(); assert_eq!(c_str.as_str(), Some("")); - let c_str = bytes!("foo", 0xff).to_c_str(); + let c_str = b"foo\xFF".to_c_str(); assert_eq!(c_str.as_str(), None); } diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index 5a8759540c8b5..5c4da38989f11 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -42,13 +42,13 @@ pub static URL_SAFE: Config = pub static MIME: Config = Config {char_set: Standard, pad: true, line_length: Some(76)}; -static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyz", - "0123456789+/"); +static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789+/"; -static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyz", - "0123456789-_"); +static URLSAFE_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789-_"; /// A trait for converting a value to base64 encoding. pub trait ToBase64 { @@ -193,7 +193,7 @@ impl<'a> FromBase64 for &'a str { * use serialize::base64::{ToBase64, FromBase64, STANDARD}; * * fn main () { - * let hello_str = bytes!("Hello, World").to_base64(STANDARD); + * let hello_str = b"Hello, World".to_base64(STANDARD); * println!("base64 output: {}", hello_str); * let res = hello_str.as_slice().from_base64(); * if res.is_ok() { diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 8ae3336c342b4..44d0606185345 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -19,7 +19,7 @@ pub trait ToHex { fn to_hex(&self) -> String; } -static CHARS: &'static[u8] = bytes!("0123456789abcdef"); +static CHARS: &'static[u8] = b"0123456789abcdef"; impl<'a> ToHex for &'a [u8] { /** diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 9450f7798edcf..4f355502eb88d 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -535,7 +535,7 @@ mod test { #[test] fn test_read_line() { - let in_buf = MemReader::new(Vec::from_slice(bytes!("a\nb\nc"))); + let in_buf = MemReader::new(Vec::from_slice(b"a\nb\nc")); let mut reader = BufferedReader::with_capacity(2, in_buf); assert_eq!(reader.read_line(), Ok("a\n".to_string())); assert_eq!(reader.read_line(), Ok("b\n".to_string())); @@ -545,7 +545,7 @@ mod test { #[test] fn test_lines() { - let in_buf = MemReader::new(Vec::from_slice(bytes!("a\nb\nc"))); + let in_buf = MemReader::new(Vec::from_slice(b"a\nb\nc")); let mut reader = BufferedReader::with_capacity(2, in_buf); let mut it = reader.lines(); assert_eq!(it.next(), Some(Ok("a\n".to_string()))); diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 20187a6dcde6b..a801dd0e7cb35 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -35,7 +35,7 @@ let path = Path::new("foo.txt"); // create the file, whether it exists or not let mut file = File::create(&path); -file.write(bytes!("foobar")); +file.write(b"foobar"); # drop(file); // open the file in read-only mode @@ -186,7 +186,7 @@ impl File { /// use std::io::File; /// /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(bytes!("This is a sample file")); + /// f.write(b"This is a sample file"); /// # drop(f); /// # ::std::io::fs::unlink(&Path::new("foo.txt")); /// ``` @@ -1141,7 +1141,7 @@ mod test { iotest!(fn file_test_fileinfo_check_exists_before_and_after_file_creation() { let tmpdir = tmpdir(); let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(File::create(file).write(bytes!("foo"))); + check!(File::create(file).write(b"foo")); assert!(file.exists()); check!(unlink(file)); assert!(!file.exists()); @@ -1253,7 +1253,7 @@ mod test { let canary = d2.join("do_not_delete"); check!(mkdir_recursive(&dtt, io::UserRWX)); check!(mkdir_recursive(&d2, io::UserRWX)); - check!(File::create(&canary).write(bytes!("foo"))); + check!(File::create(&canary).write(b"foo")); check!(symlink(&d2, &dt.join("d2"))); check!(rmdir_recursive(&d1)); @@ -1314,10 +1314,10 @@ mod test { let input = tmpdir.join("in.txt"); let out = tmpdir.join("out.txt"); - check!(File::create(&input).write(bytes!("hello"))); + check!(File::create(&input).write(b"hello")); check!(copy(&input, &out)); let contents = check!(File::open(&out).read_to_end()); - assert_eq!(contents.as_slice(), bytes!("hello")); + assert_eq!(contents.as_slice(), b"hello"); assert_eq!(check!(input.stat()).perm, check!(out.stat()).perm); }) @@ -1342,7 +1342,7 @@ mod test { check!(copy(&input, &output)); assert_eq!(check!(File::open(&output).read_to_end()), - (Vec::from_slice(bytes!("foo")))); + (Vec::from_slice(b"foo"))); }) iotest!(fn copy_file_src_dir() { @@ -1383,7 +1383,7 @@ mod test { } assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); assert_eq!(check!(File::open(&out).read_to_end()), - (Vec::from_slice(bytes!("foobar")))); + (Vec::from_slice(b"foobar"))); }) #[cfg(not(windows))] // apparently windows doesn't like symlinks @@ -1418,7 +1418,7 @@ mod test { assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); assert_eq!(check!(stat(&out)).size, check!(input.stat()).size); assert_eq!(check!(File::open(&out).read_to_end()), - (Vec::from_slice(bytes!("foobar")))); + (Vec::from_slice(b"foobar"))); // can't link to yourself match link(&input, &input) { @@ -1456,7 +1456,7 @@ mod test { let mut file = check!(File::open_mode(&path, io::Open, io::ReadWrite)); check!(file.fsync()); check!(file.datasync()); - check!(file.write(bytes!("foo"))); + check!(file.write(b"foo")); check!(file.fsync()); check!(file.datasync()); drop(file); @@ -1467,29 +1467,29 @@ mod test { let path = tmpdir.join("in.txt"); let mut file = check!(File::open_mode(&path, io::Open, io::ReadWrite)); - check!(file.write(bytes!("foo"))); + check!(file.write(b"foo")); check!(file.fsync()); // Do some simple things with truncation assert_eq!(check!(file.stat()).size, 3); check!(file.truncate(10)); assert_eq!(check!(file.stat()).size, 10); - check!(file.write(bytes!("bar"))); + check!(file.write(b"bar")); check!(file.fsync()); assert_eq!(check!(file.stat()).size, 10); assert_eq!(check!(File::open(&path).read_to_end()), - (Vec::from_slice(bytes!("foobar", 0, 0, 0, 0)))); + (Vec::from_slice(b"foobar\0\0\0\0"))); // Truncate to a smaller length, don't seek, and then write something. // Ensure that the intermediate zeroes are all filled in (we're seeked // past the end of the file). check!(file.truncate(2)); assert_eq!(check!(file.stat()).size, 2); - check!(file.write(bytes!("wut"))); + check!(file.write(b"wut")); check!(file.fsync()); assert_eq!(check!(file.stat()).size, 9); assert_eq!(check!(File::open(&path).read_to_end()), - (Vec::from_slice(bytes!("fo", 0, 0, 0, 0, "wut")))); + (Vec::from_slice(b"fo\0\0\0\0wut"))); drop(file); }) diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 71a967bb8dc5f..5eca5361835e3 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -474,7 +474,7 @@ mod test { #[test] fn test_read_char() { - let b = bytes!("Việt"); + let b = b"Vi\xE1\xBB\x87t"; let mut r = BufReader::new(b); assert_eq!(r.read_char(), Ok('V')); assert_eq!(r.read_char(), Ok('i')); @@ -485,7 +485,7 @@ mod test { #[test] fn test_read_bad_char() { - let b = bytes!(0x80); + let b = b"\x80"; let mut r = BufReader::new(b); assert!(r.read_char().is_err()); } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index a7f84899a622e..d9755cdce1a4f 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -50,7 +50,7 @@ Some examples of obvious things you might want to do use std::io::File; let mut file = File::create(&Path::new("message.txt")); - file.write(bytes!("hello, file!\n")); + file.write(b"hello, file!\n"); # drop(file); # ::std::io::fs::unlink(&Path::new("message.txt")); ``` @@ -90,7 +90,7 @@ Some examples of obvious things you might want to do # // just stop it running (#11576) # if false { let mut socket = TcpStream::connect("127.0.0.1", 8080).unwrap(); - socket.write(bytes!("GET / HTTP/1.0\n\n")); + socket.write(b"GET / HTTP/1.0\n\n"); let response = socket.read_to_end(); # } ``` @@ -151,7 +151,7 @@ while still providing feedback about errors. The basic strategy: to be 'unwrapped' before use. These features combine in the API to allow for expressions like -`File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"))` +`File::create(&Path::new("diary.txt")).write(b"Met a girl.\n")` without having to worry about whether "diary.txt" exists or whether the write succeeds. As written, if either `new` or `write_line` encounters an error then the result of the entire expression will @@ -163,7 +163,7 @@ If you wanted to handle the error though you might write: # #![allow(unused_must_use)] use std::io::File; -match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) { +match File::create(&Path::new("diary.txt")).write(b"Met a girl.\n") { Ok(()) => (), // succeeded Err(e) => println!("failed to write to my diary: {}", e), } @@ -1839,55 +1839,55 @@ mod tests { #[test] fn test_read_at_least() { - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([GoodBehavior(uint::MAX)])); let mut buf = [0u8, ..5]; assert!(r.read_at_least(1, buf).unwrap() >= 1); assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least assert!(r.read_at_least(0, buf).is_ok()); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(50), GoodBehavior(uint::MAX)])); assert!(r.read_at_least(1, buf).unwrap() >= 1); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(1), GoodBehavior(1), BadBehavior(50), GoodBehavior(uint::MAX)])); assert!(r.read_at_least(1, buf).unwrap() >= 1); assert!(r.read_at_least(1, buf).unwrap() >= 1); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(uint::MAX)])); assert_eq!(r.read_at_least(1, buf).unwrap_err().kind, NoProgress); - let mut r = MemReader::new(Vec::from_slice(bytes!("hello, world!"))); + let mut r = MemReader::new(Vec::from_slice(b"hello, world!")); assert_eq!(r.read_at_least(5, buf).unwrap(), 5); assert_eq!(r.read_at_least(6, buf).unwrap_err().kind, InvalidInput); } #[test] fn test_push_at_least() { - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([GoodBehavior(uint::MAX)])); let mut buf = Vec::new(); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); assert!(r.push_at_least(0, 5, &mut buf).is_ok()); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(50), GoodBehavior(uint::MAX)])); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(1), GoodBehavior(1), BadBehavior(50), GoodBehavior(uint::MAX)])); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - let mut r = BadReader::new(MemReader::new(Vec::from_slice(bytes!("hello, world!"))), + let mut r = BadReader::new(MemReader::new(Vec::from_slice(b"hello, world!")), Vec::from_slice([BadBehavior(uint::MAX)])); assert_eq!(r.push_at_least(1, 5, &mut buf).unwrap_err().kind, NoProgress); - let mut r = MemReader::new(Vec::from_slice(bytes!("hello, world!"))); + let mut r = MemReader::new(Vec::from_slice(b"hello, world!")); assert_eq!(r.push_at_least(5, 1, &mut buf).unwrap_err().kind, InvalidInput); } } diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index 84d388c113630..a968f41a91563 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -52,7 +52,7 @@ impl PipeStream { /// /// fn main() { /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); - /// pipe.write(bytes!("Hello, stderr!")); + /// pipe.write(b"Hello, stderr!"); /// } /// ``` pub fn open(fd: libc::c_int) -> IoResult { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c989dcc3d2945..e5a64f785ce96 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -22,7 +22,7 @@ about the stream or terminal to which it is attached. use std::io; let mut out = io::stdout(); -out.write(bytes!("Hello, world!")); +out.write(b"Hello, world!"); ``` */ diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 58f65c90b3b10..dad162d82ad47 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -463,7 +463,7 @@ pub mod builtin { /// # Example /// /// ``` - /// let rust = bytes!("r", 'u', "st", 255); + /// let rust = b"rust\xFF"; /// assert_eq!(rust[1], 'u' as u8); /// assert_eq!(rust[4], 255); /// ``` diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index 7d15893af241e..e55dc16589516 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -219,7 +219,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { let dot = '.' as u8; match name.rposition_elem(&dot) { None | Some(0) => name, - Some(1) if name == bytes!("..") => name, + Some(1) if name == b".." => name, Some(pos) => name.slice_to(pos) } }) @@ -242,7 +242,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { let dot = '.' as u8; match name.rposition_elem(&dot) { None | Some(0) => None, - Some(1) if name == bytes!("..") => None, + Some(1) if name == b".." => None, Some(pos) => Some(name.slice_from(pos+1)) } } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 494428de3a5c4..d98cfb7d8eece 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -142,7 +142,7 @@ impl GenericPathUnsafe for Path { unsafe fn set_filename_unchecked(&mut self, filename: T) { let filename = filename.container_as_bytes(); match self.sepidx { - None if bytes!("..") == self.repr.as_slice() => { + None if b".." == self.repr.as_slice() => { let mut v = Vec::with_capacity(3 + filename.len()); v.push_all(dot_dot_static); v.push(SEP_BYTE); @@ -153,7 +153,7 @@ impl GenericPathUnsafe for Path { None => { self.repr = Path::normalize(filename); } - Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => { + Some(idx) if self.repr.slice_from(idx+1) == b".." => { let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len()); v.push_all(self.repr.as_slice()); v.push(SEP_BYTE); @@ -202,20 +202,20 @@ impl GenericPath for Path { fn dirname<'a>(&'a self) -> &'a [u8] { match self.sepidx { - None if bytes!("..") == self.repr.as_slice() => self.repr.as_slice(), + None if b".." == self.repr.as_slice() => self.repr.as_slice(), None => dot_static, Some(0) => self.repr.slice_to(1), - Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => self.repr.as_slice(), + Some(idx) if self.repr.slice_from(idx+1) == b".." => self.repr.as_slice(), Some(idx) => self.repr.slice_to(idx) } } fn filename<'a>(&'a self) -> Option<&'a [u8]> { match self.sepidx { - None if bytes!(".") == self.repr.as_slice() || - bytes!("..") == self.repr.as_slice() => None, + None if b"." == self.repr.as_slice() || + b".." == self.repr.as_slice() => None, None => Some(self.repr.as_slice()), - Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => None, + Some(idx) if self.repr.slice_from(idx+1) == b".." => None, Some(0) if self.repr.slice_from(1).is_empty() => None, Some(idx) => Some(self.repr.slice_from(idx+1)) } @@ -223,13 +223,13 @@ impl GenericPath for Path { fn pop(&mut self) -> bool { match self.sepidx { - None if bytes!(".") == self.repr.as_slice() => false, + None if b"." == self.repr.as_slice() => false, None => { self.repr = vec!['.' as u8]; self.sepidx = None; true } - Some(0) if bytes!("/") == self.repr.as_slice() => false, + Some(0) if b"/" == self.repr.as_slice() => false, Some(idx) => { if idx == 0 { self.repr.truncate(idx+1); @@ -261,19 +261,19 @@ impl GenericPath for Path { } else { let mut ita = self.components(); let mut itb = other.components(); - if bytes!(".") == self.repr.as_slice() { + if b"." == self.repr.as_slice() { return match itb.next() { None => true, - Some(b) => b != bytes!("..") + Some(b) => b != b".." }; } loop { match (ita.next(), itb.next()) { (None, _) => break, (Some(a), Some(b)) if a == b => { continue }, - (Some(a), _) if a == bytes!("..") => { + (Some(a), _) if a == b".." => { // if ita contains only .. components, it's an ancestor - return ita.all(|x| x == bytes!("..")); + return ita.all(|x| x == b".."); } _ => return false } @@ -303,8 +303,8 @@ impl GenericPath for Path { } (None, _) => comps.push(dot_dot_static), (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == bytes!(".") => comps.push(a), - (Some(_), Some(b)) if b == bytes!("..") => return None, + (Some(a), Some(b)) if b == b"." => comps.push(a), + (Some(_), Some(b)) if b == b".." => return None, (Some(a), Some(_)) => { comps.push(dot_dot_static); for _ in itb { @@ -425,8 +425,8 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { let mut changed = false; for comp in v.split(is_sep_byte) { if comp.is_empty() { changed = true } - else if comp == bytes!(".") { changed = true } - else if comp == bytes!("..") { + else if comp == b"." { changed = true } + else if comp == b".." { if is_abs && comps.is_empty() { changed = true } else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 } else { comps.pop().unwrap(); changed = true } @@ -434,7 +434,7 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { } if changed { if comps.is_empty() && !is_abs { - if v == bytes!(".") { + if v == b"." { return None; } comps.push(dot_static); @@ -445,8 +445,8 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { } } -static dot_static: &'static [u8] = bytes!("."); -static dot_dot_static: &'static [u8] = bytes!(".."); +static dot_static: &'static [u8] = b"."; +static dot_dot_static: &'static [u8] = b".."; #[cfg(test)] mod tests { @@ -470,24 +470,15 @@ mod tests { ) ) - macro_rules! b( - ($($arg:expr),+) => ( - { - static the_bytes: &'static [u8] = bytes!($($arg),+); - the_bytes - } - ) - ) - #[test] fn test_paths() { let empty: &[u8] = []; - t!(v: Path::new(empty), b!(".")); - t!(v: Path::new(b!("/")), b!("/")); - t!(v: Path::new(b!("a/b/c")), b!("a/b/c")); - t!(v: Path::new(b!("a/b/c", 0xff)), b!("a/b/c", 0xff)); - t!(v: Path::new(b!(0xff, "/../foo", 0x80)), b!("foo", 0x80)); - let p = Path::new(b!("a/b/c", 0xff)); + t!(v: Path::new(empty), b"."); + t!(v: Path::new(b"/"), b"/"); + t!(v: Path::new(b"a/b/c"), b"a/b/c"); + t!(v: Path::new(b"a/b/c\xFF"), b"a/b/c\xFF"); + t!(v: Path::new(b"\xFF/../foo\x80"), b"foo\x80"); + let p = Path::new(b"a/b/c\xFF"); assert!(p.as_str() == None); t!(s: Path::new(""), "."); @@ -513,18 +504,18 @@ mod tests { t!(s: Path::new("foo/../../.."), "../.."); t!(s: Path::new("foo/../../bar"), "../bar"); - assert_eq!(Path::new(b!("foo/bar")).into_vec().as_slice(), b!("foo/bar")); - assert_eq!(Path::new(b!("/foo/../../bar")).into_vec().as_slice(), - b!("/bar")); + assert_eq!(Path::new(b"foo/bar").into_vec().as_slice(), b"foo/bar"); + assert_eq!(Path::new(b"/foo/../../bar").into_vec().as_slice(), + b"/bar"); - let p = Path::new(b!("foo/bar", 0x80)); + let p = Path::new(b"foo/bar\x80"); assert!(p.as_str() == None); } #[test] fn test_opt_paths() { - assert!(Path::new_opt(b!("foo/bar", 0)) == None); - t!(v: Path::new_opt(b!("foo/bar")).unwrap(), b!("foo/bar")); + assert!(Path::new_opt(b"foo/bar\0") == None); + t!(v: Path::new_opt(b"foo/bar").unwrap(), b"foo/bar"); assert!(Path::new_opt("foo/bar\0") == None); t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar"); } @@ -533,17 +524,17 @@ mod tests { fn test_null_byte() { use task; let result = task::try(proc() { - Path::new(b!("foo/bar", 0)) + Path::new(b"foo/bar\0") }); assert!(result.is_err()); let result = task::try(proc() { - Path::new("test").set_filename(b!("f", 0, "o")) + Path::new("test").set_filename(b"f\0o") }); assert!(result.is_err()); let result = task::try(proc() { - Path::new("test").push(b!("f", 0, "o")); + Path::new("test").push(b"f\0o"); }); assert!(result.is_err()); } @@ -559,11 +550,11 @@ mod tests { ) ) t!("foo", display, "foo"); - t!(b!("foo", 0x80), display, "foo\uFFFD"); - t!(b!("foo", 0xff, "bar"), display, "foo\uFFFDbar"); - t!(b!("foo", 0xff, "/bar"), filename_display, "bar"); - t!(b!("foo/", 0xff, "bar"), filename_display, "\uFFFDbar"); - t!(b!("/"), filename_display, ""); + t!(b"foo\x80", display, "foo\uFFFD"); + t!(b"foo\xFFbar", display, "foo\uFFFDbar"); + t!(b"foo\xFF/bar", filename_display, "bar"); + t!(b"foo/\xFFbar", filename_display, "\uFFFDbar"); + t!(b"/", filename_display, ""); macro_rules! t( ($path:expr, $exp:expr) => ( @@ -583,11 +574,11 @@ mod tests { ) t!("foo", "foo"); - t!(b!("foo", 0x80), "foo\uFFFD"); - t!(b!("foo", 0xff, "bar"), "foo\uFFFDbar"); - t!(b!("foo", 0xff, "/bar"), "bar", filename); - t!(b!("foo/", 0xff, "bar"), "\uFFFDbar", filename); - t!(b!("/"), "", filename); + t!(b"foo\x80", "foo\uFFFD"); + t!(b"foo\xFFbar", "foo\uFFFDbar"); + t!(b"foo\xFF/bar", "bar", filename); + t!(b"foo/\xFFbar", "\uFFFDbar", filename); + t!(b"/", "", filename); } #[test] @@ -604,13 +595,13 @@ mod tests { ) ) - t!(b!("foo"), "foo", "foo"); - t!(b!("foo/bar"), "foo/bar", "bar"); - t!(b!("/"), "/", ""); - t!(b!("foo", 0xff), "foo\uFFFD", "foo\uFFFD"); - t!(b!("foo", 0xff, "/bar"), "foo\uFFFD/bar", "bar"); - t!(b!("foo/", 0xff, "bar"), "foo/\uFFFDbar", "\uFFFDbar"); - t!(b!(0xff, "foo/bar", 0xff), "\uFFFDfoo/bar\uFFFD", "bar\uFFFD"); + t!(b"foo", "foo", "foo"); + t!(b"foo/bar", "foo/bar", "bar"); + t!(b"/", "/", ""); + t!(b"foo\xFF", "foo\uFFFD", "foo\uFFFD"); + t!(b"foo\xFF/bar", "foo\uFFFD/bar", "bar"); + t!(b"foo/\xFFbar", "foo/\uFFFDbar", "\uFFFDbar"); + t!(b"\xFFfoo/bar\xFF", "\uFFFDfoo/bar\uFFFD", "bar\uFFFD"); } #[test] @@ -638,9 +629,9 @@ mod tests { ); ) - t!(v: b!("a/b/c"), filename, Some(b!("c"))); - t!(v: b!("a/b/c", 0xff), filename, Some(b!("c", 0xff))); - t!(v: b!("a/b", 0xff, "/c"), filename, Some(b!("c"))); + t!(v: b"a/b/c", filename, Some(b"c")); + t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF")); + t!(v: b"a/b\xFF/c", filename, Some(b"c")); t!(s: "a/b/c", filename, Some("c"), opt); t!(s: "/a/b/c", filename, Some("c"), opt); t!(s: "a", filename, Some("a"), opt); @@ -650,9 +641,9 @@ mod tests { t!(s: "..", filename, None, opt); t!(s: "../..", filename, None, opt); - t!(v: b!("a/b/c"), dirname, b!("a/b")); - t!(v: b!("a/b/c", 0xff), dirname, b!("a/b")); - t!(v: b!("a/b", 0xff, "/c"), dirname, b!("a/b", 0xff)); + t!(v: b"a/b/c", dirname, b"a/b"); + t!(v: b"a/b/c\xFF", dirname, b"a/b"); + t!(v: b"a/b\xFF/c", dirname, b"a/b\xFF"); t!(s: "a/b/c", dirname, "a/b"); t!(s: "/a/b/c", dirname, "/a/b"); t!(s: "a", dirname, "."); @@ -662,9 +653,9 @@ mod tests { t!(s: "..", dirname, ".."); t!(s: "../..", dirname, "../.."); - t!(v: b!("hi/there.txt"), filestem, Some(b!("there"))); - t!(v: b!("hi/there", 0x80, ".txt"), filestem, Some(b!("there", 0x80))); - t!(v: b!("hi/there.t", 0x80, "xt"), filestem, Some(b!("there"))); + t!(v: b"hi/there.txt", filestem, Some(b"there")); + t!(v: b"hi/there\x80.txt", filestem, Some(b"there\x80")); + t!(v: b"hi/there.t\x80xt", filestem, Some(b"there")); t!(s: "hi/there.txt", filestem, Some("there"), opt); t!(s: "hi/there", filestem, Some("there"), opt); t!(s: "there.txt", filestem, Some("there"), opt); @@ -678,11 +669,11 @@ mod tests { t!(s: "..", filestem, None, opt); t!(s: "../..", filestem, None, opt); - t!(v: b!("hi/there.txt"), extension, Some(b!("txt"))); - t!(v: b!("hi/there", 0x80, ".txt"), extension, Some(b!("txt"))); - t!(v: b!("hi/there.t", 0x80, "xt"), extension, Some(b!("t", 0x80, "xt"))); - t!(v: b!("hi/there"), extension, None); - t!(v: b!("hi/there", 0x80), extension, None); + t!(v: b"hi/there.txt", extension, Some(b"txt")); + t!(v: b"hi/there\x80.txt", extension, Some(b"txt")); + t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt")); + t!(v: b"hi/there", extension, None); + t!(v: b"hi/there\x80", extension, None); t!(s: "hi/there.txt", extension, Some("txt"), opt); t!(s: "hi/there", extension, None, opt); t!(s: "there.txt", extension, Some("txt"), opt); @@ -762,9 +753,9 @@ mod tests { t!(s: "a/b/c", ["d", "/e"], "/e"); t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e")); - t!(v: b!("a/b/c"), [b!("d"), b!("/e"), b!("f")], b!("/e/f")); - t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e")); + t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e"); + t!(v: b"a/b/c", [b"d", b"/e", b"f"], b"/e/f"); + t!(v: b"a/b/c", [Vec::from_slice(b"d"), Vec::from_slice(b"e")], b"a/b/c/d/e"); } #[test] @@ -778,25 +769,25 @@ mod tests { assert!(result == $right); } ); - (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => ( + (b: $path:expr, $left:expr, $right:expr) => ( { - let mut p = Path::new(b!($($path),+)); + let mut p = Path::new($path); let result = p.pop(); - assert!(p.as_vec() == b!($($left),+)); + assert!(p.as_vec() == $left); assert!(result == $right); } ) ) - t!(v: ["a/b/c"], ["a/b"], true); - t!(v: ["a"], ["."], true); - t!(v: ["."], ["."], false); - t!(v: ["/a"], ["/"], true); - t!(v: ["/"], ["/"], false); - t!(v: ["a/b/c", 0x80], ["a/b"], true); - t!(v: ["a/b", 0x80, "/c"], ["a/b", 0x80], true); - t!(v: [0xff], ["."], true); - t!(v: ["/", 0xff], ["/"], true); + t!(b: b"a/b/c", b"a/b", true); + t!(b: b"a", b".", true); + t!(b: b".", b".", false); + t!(b: b"/a", b"/", true); + t!(b: b"/", b"/", false); + t!(b: b"a/b/c\x80", b"a/b", true); + t!(b: b"a/b\x80/c", b"a/b\x80", true); + t!(b: b"\xFF", b".", true); + t!(b: b"/\xFF", b"/", true); t!(s: "a/b/c", "a/b", true); t!(s: "a", ".", true); t!(s: ".", ".", false); @@ -806,15 +797,15 @@ mod tests { #[test] fn test_root_path() { - assert!(Path::new(b!("a/b/c")).root_path() == None); - assert!(Path::new(b!("/a/b/c")).root_path() == Some(Path::new("/"))); + assert!(Path::new(b"a/b/c").root_path() == None); + assert!(Path::new(b"/a/b/c").root_path() == Some(Path::new("/"))); } #[test] fn test_join() { - t!(v: Path::new(b!("a/b/c")).join(b!("..")), b!("a/b")); - t!(v: Path::new(b!("/a/b/c")).join(b!("d")), b!("/a/b/c/d")); - t!(v: Path::new(b!("a/", 0x80, "/c")).join(b!(0xff)), b!("a/", 0x80, "/c/", 0xff)); + t!(v: Path::new(b"a/b/c").join(b".."), b"a/b"); + t!(v: Path::new(b"/a/b/c").join(b"d"), b"/a/b/c/d"); + t!(v: Path::new(b"a/\x80/c").join(b"\xFF"), b"a/\x80/c/\xFF"); t!(s: Path::new("a/b/c").join(".."), "a/b"); t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d"); t!(s: Path::new("a/b").join("c/d"), "a/b/c/d"); @@ -867,18 +858,18 @@ mod tests { t!(s: "a/b/c", ["..", "d"], "a/b/d"); t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e")); - t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e")); + t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e"); + t!(v: b"a/b/c", [Vec::from_slice(b"d"), Vec::from_slice(b"e")], b"a/b/c/d/e"); } #[test] fn test_with_helpers() { let empty: &[u8] = []; - t!(v: Path::new(b!("a/b/c")).with_filename(b!("d")), b!("a/b/d")); - t!(v: Path::new(b!("a/b/c", 0xff)).with_filename(b!(0x80)), b!("a/b/", 0x80)); - t!(v: Path::new(b!("/", 0xff, "/foo")).with_filename(b!(0xcd)), - b!("/", 0xff, "/", 0xcd)); + t!(v: Path::new(b"a/b/c").with_filename(b"d"), b"a/b/d"); + t!(v: Path::new(b"a/b/c\xFF").with_filename(b"\x80"), b"a/b/\x80"); + t!(v: Path::new(b"/\xFF/foo").with_filename(b"\xCD"), + b"/\xFF/\xCD"); t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d"); t!(s: Path::new(".").with_filename("foo"), "foo"); t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d"); @@ -899,13 +890,13 @@ mod tests { t!(s: Path::new("..").with_filename(""), ".."); t!(s: Path::new("../..").with_filename(""), "../.."); - t!(v: Path::new(b!("hi/there", 0x80, ".txt")).with_extension(b!("exe")), - b!("hi/there", 0x80, ".exe")); - t!(v: Path::new(b!("hi/there.txt", 0x80)).with_extension(b!(0xff)), - b!("hi/there.", 0xff)); - t!(v: Path::new(b!("hi/there", 0x80)).with_extension(b!(0xff)), - b!("hi/there", 0x80, ".", 0xff)); - t!(v: Path::new(b!("hi/there.", 0xff)).with_extension(empty), b!("hi/there")); + t!(v: Path::new(b"hi/there\x80.txt").with_extension(b"exe"), + b"hi/there\x80.exe"); + t!(v: Path::new(b"hi/there.txt\x80").with_extension(b"\xFF"), + b"hi/there.\xFF"); + t!(v: Path::new(b"hi/there\x80").with_extension(b"\xFF"), + b"hi/there\x80.\xFF"); + t!(v: Path::new(b"hi/there.\xFF").with_extension(empty), b"hi/there"); t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe"); t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there"); t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there.."); @@ -947,17 +938,17 @@ mod tests { ) ) - t!(v: b!("a/b/c"), set_filename, with_filename, b!("d")); - t!(v: b!("/"), set_filename, with_filename, b!("foo")); - t!(v: b!(0x80), set_filename, with_filename, b!(0xff)); + t!(v: b"a/b/c", set_filename, with_filename, b"d"); + t!(v: b"/", set_filename, with_filename, b"foo"); + t!(v: b"\x80", set_filename, with_filename, b"\xFF"); t!(s: "a/b/c", set_filename, with_filename, "d"); t!(s: "/", set_filename, with_filename, "foo"); t!(s: ".", set_filename, with_filename, "foo"); t!(s: "a/b", set_filename, with_filename, ""); t!(s: "a", set_filename, with_filename, ""); - t!(v: b!("hi/there.txt"), set_extension, with_extension, b!("exe")); - t!(v: b!("hi/there.t", 0x80, "xt"), set_extension, with_extension, b!("exe", 0xff)); + t!(v: b"hi/there.txt", set_extension, with_extension, b"exe"); + t!(v: b"hi/there.t\x80xt", set_extension, with_extension, b"exe\xFF"); t!(s: "hi/there.txt", set_extension, with_extension, "exe"); t!(s: "hi/there.", set_extension, with_extension, "txt"); t!(s: "hi/there", set_extension, with_extension, "txt"); @@ -1001,10 +992,10 @@ mod tests { ) ) - t!(v: Path::new(b!("a/b/c")), Some(b!("c")), b!("a/b"), Some(b!("c")), None); - t!(v: Path::new(b!("a/b/", 0xff)), Some(b!(0xff)), b!("a/b"), Some(b!(0xff)), None); - t!(v: Path::new(b!("hi/there.", 0xff)), Some(b!("there.", 0xff)), b!("hi"), - Some(b!("there")), Some(b!(0xff))); + t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None); + t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None); + t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi", + Some(b"there"), Some(b"\xFF")); t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None); t!(s: Path::new("."), None, Some("."), None, None); t!(s: Path::new("/"), None, Some("/"), None, None); @@ -1018,16 +1009,16 @@ mod tests { t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None); t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"), Some("."), Some("there")); - t!(s: Path::new(b!("a/b/", 0xff)), None, Some("a/b"), None, None); - t!(s: Path::new(b!("a/b/", 0xff, ".txt")), None, Some("a/b"), None, Some("txt")); - t!(s: Path::new(b!("a/b/c.", 0x80)), None, Some("a/b"), Some("c"), None); - t!(s: Path::new(b!(0xff, "/b")), Some("b"), None, Some("b"), None); + t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None); + t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt")); + t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None); + t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None); } #[test] fn test_dir_path() { - t!(v: Path::new(b!("hi/there", 0x80)).dir_path(), b!("hi")); - t!(v: Path::new(b!("hi", 0xff, "/there")).dir_path(), b!("hi", 0xff)); + t!(v: Path::new(b"hi/there\x80").dir_path(), b"hi"); + t!(v: Path::new(b"hi\xFF/there").dir_path(), b"hi\xFF"); t!(s: Path::new("hi/there").dir_path(), "hi"); t!(s: Path::new("hi").dir_path(), "."); t!(s: Path::new("/hi").dir_path(), "/"); @@ -1125,9 +1116,9 @@ mod tests { t!(s: "/a/b/c", "d/e/f", false); t!(s: "a/b/c", "a/b", false); t!(s: "a/b/c", "b", false); - t!(v: b!("a/b/c"), b!("b/c"), true); - t!(v: b!("a/b/", 0xff), b!(0xff), true); - t!(v: b!("a/b/", 0xff), b!("b/", 0xff), true); + t!(v: b"a/b/c", b"b/c", true); + t!(v: b"a/b/\xFF", b"\xFF", true); + t!(v: b"a/b/\xFF", b"b/\xFF", true); } #[test] @@ -1192,11 +1183,11 @@ mod tests { comps, exps); } ); - (v: [$($arg:expr),+], [$([$($exp:expr),*]),*]) => ( + (b: $arg:expr, [$($exp:expr),*]) => ( { - let path = Path::new(b!($($arg),+)); + let path = Path::new($arg); let comps = path.components().collect::>(); - let exp: &[&[u8]] = [$(b!($($exp),*)),*]; + let exp: &[&[u8]] = [$($exp),*]; assert_eq!(comps.as_slice(), exp); let comps = path.components().rev().collect::>(); let exp = exp.iter().rev().map(|&x|x).collect::>(); @@ -1205,9 +1196,9 @@ mod tests { ) ) - t!(v: ["a/b/c"], [["a"], ["b"], ["c"]]); - t!(v: ["/", 0xff, "/a/", 0x80], [[0xff], ["a"], [0x80]]); - t!(v: ["../../foo", 0xcd, "bar"], [[".."], [".."], ["foo", 0xcd, "bar"]]); + t!(b: b"a/b/c", [b"a", b"b", b"c"]); + t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]); + t!(b: b"../../foo\xCDbar", [b"..", b"..", b"foo\xCDbar"]); t!(s: "a/b/c", ["a", "b", "c"]); t!(s: "a/b/d", ["a", "b", "d"]); t!(s: "a/b/cd", ["a", "b", "cd"]); @@ -1224,9 +1215,9 @@ mod tests { #[test] fn test_str_components() { macro_rules! t( - (v: [$($arg:expr),+], $exp:expr) => ( + (b: $arg:expr, $exp:expr) => ( { - let path = Path::new(b!($($arg),+)); + let path = Path::new($arg); let comps = path.str_components().collect::>>(); let exp: &[Option<&str>] = $exp; assert_eq!(comps.as_slice(), exp); @@ -1237,9 +1228,9 @@ mod tests { ) ) - t!(v: ["a/b/c"], [Some("a"), Some("b"), Some("c")]); - t!(v: ["/", 0xff, "/a/", 0x80], [None, Some("a"), None]); - t!(v: ["../../foo", 0xcd, "bar"], [Some(".."), Some(".."), None]); + t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]); + t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]); + t!(b: b"../../foo\xCDbar", [Some(".."), Some(".."), None]); // str_components is a wrapper around components, so no need to do // the full set of tests } diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 553c7af18cb26..4d6f8d0888f3e 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -1123,15 +1123,6 @@ mod tests { ) ) - macro_rules! b( - ($($arg:expr),+) => ( - { - static the_bytes: &'static [u8] = bytes!($($arg),+); - the_bytes - } - ) - ) - #[test] fn test_parse_prefix() { macro_rules! t( @@ -1196,9 +1187,9 @@ mod tests { #[test] fn test_paths() { let empty: &[u8] = []; - t!(v: Path::new(empty), b!(".")); - t!(v: Path::new(b!("\\")), b!("\\")); - t!(v: Path::new(b!("a\\b\\c")), b!("a\\b\\c")); + t!(v: Path::new(empty), b"."); + t!(v: Path::new(b"\\"), b"\\"); + t!(v: Path::new(b"a\\b\\c"), b"a\\b\\c"); t!(s: Path::new(""), "."); t!(s: Path::new("\\"), "\\"); @@ -1230,8 +1221,8 @@ mod tests { t!(s: Path::new("foo\\..\\..\\.."), "..\\.."); t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar"); - assert_eq!(Path::new(b!("foo\\bar")).into_vec().as_slice(), b!("foo\\bar")); - assert_eq!(Path::new(b!("\\foo\\..\\..\\bar")).into_vec().as_slice(), b!("\\bar")); + assert_eq!(Path::new(b"foo\\bar").into_vec().as_slice(), b"foo\\bar"); + assert_eq!(Path::new(b"\\foo\\..\\..\\bar").into_vec().as_slice(), b"\\bar"); t!(s: Path::new("\\\\a"), "\\a"); t!(s: Path::new("\\\\a\\"), "\\a"); @@ -1284,9 +1275,9 @@ mod tests { #[test] fn test_opt_paths() { - assert!(Path::new_opt(b!("foo\\bar", 0)) == None); - assert!(Path::new_opt(b!("foo\\bar", 0x80)) == None); - t!(v: Path::new_opt(b!("foo\\bar")).unwrap(), b!("foo\\bar")); + assert!(Path::new_opt(b"foo\\bar\0") == None); + assert!(Path::new_opt(b"foo\\bar\x80") == None); + t!(v: Path::new_opt(b"foo\\bar").unwrap(), b"foo\\bar"); assert!(Path::new_opt("foo\\bar\0") == None); t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar"); } @@ -1295,17 +1286,17 @@ mod tests { fn test_null_byte() { use task; let result = task::try(proc() { - Path::new(b!("foo/bar", 0)) + Path::new(b"foo/bar\0") }); assert!(result.is_err()); let result = task::try(proc() { - Path::new("test").set_filename(b!("f", 0, "o")) + Path::new("test").set_filename(b"f\0o") }); assert!(result.is_err()); let result = task::try(proc() { - Path::new("test").push(b!("f", 0, "o")); + Path::new("test").push(b"f\0o"); }); assert!(result.is_err()); } @@ -1313,20 +1304,20 @@ mod tests { #[test] #[should_fail] fn test_not_utf8_fail() { - Path::new(b!("hello", 0x80, ".txt")); + Path::new(b"hello\x80.txt"); } #[test] fn test_display_str() { let path = Path::new("foo"); assert_eq!(path.display().to_str(), "foo".to_string()); - let path = Path::new(b!("\\")); + let path = Path::new(b"\\"); assert_eq!(path.filename_display().to_str(), "".to_string()); let path = Path::new("foo"); let mo = path.display().as_maybe_owned(); assert_eq!(mo.as_slice(), "foo"); - let path = Path::new(b!("\\")); + let path = Path::new(b"\\"); let mo = path.filename_display().as_maybe_owned(); assert_eq!(mo.as_slice(), ""); } @@ -1377,7 +1368,7 @@ mod tests { ) ) - t!(v: b!("a\\b\\c"), filename, Some(b!("c"))); + t!(v: b"a\\b\\c", filename, Some(b"c")); t!(s: "a\\b\\c", filename_str, "c"); t!(s: "\\a\\b\\c", filename_str, "c"); t!(s: "a", filename_str, "a"); @@ -1410,7 +1401,7 @@ mod tests { t!(s: "\\\\.\\", filename_str, None, opt); t!(s: "\\\\?\\a\\b\\", filename_str, "b"); - t!(v: b!("a\\b\\c"), dirname, b!("a\\b")); + t!(v: b"a\\b\\c", dirname, b"a\\b"); t!(s: "a\\b\\c", dirname_str, "a\\b"); t!(s: "\\a\\b\\c", dirname_str, "\\a\\b"); t!(s: "a", dirname_str, "."); @@ -1441,7 +1432,7 @@ mod tests { t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo"); t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a"); - t!(v: b!("hi\\there.txt"), filestem, Some(b!("there"))); + t!(v: b"hi\\there.txt", filestem, Some(b"there")); t!(s: "hi\\there.txt", filestem_str, "there"); t!(s: "hi\\there", filestem_str, "there"); t!(s: "there.txt", filestem_str, "there"); @@ -1456,8 +1447,8 @@ mod tests { t!(s: "..\\..", filestem_str, None, opt); // filestem is based on filename, so we don't need the full set of prefix tests - t!(v: b!("hi\\there.txt"), extension, Some(b!("txt"))); - t!(v: b!("hi\\there"), extension, None); + t!(v: b"hi\\there.txt", extension, Some(b"txt")); + t!(v: b"hi\\there", extension, None); t!(s: "hi\\there.txt", extension_str, Some("txt"), opt); t!(s: "hi\\there", extension_str, None, opt); t!(s: "there.txt", extension_str, Some("txt"), opt); @@ -1583,10 +1574,10 @@ mod tests { t!(s: "a\\b\\c", ["d", "\\e"], "\\e"); t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: b!("a\\b\\c"), [b!("d"), b!("e")], b!("a\\b\\c\\d\\e")); - t!(v: b!("a\\b\\c"), [b!("d"), b!("\\e"), b!("f")], b!("\\e\\f")); - t!(v: b!("a\\b\\c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], - b!("a\\b\\c\\d\\e")); + t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e"); + t!(v: b"a\\b\\c", [b"d", b"\\e", b"f"], b"\\e\\f"); + t!(v: b"a\\b\\c", [Vec::from_slice(b"d"), Vec::from_slice(b"e")], + b"a\\b\\c\\d\\e"); } #[test] @@ -1604,11 +1595,11 @@ mod tests { assert!(result == $right); } ); - (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => ( + (b: $path:expr, $left:expr, $right:expr) => ( { - let mut p = Path::new(b!($($path),+)); + let mut p = Path::new($path); let result = p.pop(); - assert_eq!(p.as_vec(), b!($($left),+)); + assert_eq!(p.as_vec(), $left); assert!(result == $right); } ) @@ -1619,11 +1610,11 @@ mod tests { t!(s: ".", ".", false); t!(s: "\\a", "\\", true); t!(s: "\\", "\\", false); - t!(v: ["a\\b\\c"], ["a\\b"], true); - t!(v: ["a"], ["."], true); - t!(v: ["."], ["."], false); - t!(v: ["\\a"], ["\\"], true); - t!(v: ["\\"], ["\\"], false); + t!(b: b"a\\b\\c", b"a\\b", true); + t!(b: b"a", b".", true); + t!(b: b".", b".", false); + t!(b: b"\\a", b"\\", true); + t!(b: b"\\", b"\\", false); t!(s: "C:\\a\\b", "C:\\a", true); t!(s: "C:\\a", "C:\\", true); @@ -1672,8 +1663,8 @@ mod tests { t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d"); t!(s: Path::new(".").join("a\\b"), "a\\b"); t!(s: Path::new("\\").join("a\\b"), "\\a\\b"); - t!(v: Path::new(b!("a\\b\\c")).join(b!("..")), b!("a\\b")); - t!(v: Path::new(b!("\\a\\b\\c")).join(b!("d")), b!("\\a\\b\\c\\d")); + t!(v: Path::new(b"a\\b\\c").join(b".."), b"a\\b"); + t!(v: Path::new(b"\\a\\b\\c").join(b"d"), b"\\a\\b\\c\\d"); // full join testing is covered under test_push_path, so no need for // the full set of prefix tests } @@ -1724,9 +1715,9 @@ mod tests { t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d"); t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: b!("a\\b\\c"), [b!("d"), b!("e")], b!("a\\b\\c\\d\\e")); - t!(v: b!("a\\b\\c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], - b!("a\\b\\c\\d\\e")); + t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e"); + t!(v: b"a\\b\\c", [Vec::from_slice(b"d"), Vec::from_slice(b"e")], + b"a\\b\\c\\d\\e"); } #[test] @@ -1839,15 +1830,15 @@ mod tests { ) ) - t!(v: b!("a\\b\\c"), set_filename, with_filename, b!("d")); - t!(v: b!("\\"), set_filename, with_filename, b!("foo")); + t!(v: b"a\\b\\c", set_filename, with_filename, b"d"); + t!(v: b"\\", set_filename, with_filename, b"foo"); t!(s: "a\\b\\c", set_filename, with_filename, "d"); t!(s: "\\", set_filename, with_filename, "foo"); t!(s: ".", set_filename, with_filename, "foo"); t!(s: "a\\b", set_filename, with_filename, ""); t!(s: "a", set_filename, with_filename, ""); - t!(v: b!("hi\\there.txt"), set_extension, with_extension, b!("exe")); + t!(v: b"hi\\there.txt", set_extension, with_extension, b"exe"); t!(s: "hi\\there.txt", set_extension, with_extension, "exe"); t!(s: "hi\\there.", set_extension, with_extension, "txt"); t!(s: "hi\\there", set_extension, with_extension, "txt"); @@ -1894,7 +1885,7 @@ mod tests { ) ) - t!(v: Path::new(b!("a\\b\\c")), Some(b!("c")), b!("a\\b"), Some(b!("c")), None); + t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None); t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None); t!(s: Path::new("."), None, Some("."), None, None); t!(s: Path::new("\\"), None, Some("\\"), None, None); @@ -2250,21 +2241,9 @@ mod tests { assert_eq!(comps, exp); } ); - (v: [$($arg:expr),+], $exp:expr) => ( - { - let path = Path::new(b!($($arg),+)); - let comps = path.str_components().map(|x|x.unwrap()).collect::>(); - let exp: &[&str] = $exp; - assert_eq!(comps.as_slice(), exp); - let comps = path.str_components().rev().map(|x|x.unwrap()) - .collect::>(); - let exp = exp.iter().rev().map(|&x|x).collect::>(); - assert_eq!(comps, exp); - } - ) ) - t!(v: ["a\\b\\c"], ["a", "b", "c"]); + t!(s: b"a\\b\\c", ["a", "b", "c"]); t!(s: "a\\b\\c", ["a", "b", "c"]); t!(s: "a\\b\\d", ["a", "b", "d"]); t!(s: "a\\b\\cd", ["a", "b", "cd"]); @@ -2320,8 +2299,8 @@ mod tests { ) ) - t!(s: "a\\b\\c", [b!("a"), b!("b"), b!("c")]); - t!(s: ".", [b!(".")]); + t!(s: "a\\b\\c", [b"a", b"b", b"c"]); + t!(s: ".", [b"."]); // since this is really a wrapper around str_components, those tests suffice } diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index b87a25d4a44a2..658c28f820272 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -19,6 +19,14 @@ use ext::build::AstBuilder; pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { + cx.span_warn(sp, "`bytes!` is deprecated, use `b\"foo\"` literals instead"); + cx.parse_sess.span_diagnostic.span_note(sp, + "see http://doc.rust-lang.org/rust.html#byte-and-byte-string-literals \ + for documentation"); + cx.parse_sess.span_diagnostic.span_note(sp, + "see https://github.com/rust-lang/rust/blob/master/src/etc/2014-06-rewrite-bytes-macros.py \ + for a automated migration"); + // Gather all argument expressions let exprs = match get_exprs_from_tts(cx, sp, tts) { None => return DummyResult::expr(sp), diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index b49c698486450..1a7063c495199 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -106,7 +106,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) *dst = (*src).clone(); } - for c in cap.iter().map(|&x| x) { + for &c in cap.iter() { let cur = c as char; let mut old_state = state; match state { @@ -575,25 +575,25 @@ mod test { #[test] fn test_basic_setabf() { - let s = bytes!("\\E[48;5;%p1%dm"); + let s = b"\\E[48;5;%p1%dm"; assert_eq!(expand(s, [Number(1)], &mut Variables::new()).unwrap(), - bytes!("\\E[48;5;1m").iter().map(|x| *x).collect()); + "\\E[48;5;1m".bytes().collect()); } #[test] fn test_multiple_int_constants() { - assert_eq!(expand(bytes!("%{1}%{2}%d%d"), [], &mut Variables::new()).unwrap(), - bytes!("21").iter().map(|x| *x).collect()); + assert_eq!(expand(b"%{1}%{2}%d%d", [], &mut Variables::new()).unwrap(), + "21".bytes().collect()); } #[test] fn test_op_i() { let mut vars = Variables::new(); - assert_eq!(expand(bytes!("%p1%d%p2%d%p3%d%i%p1%d%p2%d%p3%d"), + assert_eq!(expand(b"%p1%d%p2%d%p3%d%i%p1%d%p2%d%p3%d", [Number(1),Number(2),Number(3)], &mut vars), - Ok(bytes!("123233").iter().map(|x| *x).collect())); - assert_eq!(expand(bytes!("%p1%d%p2%d%i%p1%d%p2%d"), [], &mut vars), - Ok(bytes!("0011").iter().map(|x| *x).collect())); + Ok("123233".bytes().collect())); + assert_eq!(expand(b"%p1%d%p2%d%i%p1%d%p2%d", [], &mut vars), + Ok("0011".bytes().collect())); } #[test] @@ -610,7 +610,7 @@ mod test { } else { Number(97) }; - let res = expand(bytes!("%p1").iter().map(|x| *x).collect::>() + let res = expand("%p1".bytes().collect::>() .append(cap.as_bytes()).as_slice(), [p], vars); @@ -622,13 +622,13 @@ mod test { let res = expand(cap.as_bytes(), [], vars); assert!(res.is_err(), "Binop {} succeeded incorrectly with 0 stack entries", *cap); - let res = expand(bytes!("%{1}").iter().map(|x| *x).collect::>() + let res = expand("%{1}".bytes().collect::>() .append(cap.as_bytes()).as_slice(), [], vars); assert!(res.is_err(), "Binop {} succeeded incorrectly with 1 stack entry", *cap); - let res = expand(bytes!("%{1}%{2}").iter().map(|x| *x).collect::>() + let res = expand("%{1}%{2}".bytes().collect::>() .append(cap.as_bytes()).as_slice(), [], vars); @@ -639,7 +639,7 @@ mod test { #[test] fn test_push_bad_param() { - assert!(expand(bytes!("%pa"), [], &mut Variables::new()).is_err()); + assert!(expand(b"%pa", [], &mut Variables::new()).is_err()); } #[test] @@ -664,39 +664,37 @@ mod test { #[test] fn test_conditionals() { let mut vars = Variables::new(); - let s = bytes!("\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"); + let s = b"\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"; let res = expand(s, [Number(1)], &mut vars); assert!(res.is_ok(), res.unwrap_err()); assert_eq!(res.unwrap(), - bytes!("\\E[31m").iter().map(|x| *x).collect()); + "\\E[31m".bytes().collect()); let res = expand(s, [Number(8)], &mut vars); assert!(res.is_ok(), res.unwrap_err()); assert_eq!(res.unwrap(), - bytes!("\\E[90m").iter().map(|x| *x).collect()); + "\\E[90m".bytes().collect()); let res = expand(s, [Number(42)], &mut vars); assert!(res.is_ok(), res.unwrap_err()); assert_eq!(res.unwrap(), - bytes!("\\E[38;5;42m").iter().map(|x| *x).collect()); + "\\E[38;5;42m".bytes().collect()); } #[test] fn test_format() { let mut varstruct = Variables::new(); let vars = &mut varstruct; - assert_eq!(expand(bytes!("%p1%s%p2%2s%p3%2s%p4%.2s"), + assert_eq!(expand(b"%p1%s%p2%2s%p3%2s%p4%.2s", [String("foo".to_string()), String("foo".to_string()), String("f".to_string()), String("foo".to_string())], vars), - Ok(bytes!("foofoo ffo").iter().map(|x| *x).collect())); - assert_eq!(expand(bytes!("%p1%:-4.2s"), [String("foo".to_string())], vars), - Ok(bytes!("fo ").iter().map(|x| *x).collect())); - - assert_eq!(expand(bytes!("%p1%d%p1%.3d%p1%5d%p1%:+d"), [Number(1)], vars), - Ok(bytes!("1001 1+1").iter().map(|x| *x).collect())); - assert_eq!(expand(bytes!("%p1%o%p1%#o%p2%6.4x%p2%#6.4X"), [Number(15), Number(27)], vars), - Ok(bytes!("17017 001b0X001B").iter() - .map(|x| *x) - .collect())); + Ok("foofoo ffo".bytes().collect())); + assert_eq!(expand(b"%p1%:-4.2s", [String("foo".to_string())], vars), + Ok("fo ".bytes().collect())); + + assert_eq!(expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", [Number(1)], vars), + Ok("1001 1+1".bytes().collect())); + assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X", [Number(15), Number(27)], vars), + Ok("17017 001b0X001B".bytes().collect())); } } diff --git a/src/libterm/terminfo/parser/compiled.rs b/src/libterm/terminfo/parser/compiled.rs index b373753613d76..916342b67434e 100644 --- a/src/libterm/terminfo/parser/compiled.rs +++ b/src/libterm/terminfo/parser/compiled.rs @@ -315,10 +315,10 @@ pub fn parse(file: &mut io::Reader, longnames: bool) /// Create a dummy TermInfo struct for msys terminals pub fn msys_terminfo() -> Box { let mut strings = HashMap::new(); - strings.insert("sgr0".to_string(), Vec::from_slice(bytes!("\x1b[0m"))); - strings.insert("bold".to_string(), Vec::from_slice(bytes!("\x1b[1m"))); - strings.insert("setaf".to_string(), Vec::from_slice(bytes!("\x1b[3%p1%dm"))); - strings.insert("setab".to_string(), Vec::from_slice(bytes!("\x1b[4%p1%dm"))); + strings.insert("sgr0".to_string(), Vec::from_slice(b"\x1B[0m")); + strings.insert("bold".to_string(), Vec::from_slice(b"\x1B[1m")); + strings.insert("setaf".to_string(), Vec::from_slice(b"\x1B[3%p1%dm")); + strings.insert("setab".to_string(), Vec::from_slice(b"\x1B[4%p1%dm")); box TermInfo { names: vec!("cygwin".to_string()), // msys is a fork of an older cygwin version bools: HashMap::new(), diff --git a/src/snapshots.txt b/src/snapshots.txt index d528cb16e72dc..e46c99cf4f0dd 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2014-06-18 d6736a1 + freebsd-x86_64 c1479bb3dc0ae3d8ba9193ff2caf92c805a95c51 + linux-i386 bb1543b21235a51e81460b9419e112396ccf1d20 + linux-x86_64 08df93f138bc6c9d083d28bb71384fcebf0380c1 + macos-i386 d6c0039ad7cbd5959e69c980ecf822e5097bac2c + macos-x86_64 ee54924aa4103d35cf490da004d3cc4e48ca8fb0 + winnt-i386 943c99971e82847abe272df58bb7656ac3b91430 + S 2014-06-14 2c6caad freebsd-x86_64 0152ba43f238014f0aede7c29f1c684c21077b0b linux-i386 2eb1897c25abe0d5978ff03171ca943e92666046 diff --git a/src/test/compile-fail/macros-nonfatal-errors.rs b/src/test/compile-fail/macros-nonfatal-errors.rs index df2c40657c814..5f8352d1e5229 100644 --- a/src/test/compile-fail/macros-nonfatal-errors.rs +++ b/src/test/compile-fail/macros-nonfatal-errors.rs @@ -22,7 +22,8 @@ enum CantDeriveThose {} fn main() { doesnt_exist!(); //~ ERROR - bytes!(invalid); //~ ERROR + bytes!(invalid); //~ ERROR non-literal in bytes! + //~^ WARN `bytes!` is deprecated asm!(invalid); //~ ERROR diff --git a/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs index f5b4342ceb749..d03696cbbbcc4 100644 --- a/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!('λ'); //~ ERROR non-ascii char literal in bytes! + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-non-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs index 281a5630f82c9..3a2e104818fd2 100644 --- a/src/test/compile-fail/syntax-extension-bytes-non-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(foo); //~ ERROR non-literal in bytes! + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs index 25688d7d17ab4..8e7c6147758ca 100644 --- a/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(1024); //~ ERROR too large integer literal in bytes! + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs index d1c8a2c091304..1a9aa3753eec7 100644 --- a/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(1024u8); //~ ERROR too large u8 literal in bytes! + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs index ef45ea06003d5..c2d4973594371 100644 --- a/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(-1024); //~ ERROR non-literal in bytes + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs index b8ba73559aa74..ac33ffb60e294 100644 --- a/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(-1024u8); //~ ERROR non-literal in bytes + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs index 142566fe8ab78..f6b3659354c5b 100644 --- a/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs +++ b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs @@ -10,4 +10,5 @@ fn main() { let vec = bytes!(45f64); //~ ERROR unsupported literal in bytes! + //~^ WARN `bytes!` is deprecated } diff --git a/src/test/run-pass/issue-4333.rs b/src/test/run-pass/issue-4333.rs index 6fb66cd3b1580..fd67b767104d5 100644 --- a/src/test/run-pass/issue-4333.rs +++ b/src/test/run-pass/issue-4333.rs @@ -12,5 +12,5 @@ use std::io; pub fn main() { let stdout = &mut io::stdout() as &mut io::Writer; - stdout.write(bytes!("Hello!")); + stdout.write(b"Hello!"); } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 316d1facb18ff..4355bf4127fc4 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -29,7 +29,7 @@ fn test_tempdir() { let path = { let p = TempDir::new_in(&Path::new("."), "foobar").unwrap(); let p = p.path(); - assert!(p.as_vec().ends_with(bytes!("foobar"))); + assert!(p.as_vec().ends_with(b"foobar")); p.clone() }; assert!(!path.exists()); diff --git a/src/test/run-pass/trait-coercion.rs b/src/test/run-pass/trait-coercion.rs index 1d229a8ae8361..55beebbf2bc57 100644 --- a/src/test/run-pass/trait-coercion.rs +++ b/src/test/run-pass/trait-coercion.rs @@ -26,7 +26,7 @@ impl Trait for Struct { } fn foo(mut a: Box) { - a.write(bytes!("Hello\n")); + a.write(b"Hello\n"); } pub fn main() { From 72f0d4535715505c1cc429ef277a954ba26366bd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 19 Jun 2014 00:59:40 +0200 Subject: [PATCH 49/55] Revert bytes!() docstring change, and fix a typo. --- src/libstd/macros.rs | 2 +- src/libsyntax/ext/bytes.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index dad162d82ad47..58f65c90b3b10 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -463,7 +463,7 @@ pub mod builtin { /// # Example /// /// ``` - /// let rust = b"rust\xFF"; + /// let rust = bytes!("r", 'u', "st", 255); /// assert_eq!(rust[1], 'u' as u8); /// assert_eq!(rust[4], 255); /// ``` diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index 658c28f820272..ce13fa2a7c6ee 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -25,7 +25,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) for documentation"); cx.parse_sess.span_diagnostic.span_note(sp, "see https://github.com/rust-lang/rust/blob/master/src/etc/2014-06-rewrite-bytes-macros.py \ - for a automated migration"); + for an automated migration"); // Gather all argument expressions let exprs = match get_exprs_from_tts(cx, sp, tts) { From 2c3bf8836f6f0cd18d8ac4f7189615f7f4098f5d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Jun 2014 17:05:15 -0700 Subject: [PATCH 50/55] Merge conflicts from the rollup Closes #14480 (vim: Add :RustRun and associated commands) Closes #14917 (Deprecate free-standing endian conversions in favor of methods on Int. Merge Bitwise into Int and add more bit operations.) Closes #14981 (librustc: Use expr_ty_adjusted in trans_overloaded_call.) Closes #14989 (std::task - Revamp TaskBuilder API) Closes #14997 (Reject double moves out of array elements) Closes #14998 (Vim: highlight escapes for byte literals.) Closes #15002 (Fix FIXME #5275) Closes #15004 (Fix #14865) Closes #15007 (debuginfo: Add test case for issue #14411.) Closes #15012 ((doc) Change search placeholder text.) Closes #15013 (Update compiler-rt.) Closes #15017 (Deprecate the bytes!() macro.) --- src/liballoc/heap.rs | 2 +- src/librustc/middle/borrowck/move_data.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 79a616b9555aa..b4d0057778a1a 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -132,7 +132,7 @@ unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, mod imp { use core::option::{None, Option}; use core::ptr::{RawPtr, mut_null, null}; - use core::num::Bitwise; + use core::num::Int; use libc::{c_char, c_int, c_void, size_t}; #[link(name = "jemalloc", kind = "static")] diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 9c2194c74f4a4..b61596908e60a 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -163,7 +163,7 @@ pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>; fn loan_path_is_precise(loan_path: &LoanPath) -> bool { match *loan_path { - LpVar(_) => { + LpVar(_) | LpUpvar(_) => { true } LpExtend(_, _, LpInterior(mc::InteriorElement(_))) => { From 8a8e497ae786ffc032c1e68fc23da0edcf6fa5e3 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sat, 24 May 2014 01:13:59 -0700 Subject: [PATCH 51/55] Handle CRLF properly in the lexer The lexer already ignores CRLF in between tokens, but it doesn't properly handle carriage returns inside strings and doc comments. Teach it to treat CRLF as LF inside these tokens, and to disallow carriage returns that are not followed by linefeeds. This includes handling an escaped CRLF inside a regular string token the same way it handles an escaped LF. This is technically a breaking change, as bare carriage returns are no longer allowed, and CRLF sequences are now treated as LF inside strings and doc comments, but it's very unlikely to actually affect any real-world code. This change is necessary to have Rust code compile on Windows the same way it does on Unix. The mozilla/rust repository explicitly sets eol=lf for Rust source files, but other Rust repositories don't. Notably, rust-http cannot be compiled on Windows without converting the CRLF line endings back to LF. [breaking-change] --- src/libsyntax/parse/lexer/mod.rs | 141 +++++++++++++++--- src/libsyntax/parse/mod.rs | 22 +++ .../lex-bare-cr-string-literal-doc-comment.rs | 30 ++++ src/test/run-pass/.gitattributes | 1 + ...line-endings-string-literal-doc-comment.rs | 44 ++++++ 5 files changed, 215 insertions(+), 23 deletions(-) create mode 100644 src/test/compile-fail/lex-bare-cr-string-literal-doc-comment.rs create mode 100644 src/test/run-pass/.gitattributes create mode 100644 src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 348445149a415..add9a4cb9f3bd 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -225,6 +225,47 @@ impl<'a> StringReader<'a> { self.byte_offset(end).to_uint())) } + /// Converts CRLF to LF in the given string, raising an error on bare CR. + fn translate_crlf<'a>(&self, start: BytePos, + s: &'a str, errmsg: &'a str) -> str::MaybeOwned<'a> { + let mut i = 0u; + while i < s.len() { + let str::CharRange { ch, next } = s.char_range_at(i); + if ch == '\r' { + if next < s.len() && s.char_at(next) == '\n' { + return translate_crlf_(self, start, s, errmsg, i).into_maybe_owned(); + } + let pos = start + BytePos(i as u32); + let end_pos = start + BytePos(next as u32); + self.err_span_(pos, end_pos, errmsg); + } + i = next; + } + return s.into_maybe_owned(); + + fn translate_crlf_(rdr: &StringReader, start: BytePos, + s: &str, errmsg: &str, mut i: uint) -> String { + let mut buf = String::with_capacity(s.len()); + let mut j = 0; + while i < s.len() { + let str::CharRange { ch, next } = s.char_range_at(i); + if ch == '\r' { + if j < i { buf.push_str(s.slice(j, i)); } + j = next; + if next >= s.len() || s.char_at(next) != '\n' { + let pos = start + BytePos(i as u32); + let end_pos = start + BytePos(next as u32); + rdr.err_span_(pos, end_pos, errmsg); + } + } + i = next; + } + if j < s.len() { buf.push_str(s.slice_from(j)); } + buf + } + } + + /// Advance the StringReader by one character. If a newline is /// discovered, add it to the FileMap's list of line start offsets. pub fn bump(&mut self) { @@ -305,7 +346,20 @@ impl<'a> StringReader<'a> { // line comments starting with "///" or "//!" are doc-comments if self.curr_is('/') || self.curr_is('!') { let start_bpos = self.pos - BytePos(3); - while !self.curr_is('\n') && !self.is_eof() { + while !self.is_eof() { + match self.curr.unwrap() { + '\n' => break, + '\r' => { + if self.nextch_is('\n') { + // CRLF + break + } else { + self.err_span_(self.last_pos, self.pos, + "bare CR not allowed in doc-comment"); + } + } + _ => () + } self.bump(); } let ret = self.with_str_from(start_bpos, |string| { @@ -370,6 +424,7 @@ impl<'a> StringReader<'a> { let start_bpos = self.last_pos - BytePos(2); let mut level: int = 1; + let mut has_cr = false; while level > 0 { if self.is_eof() { let msg = if is_doc_comment { @@ -379,25 +434,35 @@ impl<'a> StringReader<'a> { }; let last_bpos = self.last_pos; self.fatal_span_(start_bpos, last_bpos, msg); - } else if self.curr_is('/') && self.nextch_is('*') { - level += 1; - self.bump(); - self.bump(); - } else if self.curr_is('*') && self.nextch_is('/') { - level -= 1; - self.bump(); - self.bump(); - } else { - self.bump(); } + let n = self.curr.unwrap(); + match n { + '/' if self.nextch_is('*') => { + level += 1; + self.bump(); + } + '*' if self.nextch_is('/') => { + level -= 1; + self.bump(); + } + '\r' => { + has_cr = true; + } + _ => () + } + self.bump(); } let res = if is_doc_comment { self.with_str_from(start_bpos, |string| { // but comments with only "*"s between two "/"s are not if !is_block_non_doc_comment(string) { + let string = if has_cr { + self.translate_crlf(start_bpos, string, + "bare CR not allowed in block doc-comment") + } else { string.into_maybe_owned() }; Some(TokenAndSpan{ - tok: token::DOC_COMMENT(str_to_ident(string)), + tok: token::DOC_COMMENT(str_to_ident(string.as_slice())), sp: codemap::mk_sp(start_bpos, self.last_pos) }) } else { @@ -675,6 +740,10 @@ impl<'a> StringReader<'a> { self.consume_whitespace(); return None }, + '\r' if delim == '"' && self.curr_is('\n') => { + self.consume_whitespace(); + return None + } c => { let last_pos = self.last_pos; self.err_span_char( @@ -696,6 +765,15 @@ impl<'a> StringReader<'a> { else { "character constant must be escaped" }, first_source_char); } + '\r' => { + if self.curr_is('\n') { + self.bump(); + return Some('\n'); + } else { + self.err_span_(start, self.last_pos, + "bare CR not allowed in string, use \\r instead"); + } + } _ => if ascii_only && first_source_char > '\x7F' { let last_pos = self.last_pos; self.err_span_char( @@ -1042,28 +1120,45 @@ impl<'a> StringReader<'a> { self.bump(); let content_start_bpos = self.last_pos; let mut content_end_bpos; + let mut has_cr = false; 'outer: loop { if self.is_eof() { let last_bpos = self.last_pos; self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"); } - if self.curr_is('"') { - content_end_bpos = self.last_pos; - for _ in range(0, hash_count) { - self.bump(); - if !self.curr_is('#') { - continue 'outer; + //if self.curr_is('"') { + //content_end_bpos = self.last_pos; + //for _ in range(0, hash_count) { + //self.bump(); + //if !self.curr_is('#') { + //continue 'outer; + let c = self.curr.unwrap(); + match c { + '"' => { + content_end_bpos = self.last_pos; + for _ in range(0, hash_count) { + self.bump(); + if !self.curr_is('#') { + continue 'outer; + } } + break; + } + '\r' => { + has_cr = true; } - break; + _ => () } self.bump(); } self.bump(); - let str_content = self.with_str_from_to( - content_start_bpos, - content_end_bpos, - str_to_ident); + let str_content = self.with_str_from_to(content_start_bpos, content_end_bpos, |string| { + let string = if has_cr { + self.translate_crlf(content_start_bpos, string, + "bare CR not allowed in raw string") + } else { string.into_maybe_owned() }; + str_to_ident(string.as_slice()) + }); return token::LIT_STR_RAW(str_content, hash_count); } '-' => { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index eb0c6f2555aee..331a49c83beac 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -288,6 +288,8 @@ mod test { use owned_slice::OwnedSlice; use ast; use abi; + use attr; + use attr::AttrMetaMethods; use parse::parser::Parser; use parse::token::{str_to_ident}; use util::parser_testing::{string_to_tts, string_to_parser}; @@ -726,4 +728,24 @@ mod test { }".to_string()); } + #[test] fn crlf_doc_comments() { + let sess = new_parse_sess(); + + let name = "".to_string(); + let source = "/// doc comment\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap(); + let doc = attr::first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap(); + assert_eq!(doc.get(), "/// doc comment"); + + let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap(); + let docs = item.attrs.iter().filter(|a| a.name().get() == "doc") + .map(|a| a.value_str().unwrap().get().to_string()).collect::>(); + assert_eq!(docs.as_slice(), &["/// doc comment".to_string(), "/// line 2".to_string()]); + + let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap(); + let doc = attr::first_attr_value_str_by_name(item.attrs.as_slice(), "doc").unwrap(); + assert_eq!(doc.get(), "/** doc comment\n * with CRLF */"); + } } diff --git a/src/test/compile-fail/lex-bare-cr-string-literal-doc-comment.rs b/src/test/compile-fail/lex-bare-cr-string-literal-doc-comment.rs new file mode 100644 index 0000000000000..c1e5121d6dd4e --- /dev/null +++ b/src/test/compile-fail/lex-bare-cr-string-literal-doc-comment.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-cr + +/// doc comment with bare CR: ' ' +pub fn foo() {} +//~^^ ERROR: bare CR not allowed in doc-comment + +/** block doc comment with bare CR: ' ' */ +pub fn bar() {} +//~^^ ERROR: bare CR not allowed in block doc-comment + +fn main() { + // the following string literal has a bare CR in it + let _s = "foo bar"; //~ ERROR: bare CR not allowed in string + + // the following string literal has a bare CR in it + let _s = r"bar foo"; //~ ERROR: bare CR not allowed in raw string + + // the following string literal has a bare CR in it + let _s = "foo\ bar"; //~ ERROR: unknown character escape: \r +} diff --git a/src/test/run-pass/.gitattributes b/src/test/run-pass/.gitattributes new file mode 100644 index 0000000000000..c6a6f23074de0 --- /dev/null +++ b/src/test/run-pass/.gitattributes @@ -0,0 +1 @@ +lexer-crlf-line-endings-string-literal-doc-comment.rs -text diff --git a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs new file mode 100644 index 0000000000000..5c8db524cc2ed --- /dev/null +++ b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs @@ -0,0 +1,44 @@ +// ignore-tidy-cr ignore-license +// ignore-tidy-cr (repeated again because of tidy bug) +// license is ignored because tidy can't handle the CRLF here properly. + +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NB: this file needs CRLF line endings. The .gitattributes file in +// this directory should enforce it. + +// ignore-pretty + +/// Doc comment that ends in CRLF +pub fn foo() {} + +/** Block doc comment that + * contains CRLF characters + */ +pub fn bar() {} + +fn main() { + let s = "string +literal"; + assert_eq!(s, "string\nliteral"); + + let s = "literal with \ + escaped newline"; + assert_eq!(s, "literal with escaped newline"); + + let s = r"string +literal"; + assert_eq!(s, "string\nliteral"); + + // validate that our source file has CRLF endings + let source = include_str!("lexer-crlf-line-endings-string-literal-doc-comment.rs"); + assert!(source.contains("string\r\nliteral")); +} From 962d2e05d347a371b1f229abb0838b0525214094 Mon Sep 17 00:00:00 2001 From: Kasey Carrothers Date: Thu, 19 Jun 2014 00:51:43 -0700 Subject: [PATCH 52/55] Implement Eq for Bitv and BitvSet --- src/libcollections/bitv.rs | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index fb5864745d055..67c0f14b63744 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -376,27 +376,6 @@ impl Bitv { } } - /** - * Compares two bitvectors - * - * Both bitvectors must be the same length. Returns `true` if both - * bitvectors contain identical elements. - */ - #[inline] - pub fn equal(&self, v1: &Bitv) -> bool { - if self.nbits != v1.nbits { return false; } - match self.rep { - Small(ref b) => match v1.rep { - Small(ref b1) => b.equals(b1, self.nbits), - _ => false - }, - Big(ref s) => match v1.rep { - Big(ref s1) => s.equals(s1, self.nbits), - Small(_) => return false - } - } - } - /// Set all bits to 0 #[inline] pub fn clear(&mut self) { @@ -613,6 +592,25 @@ impl hash::Hash for Bitv { } } +impl cmp::PartialEq for Bitv { + #[inline] + fn eq(&self, other: &Bitv) -> bool { + if self.nbits != other.nbits { return false; } + match self.rep { + Small(ref b) => match other.rep { + Small(ref b1) => b.equals(b1, self.nbits), + _ => false + }, + Big(ref s) => match other.rep { + Big(ref s1) => s.equals(s1, self.nbits), + Small(_) => return false + } + } + } +} + +impl cmp::Eq for Bitv {} + #[inline] fn iterate_bits(base: uint, bits: uint, f: |uint| -> bool) -> bool { if bits == 0 { @@ -841,6 +839,8 @@ impl cmp::PartialEq for BitvSet { fn ne(&self, other: &BitvSet) -> bool { !self.eq(other) } } +impl cmp::Eq for BitvSet {} + impl fmt::Show for BitvSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); From 677e6ed6035b12a3ccb6becc9c9f6ea3d74ce37b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 18 Jun 2014 11:25:04 -0700 Subject: [PATCH 53/55] (doc) Properly doc hotkeys in generated docs. Updated search bar to match help text. Used correct, normalized hotkeys in search. Updated shortcut menu with working shortcuts (tabs). Changed height of search help. --- src/librustdoc/html/layout.rs | 6 +++--- src/librustdoc/html/static/main.css | 2 +- src/librustdoc/html/static/main.js | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 0304a1d690ef5..61a2d3c5d9cc8 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -63,7 +63,7 @@ r##"
@@ -82,9 +82,9 @@ r##"
Show this help dialog
S
Focus the search field
-
+
Move up in search results
-
+
Move down in search results
Go to active search result
diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index a7bd082ec17d3..a88992f6c4c50 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -347,7 +347,7 @@ p a:hover { text-decoration: underline; } margin-top: -125px; margin-left: -275px; width: 550px; - height: 250px; + height: 300px; border: 1px solid #bfbfbf; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 697199e9abf5a..fc1e480f6afcf 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -71,10 +71,10 @@ return; } - if (e.keyCode === 188 && $('#help').hasClass('hidden')) { // question mark + if (e.which === 191 && $('#help').hasClass('hidden')) { // question mark e.preventDefault(); $('#help').removeClass('hidden'); - } else if (e.keyCode === 27) { // esc + } else if (e.which === 27) { // esc if (!$('#help').hasClass('hidden')) { e.preventDefault(); $('#help').addClass('hidden'); @@ -83,7 +83,7 @@ $('#search').addClass('hidden'); $('#main').removeClass('hidden'); } - } else if (e.keyCode === 83) { // S + } else if (e.which === 83) { // S e.preventDefault(); $('.search-input').focus(); } @@ -361,7 +361,7 @@ $(document).on('keypress.searchnav', function(e) { var $active = $results.filter('.highlighted'); - if (e.keyCode === 38) { // up + if (e.which === 38) { // up e.preventDefault(); if (!$active.length || !$active.prev()) { return; @@ -369,7 +369,7 @@ $active.prev().addClass('highlighted'); $active.removeClass('highlighted'); - } else if (e.keyCode === 40) { // down + } else if (e.which === 40) { // down e.preventDefault(); if (!$active.length) { $results.first().addClass('highlighted'); @@ -377,7 +377,7 @@ $active.next().addClass('highlighted'); $active.removeClass('highlighted'); } - } else if (e.keyCode === 13) { // return + } else if (e.which === 13) { // return e.preventDefault(); if ($active.length) { document.location.href = $active.find('a').prop('href'); From 638db43ce1a45e5e9fc46bd6ec8d186a311ed773 Mon Sep 17 00:00:00 2001 From: Kasey Carrothers Date: Thu, 19 Jun 2014 00:51:43 -0700 Subject: [PATCH 54/55] Implement Eq for Bitv and BitvSet --- src/libcollections/bitv.rs | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index fb5864745d055..67c0f14b63744 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -376,27 +376,6 @@ impl Bitv { } } - /** - * Compares two bitvectors - * - * Both bitvectors must be the same length. Returns `true` if both - * bitvectors contain identical elements. - */ - #[inline] - pub fn equal(&self, v1: &Bitv) -> bool { - if self.nbits != v1.nbits { return false; } - match self.rep { - Small(ref b) => match v1.rep { - Small(ref b1) => b.equals(b1, self.nbits), - _ => false - }, - Big(ref s) => match v1.rep { - Big(ref s1) => s.equals(s1, self.nbits), - Small(_) => return false - } - } - } - /// Set all bits to 0 #[inline] pub fn clear(&mut self) { @@ -613,6 +592,25 @@ impl hash::Hash for Bitv { } } +impl cmp::PartialEq for Bitv { + #[inline] + fn eq(&self, other: &Bitv) -> bool { + if self.nbits != other.nbits { return false; } + match self.rep { + Small(ref b) => match other.rep { + Small(ref b1) => b.equals(b1, self.nbits), + _ => false + }, + Big(ref s) => match other.rep { + Big(ref s1) => s.equals(s1, self.nbits), + Small(_) => return false + } + } + } +} + +impl cmp::Eq for Bitv {} + #[inline] fn iterate_bits(base: uint, bits: uint, f: |uint| -> bool) -> bool { if bits == 0 { @@ -841,6 +839,8 @@ impl cmp::PartialEq for BitvSet { fn ne(&self, other: &BitvSet) -> bool { !self.eq(other) } } +impl cmp::Eq for BitvSet {} + impl fmt::Show for BitvSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "{{")); From 15abe855b80b855ec5f80542c3888614b42220ee Mon Sep 17 00:00:00 2001 From: Kasey Carrothers Date: Thu, 19 Jun 2014 20:45:29 -0700 Subject: [PATCH 55/55] Fix test cases for Bitv --- src/libcollections/bitv.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 67c0f14b63744..572178bd19664 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -1323,14 +1323,14 @@ mod tests { fn test_equal_differing_sizes() { let v0 = Bitv::new(10u, false); let v1 = Bitv::new(11u, false); - assert!(!v0.equal(&v1)); + assert!(v0 != v1); } #[test] fn test_equal_greatly_differing_sizes() { let v0 = Bitv::new(10u, false); let v1 = Bitv::new(110u, false); - assert!(!v0.equal(&v1)); + assert!(v0 != v1); } #[test] @@ -1341,7 +1341,7 @@ mod tests { let mut b = bitv::Bitv::new(1, true); b.set(0, true); - assert!(a.equal(&b)); + assert_eq!(a, b); } #[test] @@ -1356,7 +1356,7 @@ mod tests { b.set(i, true); } - assert!(a.equal(&b)); + assert_eq!(a, b); } #[test]