From 8f7c2d518d1892c98d2ef57992a65669834f24e2 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 17 Jan 2015 17:00:32 +0100 Subject: [PATCH 01/23] Replace `be` with `become` As per rust-lang/rfcs#601, replace `be` with `become` as reserved keyword for tail call optimization. --- src/doc/grammar.md | 2 +- src/doc/reference.md | 2 +- src/libsyntax/parse/token.rs | 2 +- .../compile-fail/{reserved-be.rs => reserved-become.rs} | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/test/compile-fail/{reserved-be.rs => reserved-become.rs} (75%) diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 59a1c8f828b29..b4e023c203911 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -157,7 +157,7 @@ token : simple_token | ident | literal | symbol | whitespace token ; | | | | | | |----------|----------|----------|----------|--------| -| abstract | alignof | as | be | box | +| abstract | alignof | as | become | box | | break | const | continue | crate | do | | else | enum | extern | false | final | | fn | for | if | impl | in | diff --git a/src/doc/reference.md b/src/doc/reference.md index 64ddb3ffdd39f..c83cbbce2b299 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -189,7 +189,7 @@ grammar as double-quoted strings. Other tokens have exact rules given. | | | | | | |----------|----------|----------|----------|---------| -| abstract | alignof | as | be | box | +| abstract | alignof | as | become | box | | break | const | continue | crate | do | | else | enum | extern | false | final | | fn | for | if | impl | in | diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5c3892e49c058..b7357e13a56d8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -562,7 +562,7 @@ declare_special_idents_and_keywords! { (45, Where, "where"); 'reserved: (46, Alignof, "alignof"); - (47, Be, "be"); + (47, Become, "become"); (48, Offsetof, "offsetof"); (49, Priv, "priv"); (50, Pure, "pure"); diff --git a/src/test/compile-fail/reserved-be.rs b/src/test/compile-fail/reserved-become.rs similarity index 75% rename from src/test/compile-fail/reserved-be.rs rename to src/test/compile-fail/reserved-become.rs index 386d53cc16e92..82e9ebc10d1c8 100644 --- a/src/test/compile-fail/reserved-be.rs +++ b/src/test/compile-fail/reserved-become.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - let be = 0; - //~^ ERROR `be` is a reserved keyword + let become = 0; + //~^ ERROR `become` is a reserved keyword } From 6f872113ab05c0a23a8784e54d22b9e0641dde41 Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Wed, 4 Feb 2015 20:00:28 +0100 Subject: [PATCH 02/23] Add QPath construction to ExtCtxt for UFCS support. --- src/libsyntax/ext/build.rs | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 53c35ef34cd0d..4d618e560c5cc 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -41,6 +41,18 @@ pub trait AstBuilder { bindings: Vec> ) -> ast::Path; + fn qpath(&self, self_type: P, + trait_ref: P, + ident: ast::Ident ) + -> P; + fn qpath_all(&self, self_type: P, + trait_ref: P, + ident: ast::Ident, + lifetimes: Vec, + types: Vec>, + bindings: Vec> ) + -> P; + // types fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy; @@ -103,6 +115,7 @@ pub trait AstBuilder { // expressions fn expr(&self, span: Span, node: ast::Expr_) -> P; fn expr_path(&self, path: ast::Path) -> P; + fn expr_qpath(&self, span: Span, qpath: P) -> P; fn expr_ident(&self, span: Span, id: ast::Ident) -> P; fn expr_self(&self, span: Span) -> P; @@ -331,6 +344,44 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } } + /// Constructs a qualified path. + /// + /// Constructs a path like `::ident`. + fn qpath(&self, + self_type: P, + trait_ref: P, + ident: ast::Ident) + -> P { + self.qpath_all(self_type, trait_ref, ident, Vec::new(), Vec::new(), Vec::new()) + } + + /// Constructs a qualified path. + /// + /// Constructs a path like `::ident`. + fn qpath_all(&self, + self_type: P, + trait_ref: P, + ident: ast::Ident, + lifetimes: Vec, + types: Vec>, + bindings: Vec> ) + -> P { + let segment = ast::PathSegment { + identifier: ident, + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + bindings: OwnedSlice::from_vec(bindings), + }) + }; + + P(ast::QPath { + self_type: self_type, + trait_ref: trait_ref, + item_path: segment, + }) + } + fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { ast::MutTy { ty: ty, @@ -554,6 +605,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(path.span, ast::ExprPath(path)) } + /// Constructs a QPath expression. + fn expr_qpath(&self, span: Span, qpath: P) -> P { + self.expr(span, ast::ExprQPath(qpath)) + } + fn expr_ident(&self, span: Span, id: ast::Ident) -> P { self.expr_path(self.path_ident(span, id)) } From 4ef7551ccacd4d2042493f2ed905813b297634d0 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sun, 18 Jan 2015 19:43:35 +0900 Subject: [PATCH 03/23] Fix type inference related to upvars in closures --- src/librustc/middle/traits/select.rs | 8 +++++++ .../run-pass/unboxed-closures-infer-upvar.rs | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/run-pass/unboxed-closures-infer-upvar.rs diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index b8af91add9efb..2fe07df1709f8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1587,6 +1587,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(ParameterBuiltin); } + // Upvars are always local variables or references to + // local variables, and local variables cannot be + // unsized, so the closure struct as a whole must be + // Sized. + if bound == ty::BoundSized { + return Ok(If(Vec::new())); + } + match self.closure_typer.closure_upvars(def_id, substs) { Some(upvars) => { Ok(If(upvars.iter().map(|c| c.ty).collect())) diff --git a/src/test/run-pass/unboxed-closures-infer-upvar.rs b/src/test/run-pass/unboxed-closures-infer-upvar.rs new file mode 100644 index 0000000000000..087ef5dcf05e4 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-infer-upvar.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +// Test that the type variable in the type(`Vec<_>`) of a closed over +// variable does not interfere with type inference. + +fn f(mut f: F) { + f(); +} + +fn main() { + let mut v: Vec<_> = vec![]; + f(|| v.push(0)); + assert_eq!(v, vec![0]); +} From 00d1873c4729f1e8c109b64a7eeb87877f075279 Mon Sep 17 00:00:00 2001 From: Kevin Yap Date: Sun, 1 Feb 2015 19:36:42 -0800 Subject: [PATCH 04/23] Use `for` instead of `while` in ascii.rs tests --- src/libstd/ascii.rs | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 892747e79ed45..ac48481027d6f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -338,7 +338,6 @@ mod tests { assert!("".is_ascii()); assert!("a".is_ascii()); assert!(!"\u{2009}".is_ascii()); - } #[test] @@ -346,13 +345,11 @@ mod tests { assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - let mut i = 0; - while i <= 500 { + for i in 0u32..501 { let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i }; assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), (from_u32(upper).unwrap()).to_string()); - i += 1; } } @@ -362,13 +359,11 @@ mod tests { // Dotted capital I, Kelvin sign, Sharp S. assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - let mut i = 0; - while i <= 500 { + for i in 0u32..501 { let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), (from_u32(lower).unwrap()).to_string()); - i += 1; } } @@ -378,13 +373,11 @@ mod tests { "URL()URL()URL()üRL".to_string()); assert_eq!(("hıKß".to_string()).into_ascii_uppercase(), "HıKß"); - let mut i = 0; - while i <= 500 { + for i in 0u32..501 { let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i }; assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_uppercase(), (from_u32(upper).unwrap()).to_string()); - i += 1; } } @@ -395,13 +388,11 @@ mod tests { // Dotted capital I, Kelvin sign, Sharp S. assert_eq!(("HİKß".to_string()).into_ascii_lowercase(), "hİKß"); - let mut i = 0; - while i <= 500 { + for i in 0u32..501 { let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; assert_eq!((from_u32(i).unwrap()).to_string().into_ascii_lowercase(), (from_u32(lower).unwrap()).to_string()); - i += 1; } } @@ -415,14 +406,11 @@ mod tests { assert!(!"K".eq_ignore_ascii_case("k")); assert!(!"ß".eq_ignore_ascii_case("s")); - let mut i = 0; - while i <= 500 { - let c = i; - let lower = if 'A' as u32 <= c && c <= 'Z' as u32 { c + 'a' as u32 - 'A' as u32 } - else { c }; + for i in 0u32..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( &from_u32(lower).unwrap().to_string())); - i += 1; } } } From d3c787a94f2b66f337334e71634b1c80a359f0bd Mon Sep 17 00:00:00 2001 From: Thiago Carvalho Date: Fri, 6 Feb 2015 15:36:31 +0100 Subject: [PATCH 05/23] Book Compound Data Types update From Issue 21829 clarify equivalency of tuples --- src/doc/trpl/compound-data-types.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md index 901b44661b04c..aaa016f5a2519 100644 --- a/src/doc/trpl/compound-data-types.md +++ b/src/doc/trpl/compound-data-types.md @@ -72,6 +72,20 @@ if x == y { This will print `no`, because some of the values aren't equal. +Note that the order of the values is considered when checking for equality, +so the following example will also print `no`. + +```rust +let x = (1, 2, 3); +let y = (2, 1, 3); + +if x == y { + println!("yes"); +} else { + println!("no"); +} +``` + One other use of tuples is to return multiple values from a function: ```rust From 403869471871f7996ac09c7a8a5553d26b1c5d9a Mon Sep 17 00:00:00 2001 From: Caspar Krieger Date: Sat, 7 Feb 2015 22:21:01 +1100 Subject: [PATCH 06/23] Link to rustdoc page in the Rust book directly No point sending people to a page which just says "this is now part of the Rust book". --- src/doc/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/index.md b/src/doc/index.md index 252a3125ebdf3..a4f7941222018 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -59,8 +59,7 @@ tools we have are really nice. [Cargo](http://crates.io) is Rust's package manager, and its website contains lots of good documentation. -[The `rustdoc` manual](rustdoc.html) contains information about Rust's -documentation tool. +[`rustdoc`](book/documentation.html) is used to generate documentation for Rust code. # FAQs From d163f1f97bf6116e3fc68c528427b0cb2130db06 Mon Sep 17 00:00:00 2001 From: Alexis Date: Sat, 7 Feb 2015 17:09:07 -0500 Subject: [PATCH 07/23] add missing features to libcollections tests --- src/libcollections/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 57c799785e82d..f2ec1eafcf2be 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -30,7 +30,7 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unsafe_destructor, slicing_syntax)] -#![cfg_attr(test, feature(test))] +#![cfg_attr(test, feature(rand, rustc_private, test))] #![cfg_attr(test, allow(deprecated))] // rand #![no_std] From 4f61e160326676cdcce94b9d5bca7d88c5f40ee9 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 8 Feb 2015 00:17:04 +0100 Subject: [PATCH 08/23] Fix std::ops::Range size_hint and ExactSizeIterator impls When self.start > self.end, these iterators simply return None, so we adjust the size_hint to just return zero in this case. Certain optimizations can be implemented in and outside libstd if we know we can trust the size_hint for all inputs to for example Range. This corrects the ExactSizeIterator implementations, which IMO were unsound and incorrect previously, since they allowed a range like (2..1) to return a size_hint of -1us in when debug assertions are turned off. --- src/libcore/iter.rs | 17 +++++++---------- src/libcoretest/iter.rs | 1 + 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index f3b42e4f0a577..fa6719a0312c0 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2646,13 +2646,7 @@ impl Iterator for RangeStepInclusive { macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl ExactSizeIterator for ::ops::Range<$t> { - #[inline] - fn len(&self) -> usize { - debug_assert!(self.end >= self.start); - (self.end - self.start) as usize - } - } + impl ExactSizeIterator for ::ops::Range<$t> { } )*) } @@ -2673,9 +2667,12 @@ impl Iterator for ::ops::Range { #[inline] fn size_hint(&self) -> (usize, Option) { - debug_assert!(self.end >= self.start); - let hint = (self.end - self.start).to_uint(); - (hint.unwrap_or(0), hint) + if self.start >= self.end { + (0, Some(0)) + } else { + let length = (self.end - self.start).to_uint(); + (length.unwrap_or(0), length) + } } } diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index c9cdf50fdbd08..3f8e330b332b8 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -756,6 +756,7 @@ fn test_range() { // this test is only meaningful when sizeof uint < sizeof u64 assert_eq!((uint::MAX - 1..uint::MAX).size_hint(), (1, Some(1))); assert_eq!((-10..-1).size_hint(), (9, Some(9))); + assert_eq!((-1..-10).size_hint(), (0, Some(0))); } #[test] From bb49195d22105e11feffc604a2c25128617816b6 Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Sat, 7 Feb 2015 19:06:49 -0500 Subject: [PATCH 09/23] reference.md: Byte string literals start with a 'b' This was correct in the EBNF, but not in the prose (which seems to have been copied-and-pasted from regular string literals). --- src/doc/reference.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 9851e1c28fbf0..26d9c60a614b1 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -381,11 +381,13 @@ character (`\`), or a single _escape_. It is equivalent to a `u8` unsigned ##### Byte string literals -A _byte string literal_ is a sequence of ASCII characters and _escapes_ -enclosed within two `U+0022` (double-quote) characters, with the exception of -`U+0022` itself, which must be _escaped_ by a preceding `U+005C` character -(`\`), or a _raw byte string literal_. It is equivalent to a `&'static [u8]` -borrowed array of unsigned 8-bit integers. +A non-raw _byte string literal_ is a sequence of ASCII characters and _escapes_, +preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and +followed by the character `U+0022`. If the character `U+0022` is present within +the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character. +Alternatively, a byte string literal can be a _raw byte string literal_, defined +below. A byte string literal is equivalent to a `&'static [u8]` borrowed array +of unsigned 8-bit integers. Some additional _escapes_ are available in either byte or non-raw byte string literals. An escape starts with a `U+005C` (`\`) and continues with one of the From 8fb426469a4f7b08a240172c8f4295e868c65db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 8 Feb 2015 09:36:08 +0100 Subject: [PATCH 10/23] adapt run-make test suite for openbsd - c-link-to-rust-staticlib: use EXTRACFLAGS defined by tools.mk for choose the good libraries to link to. - no-stack-check: disabled for openbsd (no segmented stacks here) - symbols-are-reasonable: use portable grep pattern - target-specs: use POSIX form for options when invoking grep - use-extern-for-plugins: disable as OpenBSD only support x86_64 for now --- src/test/run-make/c-link-to-rust-staticlib/Makefile | 4 +--- src/test/run-make/no-stack-check/Makefile | 5 +++++ src/test/run-make/symbols-are-reasonable/Makefile | 6 +++--- src/test/run-make/target-specs/Makefile | 4 ++-- src/test/run-make/use-extern-for-plugins/Makefile | 5 +++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/test/run-make/c-link-to-rust-staticlib/Makefile b/src/test/run-make/c-link-to-rust-staticlib/Makefile index 8a6d6e4dd6d78..477b85f362a29 100644 --- a/src/test/run-make/c-link-to-rust-staticlib/Makefile +++ b/src/test/run-make/c-link-to-rust-staticlib/Makefile @@ -1,9 +1,7 @@ -include ../tools.mk ifndef IS_WINDOWS -ifneq ($(shell uname),Darwin) - EXTRAFLAGS := -lm -lrt -ldl -lpthread -endif +EXTRAFLAGS := $(EXTRACFLAGS) endif # FIXME: ignore freebsd diff --git a/src/test/run-make/no-stack-check/Makefile b/src/test/run-make/no-stack-check/Makefile index 561056d719e60..5fce35e2beb87 100644 --- a/src/test/run-make/no-stack-check/Makefile +++ b/src/test/run-make/no-stack-check/Makefile @@ -1,6 +1,7 @@ -include ../tools.mk ifndef IS_WINDOWS +ifneq ($(UNAME),OpenBSD) all: $(RUSTC) -O --emit asm attr.rs ! grep -q morestack $(TMPDIR)/attr.s @@ -9,6 +10,10 @@ all: $(RUSTC) -O --emit asm -C no-stack-check flag.rs ! grep -q morestack $(TMPDIR)/flag.s else +# On OpenBSD, morestack isn't used as the segmented stacks are disabled +all: +endif +else # On Windows we use __chkstk and it only appears in functions with large allocations, # so this test wouldn't be reliable. all: diff --git a/src/test/run-make/symbols-are-reasonable/Makefile b/src/test/run-make/symbols-are-reasonable/Makefile index 42a72f7ca398e..89f610dee17d0 100644 --- a/src/test/run-make/symbols-are-reasonable/Makefile +++ b/src/test/run-make/symbols-are-reasonable/Makefile @@ -10,6 +10,6 @@ OUT=$(TMPDIR)/lib.s all: $(RUSTC) lib.rs --emit=asm --crate-type=staticlib # just check for symbol declarations with the names we're expecting. - grep 'str[0-9]\+:' $(OUT) - grep 'binary[0-9]\+:' $(OUT) - grep 'vtable[0-9]\+' $(OUT) + grep 'str[0-9][0-9]*:' $(OUT) + grep 'binary[0-9][0-9]*:' $(OUT) + grep 'vtable[0-9][0-9]*' $(OUT) diff --git a/src/test/run-make/target-specs/Makefile b/src/test/run-make/target-specs/Makefile index a352bc3a8cceb..db2b253a6f1a7 100644 --- a/src/test/run-make/target-specs/Makefile +++ b/src/test/run-make/target-specs/Makefile @@ -1,11 +1,11 @@ -include ../tools.mk all: $(RUSTC) foo.rs --target=my-awesome-platform.json --crate-type=lib --emit=asm - grep --quiet --invert-match morestack < $(TMPDIR)/foo.s + grep -q -v morestack < $(TMPDIR)/foo.s $(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | grep --quiet "Error loading target specification" $(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | grep 'Field llvm-target' RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=x86_64-unknown-linux-gnu --crate-type=lib --emit=asm # The built-in target *should* override the one we have here, and thus we # should have morestack - grep --quiet morestack < $(TMPDIR)/foo.s + grep -q morestack < $(TMPDIR)/foo.s diff --git a/src/test/run-make/use-extern-for-plugins/Makefile b/src/test/run-make/use-extern-for-plugins/Makefile index 84032b45159f5..bdce7b7810aaf 100644 --- a/src/test/run-make/use-extern-for-plugins/Makefile +++ b/src/test/run-make/use-extern-for-plugins/Makefile @@ -1,5 +1,6 @@ -include ../tools.mk +ifneq ($(UNAME),OpenBSD) HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //') ifeq ($(findstring i686,$(HOST)),i686) TARGET := $(subst i686,x86_64,$(HOST)) @@ -11,3 +12,7 @@ all: $(RUSTC) foo.rs -C extra-filename=-host $(RUSTC) bar.rs -C extra-filename=-targ --target $(TARGET) $(RUSTC) baz.rs --extern a=$(TMPDIR)/liba-targ.rlib --target $(TARGET) +else +# OpenBSD support only x86_64 architecture for now +all: +endif From 34afe5e193182a0029abe1ae8258f79f4cd56cd9 Mon Sep 17 00:00:00 2001 From: Alexander Korolkov Date: Thu, 5 Feb 2015 15:04:07 +0300 Subject: [PATCH 11/23] Rename Show to Debug, String to Display Update reference.md: - derive() no longer supports Zero trait - derive() now supports Copy trait --- src/doc/reference.md | 4 ++-- src/libcore/any.rs | 2 +- src/libgetopts/lib.rs | 6 +++--- src/librustc/middle/ty.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/libserialize/json.rs | 4 ++-- src/libstd/old_path/mod.rs | 4 ++-- src/libstd/sys/windows/os.rs | 2 +- src/libsyntax/ast.rs | 1 - 9 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 9c8191a386ddc..999cb217f933e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2354,8 +2354,8 @@ Supported traits for `derive` are: * `FromPrimitive`, to create an instance from a numeric primitive. * `Hash`, to iterate over the bytes in a data type. * `Rand`, to create a random instance of a data type. -* `Show`, to format a value using the `{}` formatter. -* `Zero`, to create a zero instance of a numeric data type. +* `Debug`, to format a value using the `{:?}` formatter. +* `Copy`, for "Plain Old Data" types which can be copied by simply moving bits. ### Compiler Features diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 40c2d82bf4b3f..462b6771b4a9a 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -27,7 +27,7 @@ //! # Examples //! //! Consider a situation where we want to log out a value passed to a function. -//! We know the value we're working on implements Show, but we don't know its +//! We know the value we're working on implements Debug, but we don't know its //! concrete type. We want to give special treatment to certain types: in this //! case printing out the length of String values prior to their value. //! We don't know the concrete type of our value at compile time, so we need to diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 1b30bdf230ec1..72832cb946680 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -195,7 +195,7 @@ pub struct Matches { } /// The type returned when the command line does not conform to the -/// expected format. Use the `Show` implementation to output detailed +/// expected format. Use the `Debug` implementation to output detailed /// information. #[derive(Clone, PartialEq, Eq, Debug)] pub enum Fail { @@ -545,7 +545,7 @@ impl Fail { /// Convert a `Fail` enum into an error string. #[unstable(feature = "rustc_private")] #[deprecated(since = "1.0.0", - reason = "use `fmt::String` (`{}` format specifier)")] + reason = "use `fmt::Display` (`{}` format specifier)")] pub fn to_err_msg(self) -> String { self.to_string() } @@ -579,7 +579,7 @@ impl fmt::Display for Fail { /// `opt_str`, etc. to interrogate results. /// # Panics /// -/// Returns `Err(Fail)` on failure: use the `Show` implementation of `Fail` to display +/// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` to display /// information about it. pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { let opts: Vec = optgrps.iter().map(|x| x.long_to_short()).collect(); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b29a23924bb12..034dbb4271db2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -70,7 +70,7 @@ use arena::TypedArena; use std::borrow::{BorrowFrom, Cow}; use std::cell::{Cell, RefCell}; use std::cmp; -use std::fmt::{self, Show}; +use std::fmt; use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index cc2cf21095e41..e916b63eb8dc7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -10,7 +10,7 @@ //! HTML formatting module //! -//! This module contains a large number of `fmt::String` implementations for +//! This module contains a large number of `fmt::Display` implementations for //! various types in `rustdoc::clean`. These implementations all currently //! assume that HTML output is desired, although it may be possible to redesign //! them in the future to instead emit any format desired. diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index b838357798753..daa358647d8e6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1032,7 +1032,7 @@ pub fn as_pretty_json(t: &T) -> AsPrettyJson { impl Json { /// Borrow this json object as a pretty object to generate a pretty - /// representation for it via `Show`. + /// representation for it via `Display`. pub fn pretty(&self) -> PrettyJson { PrettyJson { inner: self } } @@ -3540,7 +3540,7 @@ mod tests { fn test_hashmap_with_enum_key() { use std::collections::HashMap; use json; - #[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Show)] + #[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Debug)] enum Enum { Foo, #[allow(dead_code)] diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs index 0d80258d7e04f..17cfe1c82972f 100644 --- a/src/libstd/old_path/mod.rs +++ b/src/libstd/old_path/mod.rs @@ -228,7 +228,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { /// ``` fn into_vec(self) -> Vec; - /// Returns an object that implements `Show` for printing paths + /// Returns an object that implements `Display` for printing paths /// /// # Example /// @@ -244,7 +244,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { Display{ path: self, filename: false } } - /// Returns an object that implements `Show` for printing filenames + /// Returns an object that implements `Display` for printing filenames /// /// If there is no filename, nothing will be printed. /// diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index d8e3e6981df76..7e684c5234141 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -191,7 +191,7 @@ impl<'a> Iterator for SplitPaths<'a> { } } -#[derive(Show)] +#[derive(Debug)] pub struct JoinPathsError; pub fn join_paths(paths: I) -> Result diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 71259ff5d9ade..5ec87eaf8d1ad 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -64,7 +64,6 @@ use parse::token; use ptr::P; use std::fmt; -use std::fmt::Show; use std::num::Int; use std::rc::Rc; use serialize::{Encodable, Decodable, Encoder, Decoder}; From a6e8496601767e59acce010531f8e4dfb40c7c0a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 9 Feb 2015 19:30:22 +0200 Subject: [PATCH 12/23] Deduplicate --crate-type arguments Crate types from multiple sources appear to be deduplicated properly, but not deduplicated if they come from the command line arguments. At worst, this used to cause compiler failures when `--crate-type=lib,rlib` (the same as `--crate-type=rlib,rlib`, at least at the time of this commit) is provided and generate the output multiple times otherwise. --- src/librustc/session/config.rs | 4 +++- src/test/run-make/duplicate-output-flavors/Makefile | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index efd2392e453ed..6d09b8b09e706 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1061,7 +1061,9 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result Date: Fri, 6 Feb 2015 17:59:56 +0100 Subject: [PATCH 13/23] Given ` as Box`, infer that `Box<_>` is expected type for ``. --- src/librustc_typeck/check/vtable.rs | 109 ++++++++++++---------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 19287f19d8d50..00f6c6109faef 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -9,11 +9,11 @@ // except according to those terms. use check::{FnCtxt, structurally_resolved_type}; +use check::demand; use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode}; use middle::traits::{Obligation, ObligationCause}; use middle::traits::report_fulfillment_errors; use middle::ty::{self, Ty, AsPredicate}; -use middle::infer; use syntax::ast; use syntax::codemap::Span; use util::nodemap::FnvHashSet; @@ -24,71 +24,63 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, source_expr: &ast::Expr, target_object_ty: Ty<'tcx>) { + let tcx = fcx.tcx(); debug!("check_object_cast(cast_expr={}, target_object_ty={})", - cast_expr.repr(fcx.tcx()), - target_object_ty.repr(fcx.tcx())); + cast_expr.repr(tcx), + target_object_ty.repr(tcx)); // 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, // e.g.: `&x as &Trait` or `box x as Box` - let source_ty = fcx.expr_ty(source_expr); - let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); - debug!("source_ty={}", source_ty.repr(fcx.tcx())); - match (&source_ty.sty, &target_object_ty.sty) { - (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => { - let object_trait = object_trait(&object_trait_ty); - - // Ensure that if ~T is cast to ~Trait, then T : Trait - push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - check_object_safety(fcx.tcx(), object_trait, source_expr.span); - } - - (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, - mutbl: referent_mutbl }), - &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, - mutbl: target_mutbl })) => - { - let object_trait = object_trait(&object_trait_ty); - if !mutability_allowed(referent_mutbl, target_mutbl) { - span_err!(fcx.tcx().sess, source_expr.span, E0188, - "types differ in mutability"); - } else { - // Ensure that if &'a T is cast to &'b Trait, then T : Trait - push_cast_obligation(fcx, cast_expr, - object_trait, - referent_ty); - - // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a - infer::mk_subr(fcx.infcx(), - infer::RelateObjectBound(source_expr.span), - *target_region, - *referent_region); - - check_object_safety(fcx.tcx(), object_trait, source_expr.span); - } - } - (_, &ty::ty_uniq(..)) => { - span_err!(fcx.ccx.tcx.sess, source_expr.span, E0189, - "can only cast a boxed pointer \ - to a boxed object, not a {}", - ty::ty_sort_string(fcx.tcx(), source_ty)); + // First, construct a fresh type that we can feed into `` + // within ` as ` to inform type inference (e.g. to + // tell it that we are expecting a `Box<_>` or an `&_`). + let fresh_ty = fcx.infcx().next_ty_var(); + let (object_trait_ty, source_expected_ty) = match target_object_ty.sty { + ty::ty_uniq(object_trait_ty) => { + (object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty)) } - - (_, &ty::ty_rptr(..)) => { - span_err!(fcx.ccx.tcx.sess, source_expr.span, E0190, - "can only cast a &-pointer \ - to an &-object, not a {}", - ty::ty_sort_string(fcx.tcx(), source_ty)); + ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, + mutbl: target_mutbl }) => { + (object_trait_ty, + ty::mk_rptr(fcx.tcx(), + target_region, ty::mt { ty: fresh_ty, + mutbl: target_mutbl })) } - _ => { - fcx.tcx().sess.span_bug( - source_expr.span, - "expected object type"); + fcx.tcx().sess.span_bug(source_expr.span, "expected object type"); } - } + }; + + let source_ty = fcx.expr_ty(source_expr); + debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx)); + + // This ensures that the source_ty <: source_expected_ty, which + // will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait` + // + // FIXME (pnkfelix): do we need to use suptype_with_fn in order to + // override the error message emitted when the types do not work + // out in the manner desired? + demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty); + + debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx)); + let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); + debug!("check_object_cast resolveto source_ty={}", source_ty.repr(tcx)); + + let object_trait = object_trait(&object_trait_ty); + + let referent_ty = match source_ty.sty { + ty::ty_uniq(ty) => ty, + ty::ty_rptr(_, ty::mt { ty, mutbl: _ }) => ty, + _ => fcx.tcx().sess.span_bug(source_expr.span, + "expected appropriate reference type"), + }; + + // Ensure that if Ptr is cast to Ptr, then T : Trait. + push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); + check_object_safety(tcx, object_trait, source_expr.span); fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> { match t.sty { @@ -97,13 +89,6 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - fn mutability_allowed(a_mutbl: ast::Mutability, - b_mutbl: ast::Mutability) - -> bool { - a_mutbl == b_mutbl || - (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) - } - fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast_expr: &ast::Expr, object_trait: &ty::TyTrait<'tcx>, From a1b3189f4864f1ada755e9ebc2e0ce1ac5bf2e06 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 6 Feb 2015 18:05:32 +0100 Subject: [PATCH 14/23] add test illustrating the feature. (with multiple impls to further exercise correct trait-matching.) --- .../infer-container-across-object-cast.rs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/test/run-pass/infer-container-across-object-cast.rs diff --git a/src/test/run-pass/infer-container-across-object-cast.rs b/src/test/run-pass/infer-container-across-object-cast.rs new file mode 100644 index 0000000000000..979e76b1ff994 --- /dev/null +++ b/src/test/run-pass/infer-container-across-object-cast.rs @@ -0,0 +1,59 @@ +// Copyright 2015 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. + +// Given ` as Box`, we should be able to infer that a +// `Box<_>` is the expected type. + +trait Foo { fn foo(&self) -> u32; } +impl Foo for u32 { fn foo(&self) -> u32 { *self } } + +// (another impl to ensure trait-matching cannot just choose from a singleton set) +impl Foo for () { fn foo(&self) -> u32 { -176 } } + +trait Boxed { fn make() -> Self; } +impl Boxed for Box { fn make() -> Self { Box::new(7) } } + +// (another impl to ensure trait-matching cannot just choose from a singleton set) +impl Boxed for () { fn make() -> Self { () } } + +fn boxed_foo() { + let b7 = Boxed::make() as Box; + assert_eq!(b7.foo(), 7); +} + +trait Refed<'a,T> { fn make(&'a T) -> Self; } +impl<'a> Refed<'a, u32> for &'a u32 { fn make(x: &'a u32) -> Self { x } } + +// (another impl to ensure trait-matching cannot just choose from a singleton set) +impl<'a,'b> Refed<'a, ()> for &'b () { fn make(_: &'a ()) -> Self { static U: () = (); &U } } + +fn refed_foo() { + let a = 8; + let b7 = Refed::make(&a) as &Foo; + assert_eq!(b7.foo(), 8); +} + +fn check_subtyping_works() { + fn inner<'short, 'long:'short>(_s: &'short u32, + l: &'long u32) -> &'short (Foo+'short) { + Refed::make(l) as &Foo + } + + let a = 9; + let b = 10; + let r = inner(&b, &a); + assert_eq!(r.foo(), 9); +} + +pub fn main() { + boxed_foo(); + refed_foo(); + check_subtyping_works(); +} From 45f667286134c9d48008969c4e3f4b54d9c1dc22 Mon Sep 17 00:00:00 2001 From: Sean Collins Date: Mon, 9 Feb 2015 15:07:47 -0500 Subject: [PATCH 15/23] Make fallback font 'serif', rather than 'sans-serif' fonts --- src/doc/rust.css | 2 +- src/librustdoc/html/static/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rust.css b/src/doc/rust.css index 3f59f12e74ca3..c2a25cd7a584e 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -58,7 +58,7 @@ body { margin: 0 auto; padding: 0 15px; - font-family: "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Source Serif Pro", Georgia, Times, "Times New Roman", serif; font-size: 18px; color: #333; line-height: 1.428571429; diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 46faa3efc34a2..7267f95b31f2f 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -64,7 +64,7 @@ body { color: #333; - font: 16px/1.4 "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; + font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif; margin: 0; position: relative; padding: 10px 15px 20px 15px; From 0479d90b77ab2b9abe9e242980ce8ec53fb7761d Mon Sep 17 00:00:00 2001 From: Pierre Baillet Date: Sat, 7 Feb 2015 15:11:25 +0100 Subject: [PATCH 16/23] Update deprecation notice. - add namespace - add function parens --- src/libstd/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1a61769445664..526b5edd4cbde 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -723,7 +723,7 @@ extern "system" { /// println!("{}", argument); /// } /// ``` -#[deprecated(since = "1.0.0", reason = "use env::args instead")] +#[deprecated(since = "1.0.0", reason = "use std::env::args() instead")] #[unstable(feature = "os")] pub fn args() -> Vec { real_args() From 1163cef1c43d421c54b97ee266bb4f2ddfe4595c Mon Sep 17 00:00:00 2001 From: Luke Steensen Date: Mon, 9 Feb 2015 15:10:33 -0600 Subject: [PATCH 17/23] remove obsolete closure syntax from the guide --- src/doc/trpl/closures.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index bfb1494efc785..8cc6be7387ca1 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -9,7 +9,7 @@ arguments, really powerful things are possible. Let's make a closure: ```{rust} -let add_one = |&: x| { 1 + x }; +let add_one = |x| { 1 + x }; println!("The sum of 5 plus 1 is {}.", add_one(5)); ``` @@ -21,8 +21,8 @@ binding name and two parentheses, just like we would for a named function. Let's compare syntax. The two are pretty close: ```{rust} -let add_one = |&: x: i32| -> i32 { 1 + x }; -fn add_one (x: i32) -> i32 { 1 + x } +let add_one = |x: i32| -> i32 { 1 + x }; +fn add_one (x: i32) -> i32 { 1 + x } ``` As you may have noticed, closures infer their argument and return types, so you @@ -37,7 +37,7 @@ this: fn main() { let x: i32 = 5; - let printer = |&:| { println!("x is: {}", x); }; + let printer = || { println!("x is: {}", x); }; printer(); // prints "x is: 5" } @@ -53,7 +53,7 @@ defined. The closure borrows any variables it uses, so this will error: fn main() { let mut x: i32 = 5; - let printer = |&:| { println!("x is: {}", x); }; + let printer = || { println!("x is: {}", x); }; x = 6; // error: cannot assign to `x` because it is borrowed } @@ -80,7 +80,7 @@ fn twice i32>(x: i32, f: F) -> i32 { } fn main() { - let square = |&: x: i32| { x * x }; + let square = |x: i32| { x * x }; twice(5, square); // evaluates to 50 } @@ -89,7 +89,7 @@ fn main() { Let's break the example down, starting with `main`: ```{rust} -let square = |&: x: i32| { x * x }; +let square = |x: i32| { x * x }; ``` We've seen this before. We make a closure that takes an integer, and returns @@ -97,7 +97,7 @@ its square. ```{rust} # fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } -# let square = |&: x: i32| { x * x }; +# let square = |x: i32| { x * x }; twice(5, square); // evaluates to 50 ``` @@ -184,8 +184,8 @@ fn compose(x: i32, f: F, g: G) -> i32 fn main() { compose(5, - |&: n: i32| { n + 42 }, - |&: n: i32| { n * 2 }); // evaluates to 94 + |n: i32| { n + 42 }, + |n: i32| { n * 2 }); // evaluates to 94 } ``` From dbccd70a5736fd2e898b446e6c5f3da5d17538c6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sun, 8 Feb 2015 20:15:16 -0500 Subject: [PATCH 18/23] Add documentation on trait objects. Largely taken from @huonw's http://huonw.github.io/blog/2015/01/peeking-inside-trait-objects/ Fixes #21707 --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/static-and-dynamic-dispatch.md | 286 ++++++++++++++++++++ src/doc/trpl/traits.md | 47 +--- 3 files changed, 289 insertions(+), 45 deletions(-) create mode 100644 src/doc/trpl/static-and-dynamic-dispatch.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 9d65f30e72379..bfc1247dc3bc0 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -27,6 +27,7 @@ * [Iterators](iterators.md) * [Generics](generics.md) * [Traits](traits.md) + * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [Documentation](documentation.md) diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/static-and-dynamic-dispatch.md new file mode 100644 index 0000000000000..9421dac7bf65d --- /dev/null +++ b/src/doc/trpl/static-and-dynamic-dispatch.md @@ -0,0 +1,286 @@ +% Static and Dynamic Dispatch + +When code involves polymorphism, there needs to be a mechanism to determine +which specific version is actually run. This is called 'dispatch.' There are +two major forms of dispatch: static dispatch and dynamic dispatch. While Rust +favors static dispatch, it also supports dynamic dispatch through a mechanism +called 'trait objects.' + +## Background + +For the rest of this chapter, we'll need a trait and some implementations. +Let's make a simple one, `Foo`. It has one method that is expected to return a +`String`. + +```rust +trait Foo { + fn method(&self) -> String; +} +``` + +We'll also implement this trait for `u8` and `String`: + +```rust +# trait Foo { fn method(&self) -> String; } +impl Foo for u8 { + fn method(&self) -> String { format!("u8: {}", *self) } +} + +impl Foo for String { + fn method(&self) -> String { format!("string: {}", *self) } +} +``` + + +## Static dispatch + +We can use this trait to perform static dispatch with trait bounds: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something(x: T) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something(x); + do_something(y); +} +``` + +Rust uses 'monomorphization' to perform static dispatch here. This means that +Rust will create a special version of `do_something()` for both `u8` and +`String`, and then replace the call sites with calls to these specialized +functions. In other words, Rust generates something like this: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something_u8(x: u8) { + x.method(); +} + +fn do_something_string(x: String) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something_u8(x); + do_something_string(y); +} +``` + +This has some upsides: static dispatching of any method calls, allowing for +inlining and hence usually higher performance. It also has some downsides: +causing code bloat due to many copies of the same function existing in the +binary, one for each type. + +Furthermore, compilers aren’t perfect and may “optimise” code to become slower. +For example, functions inlined too eagerly will bloat the instruction cache +(cache rules everything around us). This is part of the reason that `#[inline]` +and `#[inline(always)]` should be used carefully, and one reason why using a +dynamic dispatch is sometimes more efficient. + +However, the common case is that it is more efficient to use static dispatch, +and one can always have a thin statically-dispatched wrapper function that does +a dynamic, but not vice versa, meaning static calls are more flexible. The +standard library tries to be statically dispatched where possible for this +reason. + +## Dynamic dispatch + +Rust provides dynamic dispatch through a feature called 'trait objects.' Trait +objects, like `&Foo` or `Box`, are normal values that store a value of +*any* type that implements the given trait, where the precise type can only be +known at runtime. The methods of the trait can be called on a trait object via +a special record of function pointers (created and managed by the compiler). + +A function that takes a trait object is not specialised to each of the types +that implements `Foo`: only one copy is generated, often (but not always) +resulting in less code bloat. However, this comes at the cost of requiring +slower virtual function calls, and effectively inhibiting any chance of +inlining and related optimisations from occurring. + +Trait objects are both simple and complicated: their core representation and +layout is quite straight-forward, but there are some curly error messages and +surprising behaviours to discover. + +### Obtaining a trait object + +There's two similar ways to get a trait object value: casts and coercions. If +`T` is a type that implements a trait `Foo` (e.g. `u8` for the `Foo` above), +then the two ways to get a `Foo` trait object out of a pointer to `T` look +like: + +```{rust,ignore} +let ref_to_t: &T = ...; + +// `as` keyword for casting +let cast = ref_to_t as &Foo; + +// using a `&T` in a place that has a known type of `&Foo` will implicitly coerce: +let coerce: &Foo = ref_to_t; + +fn also_coerce(_unused: &Foo) {} +also_coerce(ref_to_t); +``` + +These trait object coercions and casts also work for pointers like `&mut T` to +`&mut Foo` and `Box` to `Box`, but that's all at the moment. Coercions +and casts are identical. + +This operation can be seen as "erasing" the compiler's knowledge about the +specific type of the pointer, and hence trait objects are sometimes referred to +"type erasure". + +### Representation + +Let's start simple, with the runtime representation of a trait object. The +`std::raw` module contains structs with layouts that are the same as the +complicated build-in types, [including trait objects][stdraw]: + +```rust +# mod foo { +pub struct TraitObject { + pub data: *mut (), + pub vtable: *mut (), +} +# } +``` + +[stdraw]: ../std/raw/struct.TraitObject.html + +That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable" +pointer. + +The data pointer addresses the data (of some unknown type `T`) that the trait +object is storing, and the vtable pointer points to the vtable ("virtual method +table") corresponding to the implementation of `Foo` for `T`. + + +A vtable is essentially a struct of function pointers, pointing to the concrete +piece of machine code for each method in the implementation. A method call like +`trait_object.method()` will retrieve the correct pointer out of the vtable and +then do a dynamic call of it. For example: + +```{rust,ignore} +struct FooVtable { + destructor: fn(*mut ()), + size: usize, + align: usize, + method: fn(*const ()) -> String, +} + +// u8: + +fn call_method_on_u8(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a u8 + let byte: &u8 = unsafe { &*(x as *const u8) }; + + byte.method() +} + +static Foo_for_u8_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + size: 1, + align: 1, + + // cast to a function pointer + method: call_method_on_u8 as fn(*const ()) -> String, +}; + + +// String: + +fn call_method_on_String(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a String + let string: &String = unsafe { &*(x as *const String) }; + + string.method() +} + +static Foo_for_String_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + // values for a 64-bit computer, halve them for 32-bit ones + size: 24, + align: 8, + + method: call_method_on_String as fn(*const ()) -> String, +}; +``` + +The `destructor` field in each vtable points to a function that will clean up +any resources of the vtable's type, for `u8` it is trivial, but for `String` it +will free the memory. This is necessary for owning trait objects like +`Box`, which need to clean-up both the `Box` allocation and as well as the +internal type when they go out of scope. The `size` and `align` fields store +the size of the erased type, and its alignment requirements; these are +essentially unused at the moment since the information is embedded in the +destructor, but will be used in future, as trait objects are progressively made +more flexible. + +Suppose we've got some values that implement `Foo`, the explicit form of +construction and use of `Foo` trait objects might look a bit like (ignoring the +type mismatches: they're all just pointers anyway): + +```{rust,ignore} +let a: String = "foo".to_string(); +let x: u8 = 1; + +// let b: &Foo = &a; +let b = TraitObject { + // store the data + data: &a, + // store the methods + vtable: &Foo_for_String_vtable +}; + +// let y: &Foo = x; +let y = TraitObject { + // store the data + data: &x, + // store the methods + vtable: &Foo_for_u8_vtable +}; + +// b.method(); +(b.vtable.method)(b.data); + +// y.method(); +(y.vtable.method)(y.data); +``` + +If `b` or `y` were owning trait objects (`Box`), there would be a +`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of +scope. + +### Why pointers? + +The use of language like "fat pointer" implies that a trait object is +always a pointer of some form, but why? + +Rust does not put things behind a pointer by default, unlike many managed +languages, so types can have different sizes. Knowing the size of the value at +compile time is important for things like passing it as an argument to a +function, moving it about on the stack and allocating (and deallocating) space +on the heap to store it. + +For `Foo`, we would need to have a value that could be at least either a +`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which +dependent crates may implement `Foo` (any number of bytes at all). There's no +way to guarantee that this last point can work if the values are stored without +a pointer, because those other types can be arbitrarily large. + +Putting the value behind a pointer means the size of the value is not relevant +when we are tossing a trait object around, only the size of the pointer itself. diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index d12480d7dd9fa..e091878cf86ec 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -270,51 +270,8 @@ not, because both the trait and the type aren't in our crate. One last thing about traits: generic functions with a trait bound use *monomorphization* (*mono*: one, *morph*: form), so they are statically -dispatched. What's that mean? Well, let's take a look at `print_area` again: - -```{rust,ignore} -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} - -fn main() { - let c = Circle { ... }; - - let s = Square { ... }; - - print_area(c); - print_area(s); -} -``` - -When we use this trait with `Circle` and `Square`, Rust ends up generating -two different functions with the concrete type, and replacing the call sites with -calls to the concrete implementations. In other words, you get something like -this: - -```{rust,ignore} -fn __print_area_circle(shape: Circle) { - println!("This shape has an area of {}", shape.area()); -} - -fn __print_area_square(shape: Square) { - println!("This shape has an area of {}", shape.area()); -} - -fn main() { - let c = Circle { ... }; - - let s = Square { ... }; - - __print_area_circle(c); - __print_area_square(s); -} -``` - -The names don't actually change to this, it's just for illustration. But -as you can see, there's no overhead of deciding which version to call here, -hence *statically dispatched*. The downside is that we have two copies of -the same function, so our binary is a little bit larger. +dispatched. What's that mean? Check out the chapter on [static and dynamic +dispatch](static-and-dynamic-dispatch.html) for more. ## Our `inverse` Example From e40d05800bd2f6c1e68548246a21f305447ae300 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 9 Feb 2015 21:51:30 -0500 Subject: [PATCH 19/23] Remove incorrect docs from mem::transmute Fixes #22032 --- src/libcore/intrinsics.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 125e8a0e81476..5562845e11d6f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -222,12 +222,11 @@ extern "rust-intrinsic" { /// Unsafely transforms a value of one type into a value of another type. /// - /// Both types must have the same size and alignment, and this guarantee - /// is enforced at compile-time. + /// Both types must have the same size. /// /// # Examples /// - /// ```rust + /// ``` /// use std::mem; /// /// let v: &[u8] = unsafe { mem::transmute("L") }; From b42c559e9f0162e9770631e86fb21995d60d0d09 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 9 Feb 2015 21:57:14 -0500 Subject: [PATCH 20/23] Remove bottom from the reference Fixes #20172 --- src/doc/reference.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 9c8191a386ddc..c2b381fe5e416 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1253,9 +1253,7 @@ fn my_err(s: &str) -> ! { We call such functions "diverging" because they never return a value to the caller. Every control path in a diverging function must end with a `panic!()` or a call to another diverging function on every control path. The `!` annotation -does *not* denote a type. Rather, the result type of a diverging function is a -special type called ⊥ ("bottom") that unifies with any type. Rust has no -syntax for ⊥. +does *not* denote a type. It might be necessary to declare a diverging function because as mentioned previously, the typechecker checks that every control path in a function ends From 17abb43248e5b8ce65ede45d7446fa7247eed5ae Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 9 Feb 2015 21:44:11 -0500 Subject: [PATCH 21/23] Set up docs for missing core types Fixes #22085 --- src/libcore/lib.rs | 4 ++++ src/libcore/tuple.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index df4942b509b4c..a122bcb2c7aed 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -141,6 +141,10 @@ pub mod hash; pub mod fmt; pub mod error; +#[doc(primitive = "bool")] +mod bool { +} + // note: does not need to be public mod tuple; mod array; diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index 64c2964eb7c69..72b2d5dc18882 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -34,6 +34,7 @@ //! * `Default` #![stable(feature = "rust1", since = "1.0.0")] +#![doc(primitive = "tuple")] use clone::Clone; use cmp::*; From 792dc8d067d1f11e08e859ccdd45d59436773fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Tue, 10 Feb 2015 14:37:44 +0100 Subject: [PATCH 22/23] Made the `ptr::Unique` type accept unsized types, to allow for use cases like sending a raw pointer slice across thread boundaries. --- src/libcore/ptr.rs | 6 +++--- src/libcoretest/ptr.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index ba1eae551ff2a..bf801a88ca5b3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -522,21 +522,21 @@ impl PartialOrd for *mut T { /// Useful for building abstractions like `Vec` or `Box`, which /// internally use raw pointers to manage the memory that they own. #[unstable(feature = "core", reason = "recently added to this module")] -pub struct Unique(pub *mut T); +pub struct Unique(pub *mut T); /// `Unique` pointers are `Send` if `T` is `Send` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. #[unstable(feature = "core", reason = "recently added to this module")] -unsafe impl Send for Unique { } +unsafe impl Send for Unique { } /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. #[unstable(feature = "core", reason = "recently added to this module")] -unsafe impl Sync for Unique { } +unsafe impl Sync for Unique { } impl Unique { /// Returns a null Unique. diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 7f0b97c53d465..2365b907b3ff5 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -167,3 +167,12 @@ fn test_set_memory() { unsafe { set_memory(ptr, 5u8, xs.len()); } assert!(xs == [5u8; 20]); } + +#[test] +fn test_unsized_unique() { + let xs: &mut [_] = &mut [1, 2, 3]; + let ptr = Unique(xs as *mut [_]); + let ys = unsafe { &mut *ptr.0 }; + let zs: &mut [_] = &mut [1, 2, 3]; + assert!(ys == zs); +} From 6e8b8733c98fb2333224c5cfc7ffcf57fa878d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 10 Feb 2015 16:31:46 +0100 Subject: [PATCH 23/23] Add a flag to skip the LLVM version check in configure When trying to build against a newer, local LLVM version it might be preferable to have a flag to disable the LLVM version check instead of having to modify the configure script. Fixes #21998 --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index a80dafcf04779..e6b8d23544829 100755 --- a/configure +++ b/configure @@ -525,6 +525,7 @@ opt verify-install 1 "verify installed binaries work" opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt jemalloc 1 "build liballoc with jemalloc" +opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway" valopt localstatedir "/var/lib" "local state directory" valopt sysconfdir "/etc" "install system configuration files" @@ -796,7 +797,7 @@ then putvar CFG_ENABLE_CLANG fi -if [ ! -z "$CFG_LLVM_ROOT" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ] +if [ ! -z "$CFG_LLVM_ROOT" -a -z "$CFG_DISABLE_LLVM_VERSION_CHECK" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ] then step_msg "using custom LLVM at $CFG_LLVM_ROOT"