diff options
312 files changed, 6130 insertions, 4125 deletions
diff --git a/README.md b/README.md index a83f51e1571..4ea6e28546a 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ build. Download [MinGW from here](http://mingw-w64.org/doku.php/download/mingw-builds), and choose the -`threads=win32,exceptions=dwarf/seh` flavor when installing. After installing, +`threads=win32,exceptions=dwarf/seh` flavor when installing. Also, make sure to install to a path without spaces in it. After installing, add its `bin` directory to your `PATH`. This is due to [#28260](https://github.com/rust-lang/rust/issues/28260), in the future, installing from pacman should be just fine. diff --git a/mk/crates.mk b/mk/crates.mk index b7bb7c1083d..1ecceb9280a 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -49,16 +49,17 @@ # automatically generated for all stage/host/target combinations. ################################################################################ -TARGET_CRATES := libc std flate arena term \ - serialize getopts collections test rand \ - log graphviz core rbml alloc \ +TARGET_CRATES := libc std term \ + getopts collections test rand \ + core alloc \ rustc_unicode rustc_bitflags \ alloc_system alloc_jemalloc RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_front rustc_platform_intrinsics \ rustc_plugin rustc_metadata rustc_passes -HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros +HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \ + flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := @@ -84,10 +85,10 @@ DEPS_log := std DEPS_num := std DEPS_rbml := std log serialize DEPS_serialize := std log -DEPS_term := std log -DEPS_test := std getopts serialize rbml term native:rust_test_helpers +DEPS_term := std +DEPS_test := std getopts term native:rust_test_helpers -DEPS_syntax := std term serialize log arena libc rustc_bitflags +DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode DEPS_syntax_ext := syntax fmt_macros DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\ diff --git a/mk/rt.mk b/mk/rt.mk index bd17490955d..5f46b3a20c9 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -253,7 +253,7 @@ COMPRT_AR_$(1) := $$(AR_$(1)) # We chomp -Werror here because GCC warns about the type signature of # builtins not matching its own and the build fails. It's a bit hacky, # but what can we do, we're building libclang-rt using GCC ...... -COMPRT_CFLAGS_$(1) := $$(filter-out -Werror -Werror=*,$$(CFG_GCCISH_CFLAGS_$(1))) -std=c99 +COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error -std=c99 # FreeBSD Clang's packaging is problematic; it doesn't copy unwind.h to # the standard include directory. This should really be in our changes to @@ -361,7 +361,7 @@ $$(BACKTRACE_BUILD_DIR_$(1))/Makefile: $$(BACKTRACE_DEPS) $$(MKFILE_DEPS) CC="$$(CC_$(1))" \ AR="$$(AR_$(1))" \ RANLIB="$$(AR_$(1)) s" \ - CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1):-Werror=) -fno-stack-protector" \ + CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error -fno-stack-protector" \ $(S)src/libbacktrace/configure --build=$(CFG_GNU_TRIPLE_$(CFG_BUILD)) --host=$(CFG_GNU_TRIPLE_$(1))) $$(Q)echo '#undef HAVE_ATOMIC_FUNCTIONS' >> \ $$(BACKTRACE_BUILD_DIR_$(1))/config.h diff --git a/mk/tests.mk b/mk/tests.mk index ea88a7d34f5..7f5dbeff1e4 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -299,9 +299,6 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-cfail-exec \ check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \ check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \ - check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \ - check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \ - check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \ check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \ check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \ check-stage$(1)-T-$(2)-H-$(3)-crates-exec \ @@ -317,6 +314,15 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ # able to build a compiler (when the target triple is in the set of host triples) ifneq ($$(findstring $(2),$$(CFG_HOST)),) +check-stage$(1)-T-$(2)-H-$(3)-exec: \ + check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \ + check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \ + check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec + +check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \ + check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \ + check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec + check-stage$(1)-T-$(2)-H-$(3)-crates-exec: \ $$(foreach crate,$$(TEST_CRATES), \ check-stage$(1)-T-$(2)-H-$(3)-$$(crate)-exec) @@ -340,9 +346,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-exec: \ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \ check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-exec \ check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-valgrind-exec \ - check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \ check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \ - check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \ check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec endef diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 6659894a171..5de7e6957c6 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -73,7 +73,8 @@ class RustBuild: if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): - shutil.rmtree(self.bin_root()) + if os.path.exists(self.bin_root()): + shutil.rmtree(self.bin_root()) filename = "rust-std-nightly-" + self.build + ".tar.gz" url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date() tarball = os.path.join(rustc_cache, filename) diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs index 3be4199352c..fb0a840bfa2 100644 --- a/src/bootstrap/build/compile.rs +++ b/src/bootstrap/build/compile.rs @@ -83,6 +83,19 @@ pub fn std_link(build: &Build, libdir.join(staticlib("compiler-rt", target)))); } add_to_sysroot(&out_dir, &libdir); + + if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + copy_third_party_objects(build, target, &libdir); + } +} + +/// Copies the crt(1,i,n).o startup objects +/// +/// Only required for musl targets that statically link to libc +fn copy_third_party_objects(build: &Build, target: &str, into: &Path) { + for &obj in &["crt1.o", "crti.o", "crtn.o"] { + t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj))); + } } /// Build and prepare startup objects like rsbegin.o and rsend.o diff --git a/src/bootstrap/build/sanity.rs b/src/bootstrap/build/sanity.rs index 6ac581a7c69..be4416c697c 100644 --- a/src/bootstrap/build/sanity.rs +++ b/src/bootstrap/build/sanity.rs @@ -79,7 +79,7 @@ pub fn check(build: &mut Build) { } // Make sure musl-root is valid if specified - if target.contains("musl") && target.contains("x86_64") { + if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { match build.config.musl_root { Some(ref root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { diff --git a/src/doc/book/iterators.md b/src/doc/book/iterators.md index 0c4f8041266..c174d2d6bac 100644 --- a/src/doc/book/iterators.md +++ b/src/doc/book/iterators.md @@ -14,6 +14,11 @@ Now that you know more Rust, we can talk in detail about how this works. Ranges (the `0..10`) are 'iterators'. An iterator is something that we can call the `.next()` method on repeatedly, and it gives us a sequence of things. +(By the way, a range with two dots like `0..10` is inclusive on the left (so it +starts at 0) and exclusive on the right (so it ends at 9). A mathematician +would write "[0, 10)". To get a range that goes all the way up to 10 you can +write `0...10`.) + Like this: ```rust diff --git a/src/doc/book/ownership.md b/src/doc/book/ownership.md index 70d71c14ddf..7f7f7d4c8eb 100644 --- a/src/doc/book/ownership.md +++ b/src/doc/book/ownership.md @@ -51,7 +51,7 @@ fn foo() { } ``` -When `v` comes into scope, a new [vector] is created on [the stack][stack], +When `v` comes into scope, a new [vector][vectors] is created on [the stack][stack], and it allocates space on [the heap][heap] for its elements. When `v` goes out of scope at the end of `foo()`, Rust will clean up everything related to the vector, even the heap-allocated memory. This happens deterministically, at the diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 0a4e09ed00a..7be5cc442dd 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system. Rust has a focus on safety and speed. It accomplishes these goals through many ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we’ll talk about in this guide +of a zero-cost abstraction. All of the analysis we’ll talk about in this guide is _done at compile time_. You do not pay any run-time cost for any of these features. diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 6782bdb4985..3e889f51f54 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -43,39 +43,40 @@ * `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). * `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). * `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). -* `%=` (`var %= expr`): arithmetic remainder & assignment. +* `%=` (`var %= expr`): arithmetic remainder & assignment. Overloadable (`RemAssign`). * `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`). * `&` (`&expr`): borrow. See [References and Borrowing]. * `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing]. -* `&=` (`var &= expr`): bitwise and & assignment. +* `&=` (`var &= expr`): bitwise and & assignment. Overloadable (`BitAndAssign`). * `&&` (`expr && expr`): logical and. * `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). * `*` (`*expr`): dereference. * `*` (`*const type`, `*mut type`): raw pointer. See [Raw Pointers]. -* `*=` (`var *= expr`): arithmetic multiplication & assignment. +* `*=` (`var *= expr`): arithmetic multiplication & assignment. Overloadable (`MulAssign`). * `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). * `+` (`trait + trait`, `'a + trait`): compound type constraint. See [Traits (Multiple Trait Bounds)]. -* `+=` (`var += expr`): arithmetic addition & assignment. +* `+=` (`var += expr`): arithmetic addition & assignment. Overloadable (`AddAssign`). * `,`: argument and element separator. See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)]. * `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). * `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). -* `-=` (`var -= expr`): arithmetic subtraction & assignment. +* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`). * `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. * `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions]. * `.` (`expr.ident`): member access. See [Structs], [Method Syntax]. * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. * `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)]. * `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)]. -* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)]. +* `...` (`...expr`, `expr...expr`) *in an expression*: inclusive range expression. See [Iterators]. +* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. See [Patterns (Ranges)]. * `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). -* `/=` (`var /= expr`): arithmetic division & assignment. +* `/=` (`var /= expr`): arithmetic division & assignment. Overloadable (`DivAssign`). * `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits]. * `:` (`ident: expr`): struct field initializer. See [Structs]. * `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)]. * `;`: statement and item terminator. * `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)]. * `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). -* `<<=` (`var <<= expr`): left-shift & assignment. +* `<<=` (`var <<= expr`): left-shift & assignment. Overloadable (`ShlAssign`). * `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). * `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`). * `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults. @@ -84,14 +85,14 @@ * `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). * `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`). * `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). -* `>>=` (`var >>= expr`): right-shift & assignment. +* `>>=` (`var >>= expr`): right-shift & assignment. Overloadable (`ShrAssign`). * `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)]. * `^` (`expr ^ expr`): bitwise exclusive or. Overloadable (`BitXor`). -* `^=` (`var ^= expr`): bitwise exclusive or & assignment. +* `^=` (`var ^= expr`): bitwise exclusive or & assignment. Overloadable (`BitXorAssign`). * `|` (`expr | expr`): bitwise or. Overloadable (`BitOr`). * `|` (`pat | pat`): pattern alternatives. See [Patterns (Multiple patterns)]. * `|` (`|…| expr`): closures. See [Closures]. -* `|=` (`var |= expr`): bitwise or & assignment. +* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. * `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. @@ -205,6 +206,7 @@ [Functions (Early Returns)]: functions.html#early-returns [Functions]: functions.html [Generics]: generics.html +[Iterators]: iterators.html [Lifetimes]: lifetimes.html [Loops (`for`)]: loops.html#for [Loops (`loop`)]: loops.html#loop diff --git a/src/doc/reference.md b/src/doc/reference.md index 6fb8de78094..8e655ee22e3 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -379,6 +379,10 @@ Examples of integer literals of various forms: 0usize; // type usize ``` +Note that the Rust syntax considers `-1i8` as an application of the [unary minus +operator](#unary-operator-expressions) to an integer literal `1i8`, rather than +a single integer literal. + ##### Floating-point literals A _floating-point literal_ has one of two forms: @@ -1114,6 +1118,16 @@ type Point = (u8, u8); let p: Point = (41, 68); ``` +Currently a type alias to an enum type cannot be used to qualify the +constructors: + +``` +enum E { A } +type F = E; +let _: F = E::A; // OK +// let _: F = F::A; // Doesn't work +``` + ### Structs A _struct_ is a nominal [struct type](#struct-types) defined with the @@ -1191,7 +1205,8 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply called an enum variant. -Enums have a discriminant. You can assign them explicitly: +Each enum value has a _discriminant_ which is an integer associated to it. You +can specify it explicitly: ``` enum Foo { @@ -1199,10 +1214,15 @@ enum Foo { } ``` -If a discriminant isn't assigned, they start at zero, and add one for each +The right hand side of the specification is interpreted as an `isize` value, +but the compiler is allowed to use a smaller type in the actual memory layout. +The [`repr` attribute](#ffi-attributes) can be added in order to change +the type of the right hand side and specify the memory layout. + +If a discriminant isn't specified, they start at zero, and add one for each variant, in order. -You can cast an enum to get this value: +You can cast an enum to get its discriminant: ``` # enum Foo { Bar = 123 } @@ -2277,6 +2297,10 @@ The currently implemented features of the reference compiler are: `#[derive_Foo] #[derive_Bar]`, which can be user-defined syntax extensions. +* `inclusive_range_syntax` - Allows use of the `a...b` and `...b` syntax for inclusive ranges. + +* `inclusive_range` - Allows use of the types that represent desugared inclusive ranges. + * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics are inherently unstable and no promise about them is made. @@ -2747,13 +2771,34 @@ let y = 0..10; assert_eq!(x, y); ``` +Similarly, the `...` operator will construct an object of one of the +`std::ops::RangeInclusive` variants. + +``` +# #![feature(inclusive_range_syntax)] +1...2; // std::ops::RangeInclusive +...4; // std::ops::RangeToInclusive +``` + +The following expressions are equivalent. + +``` +# #![feature(inclusive_range_syntax, inclusive_range)] +let x = std::ops::RangeInclusive::NonEmpty {start: 0, end: 10}; +let y = 0...10; + +assert_eq!(x, y); +``` + ### Unary operator expressions Rust defines the following unary operators. They are all written as prefix operators, before the expression they apply to. * `-` - : Negation. May only be applied to numeric types. + : Negation. Signed integer types and floating-point types support negation. It + is an error to apply negation to unsigned types; for example, the compiler + rejects `-1u32`. * `*` : Dereference. When applied to a [pointer](#pointer-types) it denotes the pointed-to location. For pointers to mutable locations, the resulting diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py index e3aa4e688d3..0e0d4841063 100644 --- a/src/etc/platform-intrinsics/generator.py +++ b/src/etc/platform-intrinsics/generator.py @@ -691,7 +691,7 @@ def parse_args(): parser.add_argument('-o', '--out', type=argparse.FileType('w'), default=sys.stdout, help = 'File to output to (default stdout).') parser.add_argument('-i', '--info', type=argparse.FileType('r'), - help = 'File containing platform specific information to merge into' + help = 'File containing platform specific information to merge into ' 'the input files\' header.') parser.add_argument('in_', metavar="FILE", type=argparse.FileType('r'), nargs='+', help = 'JSON files to load') @@ -735,12 +735,12 @@ class CompilerDefs(object): use {{Intrinsic, i, i_, u, u_, f, v, v_, agg, p, void}}; use IntrinsicDef::Named; -use rustc::middle::ty; +use rustc::middle::ty::TyCtxt; // The default inlining settings trigger a pathological behaviour in // LLVM, which causes makes compilation very slow. See #28273. #[inline(never)] -pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {{ +pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> {{ if !name.starts_with("{0}") {{ return None }} Some(match &name["{0}".len()..] {{'''.format(platform.intrinsic_prefix()) diff --git a/src/etc/platform-intrinsics/x86/fma.json b/src/etc/platform-intrinsics/x86/fma.json new file mode 100644 index 00000000000..c922d166c8f --- /dev/null +++ b/src/etc/platform-intrinsics/x86/fma.json @@ -0,0 +1,47 @@ +{ + "llvm_prefix": "llvm.x86.fma.", + "intrinsics": [ + { + "intrinsic": "{0.width_mm}_fmadd_{0.data_type}", + "width": [128, 256], + "llvm": "vfmadd.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + }, + { + "intrinsic": "{0.width_mm}_fmaddsub_{0.data_type}", + "width": [128, 256], + "llvm": "vfmaddsub.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + }, + { + "intrinsic": "{0.width_mm}_fmsub_{0.data_type}", + "width": [128, 256], + "llvm": "vfmsub.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + }, + { + "intrinsic": "{0.width_mm}_fmsubadd_{0.data_type}", + "width": [128, 256], + "llvm": "vfmsubadd.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + }, + { + "intrinsic": "{0.width_mm}_fnmadd_{0.data_type}", + "width": [128, 256], + "llvm": "vfnmadd.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + }, + { + "intrinsic": "{0.width_mm}_fnmsub_{0.data_type}", + "width": [128, 256], + "llvm": "vfnmsub.{0.data_type_short}{0.width_suffix}", + "ret": "f(32-64)", + "args": ["0", "0", "0"] + } + ] +} diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 10b864a902d..5a7632868e4 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -398,7 +398,7 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); derived = load_properties("DerivedCoreProperties.txt", want_derived) scripts = load_properties("Scripts.txt", []) props = load_properties("PropList.txt", - ["White_Space", "Join_Control", "Noncharacter_Code_Point"]) + ["White_Space", "Join_Control", "Noncharacter_Code_Point", "Pattern_White_Space"]) norm_props = load_properties("DerivedNormalizationProps.txt", ["Full_Composition_Exclusion"]) @@ -408,7 +408,7 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); # category tables for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ ("derived_property", derived, want_derived), \ - ("property", props, ["White_Space"]): + ("property", props, ["White_Space", "Pattern_White_Space"]): emit_property_module(rf, name, cat, pfuns) # normalizations and conversions module diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 300142d5ec1..0293d5402c4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -92,16 +92,13 @@ #![feature(unsize)] #![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))] -#![cfg_attr(test, feature(test, rustc_private, box_heap))] +#![cfg_attr(test, feature(test, box_heap))] // Allow testing this library #[cfg(test)] #[macro_use] extern crate std; -#[cfg(test)] -#[macro_use] -extern crate log; // Heaps provided for low-level allocation strategies diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index c9508322a31..9e2090c3246 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -111,7 +111,7 @@ fn main() { println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); if target.contains("android") { println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("windows") { + } else if !target.contains("windows") && !target.contains("musl") { println!("cargo:rustc-link-lib=pthread"); } } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 2a950ce0ab7..1967f83ab27 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -58,6 +58,74 @@ use self::Entry::*; /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the `Ord` trait, changes while it is in the map. This is /// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// +/// # Examples +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `BTreeMap<&str, &str>` in this example). +/// let mut movie_reviews = BTreeMap::new(); +/// +/// // review some books. +/// movie_reviews.insert("Office Space", "Deals with real issues in the workplace."); +/// movie_reviews.insert("Pulp Fiction", "Masterpiece."); +/// movie_reviews.insert("The Godfather", "Very enjoyable."); +/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot."); +/// +/// // check for a specific one. +/// if !movie_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// movie_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// movie_reviews.remove("The Blues Brothers"); +/// +/// // look up the values associated with some keys. +/// let to_find = ["Up!", "Office Space"]; +/// for book in &to_find { +/// match movie_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // iterate over everything. +/// for (movie, review) in &movie_reviews { +/// println!("{}: \"{}\"", movie, review); +/// } +/// ``` +/// +/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `BTreeMap<&str, u8>` in this example). +/// let mut player_stats = BTreeMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BTreeMap<K, V> { root: node::Root<K, V>, @@ -276,6 +344,19 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { impl<K: Ord, V> BTreeMap<K, V> { /// Makes a new empty BTreeMap with a reasonable choice for B. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// + /// // entries can now be inserted into the empty map + /// map.insert(1, "a"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> BTreeMap<K, V> { BTreeMap { @@ -288,6 +369,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -309,6 +392,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -332,6 +417,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -352,6 +439,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -384,6 +473,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -414,6 +505,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -443,6 +536,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// #![feature(btree_range, collections_bound)] /// @@ -516,6 +611,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// #![feature(btree_range, collections_bound)] /// @@ -591,6 +688,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1199,6 +1298,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1229,6 +1330,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1262,6 +1365,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1281,6 +1386,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1300,6 +1407,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// @@ -1317,6 +1426,8 @@ impl<K, V> BTreeMap<K, V> { /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::collections::BTreeMap; /// diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 97b01a607f5..435c9f0e9f4 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -429,20 +429,20 @@ //! For example, these: //! //! ``` -//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)} +//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)} //! println!("Hello {0} is {1:.5}", "x", 0.01); //! -//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)} +//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)} //! println!("Hello {1} is {2:.0$}", 5, "x", 0.01); //! -//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)} +//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)} //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {second of next two args (0.01} with precision +//! // Hello {next arg (x)} is {second of next two args (0.01) with precision //! // specified in first of next two args (5)} //! println!("Hello {} is {:.*}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {arg 2 (0.01} with precision +//! // Hello {next arg (x)} is {arg 2 (0.01) with precision //! // specified in its predecessor (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); //! ``` diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index e6cf5aa6683..922e1b0fc5d 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -40,7 +40,7 @@ #![feature(fmt_internals)] #![feature(fmt_radix)] #![feature(heap_api)] -#![feature(iter_arith)] +#![feature(inclusive_range)] #![feature(iter_arith)] #![feature(lang_items)] #![feature(nonzero)] diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index afcd779ddf1..4e39191b472 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -35,6 +35,7 @@ pub trait RangeArgument<T> { } } +// FIXME add inclusive ranges to RangeArgument impl<T> RangeArgument<T> for RangeFull {} diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index a30ec452e3c..5789cd8edfc 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unicode string slices +//! Unicode string slices. //! //! *[See also the `str` primitive type](../primitive.str.html).* diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 62ae7938e15..cae6520bdb2 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -59,7 +59,7 @@ use core::fmt; use core::hash; use core::iter::FromIterator; use core::mem; -use core::ops::{self, Add}; +use core::ops::{self, Add, Index, IndexMut}; use core::ptr; use core::slice; use core::str::pattern::Pattern; @@ -1606,6 +1606,24 @@ impl ops::Index<ops::RangeFull> for String { unsafe { str::from_utf8_unchecked(&self.vec) } } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl ops::Index<ops::RangeInclusive<usize>> for String { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeInclusive<usize>) -> &str { + Index::index(&**self, index) + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl ops::Index<ops::RangeToInclusive<usize>> for String { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeToInclusive<usize>) -> &str { + Index::index(&**self, index) + } +} #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut<ops::Range<usize>> for String { @@ -1635,6 +1653,20 @@ impl ops::IndexMut<ops::RangeFull> for String { unsafe { mem::transmute(&mut *self.vec) } } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl ops::IndexMut<ops::RangeInclusive<usize>> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str { + IndexMut::index_mut(&mut **self, index) + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl ops::IndexMut<ops::RangeToInclusive<usize>> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str { + IndexMut::index_mut(&mut **self, index) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for String { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index efcb5d2ceb3..934a9f3d614 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1226,6 +1226,24 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> { self } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> { + type Output = [T]; + + #[inline] + fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] { + Index::index(&**self, index) + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> { + type Output = [T]; + + #[inline] + fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] { + Index::index(&**self, index) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> { @@ -1255,6 +1273,20 @@ impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> { self } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> { + #[inline] + fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] { + IndexMut::index_mut(&mut **self, index) + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> { + #[inline] + fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] { + IndexMut::index_mut(&mut **self, index) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl<T> ops::Deref for Vec<T> { diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index eed530d8b61..f52ed8ff43d 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -23,7 +23,6 @@ #![feature(iter_arith)] #![feature(pattern)] #![feature(rand)] -#![feature(rustc_private)] #![feature(set_recovery)] #![feature(slice_bytes)] #![feature(step_by)] @@ -33,8 +32,6 @@ #![feature(unboxed_closures)] #![feature(unicode)] -#[macro_use] extern crate log; - extern crate collections; extern crate test; extern crate rustc_unicode; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index b84b37dbf75..776d73ef10f 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -346,6 +346,26 @@ fn test_slice_fail() { &"中华Việt Nam"[0..2]; } +const LOREM_PARAGRAPH: &'static str = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam."; + +// check the panic includes the prefix of the sliced string +#[test] +#[should_panic(expected="Lorem ipsum dolor sit amet")] +fn test_slice_fail_truncated_1() { + &LOREM_PARAGRAPH[..1024]; +} +// check the truncation in the panic message +#[test] +#[should_panic(expected="luctus, im`[...] do not lie on character boundary")] +fn test_slice_fail_truncated_2() { + &LOREM_PARAGRAPH[..1024]; +} + #[test] fn test_slice_from() { assert_eq!(&"abcd"[0..], "abcd"); @@ -606,8 +626,6 @@ fn vec_str_conversions() { while i < n1 { let a: u8 = s1.as_bytes()[i]; let b: u8 = s2.as_bytes()[i]; - debug!("{}", a); - debug!("{}", b); assert_eq!(a, b); i += 1; } diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 742205df8d7..95675a2423e 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -45,10 +45,6 @@ fn test_simple() { assert_eq!(d.len(), 3); d.push_front(1); assert_eq!(d.len(), 4); - debug!("{}", d[0]); - debug!("{}", d[1]); - debug!("{}", d[2]); - debug!("{}", d[3]); assert_eq!(d[0], 1); assert_eq!(d[1], 2); assert_eq!(d[2], 3); diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 769faedf46e..b1f63ad71ca 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The `Clone` trait for types that cannot be 'implicitly copied' +//! The `Clone` trait for types that cannot be 'implicitly copied'. //! //! In Rust, some simple types are "implicitly copyable" and when you //! assign them or pass them as arguments, the receiver will get a copy, diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index a3b09e9db42..6cc3b4e01b8 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for formatting and printing strings +//! Utilities for formatting and printing strings. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 37fe4d39db8..fb8eda820f5 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Composable external iteration +//! Composable external iteration. //! //! If you've found yourself with a collection of some kind, and needed to //! perform an operation on the elements of said collection, you'll quickly run @@ -306,7 +306,7 @@ use default::Default; use marker; use mem; use num::{Zero, One}; -use ops::{self, Add, Sub, FnMut, Mul, RangeFrom}; +use ops::{self, Add, Sub, FnMut, Mul}; use option::Option::{self, Some, None}; use marker::Sized; use usize; @@ -4297,7 +4297,7 @@ step_impl_no_between!(u64 i64); /// /// The resulting iterator handles overflow by stopping. The `A` /// parameter is the type being iterated over, while `R` is the range -/// type (usually one of `std::ops::{Range, RangeFrom}`. +/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`. #[derive(Clone)] #[unstable(feature = "step_by", reason = "recent addition", issue = "27741")] @@ -4306,7 +4306,7 @@ pub struct StepBy<A, R> { range: R, } -impl<A: Step> RangeFrom<A> { +impl<A: Step> ops::RangeFrom<A> { /// Creates an iterator starting at the same point, but stepping by /// the given amount at each iteration. /// @@ -4366,8 +4366,44 @@ impl<A: Step> ops::Range<A> { } } +impl<A: Step> ops::RangeInclusive<A> { + /// Creates an iterator with the same range, but stepping by the + /// given amount at each iteration. + /// + /// The resulting iterator handles overflow by stopping. + /// + /// # Examples + /// + /// ``` + /// #![feature(step_by, inclusive_range_syntax)] + /// + /// for i in (0...10).step_by(2) { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// 0 + /// 2 + /// 4 + /// 6 + /// 8 + /// 10 + /// ``` + #[unstable(feature = "step_by", reason = "recent addition", + issue = "27741")] + pub fn step_by(self, by: A) -> StepBy<A, Self> { + StepBy { + step_by: by, + range: self + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] -impl<A> Iterator for StepBy<A, RangeFrom<A>> where +impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> { @@ -4386,95 +4422,6 @@ impl<A> Iterator for StepBy<A, RangeFrom<A>> where } } -/// An iterator over the range [start, stop] -#[derive(Clone)] -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -pub struct RangeInclusive<A> { - range: ops::Range<A>, - done: bool, -} - -/// Returns an iterator over the range [start, stop]. -#[inline] -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A> - where A: Step + One + Clone -{ - RangeInclusive { - range: start..stop, - done: false, - } -} - -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -impl<A> Iterator for RangeInclusive<A> where - A: PartialEq + Step + One + Clone, - for<'a> &'a A: Add<&'a A, Output = A> -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option<A> { - self.range.next().or_else(|| { - if !self.done && self.range.start == self.range.end { - self.done = true; - Some(self.range.end.clone()) - } else { - None - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (lo, hi) = self.range.size_hint(); - if self.done { - (lo, hi) - } else { - let lo = lo.saturating_add(1); - let hi = hi.and_then(|x| x.checked_add(1)); - (lo, hi) - } - } -} - -#[unstable(feature = "range_inclusive", - reason = "likely to be replaced by range notation and adapters", - issue = "27777")] -#[rustc_deprecated(since = "1.5.0", reason = "replaced with ... syntax")] -#[allow(deprecated)] -impl<A> DoubleEndedIterator for RangeInclusive<A> where - A: PartialEq + Step + One + Clone, - for<'a> &'a A: Add<&'a A, Output = A>, - for<'a> &'a A: Sub<Output=A> -{ - #[inline] - fn next_back(&mut self) -> Option<A> { - if self.range.end > self.range.start { - let result = self.range.end.clone(); - self.range.end = &self.range.end - &A::one(); - Some(result) - } else if !self.done && self.range.start == self.range.end { - self.done = true; - Some(self.range.end.clone()) - } else { - None - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> { type Item = A; @@ -4512,10 +4459,83 @@ impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> { } } +#[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] +impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> { + type Item = A; + + #[inline] + fn next(&mut self) -> Option<A> { + use ops::RangeInclusive::*; + + // this function has a sort of odd structure due to borrowck issues + // we may need to replace self.range, so borrows of start and end need to end early + + let (finishing, n) = match self.range { + Empty { .. } => return None, // empty iterators yield no values + + NonEmpty { ref mut start, ref mut end } => { + let zero = A::zero(); + let rev = self.step_by < zero; + + // march start towards (maybe past!) end and yield the old value + if (rev && start >= end) || + (!rev && start <= end) + { + match start.step(&self.step_by) { + Some(mut n) => { + mem::swap(start, &mut n); + (None, Some(n)) // yield old value, remain non-empty + }, + None => { + let mut n = end.clone(); + mem::swap(start, &mut n); + (None, Some(n)) // yield old value, remain non-empty + } + } + } else { + // found range in inconsistent state (start at or past end), so become empty + (Some(mem::replace(end, zero)), None) + } + } + }; + + // turn into an empty iterator if we've reached the end + if let Some(end) = finishing { + self.range = Empty { at: end }; + } + + n + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + use ops::RangeInclusive::*; + + match self.range { + Empty { .. } => (0, Some(0)), + + NonEmpty { ref start, ref end } => + match Step::steps_between(start, + end, + &self.step_by) { + Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), + None => (0, None) + } + } + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for ops::Range<$t> { } + + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + impl ExactSizeIterator for ops::RangeInclusive<$t> { } )*) } @@ -4579,6 +4599,107 @@ impl<A: Step + One> Iterator for ops::RangeFrom<A> where } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<A: Step + One> Iterator for ops::RangeInclusive<A> where + for<'a> &'a A: Add<&'a A, Output = A> +{ + type Item = A; + + #[inline] + fn next(&mut self) -> Option<A> { + use ops::RangeInclusive::*; + + // this function has a sort of odd structure due to borrowck issues + // we may need to replace self, so borrows of self.start and self.end need to end early + + let (finishing, n) = match *self { + Empty { .. } => (None, None), // empty iterators yield no values + + NonEmpty { ref mut start, ref mut end } => { + if start == end { + (Some(mem::replace(end, A::one())), Some(mem::replace(start, A::one()))) + } else if start < end { + let one = A::one(); + let mut n = &*start + &one; + mem::swap(&mut n, start); + + // if the iterator is done iterating, it will change from NonEmpty to Empty + // to avoid unnecessary drops or clones, we'll reuse either start or end + // (they are equal now, so it doesn't matter which) + // to pull out end, we need to swap something back in -- use the previously + // created A::one() as a dummy value + + (if n == *end { Some(mem::replace(end, one)) } else { None }, + // ^ are we done yet? + Some(n)) // < the value to output + } else { + (Some(mem::replace(start, A::one())), None) + } + } + }; + + // turn into an empty iterator if this is the last value + if let Some(end) = finishing { + *self = Empty { at: end }; + } + + n + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + use ops::RangeInclusive::*; + + match *self { + Empty { .. } => (0, Some(0)), + + NonEmpty { ref start, ref end } => + match Step::steps_between(start, end, &A::one()) { + Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), + None => (0, None), + } + } + } +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<A: Step + One> DoubleEndedIterator for ops::RangeInclusive<A> where + for<'a> &'a A: Add<&'a A, Output = A>, + for<'a> &'a A: Sub<&'a A, Output = A> +{ + #[inline] + fn next_back(&mut self) -> Option<A> { + use ops::RangeInclusive::*; + + // see Iterator::next for comments + + let (finishing, n) = match *self { + Empty { .. } => return None, + + NonEmpty { ref mut start, ref mut end } => { + if start == end { + (Some(mem::replace(start, A::one())), Some(mem::replace(end, A::one()))) + } else if start < end { + let one = A::one(); + let mut n = &*end - &one; + mem::swap(&mut n, end); + + (if n == *start { Some(mem::replace(start, one)) } else { None }, + Some(n)) + } else { + (Some(mem::replace(end, A::one())), None) + } + } + }; + + if let Some(start) = finishing { + *self = Empty { at: start }; + } + + n + } +} + /// An iterator that repeats an element endlessly. /// /// This `struct` is created by the [`repeat()`] function. See its documentation for more. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index c36ad592ad3..2c648d1516b 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Basic functions for dealing with memory +//! Basic functions for dealing with memory. //! //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 0f5584a952f..5d6accc4438 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Overloadable operators +//! Overloadable operators. //! //! Implementing these traits allows you to get an effect similar to //! overloading operators. @@ -67,8 +67,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -use marker::{Sized, Unsize}; +use cmp::PartialOrd; use fmt; +use convert::From; +use marker::{Sized, Unsize}; +use num::One; /// The `Drop` trait is used to run some code when a value goes out of scope. /// This is sometimes called a 'destructor'. @@ -1445,7 +1448,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> { /// An unbounded range. #[derive(Copy, Clone, PartialEq, Eq)] -#[lang = "range_full"] +#[cfg_attr(stage0, lang = "range_full")] // FIXME remove attribute after next snapshot #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -1458,7 +1461,7 @@ impl fmt::Debug for RangeFull { /// A (half-open) range which is bounded at both ends. #[derive(Clone, PartialEq, Eq)] -#[lang = "range"] +#[cfg_attr(stage0, lang = "range")] // FIXME remove attribute after next snapshot #[stable(feature = "rust1", since = "1.0.0")] pub struct Range<Idx> { /// The lower bound of the range (inclusive). @@ -1478,7 +1481,7 @@ impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> { /// A range which is only bounded below. #[derive(Clone, PartialEq, Eq)] -#[lang = "range_from"] +#[cfg_attr(stage0, lang = "range_from")] // FIXME remove attribute after next snapshot #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom<Idx> { /// The lower bound of the range (inclusive). @@ -1495,7 +1498,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> { /// A range which is only bounded above. #[derive(Copy, Clone, PartialEq, Eq)] -#[lang = "range_to"] +#[cfg_attr(stage0, lang = "range_to")] // FIXME remove attribute after next snapshot #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo<Idx> { /// The upper bound of the range (exclusive). @@ -1510,6 +1513,90 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> { } } +/// An inclusive range which is bounded at both ends. +#[derive(Copy, Clone, PartialEq, Eq)] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub enum RangeInclusive<Idx> { + /// Empty range (iteration has finished) + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + Empty { + /// The point at which iteration finished + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + at: Idx + }, + /// Non-empty range (iteration will yield value(s)) + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + NonEmpty { + /// The lower bound of the range (inclusive). + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + start: Idx, + /// The upper bound of the range (inclusive). + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + end: Idx, + }, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use self::RangeInclusive::*; + + match *self { + Empty { ref at } => write!(fmt, "[empty range @ {:?}]", at), + NonEmpty { ref start, ref end } => write!(fmt, "{:?}...{:?}", start, end), + } + } +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<Idx: PartialOrd + One + Sub<Output=Idx>> From<Range<Idx>> for RangeInclusive<Idx> { + fn from(range: Range<Idx>) -> RangeInclusive<Idx> { + use self::RangeInclusive::*; + + if range.start < range.end { + NonEmpty { + start: range.start, + end: range.end - Idx::one() // can't underflow because end > start >= MIN + } + } else { + Empty { + at: range.start + } + } + } +} + +/// An inclusive range which is only bounded above. +#[derive(Copy, Clone, PartialEq, Eq)] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub struct RangeToInclusive<Idx> { + /// The upper bound of the range (inclusive) + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + pub end: Idx, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "...{:?}", self.end) + } +} + +// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>> +// because underflow would be possible with (..0).into() + /// The `Deref` trait is used to specify the functionality of dereferencing /// operations, like `*v`. /// diff --git a/src/libcore/option.rs b/src/libcore/option.rs index e38cf9af010..56b84fd6a64 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Optional values +//! Optional values. //! //! Type `Option` represents an optional value: every `Option` //! is either `Some` and contains a value, or `None`, and diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3cf722668b2..3cbeac450e2 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Raw, unsafe pointers, `*const T`, and `*mut T` +//! Raw, unsafe pointers, `*const T`, and `*mut T`. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* diff --git a/src/libcore/result.rs b/src/libcore/result.rs index f6703d16ad9..09f612c20ec 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Error handling with the `Result` type +//! Error handling with the `Result` type. //! //! `Result<T, E>` is the type used for returning and propagating //! errors. It is an enum with the variants, `Ok(T)`, representing diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index fb15533f33c..8acd0c8f2cf 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -533,6 +533,8 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } +// FIXME implement indexing with inclusive ranges + #[stable(feature = "rust1", since = "1.0.0")] impl<T> ops::Index<ops::Range<usize>> for [T] { type Output = [T]; @@ -558,7 +560,7 @@ impl<T> ops::Index<ops::RangeTo<usize>> for [T] { #[inline] fn index(&self, index: ops::RangeTo<usize>) -> &[T] { - self.index(ops::Range{ start: 0, end: index.end }) + self.index(0 .. index.end) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -567,7 +569,7 @@ impl<T> ops::Index<ops::RangeFrom<usize>> for [T] { #[inline] fn index(&self, index: ops::RangeFrom<usize>) -> &[T] { - self.index(ops::Range{ start: index.start, end: self.len() }) + self.index(index.start .. self.len()) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -580,6 +582,32 @@ impl<T> ops::Index<RangeFull> for [T] { } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] { + type Output = [T]; + + #[inline] + fn index(&self, index: ops::RangeInclusive<usize>) -> &[T] { + match index { + ops::RangeInclusive::Empty { .. } => &[], + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => + panic!("attempted to index slice up to maximum usize"), + ops::RangeInclusive::NonEmpty { start, end } => + self.index(start .. end+1) + } + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] { + type Output = [T]; + + #[inline] + fn index(&self, index: ops::RangeToInclusive<usize>) -> &[T] { + // SNAP 4d3eebf change this to `0...index.end` + self.index(ops::RangeInclusive::NonEmpty { start: 0, end: index.end }) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<T> ops::IndexMut<ops::Range<usize>> for [T] { #[inline] @@ -601,7 +629,7 @@ impl<T> ops::IndexMut<ops::Range<usize>> for [T] { impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] { - self.index_mut(ops::Range{ start: 0, end: index.end }) + self.index_mut(0 .. index.end) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -609,7 +637,7 @@ impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] { let len = self.len(); - self.index_mut(ops::Range{ start: index.start, end: len }) + self.index_mut(index.start .. len) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -620,6 +648,27 @@ impl<T> ops::IndexMut<RangeFull> for [T] { } } +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] { + #[inline] + fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] { + match index { + ops::RangeInclusive::Empty { .. } => &mut [], + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => + panic!("attempted to index slice up to maximum usize"), + ops::RangeInclusive::NonEmpty { start, end } => + self.index_mut(start .. end+1) + } + } +} +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] { + #[inline] + fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] { + // SNAP 4d3eebf change this to `0...index.end` + self.index_mut(ops::RangeInclusive::NonEmpty { start: 0, end: index.end }) + } +} //////////////////////////////////////////////////////////////////////////////// // Common traits diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 2d898b50e0c..f5abdf65a5b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1311,13 +1311,19 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[begin .. end]`. + /// /// Returns a slice of the given string from the byte range /// [`begin`..`end`). /// /// This operation is `O(1)`. /// - /// Panics when `begin` and `end` do not point to valid characters - /// or point beyond the last character of the string. + /// # Panics + /// + /// Panics if `begin` or `end` does not point to the starting + /// byte offset of a character (as defined by `is_char_boundary`). + /// Requires that `begin <= end` and `end <= len` where `len` is the + /// length of the string. /// /// # Examples /// @@ -1353,8 +1359,20 @@ mod traits { } } + /// Implements mutable substring slicing with syntax + /// `&mut self[begin .. end]`. + /// /// Returns a mutable slice of the given string from the byte range /// [`begin`..`end`). + /// + /// This operation is `O(1)`. + /// + /// # Panics + /// + /// Panics if `begin` or `end` does not point to the starting + /// byte offset of a character (as defined by `is_char_boundary`). + /// Requires that `begin <= end` and `end <= len` where `len` is the + /// length of the string. #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut<ops::Range<usize>> for str { #[inline] @@ -1370,13 +1388,12 @@ mod traits { } } - /// Returns a slice of the string from the beginning to byte - /// `end`. + /// Implements substring slicing with syntax `&self[.. end]`. /// - /// Equivalent to `self[0 .. end]`. + /// Returns a slice of the string from the beginning to byte offset + /// `end`. /// - /// Panics when `end` does not point to a valid character, or is - /// out of bounds. + /// Equivalent to `&self[0 .. end]`. #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index<ops::RangeTo<usize>> for str { type Output = str; @@ -1392,8 +1409,12 @@ mod traits { } } - /// Returns a mutable slice of the string from the beginning to byte + /// Implements mutable substring slicing with syntax `&mut self[.. end]`. + /// + /// Returns a mutable slice of the string from the beginning to byte offset /// `end`. + /// + /// Equivalent to `&mut self[0 .. end]`. #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut<ops::RangeTo<usize>> for str { #[inline] @@ -1407,12 +1428,12 @@ mod traits { } } - /// Returns a slice of the string from `begin` to its end. + /// Implements substring slicing with syntax `&self[begin ..]`. /// - /// Equivalent to `self[begin .. self.len()]`. + /// Returns a slice of the string from byte offset `begin` + /// to the end of the string. /// - /// Panics when `begin` does not point to a valid character, or is - /// out of bounds. + /// Equivalent to `&self[begin .. len]`. #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index<ops::RangeFrom<usize>> for str { type Output = str; @@ -1428,7 +1449,12 @@ mod traits { } } - /// Returns a slice of the string from `begin` to its end. + /// Implements mutable substring slicing with syntax `&mut self[begin ..]`. + /// + /// Returns a mutable slice of the string from byte offset `begin` + /// to the end of the string. + /// + /// Equivalent to `&mut self[begin .. len]`. #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut<ops::RangeFrom<usize>> for str { #[inline] @@ -1443,6 +1469,12 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[..]`. + /// + /// Returns a slice of the whole string. This operation can + /// never panic. + /// + /// Equivalent to `&self[0 .. len]`. #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index<ops::RangeFull> for str { type Output = str; @@ -1453,6 +1485,12 @@ mod traits { } } + /// Implements mutable substring slicing with syntax `&mut self[..]`. + /// + /// Returns a mutable slice of the whole string. This operation can + /// never panic. + /// + /// Equivalent to `&mut self[0 .. len]`. #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut<ops::RangeFull> for str { #[inline] @@ -1460,6 +1498,62 @@ mod traits { self } } + + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + impl ops::Index<ops::RangeInclusive<usize>> for str { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeInclusive<usize>) -> &str { + match index { + ops::RangeInclusive::Empty { .. } => "", + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => + panic!("attempted to index slice up to maximum usize"), + ops::RangeInclusive::NonEmpty { start, end } => + self.index(start .. end+1) + } + } + } + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + impl ops::Index<ops::RangeToInclusive<usize>> for str { + type Output = str; + + #[inline] + fn index(&self, index: ops::RangeToInclusive<usize>) -> &str { + // SNAP 4d3eebf change this to `0...index.end` + self.index(ops::RangeInclusive::NonEmpty { start: 0, end: index.end }) + } + } + + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + impl ops::IndexMut<ops::RangeInclusive<usize>> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str { + match index { + ops::RangeInclusive::Empty { .. } => &mut self[0..0], // `&mut ""` doesn't work + ops::RangeInclusive::NonEmpty { end, .. } if end == usize::max_value() => + panic!("attempted to index str up to maximum usize"), + ops::RangeInclusive::NonEmpty { start, end } => + self.index_mut(start .. end+1) + } + } + } + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + impl ops::IndexMut<ops::RangeToInclusive<usize>> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str { + // SNAP 4d3eebf change this to `0...index.end` + self.index_mut(ops::RangeInclusive::NonEmpty { start: 0, end: index.end }) + } + } } /// Methods for string slices @@ -1589,12 +1683,30 @@ pub trait StrExt { fn parse<T: FromStr>(&self) -> Result<T, T::Err>; } +// truncate `&str` to length at most equal to `max` +// return `true` if it were truncated, and the new str. +fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) { + if max >= s.len() { + (false, s) + } else { + while !s.is_char_boundary(max) { + max -= 1; + } + (true, &s[..max]) + } +} + #[inline(never)] #[cold] fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { - assert!(begin <= end); - panic!("index {} and/or {} in `{}` do not lie on character boundary", - begin, end, s); + const MAX_DISPLAY_LENGTH: usize = 256; + let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH); + let ellipsis = if truncated { "[...]" } else { "" }; + + assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}", + begin, end, s, ellipsis); + panic!("index {} and/or {} in `{}`{} do not lie on character boundary", + begin, end, s, ellipsis); } #[stable(feature = "core", since = "1.6.0")] diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index fe059076926..884f4490d9f 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -92,11 +92,6 @@ #![deny(missing_docs)] #![feature(staged_api)] #![feature(str_char)] -#![cfg_attr(test, feature(rustc_private))] - -#[cfg(test)] -#[macro_use] -extern crate log; use self::Name::*; use self::HasArg::*; @@ -1544,8 +1539,6 @@ Options: let generated_usage = usage("Usage: fruits", &optgroups); - debug!("expected: <<{}>>", expected); - debug!("generated: <<{}>>", generated_usage); assert_eq!(generated_usage, expected); } @@ -1573,8 +1566,6 @@ Options: let usage = usage("Usage: fruits", &optgroups); - debug!("expected: <<{}>>", expected); - debug!("generated: <<{}>>", usage); assert!(usage == expected) } @@ -1601,8 +1592,6 @@ Options: let usage = usage("Usage: fruits", &optgroups); - debug!("expected: <<{}>>", expected); - debug!("generated: <<{}>>", usage); assert!(usage == expected) } @@ -1617,8 +1606,6 @@ Options: let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string(); let generated_usage = short_usage("fruits", &optgroups); - debug!("expected: <<{}>>", expected); - debug!("generated: <<{}>>", generated_usage); assert_eq!(generated_usage, expected); } diff --git a/src/liblibc b/src/liblibc -Subproject 07a92067930670473dc53300dfdda23ff486344 +Subproject 2278a549559c38872b4338cb002ecc2a80d860d diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 531be63b7bb..e943f861e9d 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -36,16 +36,13 @@ #![feature(custom_attribute)] #![allow(unused_attributes)] -#![cfg_attr(test, feature(test, rand, rustc_private))] +#![cfg_attr(test, feature(test, rand))] #![allow(deprecated)] #[cfg(test)] #[macro_use] extern crate std; -#[cfg(test)] -#[macro_use] -extern crate log; use core::f64; use core::intrinsics; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4bb69a2688a..97a550a4076 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -148,6 +148,12 @@ declare_lint! { "uses of #[derive] with raw pointers are rarely correct" } +declare_lint! { + pub TRANSMUTE_FROM_FN_ITEM_TYPES, + Warn, + "transmute from function item type to pointer-sized type erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -177,7 +183,8 @@ impl LintPass for HardwiredLints { INVALID_TYPE_PARAM_DEFAULT, MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, CONST_ERR, - RAW_POINTER_DERIVE + RAW_POINTER_DERIVE, + TRANSMUTE_FROM_FN_ITEM_TYPES ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d492f692703..c11e9dc822e 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -489,9 +489,14 @@ pub trait LintContext: Sized { fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> { self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls { - &(Warn, src) => { + &(Warn, _) => { let lint_id = LintId::of(builtin::WARNINGS); - (self.lints().get_level_source(lint_id).0, src) + let warn_src = self.lints().get_level_source(lint_id); + if warn_src.0 != Warn { + warn_src + } else { + *ls + } } _ => *ls }) @@ -1282,6 +1287,9 @@ pub fn check_crate(tcx: &TyCtxt, access_levels: &AccessLevels) { } *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner(); + + // Put the lint store back in the session. + mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints); } pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index a6fb5c02f54..1fb27261c4d 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -317,12 +317,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprRange(ref start, ref end) => { - let fields = start.as_ref().map(|e| &**e).into_iter() - .chain(end.as_ref().map(|e| &**e)); - self.straightline(expr, pred, fields) - } - hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { self.call(expr, pred, &e, None::<hir::Expr>.iter()) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index be8793bac5d..1f79e76f3ac 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -344,6 +344,10 @@ fn check_arms(cx: &MatchCheckCtxt, hir::MatchSource::Normal => { span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern") }, + + hir::MatchSource::TryDesugar => { + cx.tcx.sess.span_bug(pat.span, "unreachable try pattern") + }, } } Useful => (), @@ -1047,10 +1051,7 @@ fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A> { let pats = Matrix(vec!(vec!(pat))); match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) { - UsefulWithWitness(pats) => { - assert_eq!(pats.len(), 1); - Some(refutable(&pats[0])) - }, + UsefulWithWitness(pats) => Some(refutable(&pats[0])), NotUseful => None, Useful => unreachable!() } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3af987df3a8..193492ee7e1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -137,6 +137,7 @@ pub trait CrateStore<'tcx> : Any { // item info fn stability(&self, def: DefId) -> Option<attr::Stability>; fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>; + fn visibility(&self, def: DefId) -> hir::Visibility; fn closure_kind(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureKind; fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) @@ -302,6 +303,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // item info fn stability(&self, def: DefId) -> Option<attr::Stability> { unimplemented!() } fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { unimplemented!() } + fn visibility(&self, def: DefId) -> hir::Visibility { unimplemented!() } fn closure_kind(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureKind { unimplemented!() } fn closure_ty(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index e3d05388f52..e6821cf639e 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -44,7 +44,8 @@ enum RootUnsafeContext { fn type_is_unsafe_function(ty: Ty) -> bool { match ty.sty { - ty::TyBareFn(_, ref f) => f.unsafety == hir::Unsafety::Unsafe, + ty::TyFnDef(_, _, ref f) | + ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe, _ => false, } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8b042e73e79..a87ce1206b4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -398,11 +398,6 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { } } - hir::ExprRange(ref start, ref end) => { - start.as_ref().map(|e| self.consume_expr(&e)); - end.as_ref().map(|e| self.consume_expr(&e)); - } - hir::ExprCall(ref callee, ref args) => { // callee(args) self.walk_callee(expr, &callee); self.consume_exprs(args); @@ -561,7 +556,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { callee, callee_ty); let call_scope = self.tcx().region_maps.node_extent(call.id); match callee_ty.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { self.consume_expr(callee); } ty::TyError => { } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index b64fa688d51..6c0dd9b608d 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -161,7 +161,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::TySlice(..) | ty::TyRawPtr(..) | ty::TyRef(..) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyTrait(..) | ty::TyStruct(..) | ty::TyClosure(..) | diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b9a5b32b71d..1e3546269db 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -454,7 +454,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, -> UnitResult<'tcx> { debug!("mk_eqty({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b)) + cx.eq_types(a_is_expected, origin, a, b) } pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -466,7 +466,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, { debug!("mk_eq_trait_refs({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.eq_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.eq_trait_refs(a_is_expected, origin, a, b) } pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -478,7 +478,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, { debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.sub_poly_trait_refs(a_is_expected, origin, a, b) } fn expected_found<T>(a_is_expected: bool, @@ -1351,18 +1351,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn report_mismatched_types(&self, - span: Span, + origin: TypeOrigin, expected: Ty<'tcx>, actual: Ty<'tcx>, - err: &TypeError<'tcx>) { + err: TypeError<'tcx>) { let trace = TypeTrace { - origin: TypeOrigin::Misc(span), + origin: origin, values: Types(ExpectedFound { expected: expected, found: actual }) }; - self.report_and_explain_type_error(trace, err); + self.report_and_explain_type_error(trace, &err); } pub fn report_conflicting_default_types(&self, diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 7de8904e3f2..fd857513e5b 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -12,7 +12,7 @@ use dep_graph::DepNode; use middle::def::Def; use middle::def_id::DefId; use middle::subst::{Subst, Substs, EnumeratedItems}; -use middle::ty::{TransmuteRestriction, TyCtxt, TyBareFn}; +use middle::ty::{TransmuteRestriction, TyCtxt}; use middle::ty::{self, Ty, TypeFoldable}; use std::fmt; @@ -53,7 +53,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty { - ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic, + ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; intrinsic && self.tcx.item_name(def_id).as_str() == "transmute" @@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { Def::Fn(did) if self.def_id_is_transmute(did) => { let typ = self.tcx.node_id_to_type(expr.id); match typ.sty { - TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { + ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { let from = bare_fn_ty.sig.0.inputs[0]; self.check_transmute(expr.span, from, to, expr.id); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 6cbb90627ea..c432095ff06 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -32,7 +32,6 @@ use util::nodemap::FnvHashMap; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use rustc_front::intravisit::Visitor; use rustc_front::hir; @@ -120,9 +119,9 @@ impl LanguageItems { pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> { let def_id_kinds = [ - (self.fn_trait(), ty::FnClosureKind), - (self.fn_mut_trait(), ty::FnMutClosureKind), - (self.fn_once_trait(), ty::FnOnceClosureKind), + (self.fn_trait(), ty::ClosureKind::Fn), + (self.fn_mut_trait(), ty::ClosureKind::FnMut), + (self.fn_once_trait(), ty::ClosureKind::FnOnce), ]; for &(opt_def_id, kind) in &def_id_kinds { @@ -158,7 +157,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { let item_index = self.item_refs.get(&value[..]).cloned(); if let Some(item_index) = item_index { - self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span) + self.collect_item(item_index, self.ast_map.local_def_id(item.id)) } } } @@ -180,15 +179,26 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { } pub fn collect_item(&mut self, item_index: usize, - item_def_id: DefId, span: Span) { + item_def_id: DefId) { // Check for duplicates. match self.items.items[item_index] { Some(original_def_id) if original_def_id != item_def_id => { let cstore = &self.session.cstore; - span_err!(self.session, span, E0152, - "duplicate entry for `{}`, first definition found in `{}`", - LanguageItems::item_name(item_index), - cstore.crate_name(item_def_id.krate)); + let span = self.ast_map.span_if_local(item_def_id) + .expect("we should have found local duplicate earlier"); + let mut err = struct_span_err!(self.session, + span, + E0152, + "duplicate lang item found: `{}`.", + LanguageItems::item_name(item_index)); + if let Some(span) = self.ast_map.span_if_local(original_def_id) { + span_note!(&mut err, span, + "first defined here."); + } else { + err.note(&format!("first defined in crate `{}`.", + cstore.crate_name(original_def_id.krate))); + } + err.emit(); } _ => { // OK. @@ -205,17 +215,18 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { pub fn collect_external_language_items(&mut self) { let cstore = &self.session.cstore; + for cnum in cstore.crates() { for (index, item_index) in cstore.lang_items(cnum) { let def_id = DefId { krate: cnum, index: index }; - self.collect_item(item_index, def_id, DUMMY_SP); + self.collect_item(item_index, def_id); } } } pub fn collect(&mut self, krate: &hir::Crate) { - self.collect_local_language_items(krate); self.collect_external_language_items(); + self.collect_local_language_items(krate); } } @@ -302,10 +313,6 @@ lets_do_this! { ShrAssignTraitLangItem, "shr_assign", shr_assign_trait; IndexTraitLangItem, "index", index_trait; IndexMutTraitLangItem, "index_mut", index_mut_trait; - RangeStructLangItem, "range", range_struct; - RangeFromStructLangItem, "range_from", range_from_struct; - RangeToStructLangItem, "range_to", range_to_struct; - RangeFullStructLangItem, "range_full", range_full_struct; UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 81f0cb1fbb2..04240bf2875 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -498,7 +498,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprInlineAsm(..) | hir::ExprBox(..) | - hir::ExprRange(..) | hir::ExprType(..) => { + hir::ExprType(..) => { intravisit::walk_expr(ir, expr); } } @@ -1086,11 +1086,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprAssignOp(_, ref l, ref r) => { - // see comment on lvalues in - // propagate_through_lvalue_components() - let succ = self.write_lvalue(&l, succ, ACC_WRITE|ACC_READ); - let succ = self.propagate_through_expr(&r, succ); - self.propagate_through_lvalue_components(&l, succ) + // an overloaded assign op is like a method call + if self.ir.tcx.is_method_call(expr.id) { + let succ = self.propagate_through_expr(&l, succ); + self.propagate_through_expr(&r, succ) + } else { + // see comment on lvalues in + // propagate_through_lvalue_components() + let succ = self.write_lvalue(&l, succ, ACC_WRITE|ACC_READ); + let succ = self.propagate_through_expr(&r, succ); + self.propagate_through_lvalue_components(&l, succ) + } } // Uninteresting cases: just propagate in rev exec order @@ -1154,11 +1160,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&l, r_succ) } - hir::ExprRange(ref e1, ref e2) => { - let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&e, succ)); - e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&e, succ)) - } - hir::ExprBox(ref e) | hir::ExprAddrOf(_, ref e) | hir::ExprCast(ref e, _) | @@ -1415,7 +1416,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } hir::ExprAssignOp(_, ref l, _) => { - this.check_lvalue(&l); + if !this.ir.tcx.is_method_call(expr.id) { + this.check_lvalue(&l); + } intravisit::walk_expr(this, expr); } @@ -1446,7 +1449,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { hir::ExprBlock(..) | hir::ExprAddrOf(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) | - hir::ExprRange(..) | hir::ExprType(..) => { + hir::ExprType(..) => { intravisit::walk_expr(this, expr); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 11ef1dbd705..9fc240fd495 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -526,7 +526,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { hir::ExprAddrOf(..) | hir::ExprCall(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprClosure(..) | hir::ExprRet(..) | - hir::ExprUnary(..) | hir::ExprRange(..) | + hir::ExprUnary(..) | hir::ExprMethodCall(..) | hir::ExprCast(..) | hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprBinary(..) | hir::ExprWhile(..) | @@ -670,13 +670,13 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { // conceptually a `&mut` or `&` reference, so we have to add a // deref. let cmt_result = match kind { - ty::FnOnceClosureKind => { + ty::ClosureKind::FnOnce => { cmt_result } - ty::FnMutClosureKind => { + ty::ClosureKind::FnMut => { self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result) } - ty::FnClosureKind => { + ty::ClosureKind::Fn => { self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result) } }; @@ -1630,9 +1630,9 @@ impl fmt::Debug for Upvar { impl fmt::Display for Upvar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let kind = match self.kind { - ty::FnClosureKind => "Fn", - ty::FnMutClosureKind => "FnMut", - ty::FnOnceClosureKind => "FnOnce", + ty::ClosureKind::Fn => "Fn", + ty::ClosureKind::FnMut => "FnMut", + ty::ClosureKind::FnOnce => "FnOnce", }; write!(f, "captured outer variable in an `{}` closure", kind) } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 9cc94402b16..02dfeb80b92 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -148,11 +148,11 @@ impl<'tcx> Substs<'tcx> { Substs { types: types, regions: regions } } - pub fn with_method_from(self, + pub fn with_method_from(&self, meth_substs: &Substs<'tcx>) -> Substs<'tcx> { - let Substs { types, regions } = self; + let Substs { types, regions } = self.clone(); let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace)); let regions = regions.map(|r| { r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace)) diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index b0970457892..b79849e87ff 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -301,7 +301,8 @@ fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>, ty::TyUint(..) | ty::TyFloat(..) | ty::TyStr | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyArray(..) | ty::TySlice(..) | ty::TyRawPtr(..) | diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f0ff0380aaa..8a2f0c0c093 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> { #[derive(Clone, PartialEq, Eq)] pub struct VtableImplData<'tcx, N> { pub impl_def_id: DefId, - pub substs: subst::Substs<'tcx>, + pub substs: &'tcx subst::Substs<'tcx>, pub nested: Vec<N> } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index b19771420bd..e36307feddb 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>( for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { if assoc_ty.name == obligation.predicate.item_name { - return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs), + return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs), impl_vtable.nested); } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 373ec37663f..2ecfa119007 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1286,7 +1286,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // provide an impl, but only for suitable `fn` pointers - ty::TyBareFn(_, &ty::BareFnTy { + ty::TyFnDef(_, _, &ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: _, + output: ty::FnConverging(_), + variadic: false + }) + }) | + ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1646,7 +1655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyChar => { // safe for everything ok_if(Vec::new()) @@ -1850,7 +1860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyStr | ty::TyError | ty::TyInfer(ty::IntVar(_)) | @@ -2294,7 +2305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_obligations.append(&mut substs.obligations); VtableImplData { impl_def_id: impl_def_id, - substs: substs.value, + substs: self.tcx().mk_substs(substs.value), nested: impl_obligations } } diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs index 453420e2a54..903b7c80baf 100644 --- a/src/librustc/middle/traits/structural_impls.rs +++ b/src/librustc/middle/traits/structural_impls.rs @@ -147,9 +147,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { + let substs = self.substs.fold_with(folder); traits::VtableImplData { impl_def_id: self.impl_def_id, - substs: self.substs.fold_with(folder), + substs: folder.tcx().mk_substs(substs), nested: self.nested.fold_with(folder), } } diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs index 40581cfa1c5..e4c293a74e8 100644 --- a/src/librustc/middle/ty/adjustment.rs +++ b/src/librustc/middle/ty/adjustment.rs @@ -155,8 +155,8 @@ impl<'tcx> ty::TyS<'tcx> { match *adjustment { AdjustReifyFnPointer => { match self.sty { - ty::TyBareFn(Some(_), b) => { - cx.mk_fn(None, b) + ty::TyFnDef(_, _, b) => { + cx.mk_ty(ty::TyFnPtr(b)) } _ => { cx.sess.bug( @@ -168,7 +168,7 @@ impl<'tcx> ty::TyS<'tcx> { AdjustUnsafeFnPointer => { match self.sty { - ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), + ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b), ref b => { cx.sess.bug( &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \ diff --git a/src/librustc/middle/ty/cast.rs b/src/librustc/middle/ty/cast.rs index 8233b6b2b2b..b25d6e0476d 100644 --- a/src/librustc/middle/ty/cast.rs +++ b/src/librustc/middle/ty/cast.rs @@ -69,7 +69,7 @@ impl<'tcx> CastTy<'tcx> { Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), - ty::TyBareFn(..) => Some(CastTy::FnPtr), + ty::TyFnPtr(..) => Some(CastTy::FnPtr), _ => None, } } diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs index 8dfa0262f2b..47a15a14b41 100644 --- a/src/librustc/middle/ty/contents.rs +++ b/src/librustc/middle/ty/contents.rs @@ -187,7 +187,7 @@ impl<'tcx> ty::TyS<'tcx> { // Scalar and unique types are sendable, and durable ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyBareFn(..) | ty::TyChar => { + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { TC::None } diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index ffc52af19bb..61a7f49f45d 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -41,7 +41,6 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell, Ref}; use std::hash::{Hash, Hasher}; use std::rc::Rc; -use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::special_idents; @@ -734,8 +733,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn print_debug_stats(&self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait, - TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); + TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); println!("Substs interner: #{}", self.substs_interner.borrow().len()); println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len()); @@ -792,12 +791,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Create an unsafe fn ty based on a safe fn ty. pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal); - let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy { + self.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: bare_fn.abi, sig: bare_fn.sig.clone() - }); - self.mk_fn(None, unsafe_fn_ty_a) + }) } pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { @@ -946,26 +944,14 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(TyBool) } - pub fn mk_fn(&self, - opt_def_id: Option<DefId>, - fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyBareFn(opt_def_id, fty)) - } - - pub fn mk_ctor_fn(&self, - def_id: DefId, - input_tys: &[Ty<'tcx>], - output: Ty<'tcx>) -> Ty<'tcx> { - let input_args = input_tys.iter().cloned().collect(); - self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: ty::FnConverging(output), - variadic: false - }) - })) + pub fn mk_fn_def(&self, def_id: DefId, + substs: &'tcx Substs<'tcx>, + fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty))) + } + + pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnPtr(self.mk_bare_fn(fty))) } pub fn mk_trait(&self, diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs index 39a5069e129..1033af5f331 100644 --- a/src/librustc/middle/ty/error.rs +++ b/src/librustc/middle/ty/error.rs @@ -223,8 +223,8 @@ impl<'tcx> ty::TyS<'tcx> { ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), ty::TyRef(_, _) => "&-ptr".to_string(), - ty::TyBareFn(Some(_), _) => format!("fn item"), - ty::TyBareFn(None, _) => "fn pointer".to_string(), + ty::TyFnDef(..) => format!("fn item"), + ty::TyFnPtr(_) => "fn pointer".to_string(), ty::TyTrait(ref inner) => { format!("trait {}", cx.item_path_str(inner.principal_def_id())) } diff --git a/src/librustc/middle/ty/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs index a42e5fc2e85..fc4db22a8a6 100644 --- a/src/librustc/middle/ty/fast_reject.rs +++ b/src/librustc/middle/ty/fast_reject.rs @@ -83,7 +83,7 @@ pub fn simplify_type(tcx: &TyCtxt, ty::TyTuple(ref tys) => { Some(TupleSimplifiedType(tys.len())) } - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::TyProjection(_) | ty::TyParam(_) => { diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs index a0b03fe8126..c491bd6ca5e 100644 --- a/src/librustc/middle/ty/flags.rs +++ b/src/librustc/middle/ty/flags.rs @@ -134,7 +134,12 @@ impl FlagComputation { self.add_tys(&ts[..]); } - &ty::TyBareFn(_, ref f) => { + &ty::TyFnDef(_, substs, ref f) => { + self.add_substs(substs); + self.add_fn_sig(&f.sig); + } + + &ty::TyFnPtr(ref f) => { self.add_fn_sig(&f.sig); } } diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 85035b25001..2e38080bfb0 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use self::ImplOrTraitItemId::*; -pub use self::ClosureKind::*; pub use self::Variance::*; pub use self::DtorKind::*; pub use self::ImplOrTraitItemContainer::*; @@ -1699,19 +1698,19 @@ pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen // because the trait Fn is a subtrait of FnMut and so in turn, and // hence we order it so that Fn < FnMut < FnOnce. - FnClosureKind, - FnMutClosureKind, - FnOnceClosureKind, + Fn, + FnMut, + FnOnce, } impl ClosureKind { pub fn trait_did(&self, cx: &TyCtxt) -> DefId { let result = match *self { - FnClosureKind => cx.lang_items.require(FnTraitLangItem), - FnMutClosureKind => { + ClosureKind::Fn => cx.lang_items.require(FnTraitLangItem), + ClosureKind::FnMut => { cx.lang_items.require(FnMutTraitLangItem) } - FnOnceClosureKind => { + ClosureKind::FnOnce => { cx.lang_items.require(FnOnceTraitLangItem) } }; @@ -1725,12 +1724,12 @@ impl ClosureKind { /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { - (FnClosureKind, FnClosureKind) => true, - (FnClosureKind, FnMutClosureKind) => true, - (FnClosureKind, FnOnceClosureKind) => true, - (FnMutClosureKind, FnMutClosureKind) => true, - (FnMutClosureKind, FnOnceClosureKind) => true, - (FnOnceClosureKind, FnOnceClosureKind) => true, + (ClosureKind::Fn, ClosureKind::Fn) => true, + (ClosureKind::Fn, ClosureKind::FnMut) => true, + (ClosureKind::Fn, ClosureKind::FnOnce) => true, + (ClosureKind::FnMut, ClosureKind::FnMut) => true, + (ClosureKind::FnMut, ClosureKind::FnOnce) => true, + (ClosureKind::FnOnce, ClosureKind::FnOnce) => true, _ => false, } } @@ -2008,7 +2007,6 @@ impl<'tcx> TyCtxt<'tcx> { hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprStruct(..) | - hir::ExprRange(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprMatch(..) | diff --git a/src/librustc/middle/ty/outlives.rs b/src/librustc/middle/ty/outlives.rs index fc20c1bcb85..9439180a6cd 100644 --- a/src/librustc/middle/ty/outlives.rs +++ b/src/librustc/middle/ty/outlives.rs @@ -182,7 +182,8 @@ fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, ty::TyRawPtr(..) | // ... ty::TyRef(..) | // OutlivesReference ty::TyTuple(..) | // ... - ty::TyBareFn(..) | // OutlivesFunction (*) + ty::TyFnDef(..) | // OutlivesFunction (*) + ty::TyFnPtr(_) | // OutlivesFunction (*) ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) ty::TyError => { // (*) Bare functions and traits are both binders. In the diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs index 5d6106a6d77..6da65c85f91 100644 --- a/src/librustc/middle/ty/relate.rs +++ b/src/librustc/middle/ty/relate.rs @@ -139,11 +139,11 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, relate_substs(relation, opt_variances, a_subst, b_subst) } -fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, - a_subst: &Substs<'tcx>, - b_subst: &Substs<'tcx>) - -> RelateResult<'tcx, Substs<'tcx>> +pub fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> where R: TypeRelation<'a,'tcx> { let mut substs = Substs::empty(); @@ -568,11 +568,19 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, } } - (&ty::TyBareFn(a_opt_def_id, a_fty), &ty::TyBareFn(b_opt_def_id, b_fty)) - if a_opt_def_id == b_opt_def_id => + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) + if a_def_id == b_def_id => { + let substs = try!(relate_substs(relation, None, a_substs, b_substs)); let fty = try!(relation.relate(a_fty, b_fty)); - Ok(tcx.mk_fn(a_opt_def_id, tcx.mk_bare_fn(fty))) + Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty)) + } + + (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) => + { + let fty = try!(relation.relate(a_fty, b_fty)); + Ok(tcx.mk_fn_ptr(fty)) } (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 001ea02a27c..3fe9e02a90d 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -282,9 +282,16 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)), - ty::TyBareFn(opt_def_id, ref f) => { + ty::TyFnDef(def_id, substs, ref f) => { + let substs = substs.fold_with(folder); + let bfn = f.fold_with(folder); + ty::TyFnDef(def_id, + folder.tcx().mk_substs(substs), + folder.tcx().mk_bare_fn(bfn)) + } + ty::TyFnPtr(ref f) => { let bfn = f.fold_with(folder); - ty::TyBareFn(opt_def_id, folder.tcx().mk_bare_fn(bfn)) + ty::TyFnPtr(folder.tcx().mk_bare_fn(bfn)) } ty::TyRef(r, ref tm) => { let r = r.fold_with(folder); @@ -318,7 +325,10 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), ty::TyTuple(ref ts) => ts.visit_with(visitor), - ty::TyBareFn(_opt_def_id, ref f) => f.visit_with(visitor), + ty::TyFnDef(_, substs, ref f) => { + substs.visit_with(visitor) || f.visit_with(visitor) + } + ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index c8f8e073832..2d7b7dc6e9b 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -127,14 +127,14 @@ pub enum TypeVariants<'tcx> { /// `&a mut T` or `&'a T`. TyRef(&'tcx Region, TypeAndMut<'tcx>), - /// If the def-id is Some(_), then this is the type of a specific - /// fn item. Otherwise, if None(_), it is a fn pointer type. - /// - /// FIXME: Conflating function pointers and the type of a - /// function is probably a terrible idea; a function pointer is a - /// value with a specific type, but a function can be polymorphic - /// or dynamically dispatched. - TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>), + /// The anonymous type of a function declaration/definition. Each + /// function has a unique type. + TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>), + + /// A pointer to a function. Written as `fn() -> i32`. + /// FIXME: This is currently also used to represent the callee of a method; + /// see ty::MethodCallee etc. + TyFnPtr(&'tcx BareFnTy<'tcx>), /// A trait, defined with `trait`. TyTrait(Box<TraitTy<'tcx>>), @@ -1029,7 +1029,7 @@ impl<'tcx> TyS<'tcx> { match self.sty { TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | - TyBareFn(..) | TyRawPtr(_) => true, + TyFnDef(..) | TyFnPtr(_) | TyRawPtr(_) => true, _ => false } } @@ -1080,20 +1080,6 @@ impl<'tcx> TyS<'tcx> { } } - pub fn is_bare_fn(&self) -> bool { - match self.sty { - TyBareFn(..) => true, - _ => false - } - } - - pub fn is_bare_fn_item(&self) -> bool { - match self.sty { - TyBareFn(Some(_), _) => true, - _ => false - } - } - pub fn is_fp(&self) -> bool { match self.sty { TyInfer(FloatVar(_)) | TyFloat(_) => true, @@ -1154,7 +1140,7 @@ impl<'tcx> TyS<'tcx> { pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> { match self.sty { - TyBareFn(_, ref f) => &f.sig, + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig, _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self) } } @@ -1162,7 +1148,7 @@ impl<'tcx> TyS<'tcx> { /// Returns the ABI of the given function. pub fn fn_abi(&self) -> abi::Abi { match self.sty { - TyBareFn(_, ref f) => f.abi, + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi, _ => panic!("Ty::fn_abi() called on non-fn type"), } } @@ -1178,7 +1164,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_fn(&self) -> bool { match self.sty { - TyBareFn(..) => true, + TyFnDef(..) | TyFnPtr(_) => true, _ => false } } @@ -1224,7 +1210,8 @@ impl<'tcx> TyS<'tcx> { TyProjection(ref data) => { data.trait_ref.substs.regions().as_slice().to_vec() } - TyBareFn(..) | + TyFnDef(..) | + TyFnPtr(_) | TyBool | TyChar | TyInt(_) | diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs index 7c32d931fff..2b83aaccdc4 100644 --- a/src/librustc/middle/ty/util.rs +++ b/src/librustc/middle/ty/util.rs @@ -514,9 +514,12 @@ impl<'tcx> TyCtxt<'tcx> { region(state, *r); mt(state, m); } - TyBareFn(opt_def_id, ref b) => { + TyFnDef(def_id, _, _) => { byte!(14); - hash!(opt_def_id); + hash!(def_id); + } + TyFnPtr(ref b) => { + byte!(15); hash!(b.unsafety); hash!(b.abi); fn_sig(state, &b.sig); @@ -599,14 +602,14 @@ impl<'tcx> TyCtxt<'tcx> { #[derive(Debug)] pub struct ImplMethod<'tcx> { pub method: Rc<ty::Method<'tcx>>, - pub substs: Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, pub is_provided: bool } impl<'tcx> TyCtxt<'tcx> { pub fn get_impl_method(&self, impl_def_id: DefId, - substs: Substs<'tcx>, + substs: &'tcx Substs<'tcx>, name: Name) -> ImplMethod<'tcx> { @@ -633,9 +636,10 @@ impl<'tcx> TyCtxt<'tcx> { if meth.name == name { let impl_to_trait_substs = self .make_substs_for_receiver_types(&trait_ref, meth); + let substs = impl_to_trait_substs.subst(self, substs); return ImplMethod { method: meth.clone(), - substs: impl_to_trait_substs.subst(self, &substs), + substs: self.mk_substs(substs), is_provided: true } } @@ -677,7 +681,7 @@ impl<'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { + TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { mutbl: hir::MutImmutable, .. }) => Some(false), @@ -719,7 +723,7 @@ impl<'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), TyStr | TyTrait(..) | TySlice(_) => Some(false), diff --git a/src/librustc/middle/ty/walk.rs b/src/librustc/middle/ty/walk.rs index 81cad448690..b6d93ecf78b 100644 --- a/src/librustc/middle/ty/walk.rs +++ b/src/librustc/middle/ty/walk.rs @@ -98,7 +98,11 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) { ty::TyTuple(ref ts) => { push_reversed(stack, ts); } - ty::TyBareFn(_, ref ft) => { + ty::TyFnDef(_, substs, ref ft) => { + push_reversed(stack, substs.types.as_slice()); + push_sig_subtypes(stack, &ft.sig); + } + ty::TyFnPtr(ref ft) => { push_sig_subtypes(stack, &ft.sig); } } diff --git a/src/librustc/middle/ty/wf.rs b/src/librustc/middle/ty/wf.rs index c6d1bc8d649..5f81d27a1f6 100644 --- a/src/librustc/middle/ty/wf.rs +++ b/src/librustc/middle/ty/wf.rs @@ -354,8 +354,8 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { // WFedness.) } - ty::TyBareFn(..) => { - // let the loop iterator into the argument/return + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // let the loop iterate into the argument/return // types appearing in the fn signature } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index ce7b1ceb355..4556611df59 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -861,20 +861,10 @@ impl<'tcx> Debug for TypedConstVal<'tcx> { } } -#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] -pub enum ItemKind { - Constant, - /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This - /// includes functions, constructors, but not methods which have their own ItemKind. - Function, - Method, -} - #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { Item { def_id: DefId, - kind: ItemKind, substs: &'tcx Substs<'tcx>, }, Value { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9c92208191e..8fd784cbde7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -13,7 +13,7 @@ use middle::def_id::DefId; use middle::subst::{self, Subst}; use middle::ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use middle::ty::{TyBool, TyChar, TyStruct, TyEnum}; -use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn}; +use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; use middle::ty::TyClosure; use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; @@ -812,7 +812,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } write!(f, ")") } - TyBareFn(opt_def_id, ref bare_fn) => { + TyFnDef(def_id, substs, ref bare_fn) => { if bare_fn.unsafety == hir::Unsafety::Unsafe { try!(write!(f, "unsafe ")); } @@ -822,13 +822,30 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } try!(write!(f, "{}", bare_fn.sig.0)); + try!(ty::tls::with(|tcx| { + write!(f, " {{{}", tcx.item_path_str(def_id)) + })); + + let tps = substs.types.get_slice(subst::FnSpace); + if tps.len() >= 1 { + try!(write!(f, "::<{}", tps[0])); + for &ty in &tps[1..] { + try!(write!(f, ", {}", ty)); + } + try!(write!(f, ">")); + } + write!(f, "}}") + } + TyFnPtr(ref bare_fn) => { + if bare_fn.unsafety == hir::Unsafety::Unsafe { + try!(write!(f, "unsafe ")); + } - if let Some(def_id) = opt_def_id { - try!(write!(f, " {{{}}}", ty::tls::with(|tcx| { - tcx.item_path_str(def_id) - }))); + if bare_fn.abi != Abi::Rust { + try!(write!(f, "extern {} ", bare_fn.abi)); } - Ok(()) + + write!(f, "{}", bare_fn.sig.0) } TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index b2911630991..b01b80b8133 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -243,7 +243,6 @@ mod svh_visitor { SawExprAssign, SawExprAssignOp(hir::BinOp_), SawExprIndex, - SawExprRange, SawExprPath(Option<usize>), SawExprAddrOf(hir::Mutability), SawExprRet, @@ -275,7 +274,6 @@ mod svh_visitor { ExprField(_, name) => SawExprField(name.node.as_str()), ExprTupField(_, id) => SawExprTupField(id.node), ExprIndex(..) => SawExprIndex, - ExprRange(..) => SawExprRange, ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), ExprAddrOf(m, _) => SawExprAddrOf(m), ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())), diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index ceaa6625fe2..cab8125a61b 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1009,7 +1009,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Categorization::Upvar(mc::Upvar { kind, .. }) => kind, _ => unreachable!() }; - if kind == ty::FnClosureKind { + if kind == ty::ClosureKind::Fn { db.span_help( self.tcx.map.span(upvar_id.closure_expr_id), "consider changing this closure to take \ diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 7b5dacece8c..3677c8c5e59 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -10,7 +10,7 @@ /// A very simple BitVector type. pub struct BitVector { - data: Vec<u64> + data: Vec<u64>, } impl BitVector { @@ -40,7 +40,9 @@ impl BitVector { for (i, j) in self.data.iter_mut().zip(&all.data) { let value = *i; *i = value | *j; - if value != *i { changed = true; } + if value != *i { + changed = true; + } } changed } @@ -56,7 +58,7 @@ impl BitVector { BitVectorIter { iter: self.data.iter(), current: 0, - idx: 0 + idx: 0, } } } @@ -64,7 +66,7 @@ impl BitVector { pub struct BitVectorIter<'a> { iter: ::std::slice::Iter<'a, u64>, current: u64, - idx: usize + idx: usize, } impl<'a> Iterator for BitVectorIter<'a> { @@ -108,7 +110,7 @@ impl BitMatrix { let u64s_per_elem = u64s(elements); BitMatrix { elements: elements, - vector: vec![0; elements * u64s_per_elem] + vector: vec![0; elements * u64s_per_elem], } } @@ -123,9 +125,9 @@ impl BitMatrix { let (start, _) = self.range(source); let (word, mask) = word_mask(target); let mut vector = &mut self.vector[..]; - let v1 = vector[start+word]; + let v1 = vector[start + word]; let v2 = v1 | mask; - vector[start+word] = v2; + vector[start + word] = v2; v1 != v2 } @@ -136,7 +138,7 @@ impl BitMatrix { pub fn contains(&self, source: usize, target: usize) -> bool { let (start, _) = self.range(source); let (word, mask) = word_mask(target); - (self.vector[start+word] & mask) != 0 + (self.vector[start + word] & mask) != 0 } /// Returns those indices that are reachable from both `a` and @@ -150,8 +152,12 @@ impl BitMatrix { for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() { let mut v = self.vector[i] & self.vector[j]; for bit in 0..64 { - if v == 0 { break; } - if v & 0x1 != 0 { result.push(base*64 + bit); } + if v == 0 { + break; + } + if v & 0x1 != 0 { + result.push(base * 64 + bit); + } v >>= 1; } } @@ -170,9 +176,7 @@ impl BitMatrix { let (write_start, write_end) = self.range(write); let vector = &mut self.vector[..]; let mut changed = false; - for (read_index, write_index) in - (read_start..read_end).zip(write_start..write_end) - { + for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) { let v1 = vector[write_index]; let v2 = v1 | vector[read_index]; vector[write_index] = v2; @@ -204,7 +208,8 @@ fn bitvec_iter_works() { bitvec.insert(65); bitvec.insert(66); bitvec.insert(99); - assert_eq!(bitvec.iter().collect::<Vec<_>>(), [1, 10, 19, 62, 63, 64, 65, 66, 99]); + assert_eq!(bitvec.iter().collect::<Vec<_>>(), + [1, 10, 19, 62, 63, 64, 65, 66, 99]); } #[test] @@ -217,7 +222,8 @@ fn bitvec_iter_works_2() { bitvec.insert(66); bitvec.insert(99); bitvec.insert(299); - assert_eq!(bitvec.iter().collect::<Vec<_>>(), [1, 10, 19, 62, 66, 99, 299]); + assert_eq!(bitvec.iter().collect::<Vec<_>>(), + [1, 10, 19, 62, 66, 99, 299]); } diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index da5f9f20892..0000c283a7a 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -36,7 +36,9 @@ pub struct FnvHasher(u64); impl Default for FnvHasher { #[inline] - fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) } + fn default() -> FnvHasher { + FnvHasher(0xcbf29ce484222325) + } } impl Hasher for FnvHasher { @@ -51,5 +53,7 @@ impl Hasher for FnvHasher { } #[inline] - fn finish(&self) -> u64 { self.0 } + fn finish(&self) -> u64 { + self.0 + } } diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index f11856d7513..99a87d1e760 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -38,9 +38,9 @@ use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; #[cfg(test)] mod tests; -pub struct Graph<N,E> { - nodes: SnapshotVec<Node<N>> , - edges: SnapshotVec<Edge<E>> , +pub struct Graph<N, E> { + nodes: SnapshotVec<Node<N>>, + edges: SnapshotVec<Edge<E>>, } pub struct Node<N> { @@ -71,9 +71,13 @@ impl<N> SnapshotVecDelegate for Edge<N> { impl<E: Debug> Debug for Edge<E> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", - self.next_edge[0], self.next_edge[1], self.source, - self.target, self.data) + write!(f, + "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", + self.next_edge[0], + self.next_edge[1], + self.source, + self.target, + self.data) } } @@ -87,7 +91,9 @@ pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); // Use a private field here to guarantee no more instances are created: #[derive(Copy, Clone, Debug, PartialEq)] -pub struct Direction { repr: usize } +pub struct Direction { + repr: usize, +} pub const OUTGOING: Direction = Direction { repr: 0 }; @@ -95,24 +101,27 @@ pub const INCOMING: Direction = Direction { repr: 1 }; impl NodeIndex { /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { self.0 } + pub fn node_id(&self) -> usize { + self.0 + } } impl EdgeIndex { /// Returns unique id (unique with respect to the graph holding associated edge). - pub fn edge_id(&self) -> usize { self.0 } + pub fn edge_id(&self) -> usize { + self.0 + } } -impl<N:Debug,E:Debug> Graph<N,E> { - pub fn new() -> Graph<N,E> { +impl<N: Debug, E: Debug> Graph<N, E> { + pub fn new() -> Graph<N, E> { Graph { nodes: SnapshotVec::new(), edges: SnapshotVec::new(), } } - /////////////////////////////////////////////////////////////////////////// - // Simple accessors + // # Simple accessors #[inline] pub fn all_nodes(&self) -> &[Node<N>] { @@ -134,8 +143,7 @@ impl<N:Debug,E:Debug> Graph<N,E> { self.edges.len() } - /////////////////////////////////////////////////////////////////////////// - // Node construction + // # Node construction pub fn next_node_index(&self) -> NodeIndex { NodeIndex(self.nodes.len()) @@ -145,7 +153,7 @@ impl<N:Debug,E:Debug> Graph<N,E> { let idx = self.next_node_index(); self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], - data: data + data: data, }); idx } @@ -162,26 +170,20 @@ impl<N:Debug,E:Debug> Graph<N,E> { &self.nodes[idx.0] } - /////////////////////////////////////////////////////////////////////////// - // Edge construction and queries + // # Edge construction and queries pub fn next_edge_index(&self) -> EdgeIndex { EdgeIndex(self.edges.len()) } - pub fn add_edge(&mut self, - source: NodeIndex, - target: NodeIndex, - data: E) -> EdgeIndex { + pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); let idx = self.next_edge_index(); // read current first of the list of edges from each node - let source_first = self.nodes[source.0] - .first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0] - .first_edge[INCOMING.repr]; + let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; + let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; // create the new edge, with the previous firsts from each node // as the next pointers @@ -189,7 +191,7 @@ impl<N:Debug,E:Debug> Graph<N,E> { next_edge: [source_first, target_first], source: source, target: target, - data: data + data: data, }); // adjust the firsts for each node target be the next object. @@ -227,46 +229,48 @@ impl<N:Debug,E:Debug> Graph<N,E> { self.edges[edge.0].next_edge[dir.repr] } - /////////////////////////////////////////////////////////////////////////// - // Iterating over nodes, edges + // # Iterating over nodes, edges - pub fn each_node<'a, F>(&'a self, mut f: F) -> bool where - F: FnMut(NodeIndex, &'a Node<N>) -> bool, + pub fn each_node<'a, F>(&'a self, mut f: F) -> bool + where F: FnMut(NodeIndex, &'a Node<N>) -> bool { //! Iterates over all edges defined in the graph. self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node)) } - pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge<E>) -> bool, + pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool + where F: FnMut(EdgeIndex, &'a Edge<E>) -> bool { //! Iterates over all edges defined in the graph self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge)) } - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N,E> { + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> { self.adjacent_edges(source, OUTGOING) } - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N,E> { + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> { self.adjacent_edges(source, INCOMING) } - pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N,E> { + pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges<N, E> { let first_edge = self.node(source).first_edge[direction.repr]; - AdjacentEdges { graph: self, direction: direction, next: first_edge } + AdjacentEdges { + graph: self, + direction: direction, + next: first_edge, + } } - pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N,E> { + pub fn successor_nodes(&self, source: NodeIndex) -> AdjacentTargets<N, E> { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N,E> { + pub fn predecessor_nodes(&self, target: NodeIndex) -> AdjacentSources<N, E> { self.incoming_edges(target).sources() } - /////////////////////////////////////////////////////////////////////////// - // Fixed-point iteration + // # Fixed-point iteration // // A common use for graphs in our compiler is to perform // fixed-point iteration. In this case, each edge represents a @@ -274,8 +278,8 @@ impl<N:Debug,E:Debug> Graph<N,E> { // variables or other bitsets. This method facilitates such a // computation. - pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) where - F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool, + pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) + where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool { let mut iteration = 0; let mut changed = true; @@ -288,7 +292,7 @@ impl<N:Debug,E:Debug> Graph<N,E> { } } - pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> { + pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal { graph: self, stack: vec![start], @@ -297,28 +301,28 @@ impl<N:Debug,E:Debug> Graph<N,E> { } } -/////////////////////////////////////////////////////////////////////////// -// Iterators +// # Iterators -pub struct AdjacentEdges<'g,N,E> - where N:'g, E:'g +pub struct AdjacentEdges<'g, N, E> + where N: 'g, + E: 'g { graph: &'g Graph<N, E>, direction: Direction, next: EdgeIndex, } -impl<'g,N,E> AdjacentEdges<'g,N,E> { - fn targets(self) -> AdjacentTargets<'g,N,E> { +impl<'g, N, E> AdjacentEdges<'g, N, E> { + fn targets(self) -> AdjacentTargets<'g, N, E> { AdjacentTargets { edges: self } } - fn sources(self) -> AdjacentSources<'g,N,E> { + fn sources(self) -> AdjacentSources<'g, N, E> { AdjacentSources { edges: self } } } -impl<'g, N:Debug, E:Debug> Iterator for AdjacentEdges<'g, N, E> { +impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { type Item = (EdgeIndex, &'g Edge<E>); fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> { @@ -333,13 +337,14 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentEdges<'g, N, E> { } } -pub struct AdjacentTargets<'g,N:'g,E:'g> - where N:'g, E:'g +pub struct AdjacentTargets<'g, N: 'g, E: 'g> + where N: 'g, + E: 'g { - edges: AdjacentEdges<'g,N,E>, + edges: AdjacentEdges<'g, N, E>, } -impl<'g, N:Debug, E:Debug> Iterator for AdjacentTargets<'g, N, E> { +impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> { type Item = NodeIndex; fn next(&mut self) -> Option<NodeIndex> { @@ -347,13 +352,14 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentTargets<'g, N, E> { } } -pub struct AdjacentSources<'g,N:'g,E:'g> - where N:'g, E:'g +pub struct AdjacentSources<'g, N: 'g, E: 'g> + where N: 'g, + E: 'g { - edges: AdjacentEdges<'g,N,E>, + edges: AdjacentEdges<'g, N, E>, } -impl<'g, N:Debug, E:Debug> Iterator for AdjacentSources<'g, N, E> { +impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> { type Item = NodeIndex; fn next(&mut self) -> Option<NodeIndex> { @@ -361,13 +367,13 @@ impl<'g, N:Debug, E:Debug> Iterator for AdjacentSources<'g, N, E> { } } -pub struct DepthFirstTraversal<'g, N:'g, E:'g> { +pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> { graph: &'g Graph<N, E>, stack: Vec<NodeIndex>, - visited: BitVector + visited: BitVector, } -impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> { +impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { type Item = NodeIndex; fn next(&mut self) -> Option<NodeIndex> { @@ -389,8 +395,8 @@ impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> { } } -pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) where - F: FnMut(EdgeIndex) -> bool, +pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) + where F: FnMut(EdgeIndex) -> bool { let mut i = 0; let n = max_edge_index.0; diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/tests.rs index 33b2edd2e10..be7f48d27e0 100644 --- a/src/librustc_data_structures/graph/tests.rs +++ b/src/librustc_data_structures/graph/tests.rs @@ -64,11 +64,11 @@ fn each_edge() { }); } -fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E,N)], - expected_outgoing: &[(E,N)]) { +fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(graph: &Graph<N, E>, + start_index: NodeIndex, + start_data: N, + expected_incoming: &[(E, N)], + expected_outgoing: &[(E, N)]) { assert!(graph.node_data(start_index) == &start_data); let mut counter = 0; @@ -76,7 +76,10 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>, assert!(graph.edge_data(edge_index) == &edge.data); assert!(counter < expected_incoming.len()); debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_incoming[counter], edge_index, edge); + counter, + expected_incoming[counter], + edge_index, + edge); match expected_incoming[counter] { (ref e, ref n) => { assert!(e == &edge.data); @@ -93,7 +96,10 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>, assert!(graph.edge_data(edge_index) == &edge.data); assert!(counter < expected_outgoing.len()); debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_outgoing[counter], edge_index, edge); + counter, + expected_outgoing[counter], + edge_index, + edge); match expected_outgoing[counter] { (ref e, ref n) => { assert!(e == &edge.data); @@ -109,31 +115,27 @@ fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>, #[test] fn each_adjacent_from_a() { let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", - &[], - &[("AB", "B")]); + test_adjacent_edges(&graph, NodeIndex(0), "A", &[], &[("AB", "B")]); } #[test] fn each_adjacent_from_b() { let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(1), "B", - &[("FB", "F"), ("AB", "A"),], - &[("BD", "D"), ("BC", "C"),]); + test_adjacent_edges(&graph, + NodeIndex(1), + "B", + &[("FB", "F"), ("AB", "A")], + &[("BD", "D"), ("BC", "C")]); } #[test] fn each_adjacent_from_c() { let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", - &[("EC", "E"), ("BC", "B")], - &[]); + test_adjacent_edges(&graph, NodeIndex(2), "C", &[("EC", "E"), ("BC", "B")], &[]); } #[test] fn each_adjacent_from_d() { let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", - &[("BD", "B")], - &[("DE", "E")]); + test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]); } diff --git a/src/librustc_data_structures/ivar.rs b/src/librustc_data_structures/ivar.rs index dabe1b984df..f842f4a41a1 100644 --- a/src/librustc_data_structures/ivar.rs +++ b/src/librustc_data_structures/ivar.rs @@ -26,14 +26,12 @@ use std::cell::Cell; /// suffices for the current purposes. #[derive(PartialEq)] pub struct Ivar<T: Copy> { - data: Cell<Option<T>> + data: Cell<Option<T>>, } impl<T: Copy> Ivar<T> { pub fn new() -> Ivar<T> { - Ivar { - data: Cell::new(None) - } + Ivar { data: Cell::new(None) } } pub fn get(&self) -> Option<T> { @@ -41,8 +39,7 @@ impl<T: Copy> Ivar<T> { } pub fn fulfill(&self, value: T) { - assert!(self.data.get().is_none(), - "Value already set!"); + assert!(self.data.get().is_none(), "Value already set!"); self.data.set(Some(value)); } @@ -55,11 +52,11 @@ impl<T: Copy> Ivar<T> { } } -impl<T: Copy+fmt::Debug> fmt::Debug for Ivar<T> { +impl<T: Copy + fmt::Debug> fmt::Debug for Ivar<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.get() { Some(val) => write!(f, "Ivar({:?})", val), - None => f.write_str("Ivar(<unfulfilled>)") + None => f.write_str("Ivar(<unfulfilled>)"), } } } @@ -68,7 +65,7 @@ impl<T: Copy> Clone for Ivar<T> { fn clone(&self) -> Ivar<T> { match self.get() { Some(val) => Ivar { data: Cell::new(Some(val)) }, - None => Ivar::new() + None => Ivar::new(), } } } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e4b13ff548a..2234325aa01 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -32,7 +32,8 @@ #![cfg_attr(test, feature(test))] extern crate core; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; extern crate serialize as rustc_serialize; // used by deriving pub mod bitvec; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 25a77adba28..4f6d0d7e405 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -28,7 +28,7 @@ use self::tree_index::TreeIndex; #[cfg(test)] mod test; -pub struct ObligationForest<O,T> { +pub struct ObligationForest<O, T> { /// The list of obligations. In between calls to /// `process_obligations`, this list only contains nodes in the /// `Pending` or `Success` state (with a non-zero number of @@ -43,7 +43,7 @@ pub struct ObligationForest<O,T> { /// backtrace iterator (which uses `split_at`). nodes: Vec<Node<O>>, trees: Vec<Tree<T>>, - snapshots: Vec<usize> + snapshots: Vec<usize>, } pub struct Snapshot { @@ -67,7 +67,9 @@ struct Node<O> { #[derive(Debug)] enum NodeState<O> { /// Obligation not yet resolved to success or error. - Pending { obligation: O }, + Pending { + obligation: O, + }, /// Obligation resolved to success; `num_incomplete_children` /// indicates the number of children still in an "incomplete" @@ -77,7 +79,10 @@ enum NodeState<O> { /// /// Once all children have completed, success nodes are removed /// from the vector by the compression step. - Success { obligation: O, num_incomplete_children: usize }, + Success { + obligation: O, + num_incomplete_children: usize, + }, /// This obligation was resolved to an error. Error nodes are /// removed from the vector by the compression step. @@ -85,13 +90,13 @@ enum NodeState<O> { } #[derive(Debug)] -pub struct Outcome<O,E> { +pub struct Outcome<O, E> { /// Obligations that were completely evaluated, including all /// (transitive) subobligations. pub completed: Vec<O>, /// Backtrace of obligations that were found to be in error. - pub errors: Vec<Error<O,E>>, + pub errors: Vec<Error<O, E>>, /// If true, then we saw no successful obligations, which means /// there is no point in further iteration. This is based on the @@ -103,7 +108,7 @@ pub struct Outcome<O,E> { } #[derive(Debug, PartialEq, Eq)] -pub struct Error<O,E> { +pub struct Error<O, E> { pub error: E, pub backtrace: Vec<O>, } @@ -113,7 +118,7 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { ObligationForest { trees: vec![], nodes: vec![], - snapshots: vec![] + snapshots: vec![], } } @@ -148,11 +153,12 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { // snapshot but pushing trees, all nodes after that should be // roots of other trees as well let first_root_index = self.trees[trees_len].root.get(); - debug_assert!( - self.nodes[first_root_index..] - .iter() - .zip(first_root_index..) - .all(|(root, root_index)| self.trees[root.tree.get()].root.get() == root_index)); + debug_assert!(self.nodes[first_root_index..] + .iter() + .zip(first_root_index..) + .all(|(root, root_index)| { + self.trees[root.tree.get()].root.get() == root_index + })); // Pop off tree/root pairs pushed during snapshot. self.trees.truncate(trees_len); @@ -169,14 +175,17 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { pub fn push_tree(&mut self, obligation: O, tree_state: T) { let index = NodeIndex::new(self.nodes.len()); let tree = TreeIndex::new(self.trees.len()); - self.trees.push(Tree { root: index, state: tree_state }); + self.trees.push(Tree { + root: index, + state: tree_state, + }); self.nodes.push(Node::new(tree, None, obligation)); } /// Convert all remaining obligations to the given error. /// /// This cannot be done during a snapshot. - pub fn to_errors<E:Clone>(&mut self, error: E) -> Vec<Error<O,E>> { + pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> { assert!(!self.in_snapshot()); let mut errors = vec![]; for index in 0..self.nodes.len() { @@ -184,7 +193,10 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { self.inherit_error(index); if let NodeState::Pending { .. } = self.nodes[index].state { let backtrace = self.backtrace(index); - errors.push(Error { error: error.clone(), backtrace: backtrace }); + errors.push(Error { + error: error.clone(), + backtrace: backtrace, + }); } } let successful_obligations = self.compress(); @@ -193,21 +205,27 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { } /// Returns the set of obligations that are in a pending state. - pub fn pending_obligations(&self) -> Vec<O> where O: Clone { - self.nodes.iter() - .filter_map(|n| match n.state { - NodeState::Pending { ref obligation } => Some(obligation), - _ => None, - }) - .cloned() - .collect() + pub fn pending_obligations(&self) -> Vec<O> + where O: Clone + { + self.nodes + .iter() + .filter_map(|n| { + match n.state { + NodeState::Pending { ref obligation } => Some(obligation), + _ => None, + } + }) + .cloned() + .collect() } /// Process the obligations. /// /// This CANNOT be unrolled (presently, at least). - pub fn process_obligations<E,F>(&mut self, mut action: F) -> Outcome<O,E> - where E: Debug, F: FnMut(&mut O, &mut T, Backtrace<O>) -> Result<Option<Vec<O>>, E> + pub fn process_obligations<E, F>(&mut self, mut action: F) -> Outcome<O, E> + where E: Debug, + F: FnMut(&mut O, &mut T, Backtrace<O>) -> Result<Option<Vec<O>>, E> { debug!("process_obligations(len={})", self.nodes.len()); assert!(!self.in_snapshot()); // cannot unroll this action @@ -228,7 +246,8 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { self.inherit_error(index); debug!("process_obligations: node {} == {:?}", - index, self.nodes[index].state); + index, + self.nodes[index].state); let result = { let Node { tree, parent, .. } = self.nodes[index]; @@ -236,14 +255,16 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { let backtrace = Backtrace::new(prefix, parent); match suffix[0].state { NodeState::Error | - NodeState::Success { .. } => - continue, - NodeState::Pending { ref mut obligation } => - action(obligation, &mut self.trees[tree.get()].state, backtrace), + NodeState::Success { .. } => continue, + NodeState::Pending { ref mut obligation } => { + action(obligation, &mut self.trees[tree.get()].state, backtrace) + } } }; - debug!("process_obligations: node {} got result {:?}", index, result); + debug!("process_obligations: node {} got result {:?}", + index, + result); match result { Ok(None) => { @@ -256,7 +277,10 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { } Err(err) => { let backtrace = self.backtrace(index); - errors.push(Error { error: err, backtrace: backtrace }); + errors.push(Error { + error: err, + backtrace: backtrace, + }); } } } @@ -291,20 +315,21 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { // create child work let tree_index = self.nodes[index].tree; let node_index = NodeIndex::new(index); - self.nodes.extend( - children.into_iter() - .map(|o| Node::new(tree_index, Some(node_index), o))); + self.nodes.extend(children.into_iter() + .map(|o| Node::new(tree_index, Some(node_index), o))); } // change state from `Pending` to `Success`, temporarily swapping in `Error` let state = mem::replace(&mut self.nodes[index].state, NodeState::Error); self.nodes[index].state = match state { - NodeState::Pending { obligation } => - NodeState::Success { obligation: obligation, - num_incomplete_children: num_incomplete_children }, + NodeState::Pending { obligation } => { + NodeState::Success { + obligation: obligation, + num_incomplete_children: num_incomplete_children, + } + } NodeState::Success { .. } | - NodeState::Error => - unreachable!() + NodeState::Error => unreachable!(), }; } @@ -358,14 +383,19 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { // there was an error in the ancestors, it should // have been propagated down and we should never // have tried to process this obligation - panic!("encountered error in node {:?} when collecting stack trace", p); + panic!("encountered error in node {:?} when collecting stack trace", + p); } } // loop to the parent match self.nodes[p].parent { - Some(q) => { p = q.get(); } - None => { return trace; } + Some(q) => { + p = q.get(); + } + None => { + return trace; + } } } } @@ -427,18 +457,19 @@ impl<O: Debug, T: Debug> ObligationForest<O, T> { // Pop off all the nodes we killed and extract the success // stories. - let successful = - (0 .. dead_nodes) - .map(|_| self.nodes.pop().unwrap()) - .flat_map(|node| match node.state { - NodeState::Error => None, - NodeState::Pending { .. } => unreachable!(), - NodeState::Success { obligation, num_incomplete_children } => { - assert_eq!(num_incomplete_children, 0); - Some(obligation) - } - }) - .collect(); + let successful = (0..dead_nodes) + .map(|_| self.nodes.pop().unwrap()) + .flat_map(|node| { + match node.state { + NodeState::Error => None, + NodeState::Pending { .. } => unreachable!(), + NodeState::Success { obligation, num_incomplete_children } => { + assert_eq!(num_incomplete_children, 0); + Some(obligation) + } + } + }) + .collect(); // Adjust the various indices, since we compressed things. for tree in &mut self.trees { @@ -484,7 +515,10 @@ pub struct Backtrace<'b, O: 'b> { impl<'b, O> Backtrace<'b, O> { fn new(nodes: &'b [Node<O>], pointer: Option<NodeIndex>) -> Backtrace<'b, O> { - Backtrace { nodes: nodes, pointer: pointer } + Backtrace { + nodes: nodes, + pointer: pointer, + } } } @@ -497,9 +531,7 @@ impl<'b, O> Iterator for Backtrace<'b, O> { self.pointer = self.nodes[p.get()].parent; match self.nodes[p.get()].state { NodeState::Pending { ref obligation } | - NodeState::Success { ref obligation, .. } => { - Some(obligation) - } + NodeState::Success { ref obligation, .. } => Some(obligation), NodeState::Error => { panic!("Backtrace encountered an error."); } diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index 465cee0b60c..1063bb3611e 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -13,19 +13,16 @@ use std::u32; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct NodeIndex { - index: NonZero<u32> + index: NonZero<u32>, } impl NodeIndex { pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); - unsafe { - NodeIndex { index: NonZero::new((value as u32) + 1) } - } + unsafe { NodeIndex { index: NonZero::new((value as u32) + 1) } } } pub fn get(self) -> usize { (*self.index - 1) as usize } } - diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs index 9a0a4218d45..a8c24270217 100644 --- a/src/librustc_data_structures/obligation_forest/test.rs +++ b/src/librustc_data_structures/obligation_forest/test.rs @@ -21,19 +21,23 @@ fn push_pop() { // A |-> A.1 // |-> A.2 // |-> A.3 - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations(|obligation, tree, _| { - assert_eq!(obligation.chars().next(), tree.chars().next()); - match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), - "B" => Err("B is for broken"), - "C" => Ok(Some(vec![])), - _ => unreachable!(), - } - }); + let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, + tree, + _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "B" => Err("B is for broken"), + "C" => Ok(Some(vec![])), + _ => unreachable!(), + } + }); assert_eq!(ok, vec!["C"]); - assert_eq!(err, vec![Error {error: "B is for broken", - backtrace: vec!["B"]}]); + assert_eq!(err, + vec![Error { + error: "B is for broken", + backtrace: vec!["B"], + }]); // second round: two delays, one success, creating an uneven set of subtasks: // A |-> A.1 @@ -61,33 +65,41 @@ fn push_pop() { // propagates to A.3.i, but not D.1 or D.2. // D |-> D.1 |-> D.1.i // |-> D.2 |-> D.2.i - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations(|obligation, tree, _| { - assert_eq!(obligation.chars().next(), tree.chars().next()); - match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Err("A is for apple"), - "D.1" => Ok(Some(vec!["D.1.i"])), - "D.2" => Ok(Some(vec!["D.2.i"])), - _ => unreachable!(), - } - }); + let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, + tree, + _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "A.1" => Ok(Some(vec![])), + "A.2" => Err("A is for apple"), + "D.1" => Ok(Some(vec!["D.1.i"])), + "D.2" => Ok(Some(vec!["D.2.i"])), + _ => unreachable!(), + } + }); assert_eq!(ok, vec!["A.1"]); - assert_eq!(err, vec![Error { error: "A is for apple", - backtrace: vec!["A.2", "A"] }]); + assert_eq!(err, + vec![Error { + error: "A is for apple", + backtrace: vec!["A.2", "A"], + }]); // fourth round: error in D.1.i that should propagate to D.2.i - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations(|obligation, tree, _| { - assert_eq!(obligation.chars().next(), tree.chars().next()); - match *obligation { - "D.1.i" => Err("D is for dumb"), - _ => panic!("unexpected obligation {:?}", obligation), - } - }); + let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(|obligation, + tree, + _| { + assert_eq!(obligation.chars().next(), tree.chars().next()); + match *obligation { + "D.1.i" => Err("D is for dumb"), + _ => panic!("unexpected obligation {:?}", obligation), + } + }); assert_eq!(ok, Vec::<&'static str>::new()); - assert_eq!(err, vec![Error { error: "D is for dumb", - backtrace: vec!["D.1.i", "D.1", "D"] }]); + assert_eq!(err, + vec![Error { + error: "D is for dumb", + backtrace: vec!["D.1.i", "D.1", "D"], + }]); } // Test that if a tree with grandchildren succeeds, everything is @@ -104,7 +116,7 @@ fn success_in_grandchildren() { forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, _| { + forest.process_obligations::<(), _>(|obligation, tree, _| { assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), @@ -115,7 +127,7 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, _| { + forest.process_obligations::<(), _>(|obligation, tree, _| { assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.1" => Ok(Some(vec![])), @@ -128,7 +140,7 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, _| { + forest.process_obligations::<(), _>(|obligation, tree, _| { assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.2.i" => Ok(Some(vec!["A.2.i.a"])), @@ -140,7 +152,7 @@ fn success_in_grandchildren() { assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, _| { + forest.process_obligations::<(), _>(|obligation, tree, _| { assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A.2.i.a" => Ok(Some(vec![])), @@ -150,8 +162,11 @@ fn success_in_grandchildren() { assert_eq!(ok, vec!["A.2.i.a", "A.2.i", "A.2", "A"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|_, _, _| unreachable!()); + let Outcome { completed: ok, errors: err, .. } = forest.process_obligations::<(), _>(|_, + _, + _| { + unreachable!() + }); assert!(ok.is_empty()); assert!(err.is_empty()); } @@ -163,7 +178,7 @@ fn to_errors_no_throw() { let mut forest = ObligationForest::new(); forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, _| { + forest.process_obligations::<(), _>(|obligation, tree, _| { assert_eq!(obligation.chars().next(), tree.chars().next()); match *obligation { "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), @@ -183,7 +198,7 @@ fn backtrace() { let mut forest = ObligationForest::new(); forest.push_tree("A", "A"); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| { assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().is_none()); match *obligation { @@ -194,7 +209,7 @@ fn backtrace() { assert!(ok.is_empty()); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| { assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().unwrap() == &"A"); assert!(backtrace.next().is_none()); @@ -206,7 +221,7 @@ fn backtrace() { assert!(ok.is_empty()); assert!(err.is_empty()); let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations::<(),_>(|obligation, tree, mut backtrace| { + forest.process_obligations::<(), _>(|obligation, tree, mut backtrace| { assert_eq!(obligation.chars().next(), tree.chars().next()); assert!(backtrace.next().unwrap() == &"A.1"); assert!(backtrace.next().unwrap() == &"A"); diff --git a/src/librustc_data_structures/obligation_forest/tree_index.rs b/src/librustc_data_structures/obligation_forest/tree_index.rs index a9f5483f45b..499448634ac 100644 --- a/src/librustc_data_structures/obligation_forest/tree_index.rs +++ b/src/librustc_data_structures/obligation_forest/tree_index.rs @@ -12,7 +12,7 @@ use std::u32; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TreeIndex { - index: u32 + index: u32, } impl TreeIndex { @@ -25,4 +25,3 @@ impl TreeIndex { self.index as usize } } - diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs index 5f89856afdb..614e7aae74b 100644 --- a/src/librustc_data_structures/snapshot_vec.rs +++ b/src/librustc_data_structures/snapshot_vec.rs @@ -23,7 +23,7 @@ use self::UndoLog::*; use std::mem; use std::ops; -pub enum UndoLog<D:SnapshotVecDelegate> { +pub enum UndoLog<D: SnapshotVecDelegate> { /// Indicates where a snapshot started. OpenSnapshot, @@ -37,10 +37,10 @@ pub enum UndoLog<D:SnapshotVecDelegate> { SetElem(usize, D::Value), /// Extensible set of actions - Other(D::Undo) + Other(D::Undo), } -pub struct SnapshotVec<D:SnapshotVecDelegate> { +pub struct SnapshotVec<D: SnapshotVecDelegate> { values: Vec<D::Value>, undo_log: Vec<UndoLog<D>>, } @@ -58,7 +58,7 @@ pub trait SnapshotVecDelegate { fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo); } -impl<D:SnapshotVecDelegate> SnapshotVec<D> { +impl<D: SnapshotVecDelegate> SnapshotVec<D> { pub fn new() -> SnapshotVec<D> { SnapshotVec { values: Vec::new(), @@ -117,9 +117,7 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> { Snapshot { length: length } } - pub fn actions_since_snapshot(&self, - snapshot: &Snapshot) - -> &[UndoLog<D>] { + pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog<D>] { &self.undo_log[snapshot.length..] } @@ -128,11 +126,10 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> { assert!(self.undo_log.len() > snapshot.length); // Invariant established by start_snapshot(): - assert!( - match self.undo_log[snapshot.length] { - OpenSnapshot => true, - _ => false - }); + assert!(match self.undo_log[snapshot.length] { + OpenSnapshot => true, + _ => false, + }); } pub fn rollback_to(&mut self, snapshot: Snapshot) { @@ -168,7 +165,10 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> { } let v = self.undo_log.pop().unwrap(); - assert!(match v { OpenSnapshot => true, _ => false }); + assert!(match v { + OpenSnapshot => true, + _ => false, + }); assert!(self.undo_log.len() == snapshot.length); } @@ -188,20 +188,28 @@ impl<D:SnapshotVecDelegate> SnapshotVec<D> { } } -impl<D:SnapshotVecDelegate> ops::Deref for SnapshotVec<D> { +impl<D: SnapshotVecDelegate> ops::Deref for SnapshotVec<D> { type Target = [D::Value]; - fn deref(&self) -> &[D::Value] { &*self.values } + fn deref(&self) -> &[D::Value] { + &*self.values + } } -impl<D:SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> { - fn deref_mut(&mut self) -> &mut [D::Value] { &mut *self.values } +impl<D: SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> { + fn deref_mut(&mut self) -> &mut [D::Value] { + &mut *self.values + } } -impl<D:SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> { +impl<D: SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> { type Output = D::Value; - fn index(&self, index: usize) -> &D::Value { self.get(index) } + fn index(&self, index: usize) -> &D::Value { + self.get(index) + } } -impl<D:SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> { - fn index_mut(&mut self, index: usize) -> &mut D::Value { self.get_mut(index) } +impl<D: SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> { + fn index_mut(&mut self, index: usize) -> &mut D::Value { + self.get_mut(index) + } } diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 7ea5cb8721d..c3a2f978e1a 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -14,7 +14,7 @@ use std::fmt::Debug; use std::mem; #[derive(Clone)] -pub struct TransitiveRelation<T:Debug+PartialEq> { +pub struct TransitiveRelation<T: Debug + PartialEq> { // List of elements. This is used to map from a T to a usize. We // expect domain to be small so just use a linear list versus a // hashmap or something. @@ -33,7 +33,7 @@ pub struct TransitiveRelation<T:Debug+PartialEq> { // are added with new elements. Perhaps better would be to ask the // user for a batch of edges to minimize this effect, but I // already wrote the code this way. :P -nmatsakis - closure: RefCell<Option<BitMatrix>> + closure: RefCell<Option<BitMatrix>>, } #[derive(Clone, PartialEq, PartialOrd)] @@ -45,11 +45,13 @@ struct Edge { target: Index, } -impl<T:Debug+PartialEq> TransitiveRelation<T> { +impl<T: Debug + PartialEq> TransitiveRelation<T> { pub fn new() -> TransitiveRelation<T> { - TransitiveRelation { elements: vec![], - edges: vec![], - closure: RefCell::new(None) } + TransitiveRelation { + elements: vec![], + edges: vec![], + closure: RefCell::new(None), + } } fn index(&self, a: &T) -> Option<Index> { @@ -74,7 +76,10 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> { pub fn add(&mut self, a: T, b: T) { let a = self.add_index(a); let b = self.add_index(b); - let edge = Edge { source: a, target: b }; + let edge = Edge { + source: a, + target: b, + }; if !self.edges.contains(&edge) { self.edges.push(edge); @@ -86,10 +91,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> { /// Check whether `a < target` (transitively) pub fn contains(&self, a: &T, b: &T) -> bool { match (self.index(a), self.index(b)) { - (Some(a), Some(b)) => - self.with_closure(|closure| closure.contains(a.0, b.0)), - (None, _) | (_, None) => - false, + (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)), + (None, _) | (_, None) => false, } } @@ -156,7 +159,9 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> { pub fn minimal_upper_bounds(&self, a: &T, b: &T) -> Vec<&T> { let (mut a, mut b) = match (self.index(a), self.index(b)) { (Some(a), Some(b)) => (a, b), - (None, _) | (_, None) => { return vec![]; } + (None, _) | (_, None) => { + return vec![]; + } }; // in some cases, there are some arbitrary choices to be made; @@ -233,7 +238,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> { .collect() } - fn with_closure<OP,R>(&self, op: OP) -> R + fn with_closure<OP, R>(&self, op: OP) -> R where OP: FnOnce(&BitMatrix) -> R { let mut closure_cell = self.closure.borrow_mut(); @@ -431,14 +436,15 @@ fn pdub_crisscross() { // b -> b1 ---+ let mut relation = TransitiveRelation::new(); - relation.add("a", "a1"); - relation.add("a", "b1"); - relation.add("b", "a1"); - relation.add("b", "b1"); + relation.add("a", "a1"); + relation.add("a", "b1"); + relation.add("b", "a1"); + relation.add("b", "b1"); relation.add("a1", "x"); relation.add("b1", "x"); - assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]); + assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), + vec![&"a1", &"b1"]); assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x")); } @@ -451,23 +457,25 @@ fn pdub_crisscross_more() { // b -> b1 -> b2 ---------+ let mut relation = TransitiveRelation::new(); - relation.add("a", "a1"); - relation.add("a", "b1"); - relation.add("b", "a1"); - relation.add("b", "b1"); + relation.add("a", "a1"); + relation.add("a", "b1"); + relation.add("b", "a1"); + relation.add("b", "b1"); - relation.add("a1", "a2"); - relation.add("a1", "b2"); - relation.add("b1", "a2"); - relation.add("b1", "b2"); + relation.add("a1", "a2"); + relation.add("a1", "b2"); + relation.add("b1", "a2"); + relation.add("b1", "b2"); relation.add("a2", "a3"); relation.add("a3", "x"); relation.add("b2", "x"); - assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"a1", &"b1"]); - assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), vec![&"a2", &"b2"]); + assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), + vec![&"a1", &"b1"]); + assert_eq!(relation.minimal_upper_bounds(&"a1", &"b1"), + vec![&"a2", &"b2"]); assert_eq!(relation.postdom_upper_bound(&"a", &"b"), Some(&"x")); } @@ -479,8 +487,8 @@ fn pdub_lub() { // b -> b1 ---+ let mut relation = TransitiveRelation::new(); - relation.add("a", "a1"); - relation.add("b", "b1"); + relation.add("a", "a1"); + relation.add("b", "b1"); relation.add("a1", "x"); relation.add("b1", "x"); @@ -497,9 +505,9 @@ fn mubs_intermediate_node_on_one_side_only() { // "digraph { a -> c -> d; b -> d; }", let mut relation = TransitiveRelation::new(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("b", "d"); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("b", "d"); assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"d"]); } @@ -516,11 +524,11 @@ fn mubs_scc_1() { // "digraph { a -> c -> d; d -> c; a -> d; b -> d; }", let mut relation = TransitiveRelation::new(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "c"); - relation.add("a", "d"); - relation.add("b", "d"); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("d", "c"); + relation.add("a", "d"); + relation.add("b", "d"); assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]); } @@ -536,11 +544,11 @@ fn mubs_scc_2() { // "digraph { a -> c -> d; d -> c; b -> d; b -> c; }", let mut relation = TransitiveRelation::new(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "c"); - relation.add("b", "d"); - relation.add("b", "c"); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("d", "c"); + relation.add("b", "d"); + relation.add("b", "c"); assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]); } @@ -556,12 +564,12 @@ fn mubs_scc_3() { // "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }", let mut relation = TransitiveRelation::new(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "e"); - relation.add("e", "c"); - relation.add("b", "d"); - relation.add("b", "e"); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("d", "e"); + relation.add("e", "c"); + relation.add("b", "d"); + relation.add("b", "e"); assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]); } @@ -578,12 +586,12 @@ fn mubs_scc_4() { // "digraph { a -> c -> d -> e -> c; a -> d; b -> e; }" let mut relation = TransitiveRelation::new(); - relation.add("a", "c"); - relation.add("c", "d"); - relation.add("d", "e"); - relation.add("e", "c"); - relation.add("a", "d"); - relation.add("b", "e"); + relation.add("a", "c"); + relation.add("c", "d"); + relation.add("d", "e"); + relation.add("e", "c"); + relation.add("a", "d"); + relation.add("b", "e"); assert_eq!(relation.minimal_upper_bounds(&"a", &"b"), vec![&"c"]); } diff --git a/src/librustc_data_structures/tuple_slice.rs b/src/librustc_data_structures/tuple_slice.rs index f157d82eda1..9a90ab8c09d 100644 --- a/src/librustc_data_structures/tuple_slice.rs +++ b/src/librustc_data_structures/tuple_slice.rs @@ -36,13 +36,13 @@ macro_rules! impl_tuple_slice { } } -impl_tuple_slice!((T,T), 2); -impl_tuple_slice!((T,T,T), 3); -impl_tuple_slice!((T,T,T,T), 4); -impl_tuple_slice!((T,T,T,T,T), 5); -impl_tuple_slice!((T,T,T,T,T,T), 6); -impl_tuple_slice!((T,T,T,T,T,T,T), 7); -impl_tuple_slice!((T,T,T,T,T,T,T,T), 8); +impl_tuple_slice!((T, T), 2); +impl_tuple_slice!((T, T, T), 3); +impl_tuple_slice!((T, T, T, T), 4); +impl_tuple_slice!((T, T, T, T, T), 5); +impl_tuple_slice!((T, T, T, T, T, T), 6); +impl_tuple_slice!((T, T, T, T, T, T, T), 7); +impl_tuple_slice!((T, T, T, T, T, T, T, T), 8); #[test] fn test_sliced_tuples() { diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index c6da70eef75..7a1ac830b22 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -56,21 +56,21 @@ impl Combine for () { /// time of the algorithm under control. For more information, see /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>. #[derive(PartialEq,Clone,Debug)] -pub struct VarValue<K:UnifyKey> { - parent: K, // if equal to self, this is a root +pub struct VarValue<K: UnifyKey> { + parent: K, // if equal to self, this is a root value: K::Value, // value assigned (only relevant to root) - rank: u32, // max depth (only relevant to root) + rank: u32, // max depth (only relevant to root) } /// Table of unification keys and their values. -pub struct UnificationTable<K:UnifyKey> { +pub struct UnificationTable<K: UnifyKey> { /// Indicates the current value of each key. values: sv::SnapshotVec<Delegate<K>>, } /// At any time, users may snapshot a unification table. The changes /// made during the snapshot may either be *committed* or *rolled back*. -pub struct Snapshot<K:UnifyKey> { +pub struct Snapshot<K: UnifyKey> { // Link snapshot to the key type `K` of the table. marker: marker::PhantomData<K>, snapshot: sv::Snapshot, @@ -79,15 +79,17 @@ pub struct Snapshot<K:UnifyKey> { #[derive(Copy, Clone)] struct Delegate<K>(PhantomData<K>); -impl<K:UnifyKey> VarValue<K> { +impl<K: UnifyKey> VarValue<K> { fn new_var(key: K, value: K::Value) -> VarValue<K> { VarValue::new(key, value, 0) } fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> { - VarValue { parent: parent, // this is a root - value: value, - rank: rank } + VarValue { + parent: parent, // this is a root + value: value, + rank: rank, + } } fn redirect(self, to: K) -> VarValue<K> { @@ -95,7 +97,11 @@ impl<K:UnifyKey> VarValue<K> { } fn root(self, rank: u32, value: K::Value) -> VarValue<K> { - VarValue { rank: rank, value: value, ..self } + VarValue { + rank: rank, + value: value, + ..self + } } /// Returns the key of this node. Only valid if this is a root @@ -122,18 +128,18 @@ impl<K:UnifyKey> VarValue<K> { // other type parameter U, and we have no way to say // Option<U>:LatticeValue. -impl<K:UnifyKey> UnificationTable<K> { +impl<K: UnifyKey> UnificationTable<K> { pub fn new() -> UnificationTable<K> { - UnificationTable { - values: sv::SnapshotVec::new() - } + UnificationTable { values: sv::SnapshotVec::new() } } /// Starts a new snapshot. Each snapshot must be either /// rolled back or committed in a "LIFO" (stack) order. pub fn snapshot(&mut self) -> Snapshot<K> { - Snapshot { marker: marker::PhantomData::<K>, - snapshot: self.values.start_snapshot() } + Snapshot { + marker: marker::PhantomData::<K>, + snapshot: self.values.start_snapshot(), + } } /// Reverses all changes since the last snapshot. Also @@ -154,9 +160,7 @@ impl<K:UnifyKey> UnificationTable<K> { let len = self.values.len(); let key: K = UnifyKey::from_index(len as u32); self.values.push(VarValue::new_var(key, value)); - debug!("{}: created new key: {:?}", - UnifyKey::tag(None::<K>), - key); + debug!("{}: created new key: {:?}", UnifyKey::tag(None::<K>), key); key } @@ -179,9 +183,7 @@ impl<K:UnifyKey> UnificationTable<K> { } root } - None => { - value - } + None => value, } } @@ -195,8 +197,7 @@ impl<K:UnifyKey> UnificationTable<K> { fn set(&mut self, key: K, new_value: VarValue<K>) { assert!(self.is_root(key)); - debug!("Updating variable {:?} to {:?}", - key, new_value); + debug!("Updating variable {:?} to {:?}", key, new_value); let index = key.index() as usize; self.values.set(index, new_value); @@ -243,17 +244,16 @@ impl<K:UnifyKey> UnificationTable<K> { } } -impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> { +impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> { type Value = VarValue<K>; type Undo = (); fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {} } -/////////////////////////////////////////////////////////////////////////// -// Base union-find algorithm, where we are just making sets +// # Base union-find algorithm, where we are just making sets -impl<'tcx,K:UnifyKey> UnificationTable<K> +impl<'tcx, K: UnifyKey> UnificationTable<K> where K::Value: Combine { pub fn union(&mut self, a_id: K, b_id: K) { @@ -280,35 +280,30 @@ impl<'tcx,K:UnifyKey> UnificationTable<K> } } -/////////////////////////////////////////////////////////////////////////// +// # Non-subtyping unification +// // Code to handle keys which carry a value, like ints, // floats---anything that doesn't have a subtyping relationship we // need to worry about. -impl<'tcx,K,V> UnificationTable<K> - where K: UnifyKey<Value=Option<V>>, - V: Clone+PartialEq+Debug, +impl<'tcx, K, V> UnificationTable<K> + where K: UnifyKey<Value = Option<V>>, + V: Clone + PartialEq + Debug { - pub fn unify_var_var(&mut self, - a_id: K, - b_id: K) - -> Result<(),(V,V)> - { + pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<(), (V, V)> { let node_a = self.get(a_id); let node_b = self.get(b_id); let a_id = node_a.key(); let b_id = node_b.key(); - if a_id == b_id { return Ok(()); } + if a_id == b_id { + return Ok(()); + } let combined = { match (&node_a.value, &node_b.value) { - (&None, &None) => { - None - } - (&Some(ref v), &None) | (&None, &Some(ref v)) => { - Some(v.clone()) - } + (&None, &None) => None, + (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(v.clone()), (&Some(ref v1), &Some(ref v2)) => { if *v1 != *v2 { return Err((v1.clone(), v2.clone())); @@ -323,11 +318,7 @@ impl<'tcx,K,V> UnificationTable<K> /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// relationships, if `a_id` already has a value, it must be the same as `b`. - pub fn unify_var_value(&mut self, - a_id: K, - b: V) - -> Result<(),(V,V)> - { + pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> { let mut node_a = self.get(a_id); match node_a.value { @@ -358,7 +349,13 @@ impl<'tcx,K,V> UnificationTable<K> pub fn unsolved_variables(&mut self) -> Vec<K> { self.values .iter() - .filter_map(|vv| if vv.value.is_some() { None } else { Some(vv.key()) }) + .filter_map(|vv| { + if vv.value.is_some() { + None + } else { + Some(vv.key()) + } + }) .collect() } } diff --git a/src/librustc_data_structures/unify/tests.rs b/src/librustc_data_structures/unify/tests.rs index 089e629a569..f29a7132e83 100644 --- a/src/librustc_data_structures/unify/tests.rs +++ b/src/librustc_data_structures/unify/tests.rs @@ -19,9 +19,15 @@ struct UnitKey(u32); impl UnifyKey for UnitKey { type Value = (); - fn index(&self) -> u32 { self.0 } - fn from_index(u: u32) -> UnitKey { UnitKey(u) } - fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" } + fn index(&self) -> u32 { + self.0 + } + fn from_index(u: u32) -> UnitKey { + UnitKey(u) + } + fn tag(_: Option<UnitKey>) -> &'static str { + "UnitKey" + } } #[test] @@ -45,7 +51,7 @@ fn big_array() { } for i in 1..MAX { - let l = keys[i-1]; + let l = keys[i - 1]; let r = keys[i]; ut.union(l, r); } @@ -68,7 +74,7 @@ fn big_array_bench(b: &mut Bencher) { b.iter(|| { for i in 1..MAX { - let l = keys[i-1]; + let l = keys[i - 1]; let r = keys[i]; ut.union(l, r); } @@ -90,16 +96,16 @@ fn even_odd() { keys.push(key); if i >= 2 { - ut.union(key, keys[i-2]); + ut.union(key, keys[i - 2]); } } for i in 1..MAX { - assert!(!ut.unioned(keys[i-1], keys[i])); + assert!(!ut.unioned(keys[i - 1], keys[i])); } for i in 2..MAX { - assert!(ut.unioned(keys[i-2], keys[i])); + assert!(ut.unioned(keys[i - 2], keys[i])); } } @@ -108,9 +114,15 @@ struct IntKey(u32); impl UnifyKey for IntKey { type Value = Option<i32>; - fn index(&self) -> u32 { self.0 } - fn from_index(u: u32) -> IntKey { IntKey(u) } - fn tag(_: Option<IntKey>) -> &'static str { "IntKey" } + fn index(&self) -> u32 { + self.0 + } + fn from_index(u: u32) -> IntKey { + IntKey(u) + } + fn tag(_: Option<IntKey>) -> &'static str { + "IntKey" + } } /// Test unifying a key whose value is `Some(_)` with a key whose value is `None`. @@ -191,4 +203,3 @@ fn unify_key_Some_x_val_x() { assert!(ut.unify_var_value(k1, 22).is_ok()); assert_eq!(ut.probe(k1), Some(22)); } - diff --git a/src/librustc_data_structures/veccell/mod.rs b/src/librustc_data_structures/veccell/mod.rs index 008642d9d65..054eee8829a 100644 --- a/src/librustc_data_structures/veccell/mod.rs +++ b/src/librustc_data_structures/veccell/mod.rs @@ -12,11 +12,11 @@ use std::cell::UnsafeCell; use std::mem; pub struct VecCell<T> { - data: UnsafeCell<Vec<T>> + data: UnsafeCell<Vec<T>>, } impl<T> VecCell<T> { - pub fn with_capacity(capacity: usize) -> VecCell<T>{ + pub fn with_capacity(capacity: usize) -> VecCell<T> { VecCell { data: UnsafeCell::new(Vec::with_capacity(capacity)) } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9c1be4c9f2f..55ec9d82a2e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -48,12 +48,10 @@ use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeIdAssigner}; -use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrMetaMethods}; use syntax::diagnostics; use syntax::fold::Folder; -use syntax::parse; -use syntax::parse::token; +use syntax::parse::{self, PResult, token}; use syntax::util::node_count::NodeCounter; use syntax::visit; use syntax; @@ -86,7 +84,13 @@ pub fn compile_input(sess: &Session, // possible to keep the peak memory usage low let (outputs, trans) = { let (outputs, expanded_crate, id) = { - let krate = phase_1_parse_input(sess, cfg, input); + let krate = match phase_1_parse_input(sess, cfg, input) { + Ok(krate) => krate, + Err(mut parse_error) => { + parse_error.emit(); + return Err(1); + } + }; controller_entry_point!(after_parse, sess, @@ -415,17 +419,20 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { } } -pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) -> ast::Crate { +pub fn phase_1_parse_input<'a>(sess: &'a Session, + cfg: ast::CrateConfig, + input: &Input) + -> PResult<'a, ast::Crate> { // These may be left in an incoherent state after a previous compile. // `clear_tables` and `get_ident_interner().clear()` can be used to free // memory, but they do not restore the initial state. syntax::ext::mtwt::reset_tables(); token::reset_ident_interner(); - let krate = time(sess.time_passes(), "parsing", || { + let krate = try!(time(sess.time_passes(), "parsing", || { match *input { Input::File(ref file) => { - parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess) + parse::parse_crate_from_file(file, cfg.clone(), &sess.parse_sess) } Input::Str(ref src) => { parse::parse_crate_from_source_str(anon_src().to_string(), @@ -434,7 +441,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) &sess.parse_sess) } } - }); + })); if sess.opts.debugging_opts.ast_json_noexpand { println!("{}", json::as_json(&krate)); @@ -449,7 +456,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) syntax::show_span::run(sess.diagnostic(), s, &krate); } - krate + Ok(krate) } fn count_nodes(krate: &ast::Crate) -> usize { @@ -761,7 +768,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, freevars, export_map, trait_map, - external_exports, glob_map, } = time(time_passes, "resolution", @@ -822,9 +828,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.access_levels = time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx, - &analysis.export_map, - external_exports) + rustc_privacy::check_crate(tcx, &analysis.export_map) }); // Do not move this check past lint diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index da565856a9f..d1c287b1e39 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -89,7 +89,7 @@ use std::thread; use rustc::session::{early_error, early_warn}; use syntax::ast; -use syntax::parse; +use syntax::parse::{self, PResult}; use syntax::errors; use syntax::errors::emitter::Emitter; use syntax::diagnostics; @@ -531,7 +531,19 @@ impl RustcDefaultCalls { return Compilation::Continue; } - let attrs = input.map(|input| parse_crate_attrs(sess, input)); + let attrs = match input { + None => None, + Some(input) => { + let result = parse_crate_attrs(sess, input); + match result { + Ok(attrs) => Some(attrs), + Err(mut parse_error) => { + parse_error.emit(); + return Compilation::Stop; + } + } + } + }; for req in &sess.opts.prints { match *req { PrintRequest::TargetList => { @@ -977,8 +989,8 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> { Some(matches) } -fn parse_crate_attrs(sess: &Session, input: &Input) -> Vec<ast::Attribute> { - let result = match *input { +fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> { + match *input { Input::File(ref ifile) => { parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess) } @@ -988,8 +1000,7 @@ fn parse_crate_attrs(sess: &Session, input: &Input) -> Vec<ast::Attribute> { Vec::new(), &sess.parse_sess) } - }; - result.into_iter().collect() + } } /// Run a procedure which will detect panics in the compiler and print nicer diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index eb4668e6abb..9f9824eae35 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -686,7 +686,7 @@ pub fn pretty_print_input(sess: Session, ppm: PpMode, opt_uii: Option<UserIdentifiedItem>, ofile: Option<PathBuf>) { - let krate = driver::phase_1_parse_input(&sess, cfg, input); + let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, input)); let krate = if let PpmSource(PpmEveryBodyLoops) = ppm { let mut fold = ReplaceBodyWithLoop::new(); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index abeaffe80ab..3cab9cfb88c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -114,7 +114,7 @@ fn test_env<F>(source_string: &str, rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let krate_config = Vec::new(); let input = config::Input::Str(source_string.to_string()); - let krate = driver::phase_1_parse_input(&sess, krate_config, &input); + let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap(); let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None) .expect("phase 2 aborted"); @@ -261,16 +261,15 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { let input_args = input_tys.iter().cloned().collect(); - self.infcx.tcx.mk_fn(None, - self.infcx.tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: ty::FnConverging(output_ty), - variadic: false, - }), - })) + self.infcx.tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: input_args, + output: ty::FnConverging(output_ty), + variadic: false, + }), + }) } pub fn t_nil(&self) -> Ty<'tcx> { diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index 75a1363fcf9..beedb3d70b6 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -1090,10 +1090,6 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: & ExprIndex(el, er) => { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) } - ExprRange(e1, e2) => { - ExprRange(e1.map(|x| folder.fold_expr(x)), - e2.map(|x| folder.fold_expr(x))) - } ExprPath(qself, path) => { let qself = qself.map(|QSelf { ty, position }| { QSelf { diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index cc562b0f7b2..ece62364376 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -776,8 +776,6 @@ pub enum Expr_ { ExprTupField(P<Expr>, Spanned<usize>), /// An indexing operation (`foo[2]`) ExprIndex(P<Expr>, P<Expr>), - /// A range (`1..2`, `1..`, or `..2`) - ExprRange(Option<P<Expr>>, Option<P<Expr>>), /// Variable reference, possibly containing `::` and/or type /// parameters, e.g. foo::bar::<baz>. @@ -837,6 +835,7 @@ pub enum MatchSource { }, WhileLetDesugar, ForLoopDesugar, + TryDesugar, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/librustc_front/intravisit.rs b/src/librustc_front/intravisit.rs index e6f448654ac..d71e392f521 100644 --- a/src/librustc_front/intravisit.rs +++ b/src/librustc_front/intravisit.rs @@ -784,10 +784,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } - ExprRange(ref start, ref end) => { - walk_list!(visitor, visit_expr, start); - walk_list!(visitor, visit_expr, end); - } ExprPath(ref maybe_qself, ref path) => { if let Some(ref qself) = *maybe_qself { visitor.visit_ty(&qself.ty); diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 1bfcb298586..291df66755e 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -65,6 +65,7 @@ use hir; use std::collections::BTreeMap; use std::collections::HashMap; +use std::iter; use syntax::ast::*; use syntax::attr::{ThinAttributes, ThinAttributesExt}; use syntax::ext::mtwt; @@ -1217,9 +1218,79 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> { ExprKind::Index(ref el, ref er) => { hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er)) } - ExprKind::Range(ref e1, ref e2) => { - hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)), - e2.as_ref().map(|x| lower_expr(lctx, x))) + ExprKind::Range(ref e1, ref e2, lims) => { + fn make_struct(lctx: &LoweringContext, + ast_expr: &Expr, + path: &[&str], + fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> { + let strs = std_path(lctx, &iter::once(&"ops") + .chain(path) + .map(|s| *s) + .collect::<Vec<_>>()); + + let structpath = path_global(ast_expr.span, strs); + + let hir_expr = if fields.len() == 0 { + expr_path(lctx, + structpath, + ast_expr.attrs.clone()) + } else { + expr_struct(lctx, + ast_expr.span, + structpath, + fields.into_iter().map(|&(s, e)| { + field(token::intern(s), + signal_block_expr(lctx, + hir_vec![], + lower_expr(lctx, &**e), + e.span, + hir::PopUnstableBlock, + None), + ast_expr.span) + }).collect(), + None, + ast_expr.attrs.clone()) + }; + + signal_block_expr(lctx, + hir_vec![], + hir_expr, + ast_expr.span, + hir::PushUnstableBlock, + None) + } + + return cache_ids(lctx, e.id, |lctx| { + use syntax::ast::RangeLimits::*; + + match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(lctx, e, &["RangeFull"], + &[]), + + (&Some(ref e1), &None, HalfOpen) => + make_struct(lctx, e, &["RangeFrom"], + &[("start", e1)]), + + (&None, &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["RangeTo"], + &[("end", e2)]), + + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["Range"], + &[("start", e1), ("end", e2)]), + + (&None, &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeToInclusive"], + &[("end", e2)]), + + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), + + _ => panic!("impossible range in AST"), + } + }); } ExprKind::Path(ref qself, ref path) => { let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { @@ -1534,6 +1605,63 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> { }); } + // Desugar ExprKind::Try + // From: `<expr>?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // { + // match <expr> { + // Ok(val) => val, + // Err(err) => { + // return Err(From::from(err)) + // } + // } + // } + + return cache_ids(lctx, e.id, |lctx| { + // expand <expr> + let sub_expr = lower_expr(lctx, sub_expr); + + // Ok(val) => val + let ok_arm = { + let val_ident = lctx.str_to_ident("val"); + let val_pat = pat_ident(lctx, e.span, val_ident); + let val_expr = expr_ident(lctx, e.span, val_ident, None); + let ok_pat = pat_ok(lctx, e.span, val_pat); + + arm(hir_vec![ok_pat], val_expr) + }; + + // Err(err) => return Err(From::from(err)) + let err_arm = { + let err_ident = lctx.str_to_ident("err"); + let from_expr = { + let path = std_path(lctx, &["convert", "From", "from"]); + let path = path_global(e.span, path); + let from = expr_path(lctx, path, None); + let err_expr = expr_ident(lctx, e.span, err_ident, None); + + expr_call(lctx, e.span, from, hir_vec![err_expr], None) + }; + let err_expr = { + let path = std_path(lctx, &["result", "Result", "Err"]); + let path = path_global(e.span, path); + let err_ctor = expr_path(lctx, path, None); + expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) + }; + let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident)); + let ret_expr = expr(lctx, e.span, + hir::Expr_::ExprRet(Some(err_expr)), None); + + arm(hir_vec![err_pat], ret_expr) + }; + + expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar, None) + }) + } + ExprKind::Mac(_) => panic!("Shouldn't exist here"), }, span: e.span, @@ -1627,6 +1755,17 @@ fn arm(pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { } } +fn field(name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field { + hir::Field { + name: Spanned { + node: name, + span: span, + }, + span: span, + expr: expr, + } +} + fn expr_break(lctx: &LoweringContext, span: Span, attrs: ThinAttributes) -> P<hir::Expr> { expr(lctx, span, hir::ExprBreak(None), attrs) @@ -1676,6 +1815,15 @@ fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec<P<hir::Expr>> expr(lctx, sp, hir::ExprTup(exprs), attrs) } +fn expr_struct(lctx: &LoweringContext, + sp: Span, + path: hir::Path, + fields: hir::HirVec<hir::Field>, + e: Option<P<hir::Expr>>, + attrs: ThinAttributes) -> P<hir::Expr> { + expr(lctx, sp, hir::ExprStruct(path, fields, e), attrs) +} + fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_, attrs: ThinAttributes) -> P<hir::Expr> { P(hir::Expr { @@ -1728,6 +1876,18 @@ fn block_all(lctx: &LoweringContext, }) } +fn pat_ok(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { + let ok = std_path(lctx, &["result", "Result", "Ok"]); + let path = path_global(span, ok); + pat_enum(lctx, span, path, hir_vec![pat]) +} + +fn pat_err(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { + let err = std_path(lctx, &["result", "Result", "Err"]); + let path = path_global(span, err); + pat_enum(lctx, span, path, hir_vec![pat]) +} + fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> { let some = std_path(lctx, &["option", "Option", "Some"]); let path = path_global(span, some); diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs index 49fbcea3dbf..143dfce09b6 100644 --- a/src/librustc_front/print/pprust.rs +++ b/src/librustc_front/print/pprust.rs @@ -1449,15 +1449,6 @@ impl<'a> State<'a> { try!(self.print_expr(&index)); try!(word(&mut self.s, "]")); } - hir::ExprRange(ref start, ref end) => { - if let &Some(ref e) = start { - try!(self.print_expr(&e)); - } - try!(word(&mut self.s, "..")); - if let &Some(ref e) = end { - try!(self.print_expr(&e)); - } - } hir::ExprPath(None, ref path) => { try!(self.print_path(path, true, 0)) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 86ab8d45e4e..0c906f8eb54 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1065,7 +1065,7 @@ impl LateLintPass for MutableTransmutes { } let typ = cx.tcx.node_id_to_type(expr.id); match typ.sty { - ty::TyBareFn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => { + ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn.sig.0.output { let from = bare_fn.sig.0.inputs[0]; return Some((&from.sty, &to.sty)); @@ -1079,7 +1079,7 @@ impl LateLintPass for MutableTransmutes { fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { match cx.tcx.lookup_item_type(def_id).ty.sty { - ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (), + ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false } cx.tcx.with_path(def_id, |path| match path.last() { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1cf0339c086..e47f67dad8f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -171,6 +171,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\ master/text/0218-empty-struct-with-braces.md>", }, + FutureIncompatibleInfo { + id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES), + reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>", + }, ]); // We have one lint pass defined specially diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index c7cb2d15a09..10535549ceb 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -391,7 +391,7 @@ fn is_repr_nullable_ptr<'tcx>(tcx: &TyCtxt<'tcx>, if def.variants[data_idx].fields.len() == 1 { match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyBareFn(None, _) => { return true; } + ty::TyFnPtr(_) => { return true; } ty::TyRef(..) => { return true; } _ => { } } @@ -556,7 +556,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.check_type_for_ffi(cache, ty) } - ty::TyBareFn(None, bare_fn) => { + ty::TyFnPtr(bare_fn) => { match bare_fn.abi { Abi::Rust | Abi::RustIntrinsic | @@ -595,7 +595,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | ty::TyClosure(..) | ty::TyProjection(..) | - ty::TyBareFn(Some(_), _) => { + ty::TyFnDef(..) => { panic!("Unexpected type in foreign function") } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 63db3d3c870..b3f24b8f16b 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -49,6 +49,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_deprecation(&cdata, def.index) } + fn visibility(&self, def: DefId) -> hir::Visibility { + let cdata = self.get_crate_data(def.krate); + decoder::get_visibility(&cdata, def.index) + } + fn closure_kind(&self, _tcx: &TyCtxt<'tcx>, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e286e028f33..06f81a17a06 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -472,7 +472,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, variant.name, ctor_ty); let field_tys = match ctor_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { ref inputs, .. }), ..}) => { // tuple-struct constructors don't have escaping regions @@ -545,6 +545,10 @@ pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option<attr::Deprecation> { }) } +pub fn get_visibility(cdata: Cmd, id: DefIndex) -> hir::Visibility { + item_visibility(cdata.lookup_item(id)) +} + pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> { let item = cdata.lookup_item(id); match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { @@ -988,7 +992,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>, let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); let ity = tcx.lookup_item_type(def_id).ty; let fty = match ity.sty { - ty::TyBareFn(_, fty) => fty.clone(), + ty::TyFnDef(_, _, fty) => fty.clone(), _ => tcx.sess.bug(&format!( "the type {:?} of the method {:?} is not a function?", ity, name)) @@ -1582,7 +1586,8 @@ pub fn is_extern_item(cdata: Cmd, id: DefIndex, tcx: &TyCtxt) -> bool { let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); let no_generics = generics.types.is_empty(); match ty.sty { - ty::TyBareFn(_, fn_ty) if fn_ty.abi != Abi::Rust => return no_generics, + ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) + if fn_ty.abi != Abi::Rust => return no_generics, _ => no_generics, } }, diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index bf5a97232fc..e9b23eb0458 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -380,10 +380,11 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'F' => { let def_id = self.parse_def(); - return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty())); + let substs = self.tcx.mk_substs(self.parse_substs()); + return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty()); } 'G' => { - return tcx.mk_fn(None, tcx.mk_bare_fn(self.parse_bare_fn_ty())); + return tcx.mk_fn_ptr(self.parse_bare_fn_ty()); } '#' => { // This is a hacky little caching scheme. The idea is that if we encode diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 7289cd2b5b3..a6601e591ab 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -135,12 +135,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyStr => { write!(w, "v"); } - ty::TyBareFn(Some(def_id), f) => { + ty::TyFnDef(def_id, substs, f) => { write!(w, "F"); write!(w, "{}|", (cx.ds)(def_id)); + enc_substs(w, cx, substs); enc_bare_fn_ty(w, cx, f); } - ty::TyBareFn(None, f) => { + ty::TyFnPtr(f) => { write!(w, "G"); enc_bare_fn_ty(w, cx, f); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ca00b99b108..a7f4a53b022 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -239,7 +239,9 @@ impl<'a,'tcx> Builder<'a,'tcx> { } ExprKind::Call { ty, fun, args } => { let diverges = match ty.sty { - ty::TyBareFn(_, ref f) => f.sig.0.output.diverges(), + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { + f.sig.0.output.diverges() + } _ => false }; let fun = unpack!(block = this.as_operand(block, fun)); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 5d040bcb40a..8c435b45dae 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -12,7 +12,6 @@ //! kind of thing. use build::Builder; -use hair::*; use rustc::middle::ty::Ty; use rustc::mir::repr::*; use std::u32; @@ -59,16 +58,4 @@ impl<'a,'tcx> Builder<'a,'tcx> { }); temp } - - pub fn item_ref_operand(&mut self, - span: Span, - item_ref: ItemRef<'tcx>) - -> Operand<'tcx> { - let literal = Literal::Item { - def_id: item_ref.def_id, - kind: item_ref.kind, - substs: item_ref.substs, - }; - self.literal_operand(span, item_ref.ty, literal) - } } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 6b1b3a33d3d..3d14ad2374b 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -503,7 +503,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { ty: self.hir.tcx().lookup_item_type(funcdid).ty, literal: Literal::Item { def_id: funcdid, - kind: ItemKind::Function, substs: self.hir.tcx().mk_substs(Substs::empty()) } } @@ -641,7 +640,6 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>, ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs), literal: Literal::Item { def_id: free_func, - kind: ItemKind::Function, substs: substs } }), diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ac1cff527fe..cbd6bed81a6 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -22,7 +22,6 @@ use rustc::middle::ty::{self, VariantDef, Ty}; use rustc::mir::repr::*; use rustc_front::hir; use rustc_front::util as hir_util; -use syntax::parse::token; use syntax::ptr::P; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { @@ -62,7 +61,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let method = method_callee(cx, self, ty::MethodCall::expr(self.id)); let sig = match method.ty.sty { - ty::TyBareFn(_, fn_ty) => &fn_ty.sig, + ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig, _ => cx.tcx.sess.span_bug(self.span, "type of method is not an fn") }; @@ -324,38 +323,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } - hir::ExprRange(ref start, ref end) => { - let range_ty = cx.tcx.expr_ty(self); - let (adt_def, substs) = match range_ty.sty { - ty::TyStruct(adt_def, substs) => (adt_def, substs), - _ => { - cx.tcx.sess.span_bug(self.span, "unexpanded ast"); - } - }; - - let field_expr_ref = |s: &'tcx P<hir::Expr>, name: &str| { - let name = token::intern(name); - let index = adt_def.variants[0].index_of_field_named(name).unwrap(); - FieldExprRef { name: Field::new(index), expr: s.to_ref() } - }; - - let start_field = start.as_ref() - .into_iter() - .map(|s| field_expr_ref(s, "start")); - - let end_field = end.as_ref() - .into_iter() - .map(|e| field_expr_ref(e, "end")); - - ExprKind::Adt { - adt_def: adt_def, - variant_index: 0, - substs: substs, - fields: start_field.chain(end_field).collect(), - base: None, - } - } - hir::ExprPath(..) => { convert_path_expr(cx, self) } @@ -614,7 +581,6 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, kind: ExprKind::Literal { literal: Literal::Item { def_id: callee.def_id, - kind: ItemKind::Method, substs: callee.substs, }, }, @@ -651,14 +617,13 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs); // Otherwise there may be def_map borrow conflicts let def = cx.tcx.def_map.borrow()[&expr.id].full_def(); - let (def_id, kind) = match def { + let def_id = match def { // A regular function. - Def::Fn(def_id) => (def_id, ItemKind::Function), - Def::Method(def_id) => (def_id, ItemKind::Method), + Def::Fn(def_id) | Def::Method(def_id) => def_id, Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty { // A tuple-struct constructor. Should only be reached if not called in the same // expression. - ty::TyBareFn(..) => (def_id, ItemKind::Function), + ty::TyFnDef(..) => def_id, // A unit struct which is used as a value. We return a completely different ExprKind // here to account for this special case. ty::TyStruct(adt_def, substs) => return ExprKind::Adt { @@ -673,7 +638,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty { // A variant constructor. Should only be reached if not called in the same // expression. - ty::TyBareFn(..) => (variant_id, ItemKind::Function), + ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. ty::TyEnum(adt_def, substs) => { debug_assert!(adt_def.did == enum_id); @@ -693,7 +658,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) if let Some(v) = cx.try_const_eval_literal(expr) { return ExprKind::Literal { literal: v }; } else { - (def_id, ItemKind::Constant) + def_id } } @@ -710,7 +675,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) &format!("def `{:?}` not yet implemented", def)), }; ExprKind::Literal { - literal: Literal::Item { def_id: def_id, kind: kind, substs: substs } + literal: Literal::Item { def_id: def_id, substs: substs } } } @@ -758,7 +723,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, let region = cx.tcx.mk_region(region); let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) { - ty::ClosureKind::FnClosureKind => { + ty::ClosureKind::Fn => { let ref_closure_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: closure_ty, @@ -777,7 +742,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, } } } - ty::ClosureKind::FnMutClosureKind => { + ty::ClosureKind::FnMut => { let ref_closure_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: closure_ty, @@ -796,7 +761,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, } } } - ty::ClosureKind::FnOnceClosureKind => { + ty::ClosureKind::FnOnce => { Expr { ty: closure_ty, temp_lifetime: temp_lifetime, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 707dd972003..6a22dce7af9 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,7 +14,7 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind, +use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, TypedConstVal}; use rustc::middle::const_eval::ConstVal; use rustc::middle::def_id::DefId; @@ -29,14 +29,6 @@ use self::cx::Cx; pub mod cx; #[derive(Clone, Debug)] -pub struct ItemRef<'tcx> { - pub ty: Ty<'tcx>, - pub kind: ItemKind, - pub def_id: DefId, - pub substs: &'tcx Substs<'tcx>, -} - -#[derive(Clone, Debug)] pub struct Block<'tcx> { pub extent: CodeExtent, pub span: Span, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 96828628888..398f38c5ba9 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -252,15 +252,15 @@ fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>, let region = tcx.mk_region(region); match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) { - ty::ClosureKind::FnClosureKind => + ty::ClosureKind::Fn => tcx.mk_ref(region, ty::TypeAndMut { ty: closure_ty, mutbl: hir::MutImmutable }), - ty::ClosureKind::FnMutClosureKind => + ty::ClosureKind::FnMut => tcx.mk_ref(region, ty::TypeAndMut { ty: closure_ty, mutbl: hir::MutMutable }), - ty::ClosureKind::FnOnceClosureKind => + ty::ClosureKind::FnOnce => closure_ty } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bf22c7b0b8b..e021300f1b3 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -421,7 +421,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let func_ty = mir.operand_ty(tcx, func); debug!("check_terminator: call, func_ty={:?}", func_ty); let func_ty = match func_ty.sty { - ty::TyBareFn(_, func_ty) => func_ty, + ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty, _ => { span_mirbug!(self, term, "call to non-function {:?}", func_ty); return; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 3703e602746..3a39a3c6dd1 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -582,7 +582,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, v.add_qualif(ConstQualif::NON_ZERO_SIZED); } Some(Def::Struct(..)) => { - if let ty::TyBareFn(..) = node_ty.sty { + if let ty::TyFnDef(..) = node_ty.sty { // Count the function pointer. v.add_qualif(ConstQualif::NON_ZERO_SIZED); } @@ -747,9 +747,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, hir::ExprAgain(_) | hir::ExprRet(_) | - // Miscellaneous expressions that could be implemented. - hir::ExprRange(..) | - // Expressions with side-effects. hir::ExprAssign(..) | hir::ExprAssignOp(..) | diff --git a/src/librustc_platform_intrinsics/x86.rs b/src/librustc_platform_intrinsics/x86.rs index 4a9b9970caf..168ae79ab74 100644 --- a/src/librustc_platform_intrinsics/x86.rs +++ b/src/librustc_platform_intrinsics/x86.rs @@ -1108,6 +1108,126 @@ pub fn find<'tcx>(_tcx: &TyCtxt<'tcx>, name: &str) -> Option<Intrinsic> { output: v(u(16), 16), definition: Named("llvm.x86.avx2.psubus.w") }, + "_fmadd_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfmadd.ps") + }, + "_fmadd_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfmadd.pd") + }, + "256_fmadd_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfmadd.ps.256") + }, + "256_fmadd_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfmadd.pd.256") + }, + "_fmaddsub_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfmaddsub.ps") + }, + "_fmaddsub_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfmaddsub.pd") + }, + "256_fmaddsub_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfmaddsub.ps.256") + }, + "256_fmaddsub_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfmaddsub.pd.256") + }, + "_fmsub_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfmsub.ps") + }, + "_fmsub_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfmsub.pd") + }, + "256_fmsub_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfmsub.ps.256") + }, + "256_fmsub_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfmsub.pd.256") + }, + "_fmsubadd_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfmsubadd.ps") + }, + "_fmsubadd_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfmsubadd.pd") + }, + "256_fmsubadd_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfmsubadd.ps.256") + }, + "256_fmsubadd_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfmsubadd.pd.256") + }, + "_fnmadd_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfnmadd.ps") + }, + "_fnmadd_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfnmadd.pd") + }, + "256_fnmadd_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfnmadd.ps.256") + }, + "256_fnmadd_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfnmadd.pd.256") + }, + "_fnmsub_ps" => Intrinsic { + inputs: vec![v(f(32), 4), v(f(32), 4), v(f(32), 4)], + output: v(f(32), 4), + definition: Named("llvm.x86.fma.vfnmsub.ps") + }, + "_fnmsub_pd" => Intrinsic { + inputs: vec![v(f(64), 2), v(f(64), 2), v(f(64), 2)], + output: v(f(64), 2), + definition: Named("llvm.x86.fma.vfnmsub.pd") + }, + "256_fnmsub_ps" => Intrinsic { + inputs: vec![v(f(32), 8), v(f(32), 8), v(f(32), 8)], + output: v(f(32), 8), + definition: Named("llvm.x86.fma.vfnmsub.ps.256") + }, + "256_fnmsub_pd" => Intrinsic { + inputs: vec![v(f(64), 4), v(f(64), 4), v(f(64), 4)], + output: v(f(64), 4), + definition: Named("llvm.x86.fma.vfnmsub.pd.256") + }, _ => return None, }) } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 214ac81ee50..79ccc8fb2b2 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -38,10 +38,10 @@ use rustc_front::intravisit::{self, Visitor}; use rustc::dep_graph::DepNode; use rustc::lint; +use rustc::middle::cstore::CrateStore; use rustc::middle::def::{self, Def}; use rustc::middle::def_id::DefId; use rustc::middle::privacy::{AccessLevel, AccessLevels}; -use rustc::middle::privacy::ExternalExports; use rustc::middle::ty::{self, TyCtxt}; use rustc::util::nodemap::{NodeMap, NodeSet}; use rustc::front::map as ast_map; @@ -476,7 +476,6 @@ struct PrivacyVisitor<'a, 'tcx: 'a> { curitem: ast::NodeId, in_foreign: bool, parents: NodeMap<ast::NodeId>, - external_exports: ExternalExports, } #[derive(Debug)] @@ -498,7 +497,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) { node_id } else { - if self.external_exports.contains(&did) { + if self.tcx.sess.cstore.visibility(did) == hir::Public { debug!("privacy - {:?} was externally exported", did); return Allowable; } @@ -857,7 +856,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { if let Def::Struct(..) = self.tcx.resolve_expr(expr) { let expr_ty = self.tcx.expr_ty(expr); let def = match expr_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { output: ty::FnConverging(ty), .. }), ..}) => ty, _ => expr_ty @@ -1567,10 +1566,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc } } -pub fn check_crate(tcx: &TyCtxt, - export_map: &def::ExportMap, - external_exports: ExternalExports) - -> AccessLevels { +pub fn check_crate(tcx: &TyCtxt, export_map: &def::ExportMap) -> AccessLevels { let _task = tcx.dep_graph.in_task(DepNode::Privacy); let krate = tcx.map.krate(); @@ -1593,7 +1589,6 @@ pub fn check_crate(tcx: &TyCtxt, in_foreign: false, tcx: tcx, parents: visitor.parents, - external_exports: external_exports, }; intravisit::walk_crate(&mut visitor, krate); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f391597e3b1..ad4bcff1d3d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -289,7 +289,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { krate: crate_id, index: CRATE_DEF_INDEX, }; - self.external_exports.insert(def_id); let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(def_id); let module = self.new_extern_crate_module(parent_link, def, is_public, item.id); @@ -495,15 +494,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { modifiers = modifiers | DefModifiers::IMPORTABLE; } - let is_exported = is_public && - match new_parent.def_id() { - None => true, - Some(did) => self.external_exports.contains(&did), - }; - if is_exported { - self.external_exports.insert(def.def_id()); - } - match def { Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) | Def::TyAlias(..) => { debug!("(building reduced graph for external crate) building module {} {}", @@ -552,10 +542,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { trait_item_name); self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id()); - - if is_exported { - self.external_exports.insert(trait_item_def.def_id()); - } } let parent_link = ModuleParentLink(new_parent, name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a205bfb98ac..970f54207ba 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -55,10 +55,9 @@ use rustc::middle::cstore::{CrateStore, DefLike, DlDef}; use rustc::middle::def::*; use rustc::middle::def_id::DefId; use rustc::middle::pat_util::pat_bindings; -use rustc::middle::privacy::ExternalExports; use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace}; use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; +use rustc::util::nodemap::{NodeMap, FnvHashMap}; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; @@ -1093,7 +1092,6 @@ pub struct Resolver<'a, 'tcx: 'a> { freevars_seen: NodeMap<NodeMap<usize>>, export_map: ExportMap, trait_map: TraitMap, - external_exports: ExternalExports, // Whether or not to print error messages. Can be set to true // when getting additional info for error message suggestions, @@ -1184,7 +1182,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trait_map: NodeMap(), used_imports: HashSet::new(), used_crates: HashSet::new(), - external_exports: DefIdSet(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, @@ -3716,7 +3713,6 @@ pub struct CrateMap { pub freevars: FreevarMap, pub export_map: ExportMap, pub trait_map: TraitMap, - pub external_exports: ExternalExports, pub glob_map: Option<GlobMap>, } @@ -3754,7 +3750,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, freevars: resolver.freevars, export_map: resolver.export_map, trait_map: resolver.trait_map, - external_exports: resolver.external_exports, glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e8368f1bd97..c5508a8268f 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -451,8 +451,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &TyCtxt<'tcx>, // Regular thin pointer: &T/&mut T/Box<T> ty::TyRef(..) | ty::TyBox(..) => Some(path), - // Functions are just pointers - ty::TyBareFn(..) => Some(path), + // Function pointer: `fn() -> i32` + ty::TyFnPtr(_) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 33370abc3fc..98e9a1c98ad 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -50,7 +50,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &out.expr), out_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut inputs); if out.is_rw { ext_inputs.push(*inputs.last().unwrap()); @@ -64,7 +63,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &out.expr), out_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut ext_inputs); ext_constraints.push(i.to_string()); } @@ -80,7 +78,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &input), in_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut inputs); } inputs.extend_from_slice(&ext_inputs[..]); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 8f9648b333b..009d43e813e 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -131,7 +131,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx let function_type; let (fn_sig, abi, env_ty) = match fn_type.sty { - ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None), + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None), ty::TyClosure(closure_did, ref substs) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); @@ -162,7 +162,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx _ => ccx.sess().bug("expected tuple'd inputs") } }, - ty::TyBareFn(..) if abi == Abi::RustCall => { + ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => { let mut inputs = vec![fn_sig.inputs[0]]; match fn_sig.inputs[1].sty { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 33d3d66adcd..5088dabfbe7 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -195,16 +195,14 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str, - did: DefId) + attrs: &[ast::Attribute]) -> ValueRef { if let Some(n) = ccx.externs().borrow().get(name) { return *n; } let f = declare::declare_rust_fn(ccx, name, fn_ty); - - let attrs = ccx.sess().cstore.item_attrs(did); - attributes::from_fn_attrs(ccx, &attrs[..], f); + attributes::from_fn_attrs(ccx, &attrs, f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -216,13 +214,13 @@ pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> Ty<'tcx> { let closure_kind = ccx.tcx().closure_kind(closure_id); match closure_kind { - ty::FnClosureKind => { + ty::ClosureKind::Fn => { ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) } - ty::FnMutClosureKind => { + ty::ClosureKind::FnMut => { ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) } - ty::FnOnceClosureKind => fn_ty, + ty::ClosureKind::FnOnce => fn_ty, } } @@ -390,7 +388,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bcx.sess().bug("compare_scalar_types: must be a comparison operator"), } } - ty::TyBareFn(..) | ty::TyBool | ty::TyUint(_) | ty::TyChar => { + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyBool | ty::TyUint(_) | ty::TyChar => { ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, @@ -621,8 +619,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, source: Ty<'tcx>, target: Ty<'tcx>, - old_info: Option<ValueRef>, - param_substs: &'tcx Substs<'tcx>) + old_info: Option<ValueRef>) -> ValueRef { let (source, target) = ccx.tcx().struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { @@ -641,7 +638,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, def_id: principal.def_id(), substs: substs, }); - consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), + consts::ptrcast(meth::get_vtable(ccx, trait_ref), Type::vtable_ptr(ccx)) } _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}", @@ -668,7 +665,7 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, assert!(common::type_is_sized(bcx.tcx(), a)); let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to(); (PointerCast(bcx, src, ptr_ty), - unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs)) + unsized_info(bcx.ccx(), a, b, None)) } _ => bcx.sess().bug("unsize_thin_ptr: called on bad types"), } @@ -900,29 +897,31 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } } -pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - did: DefId, - t: Ty<'tcx>) - -> ValueRef { - let name = ccx.sess().cstore.item_symbol(did); - match t.sty { - ty::TyBareFn(_, ref fn_ty) => { - match ccx.sess().target.target.adjust_abi(fn_ty.abi) { - Abi::Rust | Abi::RustCall => { - get_extern_rust_fn(ccx, t, &name[..], did) - } +pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId) + -> datum::Datum<'tcx, datum::Rvalue> { + let name = ccx.sess().cstore.item_symbol(def_id); + let attrs = ccx.sess().cstore.item_attrs(def_id); + let ty = ccx.tcx().lookup_item_type(def_id).ty; + match ty.sty { + ty::TyFnDef(_, _, fty) => { + let abi = fty.abi; + let fty = infer::normalize_associated_type(ccx.tcx(), fty); + let ty = ccx.tcx().mk_fn_ptr(fty); + let llfn = match ccx.sess().target.target.adjust_abi(abi) { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { - ccx.sess().bug("unexpected intrinsic in trans_external_path") + ccx.sess().bug("unexpected intrinsic in get_extern_fn") + } + Abi::Rust | Abi::RustCall => { + get_extern_rust_fn(ccx, ty, &name, &attrs) } _ => { - let attrs = ccx.sess().cstore.item_attrs(did); - foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs) + foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs) } - } - } - _ => { - get_extern_const(ccx, did, t) + }; + datum::immediate_rvalue(llfn, ty) } + _ => unreachable!("get_extern_fn: expected fn item type, found {}", ty) } } @@ -2610,7 +2609,7 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node_id: ast::NodeId, node_type: Ty<'tcx>) -> ValueRef { - if let ty::TyBareFn(_, ref f) = node_type.sty { + if let ty::TyFnDef(_, _, ref f) = node_type.sty { if f.abi != Abi::Rust && f.abi != Abi::RustCall { ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \ @@ -2685,8 +2684,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { .as_local_node_id(start_def_id) { get_item_val(ccx, start_node_id) } else { - let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty; - trans_external_path(ccx, start_def_id, start_fn_type) + get_extern_fn(ccx, start_def_id).val }; let args = { let opaque_rust_main = @@ -2915,7 +2913,7 @@ fn register_method(ccx: &CrateContext, let sym = exported_name(ccx, id, mty, &attrs); - if let ty::TyBareFn(_, ref f) = mty.sty { + if let ty::TyFnDef(_, _, ref f) = mty.sty { let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall { register_fn(ccx, span, sym, id, mty) } else { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 5f8e31781f1..05e5ac808d0 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -14,7 +14,6 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -pub use self::AutorefArg::*; pub use self::CalleeData::*; pub use self::CallArgs::*; @@ -22,7 +21,6 @@ use arena::TypedArena; use back::link; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; -use middle::def::Def; use middle::def_id::DefId; use middle::infer; use middle::subst; @@ -32,14 +30,13 @@ use trans::adt; use trans::base; use trans::base::*; use trans::build::*; -use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, ExprOrMethodCall, FunctionContext, MethodCallKey}; use trans::consts; use trans::datum::*; -use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::debuginfo::DebugLoc; use trans::declare; use trans::expr; use trans::glue; @@ -52,177 +49,148 @@ use trans::type_::Type; use trans::type_of; use trans::Disr; use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::MethodCall; use rustc_front::hir; use syntax::abi::Abi; use syntax::ast; +use syntax::codemap::DUMMY_SP; use syntax::errors; use syntax::ptr::P; -#[derive(Copy, Clone)] -pub struct MethodData { - pub llfn: ValueRef, - pub llself: ValueRef, -} - pub enum CalleeData<'tcx> { - // Constructor for enum variant/tuple-like-struct - // i.e. Some, Ok + /// Constructor for enum variant/tuple-like-struct. NamedTupleConstructor(Disr), - // Represents a (possibly monomorphized) top-level fn item or method - // item. Note that this is just the fn-ptr and is not a Rust closure - // value (which is a pair). - Fn(/* llfn */ ValueRef), + /// Function pointer. + Fn(ValueRef), - Intrinsic(ast::NodeId, subst::Substs<'tcx>), + Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>), - TraitItem(MethodData) + /// Trait object found in the vtable at that index. + Virtual(usize) } -pub struct Callee<'blk, 'tcx: 'blk> { - pub bcx: Block<'blk, 'tcx>, +pub struct Callee<'tcx> { pub data: CalleeData<'tcx>, pub ty: Ty<'tcx> } -fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("trans_callee"); - debug!("callee::trans(expr={:?})", expr); - - // pick out special kinds of expressions that can be called: - match expr.node { - hir::ExprPath(..) => { - return trans_def(bcx, bcx.def(expr.id), expr); +impl<'tcx> Callee<'tcx> { + /// Function pointer. + pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> { + Callee { + data: Fn(datum.val), + ty: datum.ty } - _ => {} } - // any other expressions are closures: - return datum_callee(bcx, expr); - - fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr); - match datum.ty.sty { - ty::TyBareFn(..) => { - Callee { - bcx: bcx, - ty: datum.ty, - data: Fn(datum.to_llscalarish(bcx)) - } - } - _ => { - bcx.tcx().sess.span_bug( - expr.span, - &format!("type of callee is neither bare-fn nor closure: {}", - datum.ty)); - } - } + /// Trait or impl method call. + pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>, + method_call: ty::MethodCall) + -> Callee<'tcx> { + let method = bcx.tcx().tables.borrow().method_map[&method_call]; + Callee::method(bcx, method) } - fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>) - -> Callee<'blk, 'tcx> { - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } + /// Trait or impl method. + pub fn method<'blk>(bcx: Block<'blk, 'tcx>, + method: ty::MethodCallee<'tcx>) -> Callee<'tcx> { + let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs)); + let ty = bcx.fcx.monomorphize(&method.ty); + Callee::def(bcx.ccx(), method.def_id, substs, ty) } - fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def: Def, - ref_expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr); - let expr_ty = common::node_id_type(bcx, ref_expr.id); - match def { - Def::Fn(did) if { - let maybe_def_id = inline::get_local_instance(bcx.ccx(), did); - let maybe_ast_node = maybe_def_id.and_then(|def_id| { - let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); - bcx.tcx().map.find(node_id) - }); - match maybe_ast_node { - Some(hir_map::NodeStructCtor(_)) => true, - _ => false - } - } => { - Callee { - bcx: bcx, + /// Function or method definition. + pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + substs: &'tcx subst::Substs<'tcx>, + ty: Ty<'tcx>) + -> Callee<'tcx> { + let tcx = ccx.tcx(); + + if substs.self_ty().is_some() { + // Only trait methods can have a Self parameter. + let method_item = tcx.impl_or_trait_item(def_id); + let trait_id = method_item.container().id(); + let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); + let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref); + return meth::callee_for_trait_impl(ccx, def_id, substs, + trait_id, ty, vtbl); + } + + let maybe_node_id = inline::get_local_instance(ccx, def_id) + .and_then(|def_id| tcx.map.as_local_node_id(def_id)); + let maybe_ast_node = maybe_node_id.and_then(|node_id| { + tcx.map.find(node_id) + }); + match maybe_ast_node { + Some(hir_map::NodeStructCtor(_)) => { + return Callee { data: NamedTupleConstructor(Disr(0)), - ty: expr_ty - } - } - Def::Fn(did) if match expr_ty.sty { - ty::TyBareFn(_, ref f) => f.abi == Abi::RustIntrinsic || - f.abi == Abi::PlatformIntrinsic, - _ => false - } => { - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); - let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); - let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); - Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty } - } - Def::Fn(did) => { - fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), - bcx.fcx.param_substs)) - } - Def::Method(meth_did) => { - let method_item = bcx.tcx().impl_or_trait_item(meth_did); - let fn_datum = match method_item.container() { - ty::ImplContainer(_) => { - trans_fn_ref(bcx.ccx(), meth_did, - ExprId(ref_expr.id), - bcx.fcx.param_substs) - } - ty::TraitContainer(trait_did) => { - meth::trans_static_method_callee(bcx.ccx(), - meth_did, - trait_did, - ref_expr.id, - bcx.fcx.param_substs) - } + ty: ty }; - fn_callee(bcx, fn_datum) } - Def::Variant(tid, vid) => { - let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); + Some(hir_map::NodeVariant(_)) => { + let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap()); assert_eq!(vinfo.kind(), ty::VariantKind::Tuple); - Callee { - bcx: bcx, + return Callee { data: NamedTupleConstructor(Disr::from(vinfo.disr_val)), - ty: expr_ty - } + ty: ty + }; } - Def::Struct(..) => { - Callee { - bcx: bcx, - data: NamedTupleConstructor(Disr(0)), - ty: expr_ty + Some(hir_map::NodeForeignItem(fi)) => { + let abi = tcx.map.get_foreign_abi(fi.id); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + return Callee { + data: Intrinsic(fi.id, substs), + ty: ty + }; } } - Def::Static(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) => { - datum_callee(bcx, ref_expr) - } - Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) | - Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) | - Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) | - Def::SelfTy(..) | Def::Err => { - bcx.tcx().sess.span_bug( - ref_expr.span, - &format!("cannot translate def {:?} \ - to a callable thing!", def)); + _ => {} + } + Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs)) + } + + /// This behemoth of a function translates function calls. Unfortunately, in + /// order to generate more efficient LLVM output at -O0, it has quite a complex + /// signature (refactoring this into two functions seems like a good idea). + /// + /// In particular, for lang items, it is invoked with a dest of None, and in + /// that case the return value contains the result of the fn. The lang item must + /// not return a structural type or else all heck breaks loose. + /// + /// For non-lang items, `dest` is always Some, and hence the result is written + /// into memory somewhere. Nonetheless we return the actual return value of the + /// function. + pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>, + debug_loc: DebugLoc, + args: CallArgs<'a, 'tcx>, + dest: Option<expr::Dest>) + -> Result<'blk, 'tcx> { + trans_call_inner(bcx, debug_loc, self, args, dest) + } + + /// Turn the callee into a function pointer. + pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) + -> Datum<'tcx, Rvalue> { + match self.data { + Fn(llfn) => { + let fn_ptr_ty = match self.ty.sty { + ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)), + _ => self.ty + }; + immediate_rvalue(llfn, fn_ptr_ty) } + Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx), + NamedTupleConstructor(_) => match self.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs); + } + _ => unreachable!("expected fn item type, found {}", self.ty) + }, + Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty) } } } @@ -241,7 +209,17 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id, node, substs); - trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs) + let ref_ty = match node { + ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs), + ExprId(id) => ccx.tcx().node_id_to_type(id), + MethodCallKey(method_call) => { + ccx.tcx().tables.borrow().method_map[&method_call].ty + } + }; + let ref_ty = monomorphize::apply_param_substs(ccx.tcx(), + param_substs, + &ref_ty); + trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs) } /// Translates an adapter that implements the `Fn` trait for a fn @@ -270,8 +248,8 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`. let is_by_ref = match closure_kind { - ty::FnClosureKind | ty::FnMutClosureKind => true, - ty::FnOnceClosureKind => false, + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => true, + ty::ClosureKind::FnOnce => false, }; let bare_fn_ty_maybe_ref = if is_by_ref { tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), bare_fn_ty) @@ -290,33 +268,33 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`, // which is the fn pointer, and `args`, which is the arguments tuple. - let (opt_def_id, sig) = - match bare_fn_ty.sty { - ty::TyBareFn(opt_def_id, - &ty::BareFnTy { unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - ref sig }) => { - (opt_def_id, sig) - } + let sig = match bare_fn_ty.sty { + ty::TyFnDef(_, _, + &ty::BareFnTy { unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + ref sig }) | + ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + ref sig }) => sig, - _ => { - tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}", - bare_fn_ty)); - } - }; + _ => { + tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}", + bare_fn_ty)); + } + }; let sig = tcx.erase_late_bound_regions(sig); let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec()); - let tuple_fn_ty = tcx.mk_fn(opt_def_id, - tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: vec![bare_fn_ty_maybe_ref, - tuple_input_ty], - output: sig.output, - variadic: false - })})); + let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::RustCall, + sig: ty::Binder(ty::FnSig { + inputs: vec![bare_fn_ty_maybe_ref, + tuple_input_ty], + output: sig.output, + variadic: false + }) + }); debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // @@ -341,11 +319,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let llargs = get_params(fcx.llfn); let self_idx = fcx.arg_offset(); - // the first argument (`self`) will be ptr to the fn pointer - let llfnpointer = if is_by_ref { - Load(bcx, llargs[self_idx]) - } else { - llargs[self_idx] + let llfnpointer = match bare_fn_ty.sty { + ty::TyFnDef(def_id, substs, _) => { + // Function definitions have to be turned into a pointer. + Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val + } + + // the first argument (`self`) will be ptr to the fn pointer + _ => if is_by_ref { + Load(bcx, llargs[self_idx]) + } else { + llargs[self_idx] + } }; assert!(!fcx.needs_ret_allocas); @@ -354,13 +339,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")) ); - bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - Callee { - bcx: bcx, - data: Fn(llfnpointer), - ty: bare_fn_ty - } - }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; + let callee = Callee { + data: Fn(llfnpointer), + ty: bare_fn_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); @@ -379,30 +362,25 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// - `node`: node id of the reference to the fn/method, if applicable. /// This parameter may be zero; but, if so, the resulting value may not /// have the right type, so it must be cast before being used. -/// - `param_substs`: if the `node` is in a polymorphic function, these -/// are the substitutions required to monomorphize its type +/// - `ref_ty`: monotype of the reference to the fn/method, if applicable. +/// This parameter may be None; but, if so, the resulting value may not +/// have the right type, so it must be cast before being used. /// - `substs`: values for each of the fn/method's parameters pub fn trans_fn_ref_with_substs<'a, 'tcx>( ccx: &CrateContext<'a, 'tcx>, def_id: DefId, - node: ExprOrMethodCall, - param_substs: &'tcx subst::Substs<'tcx>, - substs: subst::Substs<'tcx>) + ref_ty: Option<Ty<'tcx>>, + substs: &'tcx subst::Substs<'tcx>) -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref_with_substs"); let tcx = ccx.tcx(); - debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \ - param_substs={:?}, substs={:?})", - def_id, - node, - param_substs, - substs); + debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})", + def_id, ref_ty, substs); assert!(!substs.types.needs_infer()); assert!(!substs.types.has_escaping_regions()); - let substs = substs.erase_regions(); // Check whether this fn has an inlined copy and, if so, redirect // def_id to the local id of the inlined copy. @@ -437,48 +415,45 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // Should be either intra-crate or inlined. assert_eq!(def_id.krate, LOCAL_CRATE); - let opt_ref_id = match node { - ExprId(id) => if id != 0 { Some(id) } else { None }, - MethodCallKey(_) => None, + let substs = tcx.mk_substs(substs.clone().erase_regions()); + let (mut val, fn_ty, must_cast) = + monomorphize::monomorphic_fn(ccx, def_id, substs); + let fn_ty = ref_ty.unwrap_or(fn_ty); + let fn_ptr_ty = match fn_ty.sty { + ty::TyFnDef(_, _, fty) => { + // Create a fn pointer with the substituted signature. + tcx.mk_ty(ty::TyFnPtr(fty)) + } + _ => unreachable!("expected fn item type, found {}", fn_ty) }; - - let substs = tcx.mk_substs(substs); - let (val, fn_ty, must_cast) = - monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id); - if must_cast && node != ExprId(0) { - // Monotype of the REFERENCE to the function (type params - // are subst'd) - let ref_ty = match node { - ExprId(id) => tcx.node_id_to_type(id), - MethodCallKey(method_call) => { - tcx.tables.borrow().method_map[&method_call].ty - } - }; - let ref_ty = monomorphize::apply_param_substs(tcx, - param_substs, - &ref_ty); - let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to(); + if must_cast && ref_ty.is_some() { + let llptrty = type_of::type_of(ccx, fn_ptr_ty); if llptrty != common::val_ty(val) { - let val = consts::ptrcast(val, llptrty); - return Datum::new(val, ref_ty, Rvalue::new(ByValue)); + val = consts::ptrcast(val, llptrty); } } - return Datum::new(val, fn_ty, Rvalue::new(ByValue)); + return immediate_rvalue(val, fn_ptr_ty); } - // Type scheme of the function item (may have type params) - let fn_type_scheme = tcx.lookup_item_type(def_id); - let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty); - // Find the actual function pointer. - let mut val = { - if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { - // Internal reference. - get_item_val(ccx, node_id) - } else { - // External reference. - trans_external_path(ccx, def_id, fn_type) - } + let local_node = ccx.tcx().map.as_local_node_id(def_id); + let mut datum = if let Some(node_id) = local_node { + // Type scheme of the function item (may have type params) + let fn_type_scheme = tcx.lookup_item_type(def_id); + let fn_type = match fn_type_scheme.ty.sty { + ty::TyFnDef(_, _, fty) => { + // Create a fn pointer with the normalized signature. + tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty)) + } + _ => unreachable!("expected fn item type, found {}", + fn_type_scheme.ty) + }; + + // Internal reference. + immediate_rvalue(get_item_val(ccx, node_id), fn_type) + } else { + // External reference. + get_extern_fn(ccx, def_id) }; // This is subtle and surprising, but sometimes we have to bitcast @@ -504,93 +479,36 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // This can occur on either a crate-local or crate-external // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let llty = type_of::type_of_fn_from_ty(ccx, fn_type); - let llptrty = llty.ptr_to(); - if common::val_ty(val) != llptrty { + let llptrty = type_of::type_of(ccx, datum.ty); + if common::val_ty(datum.val) != llptrty { debug!("trans_fn_ref_with_substs(): casting pointer!"); - val = consts::ptrcast(val, llptrty); + datum.val = consts::ptrcast(datum.val, llptrty); } else { debug!("trans_fn_ref_with_substs(): not casting pointer!"); } - Datum::new(val, fn_type, Rvalue::new(ByValue)) + datum } // ______________________________________________________________________ // Translating calls -pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_expr: &hir::Expr, - f: &hir::Expr, - args: CallArgs<'a, 'tcx>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_call"); - trans_call_inner(bcx, - call_expr.debug_loc(), - |bcx, _| trans(bcx, f), - args, - Some(dest)).bcx -} - -pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_expr: &hir::Expr, - rcvr: &hir::Expr, - args: CallArgs<'a, 'tcx>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_method_call"); - debug!("trans_method_call(call_expr={:?})", call_expr); - let method_call = MethodCall::expr(call_expr.id); - trans_call_inner( - bcx, - call_expr.debug_loc(), - |cx, arg_cleanup_scope| { - meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope) - }, - args, - Some(dest)).bcx -} - pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: DefId, args: &[ValueRef], dest: Option<expr::Dest>, debug_loc: DebugLoc) -> Result<'blk, 'tcx> { - callee::trans_call_inner(bcx, debug_loc, |bcx, _| { - let datum = trans_fn_ref_with_substs(bcx.ccx(), - did, - ExprId(0), - bcx.fcx.param_substs, - subst::Substs::trans_empty()); - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } - }, ArgVals(args), dest) + let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs); + Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest) } -/// This behemoth of a function translates function calls. Unfortunately, in -/// order to generate more efficient LLVM output at -O0, it has quite a complex -/// signature (refactoring this into two functions seems like a good idea). -/// -/// In particular, for lang items, it is invoked with a dest of None, and in -/// that case the return value contains the result of the fn. The lang item must -/// not return a structural type or else all heck breaks loose. -/// -/// For non-lang items, `dest` is always Some, and hence the result is written -/// into memory somewhere. Nonetheless we return the actual return value of the -/// function. -pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - debug_loc: DebugLoc, - get_callee: F, - args: CallArgs<'a, 'tcx>, - dest: Option<expr::Dest>) - -> Result<'blk, 'tcx> where - F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>, -{ +fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, + debug_loc: DebugLoc, + callee: Callee<'tcx>, + args: CallArgs<'a, 'tcx>, + dest: Option<expr::Dest>) + -> Result<'blk, 'tcx> { // Introduce a temporary cleanup scope that will contain cleanups // for the arguments while they are being evaluated. The purpose // this cleanup is to ensure that, should a panic occur while @@ -600,27 +518,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // scope will ever execute. let fcx = bcx.fcx; let ccx = fcx.ccx; - let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); - - let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope)); - let mut bcx = callee.bcx; let (abi, ret_ty) = match callee.ty.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { let sig = bcx.tcx().erase_late_bound_regions(&f.sig); let sig = infer::normalize_associated_type(bcx.tcx(), &sig); (f.abi, sig.output) } - _ => panic!("expected bare rust fn or closure in trans_call_inner") + _ => panic!("expected fn item or ptr in Callee::call") }; - let (llfn, llself) = match callee.data { - Fn(llfn) => { - (llfn, None) - } - TraitItem(d) => { - (d.llfn, Some(d.llself)) - } + match callee.data { Intrinsic(node, substs) => { assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic); assert!(dest.is_some()); @@ -632,14 +540,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } }; + let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); return intrinsic::trans_intrinsic_call(bcx, node, callee.ty, arg_cleanup_scope, args, - dest.unwrap(), substs, + dest.unwrap(), + substs, call_info); } NamedTupleConstructor(disr) => { assert!(dest.is_some()); - fcx.pop_custom_cleanup_scope(arg_cleanup_scope); return base::trans_named_tuple_constructor(bcx, callee.ty, @@ -648,7 +557,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, dest.unwrap(), debug_loc); } - }; + _ => {} + } // Intrinsics should not become actual functions. // We trans them in place in `trans_intrinsic_call` @@ -688,6 +598,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref()) }; + let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); + // The code below invokes the function, using either the Rust // conventions (if it is a rust fn) or the native conventions // (otherwise). The important part is that, when all is said @@ -711,10 +623,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } } - // Push a trait object's self. - if let Some(llself) = llself { - llargs.push(llself); - } + let arg_start = llargs.len(); // Push the arguments. bcx = trans_args(bcx, @@ -722,16 +631,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), - llself.is_some(), abi); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); + let datum = match callee.data { + Fn(f) => immediate_rvalue(f, callee.ty), + Virtual(idx) => { + // The data and vtable pointers were split by trans_arg_datum. + let vtable = llargs.remove(arg_start + 1); + meth::get_virtual_method(bcx, vtable, idx, callee.ty) + } + _ => unreachable!() + }; + // Invoke the actual rust fn and update bcx/llresult. let (llret, b) = base::invoke(bcx, - llfn, + datum.val, &llargs[..], - callee.ty, + datum.ty, debug_loc); bcx = b; llresult = llret; @@ -754,16 +672,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, assert!(dest.is_some()); let mut llargs = Vec::new(); - let arg_tys = match args { - ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(), - _ => panic!("expected arg exprs.") + let (llfn, arg_tys) = match (callee.data, &args) { + (Fn(f), &ArgExprs(a)) => { + (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect()) + } + _ => panic!("expected fn ptr and arg exprs.") }; bcx = trans_args(bcx, args, callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), - false, abi); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); @@ -800,23 +719,22 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } pub enum CallArgs<'a, 'tcx> { - // Supply value of arguments as a list of expressions that must be - // translated. This is used in the common case of `foo(bar, qux)`. + /// Supply value of arguments as a list of expressions that must be + /// translated. This is used in the common case of `foo(bar, qux)`. ArgExprs(&'a [P<hir::Expr>]), - // Supply value of arguments as a list of LLVM value refs; frequently - // used with lang items and so forth, when the argument is an internal - // value. + /// Supply value of arguments as a list of LLVM value refs; frequently + /// used with lang items and so forth, when the argument is an internal + /// value. ArgVals(&'a [ValueRef]), - // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs` - // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of - // the right-hand-side argument (if any). `autoref` indicates whether the `rhs` - // arguments should be auto-referenced - ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool), + /// For overloaded operators: `(lhs, Option(rhs))`. + /// `lhs` is the left-hand-side and `rhs` is the datum + /// of the right-hand-side argument (if any). + ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>), - // Supply value of arguments as a list of expressions that must be - // translated, for overloaded call operators. + /// Supply value of arguments as a list of expressions that must be + /// translated, for overloaded call operators. ArgOverloadedCall(Vec<&'a hir::Expr>), } @@ -825,8 +743,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>( arg_exprs: &[P<hir::Expr>], fn_ty: Ty<'tcx>, llargs: &mut Vec<ValueRef>, - arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool) + arg_cleanup_scope: cleanup::ScopeId) -> Block<'blk, 'tcx> { let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); @@ -834,15 +751,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>( let args = sig.inputs; // Translate the `self` argument first. - if !ignore_self { - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); - bcx = trans_arg_datum(bcx, - args[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg, - llargs); - } + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); + bcx = trans_arg_datum(bcx, + args[0], + arg_datum, + arg_cleanup_scope, + llargs); // Now untuple the rest of the arguments. let tuple_expr = &arg_exprs[1]; @@ -870,7 +784,6 @@ fn trans_args_under_call_abi<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -888,23 +801,19 @@ fn trans_overloaded_call_args<'blk, 'tcx>( arg_exprs: Vec<&hir::Expr>, fn_ty: Ty<'tcx>, llargs: &mut Vec<ValueRef>, - arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool) + arg_cleanup_scope: cleanup::ScopeId) -> Block<'blk, 'tcx> { // Translate the `self` argument first. let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); let sig = infer::normalize_associated_type(bcx.tcx(), &sig); let arg_tys = sig.inputs; - if !ignore_self { - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); - bcx = trans_arg_datum(bcx, - arg_tys[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg, - llargs); - } + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); + bcx = trans_arg_datum(bcx, + arg_tys[0], + arg_datum, + arg_cleanup_scope, + llargs); // Now untuple the rest of the arguments. let tuple_type = arg_tys[1]; @@ -917,7 +826,6 @@ fn trans_overloaded_call_args<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -935,7 +843,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, fn_ty: Ty<'tcx>, llargs: &mut Vec<ValueRef>, arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool, abi: Abi) -> Block<'blk, 'tcx> { debug!("trans_args(abi={})", abi); @@ -960,15 +867,11 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, arg_exprs, fn_ty, llargs, - arg_cleanup_scope, - ignore_self) + arg_cleanup_scope) } let num_formal_args = arg_tys.len(); for (i, arg_expr) in arg_exprs.iter().enumerate() { - if i == 0 && ignore_self { - continue; - } let arg_ty = if i >= num_formal_args { assert!(variadic); common::expr_ty_adjusted(cx, &arg_expr) @@ -979,7 +882,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr)); bcx = trans_arg_datum(bcx, arg_ty, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -988,22 +890,19 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, arg_exprs, fn_ty, llargs, - arg_cleanup_scope, - ignore_self) + arg_cleanup_scope) } - ArgOverloadedOp(lhs, rhs, autoref) => { + ArgOverloadedOp(lhs, rhs) => { assert!(!variadic); bcx = trans_arg_datum(bcx, arg_tys[0], lhs, arg_cleanup_scope, - DontAutorefArg, llargs); - if let Some((rhs, rhs_id)) = rhs { + if let Some(rhs) = rhs { assert_eq!(arg_tys.len(), 2); bcx = trans_arg_datum(bcx, arg_tys[1], rhs, arg_cleanup_scope, - if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }, llargs); } else { assert_eq!(arg_tys.len(), 1); @@ -1017,17 +916,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, bcx } -#[derive(Copy, Clone)] -pub enum AutorefArg { - DontAutorefArg, - DoAutorefArg(ast::NodeId) -} - pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, formal_arg_ty: Ty<'tcx>, arg_datum: Datum<'tcx, Expr>, arg_cleanup_scope: cleanup::ScopeId, - autoref_arg: AutorefArg, llargs: &mut Vec<ValueRef>) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_arg_datum"); @@ -1041,37 +933,25 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!(" arg datum: {}", arg_datum.to_string(bcx.ccx())); - let mut val; - // FIXME(#3548) use the adjustments table - match autoref_arg { - DoAutorefArg(arg_id) => { - // We will pass argument by reference - // We want an lvalue, so that we can pass by reference and - let arg_datum = unpack_datum!( - bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id)); - val = arg_datum.val; - } - DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) && - !bcx.fcx.type_needs_drop(arg_datum_ty) => { - val = arg_datum.val - } - DontAutorefArg => { - // Make this an rvalue, since we are going to be - // passing ownership. - let arg_datum = unpack_datum!( - bcx, arg_datum.to_rvalue_datum(bcx, "arg")); - - // Now that arg_datum is owned, get it into the appropriate - // mode (ref vs value). - let arg_datum = unpack_datum!( - bcx, arg_datum.to_appropriate_datum(bcx)); - - // Technically, ownership of val passes to the callee. - // However, we must cleanup should we panic before the - // callee is actually invoked. - val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope); - } - } + let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) && + !bcx.fcx.type_needs_drop(arg_datum_ty) { + arg_datum.val + } else { + // Make this an rvalue, since we are going to be + // passing ownership. + let arg_datum = unpack_datum!( + bcx, arg_datum.to_rvalue_datum(bcx, "arg")); + + // Now that arg_datum is owned, get it into the appropriate + // mode (ref vs value). + let arg_datum = unpack_datum!( + bcx, arg_datum.to_appropriate_datum(bcx)); + + // Technically, ownership of val passes to the callee. + // However, we must cleanup should we panic before the + // callee is actually invoked. + arg_datum.add_clean(bcx.fcx, arg_cleanup_scope) + }; if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty { // this could happen due to e.g. subtyping diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index b1db196ecef..95ca250e844 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -17,7 +17,7 @@ use trans::adt; use trans::attributes; use trans::base::*; use trans::build::*; -use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; +use trans::callee::{self, ArgVals, Callee}; use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue}; @@ -49,7 +49,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let closure_ty = node_id_type(bcx, bcx.fcx.id); let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty); let kind = kind_for_closure(bcx.ccx(), closure_def_id); - let llenv = if kind == ty::FnOnceClosureKind && + let llenv = if kind == ty::ClosureKind::FnOnce && !arg_is_indirect(bcx.ccx(), self_type) { let datum = rvalue_scratch_datum(bcx, self_type, @@ -85,7 +85,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let node_id = freevar.def.var_id(); bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr); - if kind == ty::FnOnceClosureKind && !captured_by_ref { + if kind == ty::ClosureKind::FnOnce && !captured_by_ref { let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id); bcx.fcx.schedule_drop_mem(arg_scope_id, upvar_ptr, @@ -271,24 +271,8 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type - let closure_kind = ccx.tcx().closure_kind(closure_def_id); - trans_closure_adapter_shim(ccx, - closure_def_id, - substs, - closure_kind, - trait_closure_kind, - llfn) -} + let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); -fn trans_closure_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - llfn_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind, - llfn: ValueRef) - -> ValueRef -{ let _icx = push_ctxt("trans_closure_adapter_shim"); let tcx = ccx.tcx(); @@ -300,20 +284,20 @@ fn trans_closure_adapter_shim<'a, 'tcx>( ccx.tn().val_to_string(llfn)); match (llfn_closure_kind, trait_closure_kind) { - (ty::FnClosureKind, ty::FnClosureKind) | - (ty::FnMutClosureKind, ty::FnMutClosureKind) | - (ty::FnOnceClosureKind, ty::FnOnceClosureKind) => { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { // No adapter needed. llfn } - (ty::FnClosureKind, ty::FnMutClosureKind) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { // The closure fn `llfn` is a `fn(&self, ...)`. We want a // `fn(&mut self, ...)`. In fact, at trans time, these are // basically the same thing, so we can just return llfn. llfn } - (ty::FnClosureKind, ty::FnOnceClosureKind) | - (ty::FnMutClosureKind, ty::FnOnceClosureKind) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut // self, ...)`. We want a `fn(self, ...)`. We can produce // this by doing something like: @@ -355,28 +339,31 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version with the type of by-ref closure. let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, &substs); sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, - abi: abi, - sig: sig.clone() }); - let llref_fn_ty = tcx.mk_fn(None, llref_bare_fn_ty); + let llref_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig.clone() + }); debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", llref_fn_ty); + let ret_ty = tcx.erase_late_bound_regions(&sig.output()); + let ret_ty = infer::normalize_associated_type(ccx.tcx(), &ret_ty); + // Make a version of the closure type with the same arguments, but // with argument #0 being by value. assert_eq!(abi, RustCall); sig.0.inputs[0] = closure_ty; - let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, - abi: abi, - sig: sig }); - let llonce_fn_ty = tcx.mk_fn(None, llonce_bare_fn_ty); + let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig + }); // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); let lloncefn = declare::define_internal_rust_fn(ccx, &function_name, llonce_fn_ty); - let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); - let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); @@ -384,13 +371,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( lloncefn, ast::DUMMY_NODE_ID, false, - sig.output, + ret_ty, substs.func_substs, None, &block_arena); - let mut bcx = init_function(&fcx, false, sig.output); + let mut bcx = init_function(&fcx, false, ret_ty); - let llargs = get_params(fcx.llfn); + let mut llargs = get_params(fcx.llfn); // the first argument (`self`) will be the (by value) closure env. let self_scope = fcx.push_custom_cleanup_scope(); @@ -405,25 +392,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( debug!("trans_fn_once_adapter_shim: env_datum={}", bcx.val_to_string(env_datum.val)); + llargs[self_idx] = env_datum.val; let dest = fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); - - let callee_data = TraitItem(MethodData { llfn: llreffn, - llself: env_datum.val }); + |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))); - bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - Callee { - bcx: bcx, - data: callee_data, - ty: llref_fn_ty - } - }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; + let callee = Callee { + data: callee::Fn(llreffn), + ty: llref_fn_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx; fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); - finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + finish_fn(&fcx, bcx, ret_ty, DebugLoc::None); lloncefn } diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index b5b0f0a82d4..abfd127f388 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -542,14 +542,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting operand {:?}", *operand); let callee = match *operand { - mir::Operand::Constant(mir::Constant { - literal: mir::Literal::Item { - def_id, - kind, - substs - }, - .. - }) if is_function_or_method(kind) => Some((def_id, substs)), + mir::Operand::Constant(mir::Constant { ty: &ty::TyS { + sty: ty::TyFnDef(def_id, substs, _), .. + }, .. }) => Some((def_id, substs)), _ => None }; @@ -588,25 +583,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_operand(operand); - fn is_function_or_method(item_kind: mir::ItemKind) -> bool { - match item_kind { - mir::ItemKind::Constant => false, - mir::ItemKind::Function | - mir::ItemKind::Method => true - } - } - fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) -> bool { if !match ccx.tcx().lookup_item_type(def_id).ty.sty { - ty::TyBareFn(Some(def_id), _) => { - // Some constructors also have type TyBareFn but they are + ty::TyFnDef(def_id, _, _) => { + // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in - // translation item. + // translation item. Same for FFI functions. match ccx.tcx().map.get_if_local(def_id) { Some(hir_map::NodeVariant(_)) | - Some(hir_map::NodeStructCtor(_)) => false, + Some(hir_map::NodeStructCtor(_)) | + Some(hir_map::NodeForeignItem(_)) => false, Some(_) => true, None => { ccx.sess().cstore.variant_kind(def_id).is_none() @@ -689,7 +677,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if can_have_local_instance(ccx, destructor_did) { let trans_item = create_fn_trans_item(ccx, destructor_did, - ccx.tcx().mk_substs(substs), + substs, &Substs::trans_empty()); output.push(trans_item); } @@ -697,17 +685,18 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Finally add the types of nested values match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyStr | - ty::TyFloat(_) | - ty::TyRawPtr(_) | - ty::TyRef(..) | - ty::TyBareFn(..) | - ty::TySlice(_) | - ty::TyTrait(_) => { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyStr | + ty::TyFloat(_) | + ty::TyRawPtr(_) | + ty::TyRef(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TySlice(_) | + ty::TyTrait(_) => { /* nothing to do */ } ty::TyStruct(ref adt_def, substs) | @@ -831,9 +820,9 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, { let callee_substs = impl_substs.with_method_from(&rcvr_substs); let impl_method = tcx.get_impl_method(impl_did, - callee_substs, + tcx.mk_substs(callee_substs), trait_method.name); - Some((impl_method.method.def_id, tcx.mk_substs(impl_method.substs))) + Some((impl_method.method.def_id, impl_method.substs)) } // If we have a closure or a function pointer, we will also encounter // the concrete closure/function somewhere else (during closure or fn @@ -991,10 +980,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // create translation items .filter_map(|impl_method| { if can_have_local_instance(ccx, impl_method.method.def_id) { - let substs = ccx.tcx().mk_substs(impl_method.substs); Some(create_fn_trans_item(ccx, impl_method.method.def_id, - substs, + impl_method.substs, &Substs::trans_empty())) } else { None @@ -1173,12 +1161,12 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. let mth = tcx.get_impl_method(impl_def_id, - callee_substs.clone(), + callee_substs, default_impl.name); assert!(mth.is_provided); - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); + let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { continue; } @@ -1289,7 +1277,8 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &trait_data.bounds.projection_bounds, output); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 3ba27a4b787..34ef4f4acec 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -1228,7 +1228,7 @@ pub enum ExprOrMethodCall { pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node: ExprOrMethodCall, param_substs: &subst::Substs<'tcx>) - -> subst::Substs<'tcx> { + -> &'tcx subst::Substs<'tcx> { let tcx = ccx.tcx(); let substs = match node { @@ -1245,9 +1245,9 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node, substs)); } - monomorphize::apply_param_substs(tcx, - param_substs, - &substs.erase_regions()) + ccx.tcx().mk_substs(monomorphize::apply_param_substs(tcx, + param_substs, + &substs.erase_regions())) } pub fn langcall(bcx: Block, @@ -1277,7 +1277,7 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, inlined_vid); let adt_def = match ctor_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { output: ty::FnConverging(ty), .. }), ..}) => ty, _ => ctor_ty diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 20da1583496..6c47cab64ef 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -28,6 +28,7 @@ use middle::def::Def; use middle::def_id::DefId; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; +use trans::callee::Callee; use trans::collector::{self, TransItem}; use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt}; use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; @@ -211,7 +212,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arg_ids = args.iter().map(|arg| arg.pat.id); let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); - let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs)); + let substs = node_id_substs(ccx, node, param_substs); match fn_like.body().expr { Some(ref expr) => { const_expr(ccx, &expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res) @@ -355,8 +356,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { Some(AdjustReifyFnPointer) => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here + match ety.sty { + ty::TyFnDef(def_id, substs, _) => { + let datum = Callee::def(cx, def_id, substs, ety).reify(cx); + llconst = datum.val; + ety_adjusted = datum.ty; + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", ety) + } + } } Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => { // purely a type-level thing @@ -413,8 +422,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .expect("consts: unsizing got non-pointer target type").ty; let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); let base = ptrcast(base, ptr_ty); - let info = base::unsized_info(cx, pointee_ty, unsized_ty, - old_info, param_substs); + let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info); if old_info.is_none() { let prev_const = cx.const_unsized().borrow_mut() @@ -894,9 +902,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, cx.sess().span_bug(e.span, "const fn argument not found") } } - Def::Fn(..) | Def::Method(..) => { - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } + Def::Fn(..) | Def::Method(..) => C_nil(cx), Def::Const(def_id) | Def::AssociatedConst(def_id) => { load_const(cx, try!(get_const_val(cx, def_id, e, param_substs)), ety) @@ -908,23 +914,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let repr = adt::represent_type(cx, ety); adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[]) } - ty::VariantKind::Tuple => { - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } + ty::VariantKind::Tuple => C_nil(cx), ty::VariantKind::Struct => { cx.sess().span_bug(e.span, "path-expr refers to a dict variant!") } } } - Def::Struct(..) => { - if let ty::TyBareFn(..) = ety.sty { - // Tuple struct. - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } else { - // Unit struct. - C_null(type_of::type_of(cx, ety)) - } - } + // Unit struct or ctor. + Def::Struct(..) => C_null(type_of::type_of(cx, ety)), _ => { cx.sess().span_bug(e.span, "expected a const, fn, struct, \ or variant def") diff --git a/src/librustc_trans/trans/debuginfo/create_scope_map.rs b/src/librustc_trans/trans/debuginfo/create_scope_map.rs index 73fdbd54b29..4ba103c0c0d 100644 --- a/src/librustc_trans/trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/trans/debuginfo/create_scope_map.rs @@ -346,11 +346,6 @@ fn walk_expr(cx: &CrateContext, walk_expr(cx, &rhs, scope_stack, scope_map); } - hir::ExprRange(ref start, ref end) => { - start.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map)); - end.as_ref().map(|e| walk_expr(cx, &e, scope_stack, scope_map)); - } - hir::ExprVec(ref init_expressions) | hir::ExprTup(ref init_expressions) => { for ie in init_expressions { diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 330d4077c41..0cd1f4e7fbf 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -253,7 +253,8 @@ impl<'tcx> TypeMap<'tcx> { principal.substs, &mut unique_type_id); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { unique_type_id.push_str("unsafe "); } @@ -765,7 +766,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - ty::TyBareFn(_, ref barefnty) => { + ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => { let fn_metadata = subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 11dd631bee1..15275a46e9b 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -430,7 +430,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type); let (sig, abi) = match fn_type.sty { - ty::TyBareFn(_, ref barefnty) => { + ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => { let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig); let sig = infer::normalize_associated_type(cx.tcx(), &sig); (sig, barefnty.abi) diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index f243b1e3bfa..cc9067677b2 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -101,7 +101,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, push_item_name(cx, principal.def_id, false, output); push_type_params(cx, principal.substs, output); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 75b60be02f7..38e456c0688 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -106,7 +106,8 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let function_type; // placeholder so that the memory ownership works out ok let (sig, abi, env) = match fn_type.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, f) | + ty::TyFnPtr(f) => { (&f.sig, f.abi, None) } ty::TyClosure(closure_did, ref substs) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 591d8a9f76c..ae03f58bce0 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -56,9 +56,10 @@ use llvm::{self, ValueRef, TypeKind}; use middle::const_qualif::ConstQualif; use middle::def::Def; use middle::subst::Substs; -use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; +use trans::{_match, adt, asm, base, closure, consts, controlflow}; use trans::base::*; use trans::build::*; +use trans::callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp}; use trans::cleanup::{self, CleanupMethods, DropHintMethods}; use trans::common::*; use trans::datum::*; @@ -66,7 +67,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::declare; use trans::glue; use trans::machine; -use trans::meth; use trans::tvec; use trans::type_of; use trans::Disr; @@ -85,8 +85,6 @@ use rustc_front::hir; use syntax::{ast, codemap}; use syntax::parse::token::InternedString; -use syntax::ptr::P; -use syntax::parse::token; use std::mem; // Destinations @@ -350,11 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } match adjustment { - AdjustReifyFnPointer => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to return true here - false - } + AdjustReifyFnPointer => true, AdjustUnsafeFnPointer | AdjustMutToConstPointer => { // purely a type-level thing false @@ -389,8 +383,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, adjustment); match adjustment { AdjustReifyFnPointer => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here + match datum.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + datum = Callee::def(bcx.ccx(), def_id, substs, datum.ty) + .reify(bcx.ccx()).to_expr_datum(); + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", datum.ty) + } + } } AdjustUnsafeFnPointer | AdjustMutToConstPointer => { // purely a type-level thing @@ -493,8 +494,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (val, None) }; - let info = unsized_info(bcx.ccx(), inner_source, inner_target, - old_info, bcx.fcx.param_substs); + let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info); // Compute the base pointer. This doesn't change the pointer value, // but merely its type. @@ -786,15 +786,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let index_expr_debug_loc = index_expr.debug_loc(); // Check for overloaded index. - let method_ty = ccx.tcx() - .tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.ty); - let elt_datum = match method_ty { - Some(method_ty) => { - let method_ty = monomorphize_type(bcx, method_ty); + let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let elt_datum = match method { + Some(method) => { + let method_ty = monomorphize_type(bcx, method.ty); let base_datum = unpack_datum!(bcx, trans(bcx, base)); @@ -812,19 +807,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(elt_tm) => elt_tm.ty, }; - // Overloaded. Evaluate `trans_overloaded_op`, which will - // invoke the user's index() method, which basically yields - // a `&T` pointer. We can then proceed down the normal - // path (below) to dereference that `&T`. + // Overloaded. Invoke the index() method, which basically + // yields a `&T` pointer. We can then proceed down the + // normal path (below) to dereference that `&T`. let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt"); - unpack_result!(bcx, - trans_overloaded_op(bcx, - index_expr, - method_call, - base_datum, - Some((ix_datum, idx.id)), - Some(SaveIn(scratch.val)), - false)); + + bcx = Callee::method(bcx, method) + .call(bcx, index_expr_debug_loc, + ArgOverloadedOp(base_datum, Some(ix_datum)), + Some(SaveIn(scratch.val))).bcx; + let datum = scratch.to_expr_datum(); let lval = Lvalue::new("expr::trans_index overload"); if type_is_sized(bcx.tcx(), elt_ty) { @@ -900,24 +892,18 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_def_lvalue"); match def { - Def::Fn(..) | Def::Method(..) | - Def::Struct(..) | Def::Variant(..) => { - let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def, - bcx.fcx.param_substs); - DatumBlock::new(bcx, datum.to_expr_datum()) - } Def::Static(did, _) => { let const_ty = expr_ty(bcx, ref_expr); let val = get_static_val(bcx.ccx(), did, const_ty); let lval = Lvalue::new("expr::trans_def"); DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval))) } - Def::Const(_) | Def::AssociatedConst(_) => { - bcx.sess().span_bug(ref_expr.span, - "constant expression should not reach expr::trans_def") + Def::Local(..) | Def::Upvar(..) => { + DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum()) } _ => { - DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum()) + bcx.sess().span_bug(ref_expr.span, + &format!("{:?} should not reach expr::trans_def", def)) } } } @@ -1025,17 +1011,18 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } hir::ExprAssignOp(op, ref dst, ref src) => { - let has_method_map = bcx.tcx() - .tables - .borrow() - .method_map - .contains_key(&MethodCall::expr(expr.id)); + let method = bcx.tcx().tables + .borrow() + .method_map + .get(&MethodCall::expr(expr.id)).cloned(); - if has_method_map { + if let Some(method) = method { let dst = unpack_datum!(bcx, trans(bcx, &dst)); let src_datum = unpack_datum!(bcx, trans(bcx, &src)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst, - Some((src_datum, src.id)), None, false).bcx + + Callee::method(bcx, method) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(dst, Some(src_datum)), None).bcx } else { trans_assign_op(bcx, expr, op, &dst, &src) } @@ -1059,10 +1046,12 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); let mut bcx = bcx; - let tcx = bcx.tcx(); debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); + // Entry into the method table if this is an overloaded call/op. + let method_call = MethodCall::expr(expr.id); + match expr.node { hir::ExprType(ref e, _) => { trans_into(bcx, &e, dest) @@ -1088,59 +1077,6 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, node_id_type(bcx, expr.id), dest) } - hir::ExprRange(ref start, ref end) => { - // FIXME it is just not right that we are synthesising ast nodes in - // trans. Shudder. - fn make_field(field_name: &str, expr: P<hir::Expr>) -> hir::Field { - hir::Field { - name: codemap::dummy_spanned(token::intern(field_name)), - expr: expr, - span: codemap::DUMMY_SP, - } - } - - // A range just desugars into a struct. - // Note that the type of the start and end may not be the same, but - // they should only differ in their lifetime, which should not matter - // in trans. - let (did, fields, ty_params) = match (start, end) { - (&Some(ref start), &Some(ref end)) => { - // Desugar to Range - let fields = vec![make_field("start", start.clone()), - make_field("end", end.clone())]; - (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)]) - } - (&Some(ref start), &None) => { - // Desugar to RangeFrom - let fields = vec![make_field("start", start.clone())]; - (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)]) - } - (&None, &Some(ref end)) => { - // Desugar to RangeTo - let fields = vec![make_field("end", end.clone())]; - (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)]) - } - _ => { - // Desugar to RangeFull - (tcx.lang_items.range_full_struct(), vec![], vec![]) - } - }; - - if let Some(did) = did { - let substs = Substs::new_type(ty_params, vec![]); - trans_struct(bcx, - &fields, - None, - expr.span, - expr.id, - tcx.mk_struct(tcx.lookup_adt_def(did), - tcx.mk_substs(substs)), - dest) - } else { - tcx.sess.span_bug(expr.span, - "No lang item for ranges (how did we get this far?)") - } - } hir::ExprTup(ref args) => { let numbered_fields: Vec<(usize, &hir::Expr)> = args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect(); @@ -1199,47 +1135,54 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &expr.attrs).unwrap_or(bcx) } hir::ExprCall(ref f, ref args) => { - if bcx.tcx().is_method_call(expr.id) { - trans_overloaded_call(bcx, - expr, - &f, - &args[..], - Some(dest)) + let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let (callee, args) = if let Some(method) = method { + let mut all_args = vec![&**f]; + all_args.extend(args.iter().map(|e| &**e)); + + (Callee::method(bcx, method), ArgOverloadedCall(all_args)) } else { - callee::trans_call(bcx, - expr, - &f, - callee::ArgExprs(&args[..]), - dest) - } + let f = unpack_datum!(bcx, trans(bcx, f)); + (match f.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + Callee::def(bcx.ccx(), def_id, substs, f.ty) + } + ty::TyFnPtr(_) => { + let f = unpack_datum!(bcx, + f.to_rvalue_datum(bcx, "callee")); + Callee::ptr(f) + } + _ => { + bcx.tcx().sess.span_bug(expr.span, + &format!("type of callee is not a fn: {}", f.ty)); + } + }, ArgExprs(&args)) + }; + callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx } hir::ExprMethodCall(_, _, ref args) => { - callee::trans_method_call(bcx, - expr, - &args[0], - callee::ArgExprs(&args[..]), - dest) + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx } - hir::ExprBinary(op, ref lhs, ref rhs) => { + hir::ExprBinary(op, ref lhs, ref rhs_expr) => { // if not overloaded, would be RvalueDatumExpr let lhs = unpack_datum!(bcx, trans(bcx, &lhs)); - let rhs_datum = unpack_datum!(bcx, trans(bcx, &rhs)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs, - Some((rhs_datum, rhs.id)), Some(dest), - !rustc_front::util::is_by_value_binop(op.node)).bcx + let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr)); + if !rustc_front::util::is_by_value_binop(op.node) { + rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr)); + } + + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx } - hir::ExprUnary(op, ref subexpr) => { + hir::ExprUnary(_, ref subexpr) => { // if not overloaded, would be RvalueDatumExpr let arg = unpack_datum!(bcx, trans(bcx, &subexpr)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), - arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx - } - hir::ExprIndex(ref base, ref idx) => { - // if not overloaded, would be RvalueDatumExpr - let base = unpack_datum!(bcx, trans(bcx, &base)); - let idx_datum = unpack_datum!(bcx, trans(bcx, &idx)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base, - Some((idx_datum, idx.id)), Some(dest), true).bcx + + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(arg, None), Some(dest)).bcx } hir::ExprCast(..) => { // Trait casts used to come this way, now they should be coercions. @@ -1273,26 +1216,22 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Ignore => { return bcx; } }; + let ty = expr_ty(bcx, ref_expr); + if let ty::TyFnDef(..) = ty.sty { + // Zero-sized function or ctor. + return bcx; + } + match def { Def::Variant(tid, vid) => { let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); - if let ty::VariantKind::Tuple = variant.kind() { - // N-ary variant. - let llfn = callee::trans_fn_ref(bcx.ccx(), vid, - ExprId(ref_expr.id), - bcx.fcx.param_substs).val; - Store(bcx, llfn, lldest); - return bcx; - } else { - // Nullary variant. - let ty = expr_ty(bcx, ref_expr); - let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val)); - return bcx; - } + // Nullary variant. + let ty = expr_ty(bcx, ref_expr); + let repr = adt::represent_type(bcx.ccx(), ty); + adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val)); + bcx } Def::Struct(..) => { - let ty = expr_ty(bcx, ref_expr); match ty.sty { ty::TyStruct(def, _) if def.has_dtor() => { let repr = adt::represent_type(bcx.ccx(), ty); @@ -1310,41 +1249,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ref_expr: &hir::Expr, - def: Def, - param_substs: &'tcx Substs<'tcx>) - -> Datum<'tcx, Rvalue> { - let _icx = push_ctxt("trans_def_datum_unadjusted"); - - match def { - Def::Fn(did) | - Def::Struct(did) | Def::Variant(_, did) => { - callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) - } - Def::Method(method_did) => { - match ccx.tcx().impl_or_trait_item(method_did).container() { - ty::ImplContainer(_) => { - callee::trans_fn_ref(ccx, method_did, - ExprId(ref_expr.id), - param_substs) - } - ty::TraitContainer(trait_did) => { - meth::trans_static_method_callee(ccx, method_did, - trait_did, ref_expr.id, - param_substs) - } - } - } - _ => { - ccx.tcx().sess.span_bug(ref_expr.span, &format!( - "trans_def_fn_unadjusted invoked on: {:?} for {:?}", - def, - ref_expr)); - } - } -} - /// Translates a reference to a local variable or argument. This always results in an lvalue datum. pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def) @@ -1953,51 +1857,6 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - method_call: MethodCall, - lhs: Datum<'tcx, Expr>, - rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>, - dest: Option<Dest>, - autoref: bool) - -> Result<'blk, 'tcx> { - callee::trans_call_inner(bcx, - expr.debug_loc(), - |bcx, arg_cleanup_scope| { - meth::trans_method_callee(bcx, - method_call, - None, - arg_cleanup_scope) - }, - callee::ArgOverloadedOp(lhs, rhs, autoref), - dest) -} - -fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - callee: &'a hir::Expr, - args: &'a [P<hir::Expr>], - dest: Option<Dest>) - -> Block<'blk, 'tcx> { - debug!("trans_overloaded_call {}", expr.id); - let method_call = MethodCall::expr(expr.id); - let mut all_args = vec!(callee); - all_args.extend(args.iter().map(|e| &**e)); - unpack_result!(bcx, - callee::trans_call_inner(bcx, - expr.debug_loc(), - |bcx, arg_cleanup_scope| { - meth::trans_method_callee( - bcx, - method_call, - None, - arg_cleanup_scope) - }, - callee::ArgOverloadedCall(all_args), - dest)); - bcx -} - pub fn cast_is_noop<'tcx>(tcx: &TyCtxt<'tcx>, expr: &hir::Expr, t_in: Ty<'tcx>, @@ -2234,18 +2093,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut bcx = bcx; // Check for overloaded deref. - let method_ty = ccx.tcx() - .tables - .borrow() - .method_map - .get(&method_call).map(|method| method.ty); - - let datum = match method_ty { - Some(method_ty) => { - let method_ty = monomorphize_type(bcx, method_ty); - - // Overloaded. Evaluate `trans_overloaded_op`, which will - // invoke the user's deref() method, which basically + let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let datum = match method { + Some(method) => { + let method_ty = monomorphize_type(bcx, method.ty); + + // Overloaded. Invoke the deref() method, which basically // converts from the `Smaht<T>` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. @@ -2260,9 +2113,10 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); - unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, - datum, None, Some(SaveIn(scratch.val)), - false)); + bcx = Callee::method(bcx, method) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(datum, None), + Some(SaveIn(scratch.val))).bcx; scratch.to_expr_datum() } None => { @@ -2579,18 +2433,13 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind { match expr.node { hir::ExprPath(..) => { match tcx.resolve_expr(expr) { - Def::Struct(..) | Def::Variant(..) => { - if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty { - // ctor function - ExprKind::RvalueDatum - } else { - ExprKind::RvalueDps - } + // Put functions and ctors with the ADTs, as they + // are zero-sized, so DPS is the cheapest option. + Def::Struct(..) | Def::Variant(..) | + Def::Fn(..) | Def::Method(..) => { + ExprKind::RvalueDps } - // Fn pointers are just scalar values. - Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum, - // Note: there is actually a good case to be made that // DefArg's, particularly those of immediate type, ought to // considered rvalues. @@ -2625,7 +2474,6 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind { hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprStruct(..) | - hir::ExprRange(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprMatch(..) | diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 2a2178dd63b..cace98a230f 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -262,7 +262,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tn().val_to_string(llretptr)); let (fn_abi, fn_sig) = match callee_ty.sty { - ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig), + ty::TyFnDef(_, _, ref fn_ty) | + ty::TyFnPtr(ref fn_ty) => (fn_ty.abi, &fn_ty.sig), _ => ccx.sess().bug("trans_native_call called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); @@ -501,7 +502,8 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) { abi => { let ty = ccx.tcx().node_id_to_type(foreign_item.id); match ty.sty { - ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &decl, bft), + ty::TyFnDef(_, _, bft) | + ty::TyFnPtr(bft) => gate_simd_ffi(ccx.tcx(), &decl, bft), _ => ccx.tcx().sess.span_bug(foreign_item.span, "foreign fn's sty isn't a bare_fn_ty?") } @@ -552,7 +554,7 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tys = foreign_types_for_fn_ty(ccx, t); let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let cconv = match t.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => { llvm_calling_convention(ccx, fn_ty.abi) } _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") @@ -574,7 +576,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, let t = ccx.tcx().node_id_to_type(node_id); let cconv = match t.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => { llvm_calling_convention(ccx, fn_ty.abi) } _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi") @@ -634,7 +636,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Compute the type that the function would have if it were just a // normal Rust function. This will be the type of the wrappee fn. match t.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f)=> { assert!(f.abi != Abi::Rust); assert!(f.abi != Abi::RustIntrinsic); assert!(f.abi != Abi::PlatformIntrinsic); @@ -957,7 +959,7 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> ForeignTypes<'tcx> { let fn_sig = match ty.sty { - ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig, + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => &fn_ty.sig, _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 0b2ab58a835..d5f8cff4956 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -356,27 +356,18 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &unsized_args }; - bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - let trait_ref = ty::Binder(ty::TraitRef { - def_id: tcx.lang_items.drop_trait().unwrap(), - substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t)) - }); - let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data, - _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t)) - }; - let dtor_did = def.destructor().unwrap(); - let datum = callee::trans_fn_ref_with_substs(bcx.ccx(), - dtor_did, - ExprId(0), - bcx.fcx.param_substs, - vtbl.substs); - callee::Callee { - bcx: bcx, - data: callee::Fn(datum.val), - ty: datum.ty - } - }, callee::ArgVals(args), Some(expr::Ignore)).bcx; + let trait_ref = ty::Binder(ty::TraitRef { + def_id: tcx.lang_items.drop_trait().unwrap(), + substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t)) + }); + let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) { + traits::VtableImpl(data) => data, + _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t)) + }; + let dtor_did = def.destructor().unwrap(); + bcx = callee::Callee::ptr(callee::trans_fn_ref_with_substs( + bcx.ccx(), dtor_did, None, vtbl.substs)) + .call(bcx, DebugLoc::None, callee::ArgVals(args), Some(expr::Ignore)).bcx; bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope) } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index b7b520f6c82..96c1d6a4d69 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -22,7 +22,7 @@ use trans::adt; use trans::attributes; use trans::base::*; use trans::build::*; -use trans::callee; +use trans::callee::{self, Callee}; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; @@ -45,6 +45,7 @@ use syntax::ast; use syntax::ptr::P; use syntax::parse::token; +use rustc::lint; use rustc::session::Session; use syntax::codemap::Span; @@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) { transmute_restriction.substituted_to); let from_type_size = machine::llbitsize_of_real(ccx, llfromtype); let to_type_size = machine::llbitsize_of_real(ccx, lltotype); + + if let ty::TyFnDef(..) = transmute_restriction.substituted_from.sty { + if to_type_size == machine::llbitsize_of_real(ccx, ccx.int_type()) { + // FIXME #19925 Remove this warning after a release cycle. + lint::raw_emit_lint(&ccx.tcx().sess, + &ccx.tcx().sess.lint_store.borrow(), + lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES, + (lint::Warn, lint::LintSource::Default), + Some(transmute_restriction.span), + &format!("`{}` is now zero-sized and has to be cast \ + to a pointer before transmuting to `{}`", + transmute_restriction.substituted_from, + transmute_restriction.substituted_to)); + continue; + } + } if from_type_size != to_type_size { last_failing_id = Some(transmute_restriction.id); if transmute_restriction.original_from != transmute_restriction.substituted_from { span_transmute_size_error(ccx.sess(), transmute_restriction.span, &format!("transmute called with differently sized types: \ - {} (could be {} bit{}) to {} (could be {} bit{})", + {} (could be {} bits) to {} (could be {} bits)", transmute_restriction.original_from, - from_type_size as usize, - if from_type_size == 1 {""} else {"s"}, + from_type_size, transmute_restriction.original_to, - to_type_size as usize, - if to_type_size == 1 {""} else {"s"})); + to_type_size)); } else { span_transmute_size_error(ccx.sess(), transmute_restriction.span, &format!("transmute called with differently sized types: \ - {} ({} bit{}) to {} ({} bit{})", + {} ({} bits) to {} ({} bits)", transmute_restriction.original_from, - from_type_size as usize, - if from_type_size == 1 {""} else {"s"}, + from_type_size, transmute_restriction.original_to, - to_type_size as usize, - if to_type_size == 1 {""} else {"s"})); + to_type_size)); } } } @@ -163,7 +176,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, cleanup_scope: cleanup::CustomScopeIndex, args: callee::CallArgs<'a, 'tcx>, dest: expr::Dest, - substs: subst::Substs<'tcx>, + substs: &'tcx subst::Substs<'tcx>, call_info: NodeIdAndSpan) -> Result<'blk, 'tcx> { let fcx = bcx.fcx; @@ -179,6 +192,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let foreign_item = tcx.map.expect_foreign_item(node); let name = foreign_item.name.as_str(); + let call_debug_location = DebugLoc::At(call_info.id, call_info.span); + // For `transmute` we can just trans the input expr directly into dest if name == "transmute" { let llret_ty = type_of::type_of(ccx, ret_ty.unwrap()); @@ -194,6 +209,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let in_type_size = machine::llbitsize_of_real(ccx, llintype); let out_type_size = machine::llbitsize_of_real(ccx, llouttype); + if let ty::TyFnDef(def_id, substs, _) = in_type.sty { + if out_type_size != 0 { + // FIXME #19925 Remove this hack after a release cycle. + let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); + let llfn = Callee::def(ccx, def_id, substs, in_type).reify(ccx).val; + let llfnty = val_ty(llfn); + let llresult = match dest { + expr::SaveIn(d) => d, + expr::Ignore => alloc_ty(bcx, out_type, "ret") + }; + Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to())); + if dest == expr::Ignore { + bcx = glue::drop_ty(bcx, llresult, out_type, + call_debug_location); + } + fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); + fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); + return Result::new(bcx, llresult); + } + } + // This should be caught by the intrinsicck pass assert_eq!(in_type_size, out_type_size); @@ -311,8 +347,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } - let call_debug_location = DebugLoc::At(call_info.id, call_info.span); - // For `try` we need some custom control flow if &name[..] == "try" { if let callee::ArgExprs(ref exprs) = args { @@ -364,7 +398,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, callee_ty, &mut llargs, cleanup::CustomScope(cleanup_scope), - false, Abi::RustIntrinsic); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); @@ -1264,7 +1297,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // Define the type up front for the signature of the rust_try function. let tcx = ccx.tcx(); let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1273,9 +1306,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let fn_ty = tcx.mk_fn(None, fn_ty); let output = ty::FnOutput::FnConverging(tcx.types.i32); - let try_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let try_fn_ty = ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1283,8 +1315,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, output: output, variadic: false, }), - }); - let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn(None, try_fn_ty), output, + }; + let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn_ptr(try_fn_ty), output, trans); *ccx.rust_try_fn().borrow_mut() = Some(rust_try); return rust_try @@ -1353,7 +1385,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // going on here, all I can say is that there's a few tests cases in // LLVM's test suite which follow this pattern of instructions, so we // just do the same. - let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1362,7 +1394,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty); gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| { let ebp = Call(bcx, frameaddress, &[C_i32(ccx, 1)], None, dloc); let exn = InBoundsGEP(bcx, ebp, &[C_i32(ccx, -20)]); @@ -1373,7 +1404,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // Conveniently on x86_64 the EXCEPTION_POINTERS handle and base pointer // are passed in as arguments to the filter function, so we just pass // those along. - let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1382,7 +1413,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty); gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| { let exn = llvm::get_param(bcx.fcx.llfn, 0); let rbp = llvm::get_param(bcx.fcx.llfn, 1); @@ -1400,7 +1430,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { fn generic_simd_intrinsic<'blk, 'tcx, 'a> (bcx: Block<'blk, 'tcx>, name: &str, - substs: subst::Substs<'tcx>, + substs: &'tcx subst::Substs<'tcx>, callee_ty: Ty<'tcx>, args: Option<&[P<hir::Expr>]>, llargs: &[ValueRef], @@ -1508,11 +1538,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> None => bcx.sess().span_bug(call_info.span, "intrinsic call with unexpected argument shape"), }; - let vector = match consts::const_expr( - bcx.ccx(), - vector, - tcx.mk_substs(substs), - None, + let vector = match consts::const_expr(bcx.ccx(), vector, substs, None, consts::TrueConst::Yes, // this should probably help simd error reporting ) { Ok((vector, _)) => vector, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 221d17e6641..78b86dafa18 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -18,9 +18,8 @@ use middle::subst; use middle::traits; use trans::base::*; use trans::build::*; -use trans::callee::*; -use trans::callee; -use trans::cleanup; +use trans::callee::{Callee, Virtual, ArgVals, + trans_fn_pointer_shim, trans_fn_ref_with_substs}; use trans::closure; use trans::common::*; use trans::consts; @@ -30,11 +29,9 @@ use trans::declare; use trans::expr; use trans::glue; use trans::machine; -use trans::monomorphize; use trans::type_::Type; use trans::type_of::*; use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::MethodCall; use syntax::ast; use syntax::attr; @@ -92,264 +89,99 @@ pub fn trans_impl(ccx: &CrateContext, } } -pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - method_call: MethodCall, - self_expr: Option<&hir::Expr>, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_method_callee"); - - let method = bcx.tcx().tables.borrow().method_map[&method_call]; - - match bcx.tcx().impl_or_trait_item(method.def_id).container() { - ty::ImplContainer(_) => { - debug!("trans_method_callee: static, {:?}", method.def_id); - let datum = callee::trans_fn_ref(bcx.ccx(), - method.def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs); - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } - } - - ty::TraitContainer(trait_def_id) => { - let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id); - let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref)); - let span = bcx.tcx().map.span(method_call.expr_id); - debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}", - method_call, - trait_ref, - trait_ref.0.def_id, - trait_ref.0.substs); - let origin = fulfill_obligation(bcx.ccx(), span, trait_ref); - debug!("origin = {:?}", origin); - trans_monomorphized_callee(bcx, - method_call, - self_expr, - trait_def_id, - method.def_id, - method.ty, - origin, - arg_cleanup_scope) - } - } -} - -pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - method_id: DefId, - trait_id: DefId, - expr_id: ast::NodeId, - param_substs: &'tcx subst::Substs<'tcx>) - -> Datum<'tcx, Rvalue> -{ - let _icx = push_ctxt("meth::trans_static_method_callee"); - let tcx = ccx.tcx(); - - debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \ - expr_id={})", - method_id, - tcx.item_path_str(trait_id), - expr_id); - - let mname = tcx.item_name(method_id); - - debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \ - name={}", method_id, expr_id, mname); - - // Find the substitutions for the fn itself. This includes - // type parameters that belong to the trait but also some that - // belong to the method: - let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs); - debug!("rcvr_substs={:?}", rcvr_substs); - let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(traits::VtableImplData { - impl_def_id: impl_did, - substs: impl_substs, - nested: _ }) => - { - let callee_substs = impl_substs.with_method_from(&rcvr_substs); - let mth = tcx.get_impl_method(impl_did, callee_substs, mname); - trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id), - param_substs, - mth.substs) - } - traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); - trans_object_shim(ccx, - data.upcast_trait_ref.clone(), - method_id, - idx) - } - _ => { - // FIXME(#20847): handle at least VtableFnPointer - tcx.sess.bug(&format!("static call to invalid vtable: {:?}", - vtbl)); - } - } -} - -fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - method_call: MethodCall, - self_expr: Option<&hir::Expr>, - trait_id: DefId, - method_id: DefId, - method_ty: Ty<'tcx>, - vtable: traits::Vtable<'tcx, ()>, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_monomorphized_callee"); +/// Compute the appropriate callee, give na method's ID, trait ID, +/// substitutions and a Vtable for that trait. +pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + method_id: DefId, + substs: &'tcx subst::Substs<'tcx>, + trait_id: DefId, + method_ty: Ty<'tcx>, + vtable: traits::Vtable<'tcx, ()>) + -> Callee<'tcx> { + let _icx = push_ctxt("meth::callee_for_trait_impl"); match vtable { traits::VtableImpl(vtable_impl) => { - let ccx = bcx.ccx(); let impl_did = vtable_impl.impl_def_id; - let mname = match ccx.tcx().impl_or_trait_item(method_id) { - ty::MethodTraitItem(method) => method.name, - _ => { - bcx.tcx().sess.bug("can't monomorphize a non-method trait \ - item") - } - }; + let mname = ccx.tcx().item_name(method_id); // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let meth_substs = node_id_substs(ccx, - MethodCallKey(method_call), - bcx.fcx.param_substs); - let impl_substs = vtable_impl.substs.with_method_from(&meth_substs); - let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname); - // translate the function - let datum = trans_fn_ref_with_substs(bcx.ccx(), - mth.method.def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs, - mth.substs); - - Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } + let impl_substs = vtable_impl.substs.with_method_from(&substs); + let substs = ccx.tcx().mk_substs(impl_substs); + let mth = ccx.tcx().get_impl_method(impl_did, substs, mname); + + // Translate the function, bypassing Callee::def. + // That is because default methods have the same ID as the + // trait method used to look up the impl method that ended + // up here, so calling Callee::def would infinitely recurse. + Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id, + Some(method_ty), mth.substs)) } traits::VtableClosure(vtable_closure) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = closure::trans_closure_method(bcx.ccx(), + let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = closure::trans_closure_method(ccx, vtable_closure.closure_def_id, vtable_closure.substs, trait_closure_kind); - Callee { - bcx: bcx, - data: Fn(llfn), - ty: monomorphize_type(bcx, method_ty) - } + let fn_ptr_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", + method_ty) + }; + Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) } traits::VtableFnPointer(fn_ty) => { - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); - Callee { - bcx: bcx, - data: Fn(llfn), - ty: monomorphize_type(bcx, method_ty) - } + let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty); + let fn_ptr_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", + method_ty) + }; + Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) } traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id); - if let Some(self_expr) = self_expr { - if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty { - let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty)); - return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope); - } + Callee { + data: Virtual(traits::get_vtable_index_of_object_method( + ccx.tcx(), data, method_id)), + ty: method_ty } - let datum = trans_object_shim(bcx.ccx(), - data.upcast_trait_ref.clone(), - method_id, - idx); - Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } } traits::VtableBuiltin(..) | traits::VtableDefaultImpl(..) | traits::VtableParam(..) => { - bcx.sess().bug( + ccx.sess().bug( &format!("resolved vtable bad vtable {:?} in trans", vtable)); } } } -/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type). -/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the -/// object. Objects are represented as a pair, so we first evaluate the self expression and then -/// extract the self data and vtable out of the pair. -fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - opaque_fn_ty: Ty<'tcx>, - vtable_index: usize, - self_expr: &hir::Expr, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_trait_callee"); - let mut bcx = bcx; - - // Translate self_datum and take ownership of the value by - // converting to an rvalue. - let self_datum = unpack_datum!( - bcx, expr::trans(bcx, self_expr)); - - let llval = if bcx.fcx.type_needs_drop(self_datum.ty) { - let self_datum = unpack_datum!( - bcx, self_datum.to_rvalue_datum(bcx, "trait_callee")); - - // Convert to by-ref since `trans_trait_callee_from_llval` wants it - // that way. - let self_datum = unpack_datum!( - bcx, self_datum.to_ref_datum(bcx)); - - // Arrange cleanup in case something should go wrong before the - // actual call occurs. - self_datum.add_clean(bcx.fcx, arg_cleanup_scope) - } else { - // We don't have to do anything about cleanups for &Trait and &mut Trait. - assert!(self_datum.kind.is_by_ref()); - self_datum.val - }; - - let llself = Load(bcx, expr::get_dataptr(bcx, llval)); - let llvtable = Load(bcx, expr::get_meta(bcx, llval)); - trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable) -} - -/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object -/// pair. -fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - opaque_fn_ty: Ty<'tcx>, - vtable_index: usize, - llself: ValueRef, - llvtable: ValueRef) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_trait_callee"); +/// Extracts a method from a trait object's vtable, at the +/// specified index, and casts it to the given type. +pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + llvtable: ValueRef, + vtable_index: usize, + method_ty: Ty<'tcx>) + -> Datum<'tcx, Rvalue> { + let _icx = push_ctxt("meth::get_virtual_method"); let ccx = bcx.ccx(); // Load the data pointer from the object. - debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})", - opaque_fn_ty, + debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})", + method_ty, vtable_index, - bcx.val_to_string(llself), bcx.val_to_string(llvtable)); - // Replace the self type (&Self or Box<Self>) with an opaque pointer. let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET])); - let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty); - Callee { - bcx: bcx, - data: TraitItem(MethodData { - llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()), - llself: PointerCast(bcx, llself, Type::i8p(ccx)), - }), - ty: opaque_fn_ty + // Replace the self type (&Self or Box<Self>) with an opaque pointer. + if let ty::TyFnDef(_, _, fty) = method_ty.sty { + let opaque_ty = opaque_method_ty(ccx.tcx(), fty); + immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty) + } else { + immediate_rvalue(mptr, method_ty) } } @@ -374,46 +206,29 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// /// In fact, all virtual calls can be thought of as normal trait calls /// that go through this shim function. -pub fn trans_object_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - upcast_trait_ref: ty::PolyTraitRef<'tcx>, - method_id: DefId, - vtable_index: usize) - -> Datum<'tcx, Rvalue> -{ +pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + method_ty: Ty<'tcx>, + vtable_index: usize) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_object_shim"); let tcx = ccx.tcx(); - debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})", - upcast_trait_ref, - method_id); + debug!("trans_object_shim(vtable_index={}, method_ty={:?})", + vtable_index, + method_ty); - // Upcast to the trait in question and extract out the substitutions. - let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref); - let object_substs = upcast_trait_ref.substs.clone().erase_regions(); - debug!("trans_object_shim: object_substs={:?}", object_substs); + let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret()); + let ret_ty = infer::normalize_associated_type(tcx, &ret_ty); - // Lookup the type of this method as declared in the trait and apply substitutions. - let method_ty = match tcx.impl_or_trait_item(method_id) { - ty::MethodTraitItem(method) => method, - _ => { - tcx.sess.bug("can't create a method shim for a non-method item") - } + let shim_fn_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", method_ty) }; - let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty); - let fty = tcx.mk_bare_fn(fty); - let method_ty = opaque_method_ty(tcx, fty); - debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty); // - let shim_fn_ty = tcx.mk_fn(None, fty); - let method_bare_fn_ty = tcx.mk_fn(None, method_ty); let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); - let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); - let sig = infer::normalize_associated_type(ccx.tcx(), &sig); - let empty_substs = tcx.mk_substs(Substs::trans_empty()); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); @@ -421,11 +236,11 @@ pub fn trans_object_shim<'a, 'tcx>( llfn, ast::DUMMY_NODE_ID, false, - sig.output, + ret_ty, empty_substs, None, &block_arena); - let mut bcx = init_function(&fcx, false, sig.output); + let mut bcx = init_function(&fcx, false, ret_ty); let llargs = get_params(fcx.llfn); @@ -440,21 +255,18 @@ pub fn trans_object_shim<'a, 'tcx>( let dest = fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); + |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))); debug!("trans_object_shim: method_offset_in_vtable={}", vtable_index); - bcx = trans_call_inner(bcx, - DebugLoc::None, - |bcx, _| trans_trait_callee_from_llval(bcx, - method_bare_fn_ty, - vtable_index, - llself, llvtable), - ArgVals(&llargs[(self_idx + 2)..]), - dest).bcx; + let callee = Callee { + data: Virtual(vtable_index), + ty: method_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx; - finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + finish_fn(&fcx, bcx, ret_ty, DebugLoc::None); immediate_rvalue(llfn, shim_fn_ty) } @@ -466,8 +278,7 @@ pub fn trans_object_shim<'a, 'tcx>( /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then /// `trait_ref` would map `T:Trait`. pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>) + trait_ref: ty::PolyTraitRef<'tcx>) -> ValueRef { let tcx = ccx.tcx(); @@ -503,8 +314,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(mth) => { trans_fn_ref_with_substs(ccx, mth.method.def_id, - ExprId(0), - param_substs, + None, mth.substs).val } None => nullptr @@ -567,7 +377,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, impl_id: DefId, - substs: subst::Substs<'tcx>) + substs: &'tcx subst::Substs<'tcx>) -> Vec<Option<ty::util::ImplMethod<'tcx>>> { let tcx = ccx.tcx(); @@ -618,7 +428,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. - let mth = tcx.get_impl_method(impl_id, substs.clone(), name); + let mth = tcx.get_impl_method(impl_id, substs, name); debug!("get_vtable_methods: mth={:?}", mth); @@ -628,7 +438,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // method could then never be called, so we do not want to // try and trans it, in that case. Issue #23435. if mth.is_provided { - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); + let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { debug!("get_vtable_methods: predicates do not hold"); return None; @@ -642,11 +452,11 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// Replace the self type (&Self or Box<Self>) with an opaque pointer. fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) - -> &'tcx ty::BareFnTy<'tcx> { + -> Ty<'tcx> { let mut inputs = method_ty.sig.0.inputs.clone(); inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::IntTy::I8)); - tcx.mk_bare_fn(ty::BareFnTy { + tcx.mk_fn_ptr(ty::BareFnTy { unsafety: method_ty.unsafety, abi: method_ty.abi, sig: ty::Binder(ty::FnSig { diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index a9fee18ded8..50283c0959c 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,72 +9,27 @@ // except according to those terms. use llvm::{BasicBlockRef, ValueRef, OperandBundleDef}; -use rustc::middle::ty::{self, Ty}; +use rustc::middle::ty; use rustc::mir::repr as mir; use syntax::abi::Abi; use trans::adt; use trans::attributes; use trans::base; use trans::build; +use trans::callee::{Callee, Fn, Virtual}; use trans::common::{self, Block, BlockAndBuilder}; use trans::debuginfo::DebugLoc; use trans::Disr; use trans::foreign; +use trans::meth; use trans::type_of; use trans::glue; use trans::type_::Type; use super::{MirContext, drop}; use super::operand::OperandValue::{FatPtr, Immediate, Ref}; -use super::operand::OperandRef; - -#[derive(PartialEq, Eq)] -enum AbiStyle { - Foreign, - RustCall, - Rust -} impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { - fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle { - if let ty::TyBareFn(_, ref f) = fn_ty.sty { - // We do not translate intrinsics here (they shouldn’t be functions) - assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic); - - match f.abi { - Abi::Rust => AbiStyle::Rust, - Abi::RustCall => AbiStyle::RustCall, - _ => AbiStyle::Foreign - } - } else { - unreachable!() - } - } - - fn arg_operands(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - abi_style: AbiStyle, - args: &[mir::Operand<'tcx>]) - -> Vec<OperandRef<'tcx>> - { - match abi_style { - AbiStyle::Foreign | AbiStyle::Rust => { - args.iter().map(|arg| self.trans_operand(bcx, arg)).collect() - } - AbiStyle::RustCall => match args.split_last() { - None => vec![], - Some((tup, self_ty)) => { - // we can reorder safely because of MIR - let untupled_args = self.trans_operand_untupled(bcx, tup); - self_ty - .iter().map(|arg| self.trans_operand(bcx, arg)) - .chain(untupled_args.into_iter()) - .collect() - } - } - } - } - pub fn trans_block(&mut self, bb: mir::BasicBlock) { debug!("trans_block({:?})", bb); @@ -197,9 +152,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => { - // Create the callee. This will always be a fn ptr and hence a kind of scalar. + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); - let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); let debugloc = DebugLoc::None; // The arguments we'll be passing. Plus one to account for outptr, if used. let mut llargs = Vec::with_capacity(args.len() + 1); @@ -207,9 +161,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // filled when `is_foreign` is `true` and foreign calls are minority of the cases. let mut arg_tys = Vec::new(); + let (callee, fty) = match callee.ty.sty { + ty::TyFnDef(def_id, substs, f) => { + (Callee::def(bcx.ccx(), def_id, substs, callee.ty), f) + } + ty::TyFnPtr(f) => { + (Callee { + data: Fn(callee.immediate()), + ty: callee.ty + }, f) + } + _ => unreachable!("{} is not callable", callee.ty) + }; + + // We do not translate intrinsics here (they shouldn’t be functions) + assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic); // Foreign-ABI functions are translated differently - let abi_style = self.abi_style(callee.ty); - let is_foreign = abi_style == AbiStyle::Foreign; + let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall; // Prepare the return value destination let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination { @@ -225,19 +193,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (None, false) }; - // Process the rest of the args. - for operand in self.arg_operands(&bcx, abi_style, args) { - match operand.val { - Ref(llval) | Immediate(llval) => llargs.push(llval), - FatPtr(b, e) => { - llargs.push(b); - llargs.push(e); + // Split the rust-call tupled arguments off. + let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() { + let (tup, args) = args.split_last().unwrap(); + // we can reorder safely because of MIR + (args, self.trans_operand_untupled(&bcx, tup)) + } else { + (&args[..], vec![]) + }; + + let datum = { + let mut arg_ops = args.iter().map(|arg| { + self.trans_operand(&bcx, arg) + }).chain(rest.into_iter()); + + // Get the actual pointer we can call. + // This can involve vtable accesses or reification. + let datum = if let Virtual(idx) = callee.data { + assert!(!is_foreign); + + // Grab the first argument which is a trait object. + let vtable = match arg_ops.next().unwrap().val { + FatPtr(data, vtable) => { + llargs.push(data); + vtable + } + _ => unreachable!("expected FatPtr for Virtual call") + }; + + bcx.with_block(|bcx| { + meth::get_virtual_method(bcx, vtable, idx, callee.ty) + }) + } else { + callee.reify(bcx.ccx()) + }; + + // Process the rest of the args. + for operand in arg_ops { + match operand.val { + Ref(llval) | Immediate(llval) => llargs.push(llval), + FatPtr(b, e) => { + llargs.push(b); + llargs.push(e); + } + } + if is_foreign { + arg_tys.push(operand.ty); } } - if is_foreign { - arg_tys.push(operand.ty); - } - } + + datum + }; + let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty); // Many different ways to call a function handled here match (is_foreign, cleanup, destination) { @@ -246,7 +253,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let unreachable_blk = self.unreachable_block(); - bcx.invoke(callee.immediate(), + bcx.invoke(datum.val, &llargs[..], unreachable_blk.llbb, landingpad.llbb(), @@ -259,7 +266,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (false, &Some(cleanup), &Some((_, success))) => { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); - let invokeret = bcx.invoke(callee.immediate(), + let invokeret = bcx.invoke(datum.val, &llargs[..], self.llblock(success), landingpad.llbb(), @@ -282,7 +289,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }); }, (false, _, &None) => { - bcx.call(callee.immediate(), + bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -290,7 +297,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx.unreachable(); } (false, _, &Some((_, target))) => { - let llret = bcx.call(callee.immediate(), + let llret = bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -312,8 +319,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { .expect("return destination is not set"); bcx = bcx.map_block(|bcx| { foreign::trans_native_call(bcx, - callee.ty, - callee.immediate(), + datum.ty, + datum.val, dest.llval, &llargs[..], arg_tys, diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 7f03069385f..a0615a6cf5b 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -10,14 +10,14 @@ use back::abi; use llvm::ValueRef; -use middle::subst::Substs; use middle::ty::{Ty, TypeFoldable}; -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_eval::{self, ConstVal}; use rustc::mir::repr as mir; use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral, - C_str_slice}; + C_str_slice, C_nil, C_undef}; use trans::consts; use trans::expr; +use trans::inline; use trans::type_of; use super::operand::{OperandRef, OperandValue}; @@ -32,7 +32,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { -> OperandRef<'tcx> { let ccx = bcx.ccx(); - let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs); + let val = self.trans_constval_inner(bcx, cv, ty); let val = if common::type_is_immediate(ccx, ty) { OperandValue::Immediate(val) } else if common::type_is_fat_ptr(bcx.tcx(), ty) { @@ -55,8 +55,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { fn trans_constval_inner(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, cv: &ConstVal, - ty: Ty<'tcx>, - param_substs: &'tcx Substs<'tcx>) + ty: Ty<'tcx>) -> ValueRef { let ccx = bcx.ccx(); @@ -75,8 +74,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { expr::trans(bcx, expr).datum.val }) }, - ConstVal::Function(did) => - self.trans_fn_ref(bcx, ty, param_substs, did).immediate() + ConstVal::Function(_) => C_nil(ccx) } } @@ -85,13 +83,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { constant: &mir::Constant<'tcx>) -> OperandRef<'tcx> { + let ty = bcx.monomorphize(&constant.ty); match constant.literal { - mir::Literal::Item { def_id, kind, substs } => { + mir::Literal::Item { def_id, substs } => { + // Shortcut for zero-sized types, including function item + // types, which would not work with lookup_const_by_id. + if common::type_is_zero_size(bcx.ccx(), ty) { + let llty = type_of::type_of(bcx.ccx(), ty); + return OperandRef { + val: OperandValue::Immediate(C_undef(llty)), + ty: ty + }; + } + let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs)); - self.trans_item_ref(bcx, constant.ty, kind, substs, def_id) + let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id); + let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs)) + .expect("def was const, but lookup_const_by_id failed"); + // FIXME: this is falling back to translating from HIR. This is not easy to fix, + // because we would have somehow adapt const_eval to work on MIR rather than HIR. + let d = bcx.with_block(|bcx| { + expr::trans(bcx, expr) + }); + OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) } mir::Literal::Value { ref value } => { - let ty = bcx.monomorphize(&constant.ty); self.trans_constval(bcx, value, ty) } } diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs deleted file mode 100644 index 3741b07d248..00000000000 --- a/src/librustc_trans/trans/mir/did.rs +++ /dev/null @@ -1,171 +0,0 @@ -// 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Code for translating references to other items (DefIds). - -use syntax::codemap::DUMMY_SP; -use rustc::front::map; -use rustc::middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::middle::subst::Substs; -use rustc::middle::const_eval; -use rustc::middle::def_id::DefId; -use rustc::middle::traits; -use rustc::mir::repr::ItemKind; -use trans::common::{BlockAndBuilder, fulfill_obligation}; -use trans::base; -use trans::closure; -use trans::expr; -use trans::monomorphize; -use trans::meth; -use trans::inline; - -use super::MirContext; -use super::operand::{OperandRef, OperandValue}; - -impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { - /// Translate reference to item. - pub fn trans_item_ref(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - kind: ItemKind, - substs: &'tcx Substs<'tcx>, - did: DefId) - -> OperandRef<'tcx> { - debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})", - ty, kind, substs, bcx.tcx().item_path_str(did)); - - match kind { - ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did), - ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() { - ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did), - ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs) - }, - ItemKind::Constant => { - let did = inline::maybe_instantiate_inline(bcx.ccx(), did); - let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs)) - .expect("def was const, but lookup_const_by_id failed"); - // FIXME: this is falling back to translating from HIR. This is not easy to fix, - // because we would have somehow adapt const_eval to work on MIR rather than HIR. - let d = bcx.with_block(|bcx| { - expr::trans(bcx, expr) - }); - OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) - } - } - } - - /// Translates references to a function-like items. - /// - /// That includes regular functions, non-static methods, struct and enum variant constructors, - /// closures and possibly more. - /// - /// This is an adaptation of callee::trans_fn_ref_with_substs. - pub fn trans_fn_ref(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - did: DefId) - -> OperandRef<'tcx> { - debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})", - ty, substs, bcx.tcx().item_path_str(did)); - - let did = inline::maybe_instantiate_inline(bcx.ccx(), did); - - if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) { - let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None); - // FIXME: cast fnptr to proper type if necessary - OperandRef { - ty: fn_ty, - val: OperandValue::Immediate(val) - } - } else { - let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) { - base::get_item_val(bcx.ccx(), node_id) - } else { - base::trans_external_path(bcx.ccx(), did, ty) - }; - // FIXME: cast fnptr to proper type if necessary - OperandRef { - ty: ty, - val: OperandValue::Immediate(val) - } - } - } - - /// Translates references to trait methods. - /// - /// This is an adaptation of meth::trans_static_method_callee - pub fn trans_trait_method(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - method_id: DefId, - trait_id: DefId, - substs: &'tcx Substs<'tcx>) - -> OperandRef<'tcx> { - debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})", - ty, - bcx.tcx().item_path_str(method_id), - bcx.tcx().item_path_str(trait_id), - substs); - - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); - match vtbl { - traits::VtableImpl(traits::VtableImplData { - impl_def_id, substs: impl_substs, .. - }) => { - assert!(!impl_substs.types.needs_infer()); - - let mname = tcx.item_name(method_id); - - let callee_substs = impl_substs.with_method_from(substs); - let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname); - let mth_substs = tcx.mk_substs(mth.substs); - self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id) - }, - traits::VtableClosure(data) => { - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = closure::trans_closure_method(bcx.ccx(), - data.closure_def_id, - data.substs, - trait_closure_kind); - OperandRef { - ty: ty, - val: OperandValue::Immediate(llfn) - } - }, - traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); - OperandRef::from_rvalue_datum( - meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx) - ) - } - _ => { - tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl)); - } - } - } -} - -fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool { - let node_id = match tcx.map.as_local_node_id(def_id) { - Some(n) => n, - None => { return false; } - }; - match tcx.map.find(node_id).expect("local item should be in ast map") { - map::NodeVariant(v) => { - v.node.data.is_tuple() - } - map::NodeStructCtor(_) => true, - _ => false - } -} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 40dc22e31aa..4ad2e035945 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -196,7 +196,6 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mod analyze; mod block; mod constant; -mod did; mod drop; mod lvalue; mod operand; diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 541df43b49b..ce10ed425f6 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -15,6 +15,7 @@ use rustc::mir::repr as mir; use trans::asm; use trans::base; +use trans::callee::Callee; use trans::common::{self, BlockAndBuilder, Result}; use trans::debuginfo::DebugLoc; use trans::declare; @@ -193,9 +194,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cast_ty = bcx.monomorphize(&cast_ty); let val = match *kind { - mir::CastKind::ReifyFnPointer | + mir::CastKind::ReifyFnPointer => { + match operand.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + OperandValue::Immediate( + Callee::def(bcx.ccx(), def_id, substs, operand.ty) + .reify(bcx.ccx()).val) + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", operand.ty) + } + } + } mir::CastKind::UnsafeFnPointer => { - // these are no-ops at the LLVM level + // this is a no-op at the LLVM level operand.val } mir::CastKind::Unsize => { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 9edda3d2b5c..c6119416e47 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -37,16 +37,9 @@ use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, - psubsts: &'tcx subst::Substs<'tcx>, - ref_id: Option<ast::NodeId>) + psubsts: &'tcx subst::Substs<'tcx>) -> (ValueRef, Ty<'tcx>, bool) { - debug!("monomorphic_fn(\ - fn_id={:?}, \ - real_substs={:?}, \ - ref_id={:?})", - fn_id, - psubsts, - ref_id); + debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts); assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 24a7fd372f6..b78bf9bfc3f 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -150,26 +150,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Type::func(&atys[..], &lloutputtype) } -// Given a function type and a count of ty params, construct an llvm type -pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type { - match fty.sty { - ty::TyBareFn(_, ref f) => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here - if f.abi == Abi::Rust || f.abi == Abi::RustCall { - let sig = cx.tcx().erase_late_bound_regions(&f.sig); - let sig = infer::normalize_associated_type(cx.tcx(), &sig); - type_of_rust_fn(cx, None, &sig, f.abi) - } else { - foreign::lltype_for_foreign_fn(cx, fty) - } - } - _ => { - cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn") - } - } -} - // A "sizing type" is an LLVM type, the size and alignment of which are // guaranteed to be equivalent to what you would get out of `type_of()`. It's // useful because: @@ -210,7 +190,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } } - ty::TyBareFn(..) => Type::i8p(cx), + ty::TyFnDef(..) => Type::nil(cx), + ty::TyFnPtr(_) => Type::i8p(cx), ty::TyArray(ty, size) => { let llty = sizing_type_of(cx, ty); @@ -415,8 +396,15 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TySlice(ty) => in_memory_type_of(cx, ty), ty::TyStr | ty::TyTrait(..) => Type::i8(cx), - ty::TyBareFn(..) => { - type_of_fn_from_ty(cx, t).ptr_to() + ty::TyFnDef(..) => Type::nil(cx), + ty::TyFnPtr(f) => { + if f.abi == Abi::Rust || f.abi == Abi::RustCall { + let sig = cx.tcx().erase_late_bound_regions(&f.sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + type_of_rust_fn(cx, None, &sig, f.abi).ptr_to() + } else { + foreign::lltype_for_foreign_fn(cx, t).ptr_to() + } } ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx), ty::TyTuple(..) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 134da7a3bb0..1938fa75829 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1636,8 +1636,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl); - tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn)) + tcx.mk_fn_ptr(ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl)) } hir::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 548f5ee5e94..305970db9e7 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,9 +15,10 @@ use middle::pat_util::pat_is_resolved_const; use middle::subst::Substs; use middle::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; -use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; +use check::{demand, FnCtxt, Expectation}; use check::{check_expr_with_lvalue_pref}; use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; +use check::coercion; use lint; use require_same_types; use util::nodemap::FnvHashMap; @@ -492,54 +493,67 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // of execution reach it, we will panic, so bottom is an appropriate // type in that case) let expected = expected.adjust_for_branches(fcx); - let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| { - let bty = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { - check_expr_coercable_to_type(fcx, &arm.body, ety); - ety - } - _ => { - check_expr_with_expectation(fcx, &arm.body, expected); - fcx.node_ty(arm.body.id) + let mut result_ty = fcx.infcx().next_diverging_ty_var(); + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { + ety + } + _ => result_ty + }; + for (i, arm) in arms.iter().enumerate() { + if let Some(ref e) = arm.guard { + check_expr_has_type(fcx, e, tcx.types.bool); + } + check_expr_with_expectation(fcx, &arm.body, expected); + let arm_ty = fcx.expr_ty(&arm.body); + + if result_ty.references_error() || arm_ty.references_error() { + result_ty = tcx.types.err; + continue; + } + + // Handle the fallback arm of a desugared if-let like a missing else. + let is_if_let_fallback = match match_src { + hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { + i == arms.len() - 1 && arm_ty.is_nil() } + _ => false }; - if let Some(ref e) = arm.guard { - check_expr_has_type(fcx, &e, tcx.types.bool); - } + let origin = if is_if_let_fallback { + TypeOrigin::IfExpressionWithNoElse(expr.span) + } else { + TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + }; - if result_ty.references_error() || bty.references_error() { - tcx.types.err + let result = if is_if_let_fallback { + fcx.infcx().eq_types(true, origin, arm_ty, result_ty).map(|_| arm_ty) + } else if i == 0 { + // Special-case the first arm, as it has no "previous expressions". + coercion::try(fcx, &arm.body, coerce_first) } else { - let (origin, expected, found) = match match_src { - /* if-let construct without an else block */ - hir::MatchSource::IfLetDesugar { contains_else_clause } - if !contains_else_clause => ( - TypeOrigin::IfExpressionWithNoElse(expr.span), - bty, - result_ty, - ), - _ => ( - TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src), - result_ty, - bty, - ), - }; + let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); + coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body) + }; - infer::common_supertype( - fcx.infcx(), - origin, - true, - expected, - found, - ) - } - }); + result_ty = match result { + Ok(ty) => ty, + Err(e) => { + let (expected, found) = if is_if_let_fallback { + (arm_ty, result_ty) + } else { + (result_ty, arm_ty) + }; + fcx.infcx().report_mismatched_types(origin, expected, found, e); + fcx.tcx().types.err + } + }; + } fcx.write_ty(expr.id, result_ty); } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 42ea3cc2aaa..bf60f435a22 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -82,7 +82,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, autoderef(fcx, callee_expr.span, original_callee_ty, - Some(callee_expr), + || Some(callee_expr), UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { @@ -130,7 +130,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -225,7 +225,8 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, let error_fn_sig; let fn_sig = match callee_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => { + ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) | + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => { sig } _ => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2ea0df280db..b5cd5d7f8e5 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -55,7 +55,7 @@ use syntax::ast; /// Reifies a cast check to be checked once we have full type information for /// a function context. pub struct CastCheck<'tcx> { - expr: hir::Expr, + expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span, @@ -109,7 +109,7 @@ enum CastError { } impl<'tcx> CastCheck<'tcx> { - pub fn new(expr: hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) + pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) -> CastCheck<'tcx> { CastCheck { expr: expr, @@ -235,6 +235,20 @@ impl<'tcx> CastCheck<'tcx> { let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), + // Function item types may need to be reified before casts. + (None, Some(t_cast)) => { + if let ty::TyFnDef(_, _, f) = self.expr_ty.sty { + // Attempt a coercion to a fn pointer type. + let res = coercion::try(fcx, self.expr, + fcx.tcx().mk_ty(ty::TyFnPtr(f))); + if !res.is_ok() { + return Err(CastError::NonScalar); + } + (FnPtr, t_cast) + } else { + return Err(CastError::NonScalar); + } + } _ => { return Err(CastError::NonScalar) } @@ -376,14 +390,7 @@ impl<'tcx> CastCheck<'tcx> { } fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { - if let Ok(()) = coercion::mk_assignty(fcx, - &self.expr, - self.expr_ty, - self.cast_ty) { - true - } else { - false - } + coercion::try(fcx, self.expr, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5ab3c6f983f..aa359c95e2d 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,7 +62,7 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction}; -use middle::infer::{self, Coercion, TypeOrigin}; +use middle::infer::{Coercion, TypeOrigin, TypeTrace}; use middle::traits::{self, ObligationCause}; use middle::traits::{predicate_for_trait_def, report_selection_error}; use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; @@ -71,7 +71,7 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; use middle::ty::fold::TypeFoldable; use middle::ty::error::TypeError; -use middle::ty::relate::RelateResult; +use middle::ty::relate::{relate_substs, RelateResult, TypeRelation}; use util::common::indent; use std::cell::RefCell; @@ -80,42 +80,75 @@ use rustc_front::hir; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - origin: infer::TypeOrigin, + origin: TypeOrigin, + use_lub: bool, unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>, } -type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>; +type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>; + +fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, + to_mutbl: hir::Mutability) + -> RelateResult<'tcx, ()> { + match (from_mutbl, to_mutbl) { + (hir::MutMutable, hir::MutMutable) | + (hir::MutImmutable, hir::MutImmutable) | + (hir::MutMutable, hir::MutImmutable) => Ok(()), + (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability) + } +} impl<'f, 'tcx> Coerce<'f, 'tcx> { + fn new(fcx: &'f FnCtxt<'f, 'tcx>, origin: TypeOrigin) -> Self { + Coerce { + fcx: fcx, + origin: origin, + use_lub: false, + unsizing_obligations: RefCell::new(vec![]) + } + } + fn tcx(&self) -> &TyCtxt<'tcx> { self.fcx.tcx() } - fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b)); - Ok(None) // No coercion required. + /// Unify two types (using sub or lub) and produce a noop coercion. + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + let infcx = self.fcx.infcx(); + infcx.commit_if_ok(|_| { + let trace = TypeTrace::types(self.origin, false, a, b); + if self.use_lub { + infcx.lub(false, trace).relate(&a, &b) + } else { + infcx.sub(false, trace).relate(&a, &b) + } + }).and_then(|ty| self.identity(ty)) } - fn unpack_actual_value<T, F>(&self, a: Ty<'tcx>, f: F) -> T where - F: FnOnce(Ty<'tcx>) -> T, - { - f(self.fcx.infcx().shallow_resolve(a)) + /// Synthesize an identity adjustment. + fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { + Ok((ty, AdjustDerefRef(AutoDerefRef { + autoderefs: 0, + autoref: None, + unsize: None + }))) } - fn coerce(&self, - expr_a: &hir::Expr, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CoerceResult<'tcx> { - debug!("Coerce.tys({:?} => {:?})", - a, - b); + fn coerce<'a, E, I>(&self, + exprs: &E, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator<Item=&'a hir::Expr> { let a = self.fcx.infcx().shallow_resolve(a); + debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. if a.references_error() || b.references_error() { - return Ok(None); + return self.identity(b); } // Consider coercing the subtype to a DST @@ -134,27 +167,27 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } ty::TyRef(_, mt_b) => { - return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl); + return self.coerce_borrowed_pointer(exprs, a, b, mt_b.mutbl); } _ => {} } match a.sty { - ty::TyBareFn(Some(_), a_f) => { + ty::TyFnDef(_, _, a_f) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). self.coerce_from_fn_item(a, a_f, b) } - ty::TyBareFn(None, a_f) => { + ty::TyFnPtr(a_f) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. self.coerce_from_fn_pointer(a, a_f, b) } _ => { - // Otherwise, just use subtyping rules. - self.subtype(a, b) + // Otherwise, just use unification rules. + self.unify(a, b) } } } @@ -162,15 +195,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer(&self, - expr_a: &hir::Expr, - a: Ty<'tcx>, - b: Ty<'tcx>, - mutbl_b: hir::Mutability) - -> CoerceResult<'tcx> { - debug!("coerce_borrowed_pointer(a={:?}, b={:?})", - a, - b); + fn coerce_borrowed_pointer<'a, E, I>(&self, + exprs: &E, + a: Ty<'tcx>, + b: Ty<'tcx>, + mutbl_b: hir::Mutability) + -> CoerceResult<'tcx> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator<Item=&'a hir::Expr> { + + debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -182,20 +217,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyRef(_, mt_a) => { try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); } - _ => return self.subtype(a, b) + _ => return self.unify(a, b) } - let coercion = Coercion(self.origin.span()); + let span = self.origin.span(); + let coercion = Coercion(span); let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.tcx().mk_region(r_borrow); let autoref = Some(AutoPtr(r_borrow, mutbl_b)); let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); let mut first_error = None; - let (_, autoderefs, success) = autoderef(self.fcx, - expr_a.span, - a, - Some(expr_a), + let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs, UnresolvedTypeAction::Ignore, lvalue_pref, |inner_ty, autoderef| { @@ -206,19 +239,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let ty = self.tcx().mk_ref(r_borrow, TypeAndMut {ty: inner_ty, mutbl: mutbl_b}); - if let Err(err) = self.subtype(ty, b) { - if first_error.is_none() { - first_error = Some(err); + match self.unify(ty, b) { + Err(err) => { + if first_error.is_none() { + first_error = Some(err); + } + None } - None - } else { - Some(()) + Ok((ty, _)) => Some(ty) } }); match success { - Some(_) => { - Ok(Some(AdjustDerefRef(AutoDerefRef { + Some(ty) => { + Ok((ty, AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, autoref: autoref, unsize: None @@ -329,9 +363,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - let mut obligations = self.unsizing_obligations.borrow_mut(); - assert!(obligations.is_empty()); - *obligations = leftover_predicates; + *self.unsizing_obligations.borrow_mut() = leftover_predicates; let adjustment = AutoDerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, @@ -339,7 +371,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { unsize: Some(target) }; debug!("Success, coerced with {:?}", adjustment); - Ok(Some(AdjustDerefRef(adjustment))) + Ok((target, AdjustDerefRef(adjustment))) } fn coerce_from_fn_pointer(&self, @@ -353,22 +385,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { * into a closure or a `proc`. */ - self.unpack_actual_value(b, |b| { - debug!("coerce_from_fn_pointer(a={:?}, b={:?})", - a, b); + let b = self.fcx.infcx().shallow_resolve(b); + debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - if let ty::TyBareFn(None, fn_ty_b) = b.sty { - match (fn_ty_a.unsafety, fn_ty_b.unsafety) { - (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { - let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); - try!(self.subtype(unsafe_a, b)); - return Ok(Some(AdjustUnsafeFnPointer)); - } - _ => {} + if let ty::TyFnPtr(fn_ty_b) = b.sty { + match (fn_ty_a.unsafety, fn_ty_b.unsafety) { + (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { + let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); + return self.unify(unsafe_a, b).map(|(ty, _)| { + (ty, AdjustUnsafeFnPointer) + }); } + _ => {} } - self.subtype(a, b) - }) + } + self.unify(a, b) } fn coerce_from_fn_item(&self, @@ -381,19 +412,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { * into a closure or a `proc`. */ - self.unpack_actual_value(b, |b| { - debug!("coerce_from_fn_item(a={:?}, b={:?})", - a, b); + let b = self.fcx.infcx().shallow_resolve(b); + debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); - match b.sty { - ty::TyBareFn(None, _) => { - let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a); - try!(self.subtype(a_fn_pointer, b)); - Ok(Some(AdjustReifyFnPointer)) - } - _ => self.subtype(a, b) + match b.sty { + ty::TyFnPtr(_) => { + let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a)); + self.unify(a_fn_pointer, b).map(|(ty, _)| { + (ty, AdjustReifyFnPointer) + }) } - }) + _ => self.unify(a, b) + } } fn coerce_unsafe_ptr(&self, @@ -409,74 +439,192 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.subtype(a, b); + return self.unify(a, b); } }; // Check that the types which they point at are compatible. let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty }); - try!(self.subtype(a_unsafe, b)); + let (ty, noop) = try!(self.unify(a_unsafe, b)); try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that // regionck knows that the region for `a` must be valid here. - if is_ref { - Ok(Some(AdjustDerefRef(AutoDerefRef { + Ok((ty, if is_ref { + AdjustDerefRef(AutoDerefRef { autoderefs: 1, autoref: Some(AutoUnsafe(mutbl_b)), unsize: None - }))) + }) } else if mt_a.mutbl != mutbl_b { - Ok(Some(AdjustMutToConstPointer)) + AdjustMutToConstPointer } else { - Ok(None) - } + noop + })) } } -pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &hir::Expr, +fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>, + exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) - -> RelateResult<'tcx, ()> { - debug!("mk_assignty({:?} -> {:?})", a, b); - let mut unsizing_obligations = vec![]; - let adjustment = try!(indent(|| { - fcx.infcx().commit_if_ok(|_| { - let coerce = Coerce { - fcx: fcx, - origin: TypeOrigin::ExprAssignable(expr.span), - unsizing_obligations: RefCell::new(vec![]) - }; - let adjustment = try!(coerce.coerce(expr, a, b)); - unsizing_obligations = coerce.unsizing_obligations.into_inner(); - Ok(adjustment) - }) - })); + -> CoerceResult<'tcx> + where E: Fn() -> I, + I: IntoIterator<Item=&'b hir::Expr> { - if let Some(AdjustDerefRef(auto)) = adjustment { + let (ty, adjustment) = try!(indent(|| coerce.coerce(exprs, a, b))); + + let fcx = coerce.fcx; + if let AdjustDerefRef(auto) = adjustment { if auto.unsize.is_some() { - for obligation in unsizing_obligations { + let mut obligations = coerce.unsizing_obligations.borrow_mut(); + for obligation in obligations.drain(..) { fcx.register_predicate(obligation); } } } - if let Some(adjustment) = adjustment { - debug!("Success, coerced with {:?}", adjustment); - fcx.write_adjustment(expr.id, adjustment); - } - Ok(()) + Ok((ty, adjustment)) } -fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, - to_mutbl: hir::Mutability) - -> CoerceResult<'tcx> { - match (from_mutbl, to_mutbl) { - (hir::MutMutable, hir::MutMutable) | - (hir::MutImmutable, hir::MutImmutable) | - (hir::MutMutable, hir::MutImmutable) => Ok(None), - (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability) +/// Attempt to coerce an expression to a type, and return the +/// adjusted type of the expression, if successful. +/// Adjustments are only recorded if the coercion succeeded. +/// The expressions *must not* have any pre-existing adjustments. +pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &hir::Expr, + target: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> { + let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); + debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + + let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span)); + fcx.infcx().commit_if_ok(|_| { + let (ty, adjustment) = + try!(apply(&mut coerce, &|| Some(expr), source, target)); + if !adjustment.is_identity() { + debug!("Success, coerced with {:?}", adjustment); + assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); + fcx.write_adjustment(expr.id, adjustment); + } + Ok(ty) + }) +} + +/// Given some expressions, their known unified type and another expression, +/// tries to unify the types, potentially inserting coercions on any of the +/// provided expressions and returns their LUB (aka "common supertype"). +pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, + origin: TypeOrigin, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr) + -> RelateResult<'tcx, Ty<'tcx>> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator<Item=&'b hir::Expr> { + + let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty); + let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new)); + debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + + let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + let mut lub = fcx.infcx().lub(true, trace); + + // Special-case that coercion alone cannot handle: + // Two function item types of differing IDs or Substs. + match (&prev_ty.sty, &new_ty.sty) { + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { + // The signature must always match. + let fty = try!(lub.relate(a_fty, b_fty)); + + if a_def_id == b_def_id { + // Same function, maybe the parameters match. + let substs = fcx.infcx().commit_if_ok(|_| { + relate_substs(&mut lub, None, a_substs, b_substs) + }).map(|s| fcx.tcx().mk_substs(s)); + + if let Ok(substs) = substs { + // We have a LUB of prev_ty and new_ty, just return it. + return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty)); + } + } + + // Reify both sides and return the reified fn pointer type. + for expr in exprs().into_iter().chain(Some(new)) { + // No adjustments can produce a fn item, so this should never trip. + assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); + fcx.write_adjustment(expr.id, AdjustReifyFnPointer); + } + return Ok(fcx.tcx().mk_fn_ptr(fty)); + } + _ => {} + } + + let mut coerce = Coerce::new(fcx, origin); + coerce.use_lub = true; + + // First try to coerce the new expression to the type of the previous ones, + // but only if the new expression has no coercion already applied to it. + let mut first_error = None; + if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) { + let result = fcx.infcx().commit_if_ok(|_| { + apply(&mut coerce, &|| Some(new), new_ty, prev_ty) + }); + match result { + Ok((ty, adjustment)) => { + if !adjustment.is_identity() { + fcx.write_adjustment(new.id, adjustment); + } + return Ok(ty); + } + Err(e) => first_error = Some(e) + } + } + + // Then try to coerce the previous expressions to the type of the new one. + // This requires ensuring there are no coercions applied to *any* of the + // previous expressions, other than noop reborrows (ignoring lifetimes). + for expr in exprs() { + let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) { + Some(&AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(AutoPtr(_, mutbl_adj)), + unsize: None + })) => match fcx.expr_ty(expr).sty { + ty::TyRef(_, mt_orig) => { + // Reborrow that we can safely ignore. + mutbl_adj == mt_orig.mutbl + } + _ => false + }, + Some(_) => false, + None => true + }; + + if !noop { + return fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty)); + } + } + + match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + Err(_) => { + // Avoid giving strange errors on failed attempts. + if let Some(e) = first_error { + Err(e) + } else { + fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty)) + } + } + Ok((ty, adjustment)) => { + if !adjustment.is_identity() { + for expr in exprs() { + fcx.write_adjustment(expr.id, adjustment); + } + } + Ok(ty) + } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2bf7d65e331..ff7b809577f 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -276,9 +276,9 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, // type. // Compute skolemized form of impl and trait method tys. - let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(impl_m.fty.clone())); + let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); - let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(trait_m.fty.clone())); + let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); let err = infcx.commit_if_ok(|snapshot| { @@ -296,11 +296,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, impl_m_span, impl_m_body_id, &impl_sig); - let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, sig: ty::Binder(impl_sig) - })); + }); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -314,11 +314,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, impl_m_span, impl_m_body_id, &trait_sig); - let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, sig: ty::Binder(trait_sig) - })); + }); debug!("compare_impl_method: trait_fty={:?}", trait_fty); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 63dac49b384..1f61198bef9 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,45 +10,27 @@ use check::{coercion, FnCtxt}; -use middle::ty::{self, Ty}; -use middle::infer::{self, TypeOrigin}; +use middle::ty::Ty; +use middle::infer::TypeOrigin; -use std::result::Result::{Err, Ok}; use syntax::codemap::Span; use rustc_front::hir; // Requires that the two types unify, and prints an error message if // they don't. pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, false, ty_expected, ty_actual, - |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) -} - -/// As `suptype`, but call `handle_err` if unification for subtyping fails. -pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - b_is_expected: bool, - ty_a: Ty<'tcx>, - ty_b: Ty<'tcx>, - handle_err: F) where - F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>), -{ - // n.b.: order of actual, expected is reversed - match infer::mk_subty(fcx.infcx(), b_is_expected, TypeOrigin::Misc(sp), - ty_b, ty_a) { - Ok(()) => { /* ok */ } - Err(ref err) => { - handle_err(sp, ty_a, ty_b, err); - } + expected: Ty<'tcx>, actual: Ty<'tcx>) { + let origin = TypeOrigin::Misc(sp); + if let Err(e) = fcx.infcx().sub_types(false, origin, actual, expected) { + fcx.infcx().report_mismatched_types(origin, expected, actual, e); } } pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - match infer::mk_eqty(fcx.infcx(), false, TypeOrigin::Misc(sp), actual, expected) { - Ok(()) => { /* ok */ } - Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } + let origin = TypeOrigin::Misc(sp); + if let Err(e) = fcx.infcx().eq_types(false, origin, actual, expected) { + fcx.infcx().report_mismatched_types(origin, expected, actual, e); } } @@ -57,16 +39,10 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, expr: &hir::Expr) { - let expr_ty = fcx.expr_ty(expr); - debug!("demand::coerce(expected = {:?}, expr_ty = {:?})", - expected, - expr_ty); - let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty); let expected = fcx.resolve_type_vars_if_possible(expected); - match coercion::mk_assignty(fcx, expr, expr_ty, expected) { - Ok(()) => { /* ok */ } - Err(ref err) => { - fcx.report_mismatched_types(sp, expected, expr_ty, err); - } + if let Err(e) = coercion::try(fcx, expr, expected) { + let origin = TypeOrigin::Misc(sp); + let expr_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); + fcx.infcx().report_mismatched_types(origin, expected, expr_ty, e); } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 78faef473dd..4ebe4c25dd1 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -479,7 +479,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( Ok(()) } - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { // FIXME(#26656): this type is always destruction-safe, but // it implicitly witnesses Self: Fn, which can be false. Ok(()) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 6d8fff3caca..a05329bc4a4 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,7 @@ use astconv::AstConv; use intrinsics; -use middle::subst; +use middle::subst::{self, Substs}; use middle::ty::FnSig; use middle::ty::{self, Ty, TyCtxt}; use middle::ty::fold::TypeFolder; @@ -33,7 +33,13 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, abi: Abi, inputs: Vec<ty::Ty<'tcx>>, output: ty::FnOutput<'tcx>) { - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let def_id = tcx.map.local_def_id(it.id); + let i_ty = tcx.lookup_item_type(def_id); + + let mut substs = Substs::empty(); + substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def)); + + let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs), ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: abi, sig: ty::Binder(FnSig { @@ -41,8 +47,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, output: output, variadic: false, }), - })); - let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); + }); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); if i_n_tps != n_tps { span_err!(tcx.sess, it.span, E0094, @@ -296,8 +301,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { variadic: false, }), }; - let fn_ty = tcx.mk_bare_fn(fn_ty); - (0, vec![tcx.mk_fn(None, fn_ty), mut_u8, mut_u8], tcx.types.i32) + (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) } ref other => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f2f2eb66444..f4268deee37 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -98,27 +98,29 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let InstantiatedMethodSig { method_sig, all_substs, method_predicates } = self.instantiate_method_sig(&pick, all_substs); + let all_substs = self.tcx().mk_substs(all_substs); let method_self_ty = method_sig.inputs[0]; // Unify the (adjusted) self type with what the method expects. self.unify_receivers(self_ty, method_self_ty); // Create the method type + let def_id = pick.item.def_id(); let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy { + let fty = self.tcx().mk_fn_def(def_id, all_substs, ty::BareFnTy { sig: ty::Binder(method_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), - })); + }); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(fty, &all_substs, &method_predicates); + self.add_obligations(fty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { - def_id: pick.item.def_id(), + def_id: def_id, ty: fty, - substs: self.tcx().mk_substs(all_substs) + substs: all_substs }; // If this is an `&mut self` method, bias the receiver // expression towards mutability (this will switch @@ -156,7 +158,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let (autoderefd_ty, n, result) = check::autoderef(self.fcx, self.span, unadjusted_self_ty, - Some(self.self_expr), + || Some(self.self_expr), UnresolvedTypeAction::Error, NoPreference, |_, n| { @@ -285,7 +287,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let (_, _, result) = check::autoderef(self.fcx, self.span, self_ty, - None, + || None, UnresolvedTypeAction::Error, NoPreference, |ty, _| { @@ -457,7 +459,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn fixup_derefs_on_method_receiver_if_necessary(&self, method_callee: &ty::MethodCallee) { let sig = match method_callee.ty.sty { - ty::TyBareFn(_, ref f) => f.sig.clone(), + ty::TyFnDef(_, _, ref f) => f.sig.clone(), _ => return, }; @@ -507,7 +509,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { check::autoderef(self.fcx, expr.span, self.fcx.expr_ty(expr), - Some(expr), + || Some(expr), UnresolvedTypeAction::Error, PreferMutLvalue, |_, autoderefs| { @@ -520,92 +522,94 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } // Don't retry the first one or we might infinite loop! - if i != 0 { - match expr.node { - hir::ExprIndex(ref base_expr, ref index_expr) => { - // If this is an overloaded index, the - // adjustment will include an extra layer of - // autoref because the method is an &self/&mut - // self method. We have to peel it off to get - // the raw adjustment that `try_index_step` - // expects. This is annoying and horrible. We - // ought to recode this routine so it doesn't - // (ab)use the normal type checking paths. - let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) - .cloned(); - let (autoderefs, unsize) = match adj { - Some(AdjustDerefRef(adr)) => match adr.autoref { - None => { - assert!(adr.unsize.is_none()); - (adr.autoderefs, None) - } - Some(AutoPtr(_, _)) => { - (adr.autoderefs, adr.unsize.map(|target| { - target.builtin_deref(false, NoPreference) - .expect("fixup: AutoPtr is not &T").ty - })) - } - Some(_) => { - self.tcx().sess.span_bug( - base_expr.span, - &format!("unexpected adjustment autoref {:?}", - adr)); - } - }, - None => (0, None), + if i == 0 { + continue; + } + match expr.node { + hir::ExprIndex(ref base_expr, ref index_expr) => { + // If this is an overloaded index, the + // adjustment will include an extra layer of + // autoref because the method is an &self/&mut + // self method. We have to peel it off to get + // the raw adjustment that `try_index_step` + // expects. This is annoying and horrible. We + // ought to recode this routine so it doesn't + // (ab)use the normal type checking paths. + let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) + .cloned(); + let (autoderefs, unsize) = match adj { + Some(AdjustDerefRef(adr)) => match adr.autoref { + None => { + assert!(adr.unsize.is_none()); + (adr.autoderefs, None) + } + Some(AutoPtr(_, _)) => { + (adr.autoderefs, adr.unsize.map(|target| { + target.builtin_deref(false, NoPreference) + .expect("fixup: AutoPtr is not &T").ty + })) + } Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment type"); + &format!("unexpected adjustment autoref {:?}", + adr)); } - }; - - let (adjusted_base_ty, unsize) = if let Some(target) = unsize { - (target, true) - } else { - (self.fcx.adjust_expr_ty(base_expr, - Some(&AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - }))), false) - }; - let index_expr_ty = self.fcx.expr_ty(&index_expr); - - let result = check::try_index_step( - self.fcx, - ty::MethodCall::expr(expr.id), - expr, - &base_expr, - adjusted_base_ty, - autoderefs, - unsize, - PreferMutLvalue, - index_expr_ty); - - if let Some((input_ty, return_ty)) = result { - demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); - - let expr_ty = self.fcx.expr_ty(&expr); - demand::suptype(self.fcx, expr.span, expr_ty, return_ty); + }, + None => (0, None), + Some(_) => { + self.tcx().sess.span_bug( + base_expr.span, + "unexpected adjustment type"); } + }; + + let (adjusted_base_ty, unsize) = if let Some(target) = unsize { + (target, true) + } else { + (self.fcx.adjust_expr_ty(base_expr, + Some(&AdjustDerefRef(AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: None + }))), false) + }; + let index_expr_ty = self.fcx.expr_ty(&index_expr); + + let result = check::try_index_step( + self.fcx, + ty::MethodCall::expr(expr.id), + expr, + &base_expr, + adjusted_base_ty, + autoderefs, + unsize, + PreferMutLvalue, + index_expr_ty); + + if let Some((input_ty, return_ty)) = result { + demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); + + let expr_ty = self.fcx.expr_ty(&expr); + demand::suptype(self.fcx, expr.span, expr_ty, return_ty); } - hir::ExprUnary(hir::UnDeref, ref base_expr) => { - // if this is an overloaded deref, then re-evaluate with - // a preference for mut - let method_call = ty::MethodCall::expr(expr.id); - if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { - check::try_overloaded_deref( - self.fcx, - expr.span, - Some(method_call), - Some(&base_expr), - self.fcx.expr_ty(&base_expr), - PreferMutLvalue); - } + } + hir::ExprUnary(hir::UnDeref, ref base_expr) => { + // if this is an overloaded deref, then re-evaluate with + // a preference for mut + let method_call = ty::MethodCall::expr(expr.id); + if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { + let method = check::try_overloaded_deref( + self.fcx, + expr.span, + Some(&base_expr), + self.fcx.expr_ty(&base_expr), + PreferMutLvalue); + let method = method.expect("re-trying deref failed"); + self.fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); } - _ => {} } + _ => {} } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index fce44683413..e74623eda6d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -230,11 +230,12 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, &method_ty.fty.sig).0; let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let def_id = method_item.def_id(); + let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy { sig: ty::Binder(fn_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), - })); + }); debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", fty, @@ -318,7 +319,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } let callee = ty::MethodCallee { - def_id: method_item.def_id(), + def_id: def_id, ty: fty, substs: trait_ref.substs }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 02f8584c55d..d11a07cb41f 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -200,7 +200,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (final_ty, dereferences, _) = check::autoderef(fcx, span, self_ty, - None, + || None, UnresolvedTypeAction::Error, NoPreference, |t, d| { @@ -697,11 +697,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx(); let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() { - ty::FnClosureKind + ty::ClosureKind::Fn } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() { - ty::FnMutClosureKind + ty::ClosureKind::FnMut } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() { - ty::FnOnceClosureKind + ty::ClosureKind::FnOnce } else { return Ok(()); }; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e7d84efdaa2..7dc9d46c303 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -101,7 +101,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match field_ty.sty { // Not all of these (e.g. unsafe fns) implement FnOnce // so we look for these beforehand - ty::TyClosure(..) | ty::TyBareFn(..) => { + ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { span_stored_function!(); } // If it's not a simple function, look for things which implement FnOnce @@ -351,7 +351,7 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); } - check::autoderef(fcx, span, rcvr_ty, None, + check::autoderef(fcx, span, rcvr_ty, || None, check::UnresolvedTypeAction::Ignore, ty::NoPreference, |ty, _| { if is_local(ty) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9be46cf4053..0743c0b9e18 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -89,7 +89,7 @@ use middle::cstore::LOCAL_CRATE; use middle::def::{self, Def}; use middle::def_id::DefId; use middle::infer; -use middle::infer::{TypeOrigin, type_variable}; +use middle::infer::{TypeOrigin, TypeTrace, type_variable}; use middle::pat_util::{self, pat_id_map}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::traits::{self, report_fulfillment_errors}; @@ -101,6 +101,7 @@ use middle::ty::{MethodCall, MethodCallee}; use middle::ty::adjustment; use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::relate::TypeRelation; use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; @@ -434,7 +435,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, param_env: ty::ParameterEnvironment<'a, 'tcx>) { match raw_fty.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) => { let tables = RefCell::new(ty::Tables::empty()); let inh = Inherited::new(ccx.tcx, &tables, param_env); @@ -1622,14 +1623,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.infcx().type_error_struct(sp, mk_msg, actual_ty, err) } - pub fn report_mismatched_types(&self, - sp: Span, - e: Ty<'tcx>, - a: Ty<'tcx>, - err: &TypeError<'tcx>) { - self.infcx().report_mismatched_types(sp, e, a, err) - } - /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. pub fn register_region_obligation(&self, @@ -1709,6 +1702,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // FIXME(arielb1): use this instead of field.ty everywhere + // Only for fields! Returns <none> for methods> + // Indifferent to privacy flags pub fn field_ty(&self, span: Span, field: ty::FieldDef<'tcx>, @@ -1719,8 +1714,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &field.ty(self.tcx(), substs)) } - // Only for fields! Returns <none> for methods> - // Indifferent to privacy flags fn check_casts(&self) { let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); for cast in deferred_cast_checks.drain(..) { @@ -2061,20 +2054,21 @@ pub enum UnresolvedTypeAction { /// /// Note: this method does not modify the adjustments table. The caller is responsible for /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. -pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - base_ty: Ty<'tcx>, - opt_expr: Option<&hir::Expr>, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option<T>) - where F: FnMut(Ty<'tcx>, usize) -> Option<T>, +pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + base_ty: Ty<'tcx>, + maybe_exprs: E, + unresolved_type_action: UnresolvedTypeAction, + mut lvalue_pref: LvaluePreference, + mut should_stop: F) + -> (Ty<'tcx>, usize, Option<T>) + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator<Item=&'b hir::Expr>, + F: FnMut(Ty<'tcx>, usize) -> Option<T>, { - debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})", - base_ty, - opt_expr, - lvalue_pref); + debug!("autoderef(base_ty={:?}, lvalue_pref={:?})", + base_ty, lvalue_pref); let mut t = base_ty; for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { @@ -2087,7 +2081,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // (i.e. it is an inference variable) because `Ty::builtin_deref` // and `try_overloaded_deref` both simply return `None` // in such a case without producing spurious errors. - fcx.resolve_type_vars_if_possible(t) + fcx.infcx().resolve_type_vars_if_possible(&t) } }; if resolved_t.references_error() { @@ -2100,34 +2094,34 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } // Otherwise, deref if type is derefable: - let mt = match resolved_t.builtin_deref(false, lvalue_pref) { - Some(mt) => Some(mt), - None => { - let method_call = - opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32)); - - // Super subtle: it might seem as though we should - // pass `opt_expr` to `try_overloaded_deref`, so that - // the (implicit) autoref of using an overloaded deref - // would get added to the adjustment table. However we - // do not do that, because it's kind of a - // "meta-adjustment" -- instead, we just leave it - // unrecorded and know that there "will be" an - // autoref. regionck and other bits of the code base, - // when they encounter an overloaded autoderef, have - // to do some reconstructive surgery. This is a pretty - // complex mess that is begging for a proper MIR. - try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) + + // Super subtle: it might seem as though we should + // pass `opt_expr` to `try_overloaded_deref`, so that + // the (implicit) autoref of using an overloaded deref + // would get added to the adjustment table. However we + // do not do that, because it's kind of a + // "meta-adjustment" -- instead, we just leave it + // unrecorded and know that there "will be" an + // autoref. regionck and other bits of the code base, + // when they encounter an overloaded autoderef, have + // to do some reconstructive surgery. This is a pretty + // complex mess that is begging for a proper MIR. + let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { + mt + } else if let Some(method) = try_overloaded_deref(fcx, sp, None, + resolved_t, lvalue_pref) { + for expr in maybe_exprs() { + let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); } + make_overloaded_lvalue_return_type(fcx.tcx(), method) + } else { + return (resolved_t, autoderefs, None); }; - match mt { - Some(mt) => { - t = mt.ty; - if mt.mutbl == hir::MutImmutable { - lvalue_pref = NoPreference; - } - } - None => return (resolved_t, autoderefs, None) + + t = mt.ty; + if mt.mutbl == hir::MutImmutable { + lvalue_pref = NoPreference; } } @@ -2140,11 +2134,10 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, - method_call: Option<MethodCall>, base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option<ty::TypeAndMut<'tcx>> + -> Option<MethodCallee<'tcx>> { // Try DerefMut first, if preferred. let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) { @@ -2166,33 +2159,23 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, (method, _) => method }; - make_overloaded_lvalue_return_type(fcx, method_call, method) + method } /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the /// actual type we assign to the *expression* is `T`. So this function just peels off the return -/// type by one layer to yield `T`. It also inserts the `method-callee` into the method map. -fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - method_call: Option<MethodCall>, - method: Option<MethodCallee<'tcx>>) - -> Option<ty::TypeAndMut<'tcx>> +/// type by one layer to yield `T`. +fn make_overloaded_lvalue_return_type<'tcx>(tcx: &TyCtxt<'tcx>, + method: MethodCallee<'tcx>) + -> ty::TypeAndMut<'tcx> { - match method { - Some(method) => { - // extract method return type, which will be &T; - // all LB regions should have been instantiated during method lookup - let ret_ty = method.ty.fn_ret(); - let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); - - if let Some(method_call) = method_call { - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); - } + // extract method return type, which will be &T; + // all LB regions should have been instantiated during method lookup + let ret_ty = method.ty.fn_ret(); + let ret_ty = tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap(); - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true, NoPreference) - } - None => None, - } + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true, NoPreference).unwrap() } fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -2210,7 +2193,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (ty, autoderefs, final_mt) = autoderef(fcx, base_expr.span, base_ty, - Some(base_expr), + || Some(base_expr), UnresolvedTypeAction::Error, lvalue_pref, |adj_ty, idx| { @@ -2307,10 +2290,10 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - method.and_then(|method| { + method.map(|method| { debug!("try_index_step: success, using overloaded indexing"); - make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)). - map(|ret| (input_ty, ret.ty)) + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); + (input_ty, make_overloaded_lvalue_return_type(fcx.tcx(), method).ty) }) } @@ -2340,7 +2323,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::FnConverging(fcx.tcx().types.err) } else { match method_fn_ty.sty { - ty::TyBareFn(_, ref fty) => { + ty::TyFnDef(_, _, ref fty) => { // HACK(eddyb) ignore self in the definition (see above). let expected_arg_tys = expected_types_for_fn_args(fcx, sp, @@ -2509,20 +2492,17 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Expectation::rvalue_hint(fcx.tcx(), ty) }); - check_expr_with_unifier(fcx, - &arg, - expected.unwrap_or(ExpectHasType(formal_ty)), - NoPreference, || { - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExprHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(fcx)); - demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty)); - }); + check_expr_with_expectation(fcx, &arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(fcx)); + demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty)); } if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) { @@ -2619,7 +2599,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::TyInt(_) | ty::TyUint(_) => Some(ty), ty::TyChar => Some(tcx.types.u8), ty::TyRawPtr(..) => Some(tcx.types.usize), - ty::TyBareFn(..) => Some(tcx.types.usize), + ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize), _ => None } }); @@ -2644,57 +2624,42 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr))); + check_expr_with_hint(fcx, expr, expected); + demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)); } pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr))); + check_expr_with_hint(fcx, expr, expected); + demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr)); } fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::coerce(fcx, expr.span, expected, expr)); + check_expr_with_hint(fcx, expr, expected); + demand::coerce(fcx, expr.span, expected, expr); } fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || ()) + check_expr_with_expectation(fcx, expr, ExpectHasType(expected)) } fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Expectation<'tcx>) { - check_expr_with_unifier( - fcx, expr, expected, NoPreference, - || ()) -} - -fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) -{ - check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ()) + check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference) } fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr) { - check_expr_with_unifier(fcx, expr, NoExpectation, NoPreference, || ()) + check_expr_with_expectation(fcx, expr, NoExpectation) } fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr, lvalue_pref: LvaluePreference) { - check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ()) + check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref) } // determine the `self` type, using fresh variables for all variables @@ -2796,13 +2761,10 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `TyError`, so avoid /// that when err needs to be handled differently. -fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference, - unifier: F) where - F: FnOnce(), -{ +fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); @@ -2873,30 +2835,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); - let branches_ty = match opt_else_expr { - Some(ref else_expr) => { - check_expr_with_expectation(fcx, &else_expr, expected); - let else_ty = fcx.expr_ty(&else_expr); - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpression(sp), - true, - then_ty, - else_ty) - } - None => { - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpressionWithNoElse(sp), - false, - then_ty, - fcx.tcx().mk_nil()) - } - }; + let unit = fcx.tcx().mk_nil(); + let (origin, expected, found, result) = + if let Some(else_expr) = opt_else_expr { + check_expr_with_expectation(fcx, else_expr, expected); + let else_ty = fcx.expr_ty(else_expr); + let origin = TypeOrigin::IfExpression(sp); + + // Only try to coerce-unify if we have a then expression + // to assign coercions to, otherwise it's () or diverging. + let result = if let Some(ref then) = then_blk.expr { + let res = coercion::try_find_lub(fcx, origin, || Some(&**then), + then_ty, else_expr); + + // In case we did perform an adjustment, we have to update + // the type of the block, because old trans still uses it. + let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned(); + if res.is_ok() && adj.is_some() { + fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref())); + } - let cond_ty = fcx.expr_ty(cond_expr); - let if_ty = if cond_ty.references_error() { - fcx.tcx().types.err + res + } else { + fcx.infcx().commit_if_ok(|_| { + let trace = TypeTrace::types(origin, true, then_ty, else_ty); + fcx.infcx().lub(true, trace).relate(&then_ty, &else_ty) + }) + }; + (origin, then_ty, else_ty, result) } else { - branches_ty + let origin = TypeOrigin::IfExpressionWithNoElse(sp); + (origin, unit, then_ty, + fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit)) + }; + + let if_ty = match result { + Ok(ty) => { + if fcx.expr_ty(cond_expr).references_error() { + fcx.tcx().types.err + } else { + ty + } + } + Err(e) => { + fcx.infcx().report_mismatched_types(origin, expected, found, e); + fcx.tcx().types.err + } }; fcx.write_ty(id, if_ty); @@ -2915,7 +2899,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, - Some(base), + || Some(base), UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { @@ -3013,7 +2997,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, - Some(base), + || Some(base), UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { @@ -3261,21 +3245,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match unop { hir::UnDeref => { oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); - oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => match try_overloaded_deref(fcx, expr.span, - Some(MethodCall::expr(expr.id)), - Some(&oprnd), oprnd_t, lvalue_pref) { - Some(mt) => mt.ty, - None => { - fcx.type_error_message(expr.span, |actual| { - format!("type `{}` cannot be \ - dereferenced", actual) - }, oprnd_t, None); - tcx.types.err - } - } - }; + + if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { + oprnd_t = mt.ty; + } else if let Some(method) = try_overloaded_deref( + fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + oprnd_t = make_overloaded_lvalue_return_type(tcx, method).ty; + fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), + method); + } else { + fcx.type_error_message(expr.span, |actual| { + format!("type `{}` cannot be \ + dereferenced", actual) + }, oprnd_t, None); + oprnd_t = tcx.types.err; + } } hir::UnNot => { oprnd_t = structurally_resolved_type(fcx, oprnd.span, @@ -3519,7 +3503,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span); + let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span); deferred_cast_checks.push(cast_check); } } @@ -3536,23 +3520,30 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } }); - let typ = match uty { - Some(uty) => { - for e in args { - check_expr_coercable_to_type(fcx, &e, uty); - } - uty - } - None => { - let t: Ty = fcx.infcx().next_ty_var(); - for e in args { - check_expr_has_type(fcx, &e, t); + let mut unified = fcx.infcx().next_ty_var(); + let coerce_to = uty.unwrap_or(unified); + + for (i, e) in args.iter().enumerate() { + check_expr_with_hint(fcx, e, coerce_to); + let e_ty = fcx.expr_ty(e); + let origin = TypeOrigin::Misc(e.span); + + // Special-case the first element, as it has no "previous expressions". + let result = if i == 0 { + coercion::try(fcx, e, coerce_to) + } else { + let prev_elems = || args[..i].iter().map(|e| &**e); + coercion::try_find_lub(fcx, origin, prev_elems, unified, e) + }; + + match result { + Ok(ty) => unified = ty, + Err(e) => { + fcx.infcx().report_mismatched_types(origin, unified, e_ty, e); } - t } - }; - let typ = tcx.mk_array(typ, args.len()); - fcx.write_ty(id, typ); + } + fcx.write_ty(id, tcx.mk_array(unified, args.len())); } hir::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &count_expr, tcx.types.usize); @@ -3673,87 +3664,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } } - hir::ExprRange(ref start, ref end) => { - let t_start = start.as_ref().map(|e| { - check_expr(fcx, &e); - fcx.expr_ty(&e) - }); - let t_end = end.as_ref().map(|e| { - check_expr(fcx, &e); - fcx.expr_ty(&e) - }); - - let idx_type = match (t_start, t_end) { - (Some(ty), None) | (None, Some(ty)) => { - Some(ty) - } - (Some(t_start), Some(t_end)) if (t_start.references_error() || - t_end.references_error()) => { - Some(fcx.tcx().types.err) - } - (Some(t_start), Some(t_end)) => { - Some(infer::common_supertype(fcx.infcx(), - TypeOrigin::RangeExpression(expr.span), - true, - t_start, - t_end)) - } - _ => None - }; - - // Note that we don't check the type of start/end satisfy any - // bounds because right now the range structs do not have any. If we add - // some bounds, then we'll need to check `t_start` against them here. - - let range_type = match idx_type { - Some(idx_type) if idx_type.references_error() => { - fcx.tcx().types.err - } - Some(idx_type) => { - // Find the did from the appropriate lang item. - let did = match (start, end) { - (&Some(_), &Some(_)) => tcx.lang_items.range_struct(), - (&Some(_), &None) => tcx.lang_items.range_from_struct(), - (&None, &Some(_)) => tcx.lang_items.range_to_struct(), - (&None, &None) => { - tcx.sess.span_bug(expr.span, "full range should be dealt with above") - } - }; - - if let Some(did) = did { - let def = tcx.lookup_adt_def(did); - let predicates = tcx.lookup_predicates(did); - let substs = Substs::new_type(vec![idx_type], vec![]); - let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates); - fcx.add_obligations_for_parameters( - traits::ObligationCause::new(expr.span, - fcx.body_id, - traits::ItemObligation(did)), - &bounds); - - tcx.mk_struct(def, tcx.mk_substs(substs)) - } else { - span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax"); - fcx.tcx().types.err - } - } - None => { - // Neither start nor end => RangeFull - if let Some(did) = tcx.lang_items.range_full_struct() { - tcx.mk_struct( - tcx.lookup_adt_def(did), - tcx.mk_substs(Substs::empty()) - ) - } else { - span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax"); - fcx.tcx().types.err - } - } - }; - - fcx.write_ty(id, range_type); - } - } debug!("type of expr({}) {} is...", expr.id, @@ -3761,8 +3671,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, debug!("... {:?}, expected is {:?}", fcx.expr_ty(expr), expected); - - unifier(); } pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index f6225cf6ca7..e428fc927f0 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -881,7 +881,7 @@ fn constrain_callee(rcx: &mut Rcx, _callee_expr: &hir::Expr) { let callee_ty = rcx.resolve_node_type(callee_id); match callee_ty.sty { - ty::TyBareFn(..) => { } + ty::TyFnDef(..) | ty::TyFnPtr(_) => { } _ => { // this should not happen, but it does if the program is // erroneous diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index fca2c8193a7..2bb8c874d20 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -131,7 +131,7 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) { self.closures_with_inferred_kinds.insert(expr.id); self.fcx.inh.tables.borrow_mut().closure_kinds - .insert(closure_def_id, ty::FnClosureKind); + .insert(closure_def_id, ty::ClosureKind::Fn); debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds", closure_def_id); } @@ -301,7 +301,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { upvar_id); // to move out of an upvar, this must be a FnOnce closure - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind); + self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce); let upvar_capture_map = &mut self.fcx.inh.tables.borrow_mut().upvar_capture_map; @@ -314,7 +314,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { // must still adjust the kind of the closure // to be a FnOnce closure to permit moves out // of the environment. - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnOnceClosureKind); + self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce); } mc::NoteNone => { } @@ -418,7 +418,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } // also need to be in an FnMut closure since this is not an ImmBorrow - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind); + self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); true } @@ -426,7 +426,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { // this kind of deref occurs in a `move` closure, or // for a by-value upvar; in either case, to mutate an // upvar, we need to be an FnMut closure - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::FnMutClosureKind); + self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); true } @@ -488,16 +488,16 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { closure_id, existing_kind, new_kind); match (existing_kind, new_kind) { - (ty::FnClosureKind, ty::FnClosureKind) | - (ty::FnMutClosureKind, ty::FnClosureKind) | - (ty::FnMutClosureKind, ty::FnMutClosureKind) | - (ty::FnOnceClosureKind, _) => { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, _) => { // no change needed } - (ty::FnClosureKind, ty::FnMutClosureKind) | - (ty::FnClosureKind, ty::FnOnceClosureKind) | - (ty::FnMutClosureKind, ty::FnOnceClosureKind) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind closure_kinds.insert(closure_def_id, new_kind); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 997f56bd449..a8ada806131 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -255,9 +255,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { - ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty, + ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty, _ => { - this.tcx().sess.span_bug(item.span, "Fn item without bare fn type"); + this.tcx().sess.span_bug(item.span, "Fn item without fn type"); } }; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 61060114330..cad321c0b23 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -27,7 +27,7 @@ use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; use middle::ty::{TyParam, TyRawPtr}; use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple}; use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn}; +use middle::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use middle::ty::TyProjection; use middle::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; @@ -67,8 +67,8 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, } TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyStr | TyArray(..) | TySlice(..) | TyBareFn(..) | TyTuple(..) | - TyParam(..) | TyError | + TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | + TyTuple(..) | TyParam(..) | TyError | TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => { None } @@ -385,11 +385,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); + let origin = TypeOrigin::Misc(span); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { - infcx.report_mismatched_types(span, mk_ptr(mt_b.ty), - target, &ty::error::TypeError::Mutability); + infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty), + target, ty::error::TypeError::Mutability); } (mt_a.ty, mt_b.ty, unsize_trait, None) }; @@ -418,7 +419,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return; } - let origin = TypeOrigin::Misc(span); let fields = &def_a.struct_variant().fields; let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b3305fdb9a0..3ce03e24578 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -543,6 +543,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, sig, untransformed_rcvr_ty); let def_id = ccx.tcx.map.local_def_id(id); + let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let ty_method = ty::Method::new(name, ty_generics, ty_generic_predicates, @@ -552,8 +554,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id, container); - let fty = ccx.tcx.mk_fn(Some(def_id), - ccx.tcx.mk_bare_fn(ty_method.fty.clone())); + let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty.clone()); debug!("method {} (id {}) has type {:?}", name, id, fty); ccx.tcx.register_item_type(def_id, TypeScheme { @@ -715,17 +716,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { tcx.register_item_type(def_id, TypeScheme { generics: ty_generics.clone(), ty: selfty }); - if let &Some(ref ast_trait_ref) = opt_trait_ref { - tcx.impl_trait_refs.borrow_mut().insert( - def_id, - Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, - ast_trait_ref, - Some(selfty))) - ); - } else { - tcx.impl_trait_refs.borrow_mut().insert(def_id, None); - } + let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { + astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), + &ExplicitRscope, + ast_trait_ref, + Some(selfty)) + }); + tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); enforce_impl_params_are_constrained(tcx, generics, &mut ty_predicates, def_id); tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); @@ -902,7 +899,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } if !struct_def.is_struct() { - convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates); + convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates); } }, hir::ItemTy(_, ref generics) => { @@ -920,11 +917,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } -fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>, +fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctor_id: ast::NodeId, variant: ty::VariantDef<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { + let tcx = ccx.tcx; let ctor_ty = match variant.kind() { VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { @@ -933,9 +931,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>, .iter() .map(|field| field.unsubst_ty()) .collect(); - tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id), - &inputs[..], - scheme.ty) + let def_id = tcx.map.local_def_id(ctor_id); + let substs = tcx.mk_substs(mk_item_substs(ccx, &scheme.generics)); + tcx.mk_fn_def(def_id, substs, ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: abi::Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: inputs, + output: ty::FnConverging(scheme.ty), + variadic: false + }) + }) } }; write_ty_to_tcx(tcx, ctor_id, ctor_ty); @@ -961,7 +967,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Convert the ctor, if any. This also registers the variant as // an item. convert_variant_ctor( - ccx.tcx, + ccx, variant.node.data.id(), ty_variant, scheme.clone(), @@ -1436,7 +1442,9 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl); - let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd)); + let def_id = ccx.tcx.map.local_def_id(it.id); + let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let ty = tcx.mk_fn_def(def_id, substs, tofd); ty::TypeScheme { ty: ty, generics: ty_generics } } hir::ItemTy(ref t, ref generics) => { @@ -1556,7 +1564,9 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>( { match it.node { hir::ForeignItemFn(ref fn_decl, ref generics) => { - compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi) + compute_type_scheme_of_foreign_fn_decl( + ccx, ccx.tcx.map.local_def_id(it.id), + fn_decl, generics, abi) } hir::ForeignItemStatic(ref t, _) => { ty::TypeScheme { @@ -2107,6 +2117,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, + id: DefId, decl: &hir::FnDecl, ast_generics: &hir::Generics, abi: abi::Abi) @@ -2140,14 +2151,14 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ty::FnDiverging }; - let t_fn = ccx.tcx.mk_fn(None, - ccx.tcx.mk_bare_fn(ty::BareFnTy { - abi: abi, - unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic}), - })); + let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let t_fn = ccx.tcx.mk_fn_def(id, substs, ty::BareFnTy { + abi: abi, + unsafety: hir::Unsafety::Unsafe, + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output, + variadic: decl.variadic}), + }); ty::TypeScheme { generics: ty_generics, diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 336bff26e2c..907ee15c41b 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -72,7 +72,8 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> { parameters_for_regions_in_substs(&pi.trait_ref.substs), ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr | - ty::TyArray(..) | ty::TySlice(..) | ty::TyBareFn(..) | + ty::TyArray(..) | ty::TySlice(..) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyTuple(..) | ty::TyRawPtr(..) | ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError => vec![] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0ff6dcccde6..cfe76206b02 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1133,15 +1133,16 @@ enum Bad { } ``` -Here `X` will have already been assigned the discriminant 0 by the time `Y` is +Here `X` will have already been specified the discriminant 0 by the time `Y` is encountered, so a conflict occurs. "##, E0082: r##" -The default type for enum discriminants is `isize`, but it can be adjusted by -adding the `repr` attribute to the enum declaration. This error indicates that -an integer literal given as a discriminant is not a member of the discriminant -type. For example: +When you specify enum discriminants with `=`, the compiler expects `isize` +values by default. Or you can add the `repr` attibute to the enum declaration +for an explicit choice of the discriminant type. In either cases, the +discriminant values must fall within a valid range for the expected type; +otherwise this error is raised. For example: ```compile_fail #[repr(u8)] @@ -1152,11 +1153,19 @@ enum Thing { ``` Here, 1024 lies outside the valid range for `u8`, so the discriminant for `A` is -invalid. You may want to change representation types to fix this, or else change -invalid discriminant values so that they fit within the existing type. +invalid. Here is another, more subtle example which depends on target word size: -Note also that without a representation manually defined, the compiler will -optimize by using the smallest integer type possible. +```compile_fail +enum DependsOnPointerSize { + A = 1 << 32 +} +``` + +Here, `1 << 32` is interpreted as an `isize` value. So it is invalid for 32 bit +target (`target_pointer_width = "32"`) but valid for 64 bit target. + +You may want to change representation types to fix this, or else change invalid +discriminant values so that they fit within the existing type. "##, E0084: r##" @@ -3643,8 +3652,8 @@ register_diagnostics! { // E0233, // E0234, // E0235, // structure constructor specifies a structure of type but - E0236, // no lang item for range syntax - E0237, // no lang item for range syntax +// E0236, // no lang item for range syntax +// E0237, // no lang item for range syntax E0238, // parenthesized parameters may only be used with a trait // E0239, // `next` method of `Iterator` trait has unexpected type // E0240, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index a103cbc928b..035f8c60500 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -103,7 +103,7 @@ use dep_graph::DepNode; use front::map as hir_map; use middle::def::Def; use middle::infer::{self, TypeOrigin}; -use middle::subst; +use middle::subst::Substs; use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use session::{config, CompileResult}; use util::common::time; @@ -128,7 +128,7 @@ pub mod coherence; pub mod variance; pub struct TypeAndSubsts<'tcx> { - pub substs: subst::Substs<'tcx>, + pub substs: Substs<'tcx>, pub ty: Ty<'tcx>, } @@ -220,7 +220,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let tcx = ccx.tcx; let main_t = tcx.node_id_to_type(main_id); match main_t.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) => { match tcx.map.find(main_id) { Some(hir_map::NodeItem(it)) => { match it.node { @@ -236,7 +236,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, _ => () } let main_def_id = tcx.map.local_def_id(main_id); - let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy { + let substs = tcx.mk_substs(Substs::empty()); + let se_ty = tcx.mk_fn_def(main_def_id, substs, ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -244,7 +245,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, output: ty::FnConverging(tcx.mk_nil()), variadic: false }) - })); + }); require_same_types(tcx, None, false, main_span, main_t, se_ty, || { @@ -266,7 +267,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, let tcx = ccx.tcx; let start_t = tcx.node_id_to_type(start_id); match start_t.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) => { match tcx.map.find(start_id) { Some(hir_map::NodeItem(it)) => { match it.node { @@ -282,8 +283,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)), - tcx.mk_bare_fn(ty::BareFnTy { + let start_def_id = ccx.tcx.map.local_def_id(start_id); + let substs = tcx.mk_substs(Substs::empty()); + let se_ty = tcx.mk_fn_def(start_def_id, substs, ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -294,7 +296,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, output: ty::FnConverging(tcx.types.isize), variadic: false, }), - })); + }); require_same_types(tcx, None, false, start_span, start_t, se_ty, || { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 0c9fa9fd0ab..aecc588c3e2 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -429,7 +429,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyBareFn(_, &ty::BareFnTy { ref sig, .. }) => { + ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) | + ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => { self.add_constraints_from_sig(generics, sig, variance); } diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index 4cbcfd5a0b2..fb85176340e 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -51,3 +51,8 @@ pub mod str { pub mod derived_property { pub use tables::derived_property::{Cased, Case_Ignorable}; } + +// For use in libsyntax +pub mod property { + pub use tables::property::Pattern_White_Space; +} diff --git a/src/librustc_unicode/tables.rs b/src/librustc_unicode/tables.rs index a147bea791c..ad17016eae8 100644 --- a/src/librustc_unicode/tables.rs +++ b/src/librustc_unicode/tables.rs @@ -1180,6 +1180,15 @@ pub mod derived_property { } pub mod property { + pub const Pattern_White_Space_table: &'static [(char, char)] = &[ + ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'), + ('\u{2028}', '\u{2029}') + ]; + + pub fn Pattern_White_Space(c: char) -> bool { + super::bsearch_range_table(c, Pattern_White_Space_table) + } + pub const White_Space_table: &'static [(char, char)] = &[ ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), ('\u{2028}', '\u{2029}'), ('\u{202f}', diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 02ea83615a3..c14e4af8103 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -26,7 +26,7 @@ use rustc::middle::const_eval; use core::DocContext; use doctree; -use clean; +use clean::{self, Attributes}; use super::{Clean, ToSource}; @@ -138,13 +138,10 @@ pub fn load_attrs(cx: &DocContext, tcx: &TyCtxt, /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { - match cx.tcx_opt() { - Some(tcx) => { - let fqn = tcx.sess.cstore.extern_item_path(did); - let fqn = fqn.into_iter().map(|i| i.to_string()).collect(); - cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); - } - None => {} + if let Some(tcx) = cx.tcx_opt() { + let fqn = tcx.sess.cstore.extern_item_path(did); + let fqn = fqn.into_iter().map(|i| i.to_string()).collect(); + cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); } } @@ -167,7 +164,7 @@ pub fn build_external_trait(cx: &DocContext, tcx: &TyCtxt, fn build_external_function(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Function { let t = tcx.lookup_item_type(did); let (decl, style, abi) = match t.ty.sty { - ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), + ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; @@ -230,12 +227,9 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, tcx.populate_inherent_implementations_for_type_if_necessary(did); let mut impls = Vec::new(); - match tcx.inherent_impls.borrow().get(&did) { - None => {} - Some(i) => { - for &did in i.iter() { - build_impl(cx, tcx, did, &mut impls); - } + if let Some(i) = tcx.inherent_impls.borrow().get(&did) { + for &did in i.iter() { + build_impl(cx, tcx, did, &mut impls); } } @@ -259,7 +253,7 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, cstore::DlImpl(did) => build_impl(cx, tcx, did, impls), cstore::DlDef(Def::Mod(did)) => { // Don't recurse if this is a #[doc(hidden)] module - if load_attrs(cx, tcx, did).iter().any(|a| is_doc_hidden(a)) { + if load_attrs(cx, tcx, did).list_def("doc").has_word("hidden") { return; } @@ -288,7 +282,7 @@ pub fn build_impl(cx: &DocContext, if let Some(ref t) = associated_trait { // If this is an impl for a #[doc(hidden)] trait, be sure to not inline let trait_attrs = load_attrs(cx, tcx, t.def_id); - if trait_attrs.iter().any(|a| is_doc_hidden(a)) { + if trait_attrs.list_def("doc").has_word("hidden") { return } } @@ -428,20 +422,6 @@ pub fn build_impl(cx: &DocContext, }); } -fn is_doc_hidden(a: &clean::Attribute) -> bool { - match *a { - clean::List(ref name, ref inner) if *name == "doc" => { - inner.iter().any(|a| { - match *a { - clean::Word(ref s) => *s == "hidden", - _ => false, - } - }) - } - _ => false - } -} - fn build_module(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Module { let mut items = Vec::new(); @@ -464,9 +444,8 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt, } cstore::DlDef(def) if item.vis == hir::Public => { if !visited.insert(def) { continue } - match try_inline_def(cx, tcx, def) { - Some(i) => items.extend(i), - None => {} + if let Some(i) = try_inline_def(cx, tcx, def) { + items.extend(i) } } cstore::DlDef(..) => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b6da5b0ef20..5921093bcac 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -100,10 +100,7 @@ impl<T: Clean<U>, U> Clean<U> for Rc<T> { impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> { fn clean(&self, cx: &DocContext) -> Option<U> { - match self { - &None => None, - &Some(ref v) => Some(v.clean(cx)) - } + self.as_ref().map(|v| v.clean(cx)) } } @@ -178,9 +175,8 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> { }; let mut tmp = Vec::new(); for child in &mut m.items { - match child.inner { - ModuleItem(..) => {} - _ => continue, + if !child.is_mod() { + continue; } let prim = match PrimitiveType::find(&child.attrs) { Some(prim) => prim, @@ -261,7 +257,7 @@ pub struct Item { pub source: Span, /// Not everything has a name. E.g., impls pub name: Option<String>, - pub attrs: Vec<Attribute> , + pub attrs: Vec<Attribute>, pub inner: ItemEnum, pub visibility: Option<Visibility>, pub def_id: DefId, @@ -270,51 +266,17 @@ pub struct Item { } impl Item { - /// Finds the `doc` attribute as a List and returns the list of attributes - /// nested inside. - pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> { - for attr in &self.attrs { - match *attr { - List(ref x, ref list) if "doc" == *x => { - return Some(list); - } - _ => {} - } - } - return None; - } - /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. pub fn doc_value<'a>(&'a self) -> Option<&'a str> { - for attr in &self.attrs { - match *attr { - NameValue(ref x, ref v) if "doc" == *x => { - return Some(v); - } - _ => {} - } - } - return None; + self.attrs.value("doc") } - - pub fn is_hidden_from_doc(&self) -> bool { - match self.doc_list() { - Some(l) => { - for innerattr in l { - match *innerattr { - Word(ref s) if "hidden" == *s => { - return true - } - _ => (), - } - } - }, - None => () + pub fn is_crate(&self) -> bool { + match self.inner { + ModuleItem(Module { items: _, is_crate: true }) => true, + _ => false } - return false; } - pub fn is_mod(&self) -> bool { match self.inner { ModuleItem(..) => true, _ => false } } @@ -330,29 +292,34 @@ impl Item { pub fn is_fn(&self) -> bool { match self.inner { FunctionItem(..) => true, _ => false } } + pub fn is_associated_type(&self) -> bool { + match self.inner { AssociatedTypeItem(..) => true, _ => false } + } + pub fn is_associated_const(&self) -> bool { + match self.inner { AssociatedConstItem(..) => true, _ => false } + } + pub fn is_method(&self) -> bool { + match self.inner { MethodItem(..) => true, _ => false } + } + pub fn is_ty_method(&self) -> bool { + match self.inner { TyMethodItem(..) => true, _ => false } + } pub fn stability_class(&self) -> String { - match self.stability { - Some(ref s) => { - let mut base = match s.level { - stability::Unstable => "unstable".to_string(), - stability::Stable => String::new(), - }; - if !s.deprecated_since.is_empty() { - base.push_str(" deprecated"); - } - base + self.stability.as_ref().map(|ref s| { + let mut base = match s.level { + stability::Unstable => "unstable".to_string(), + stability::Stable => String::new(), + }; + if !s.deprecated_since.is_empty() { + base.push_str(" deprecated"); } - _ => String::new(), - } + base + }).unwrap_or(String::new()) } pub fn stable_since(&self) -> Option<&str> { - if let Some(ref s) = self.stability { - return Some(&s.since[..]); - } - - None + self.stability.as_ref().map(|s| &s.since[..]) } } @@ -448,10 +415,54 @@ impl Clean<Item> for doctree::Module { } } +pub trait Attributes { + fn has_word(&self, &str) -> bool; + fn value<'a>(&'a self, &str) -> Option<&'a str>; + fn list_def<'a>(&'a self, &str) -> &'a [Attribute]; +} + +impl Attributes for [Attribute] { + /// Returns whether the attribute list contains a specific `Word` + fn has_word(&self, word: &str) -> bool { + for attr in self { + if let Word(ref w) = *attr { + if word == *w { + return true; + } + } + } + false + } + + /// Finds an attribute as NameValue and returns the corresponding value found. + fn value<'a>(&'a self, name: &str) -> Option<&'a str> { + for attr in self { + if let NameValue(ref x, ref v) = *attr { + if name == *x { + return Some(v); + } + } + } + None + } + + /// Finds an attribute as List and returns the list of attributes nested inside. + fn list_def<'a>(&'a self, name: &str) -> &'a [Attribute] { + for attr in self { + if let List(ref x, ref list) = *attr { + if name == *x { + return &list[..]; + } + } + } + &[] + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub enum Attribute { Word(String), - List(String, Vec<Attribute> ), + List(String, Vec<Attribute>), NameValue(String, String) } @@ -496,12 +507,6 @@ impl attr::AttrMetaMethods for Attribute { fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None } fn span(&self) -> codemap::Span { unimplemented!() } } -impl<'a> attr::AttrMetaMethods for &'a Attribute { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option<InternedString> { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None } - fn span(&self) -> codemap::Span { unimplemented!() } -} #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct TyParam { @@ -711,7 +716,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> { if let &ty::Region::ReLateBound(_, _) = *reg { debug!(" hit an ReLateBound {:?}", reg); if let Some(lt) = reg.clean(cx) { - late_bounds.push(lt) + late_bounds.push(lt); } } } @@ -780,8 +785,7 @@ impl Clean<Option<Lifetime>> for ty::Region { fn clean(&self, cx: &DocContext) -> Option<Lifetime> { match *self { ty::ReStatic => Some(Lifetime::statik()), - ty::ReLateBound(_, ty::BrNamed(_, name)) => - Some(Lifetime(name.to_string())), + ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())), ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))), ty::ReLateBound(..) | @@ -1151,12 +1155,12 @@ impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> { impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; - let mut names = if let Some(_) = cx.map.as_local_node_id(did) { + let mut names = if cx.map.as_local_node_id(did).is_some() { vec![].into_iter() } else { cx.tcx().sess.cstore.method_arg_names(did).into_iter() }.peekable(); - if names.peek().map(|s| &**s) == Some("self") { + if let Some("self") = names.peek().map(|s| &s[..]) { let _ = names.next(); } FnDecl { @@ -1524,24 +1528,16 @@ impl PrimitiveType { } fn find(attrs: &[Attribute]) -> Option<PrimitiveType> { - for attr in attrs { - let list = match *attr { - List(ref k, ref l) if *k == "doc" => l, - _ => continue, - }; - for sub_attr in list { - let value = match *sub_attr { - NameValue(ref k, ref v) - if *k == "primitive" => v, - _ => continue, - }; - match PrimitiveType::from_str(value) { - Some(p) => return Some(p), - None => {} + for attr in attrs.list_def("doc") { + if let NameValue(ref k, ref v) = *attr { + if "primitive" == *k { + if let ret@Some(..) = PrimitiveType::from_str(v) { + return ret; + } } } } - return None + None } pub fn to_string(&self) -> &'static str { @@ -1627,15 +1623,9 @@ impl Clean<Type> for hir::Ty { } } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), - TyPolyTraitRef(ref bounds) => { - PolyTraitRef(bounds.clean(cx)) - }, - TyInfer => { - Infer - }, - TyTypeof(..) => { - panic!("Unimplemented type {:?}", self.node) - }, + TyPolyTraitRef(ref bounds) => PolyTraitRef(bounds.clean(cx)), + TyInfer => Infer, + TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } } } @@ -1673,7 +1663,8 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> { mutability: mt.mutbl.clean(cx), type_: box mt.ty.clean(cx), }, - ty::TyBareFn(_, ref fty) => BareFunction(box BareFunctionDecl { + ty::TyFnDef(_, _, ref fty) | + ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl { unsafety: fty.unsafety, generics: Generics { lifetimes: Vec::new(), @@ -2253,7 +2244,7 @@ impl Clean<Vec<Item>> for doctree::Impl { polarity: Some(self.polarity.clean(cx)), }), }); - return ret; + ret } } @@ -2393,9 +2384,8 @@ impl Clean<Vec<Item>> for doctree::Import { } hir::ViewPathSimple(name, ref p) => { if !denied { - match inline::try_inline(cx, self.id, Some(name)) { - Some(items) => return items, - None => {} + if let Some(items) = inline::try_inline(cx, self.id, Some(name)) { + return items; } } (vec![], SimpleImport(name.clean(cx), @@ -2460,9 +2450,8 @@ impl Clean<Vec<Item>> for hir::ForeignMod { fn clean(&self, cx: &DocContext) -> Vec<Item> { let mut items = self.items.clean(cx); for item in &mut items { - match item.inner { - ForeignFunctionItem(ref mut f) => f.abi = self.abi, - _ => {} + if let ForeignFunctionItem(ref mut f) = item.inner { + f.abi = self.abi; } } items @@ -2598,11 +2587,7 @@ fn resolve_type(cx: &DocContext, }; } }; - let def = match tcx.def_map.borrow().get(&id) { - Some(k) => k.full_def(), - None => panic!("unresolved id not in defmap") - }; - + let def = tcx.def_map.borrow().get(&id).expect("unresolved id not in defmap").full_def(); debug!("resolve_type: def={:?}", def); let is_generic = match def { @@ -2659,7 +2644,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { let t = inline::build_external_trait(cx, tcx, did); cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t); } - return did; + did } fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource { @@ -2732,12 +2717,10 @@ impl Clean<Stability> for attr::Stability { _=> "".to_string(), }, reason: { - if let Some(ref depr) = self.rustc_depr { - depr.reason.to_string() - } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level { - reason.to_string() - } else { - "".to_string() + match (&self.rustc_depr, &self.level) { + (&Some(ref depr), _) => depr.reason.to_string(), + (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(), + _ => "".to_string(), } }, issue: match self.level { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 345b84e0cac..5a6fe060eb8 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -133,7 +133,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs, let mut cfg = config::build_configuration(&sess); target_features::add_configuration(&mut cfg, &sess); - let krate = driver::phase_1_parse_input(&sess, cfg, &input); + let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); let name = link::find_crate_name(Some(&sess), &krate.attrs, &input); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 5a4f95d1a1a..ceec80402c0 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -9,8 +9,6 @@ // except according to those terms. use clean::*; -use std::collections::HashMap; -use std::mem::{replace, swap}; pub trait DocFolder : Sized { fn fold_item(&mut self, item: Item) -> Option<Item> { @@ -20,12 +18,10 @@ pub trait DocFolder : Sized { /// don't override! fn fold_item_recur(&mut self, item: Item) -> Option<Item> { let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item; - let inner = inner; let inner = match inner { StructItem(mut i) => { - let mut foo = Vec::new(); swap(&mut foo, &mut i.fields); - let num_fields = foo.len(); - i.fields.extend(foo.into_iter().filter_map(|x| self.fold_item(x))); + let num_fields = i.fields.len(); + i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); i.fields_stripped |= num_fields != i.fields.len(); StructItem(i) }, @@ -33,29 +29,25 @@ pub trait DocFolder : Sized { ModuleItem(self.fold_mod(i)) }, EnumItem(mut i) => { - let mut foo = Vec::new(); swap(&mut foo, &mut i.variants); - let num_variants = foo.len(); - i.variants.extend(foo.into_iter().filter_map(|x| self.fold_item(x))); + let num_variants = i.variants.len(); + i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect(); i.variants_stripped |= num_variants != i.variants.len(); EnumItem(i) }, TraitItem(mut i) => { - let mut foo = Vec::new(); swap(&mut foo, &mut i.items); - i.items.extend(foo.into_iter().filter_map(|x| self.fold_item(x))); + i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect(); TraitItem(i) }, ImplItem(mut i) => { - let mut foo = Vec::new(); swap(&mut foo, &mut i.items); - i.items.extend(foo.into_iter().filter_map(|x| self.fold_item(x))); + i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect(); ImplItem(i) }, VariantItem(i) => { let i2 = i.clone(); // this clone is small match i.kind { StructVariant(mut j) => { - let mut foo = Vec::new(); swap(&mut foo, &mut j.fields); - let num_fields = foo.len(); - j.fields.extend(foo.into_iter().filter_map(|x| self.fold_item(x))); + let num_fields = j.fields.len(); + j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); j.fields_stripped |= num_fields != j.fields.len(); VariantItem(Variant {kind: StructVariant(j), ..i2}) }, @@ -78,16 +70,13 @@ pub trait DocFolder : Sized { } fn fold_crate(&mut self, mut c: Crate) -> Crate { - c.module = match replace(&mut c.module, None) { - Some(module) => self.fold_item(module), None => None - }; - let external_traits = replace(&mut c.external_traits, HashMap::new()); - c.external_traits = external_traits.into_iter().map(|(k, mut v)| { - let items = replace(&mut v.items, Vec::new()); - v.items = items.into_iter().filter_map(|i| self.fold_item(i)) - .collect(); + c.module = c.module.and_then(|module| { + self.fold_item(module) + }); + c.external_traits = c.external_traits.into_iter().map(|(k, mut v)| { + v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); (k, v) }).collect(); - return c; + c } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index af6dec8dc86..2cb2b299e40 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -62,7 +62,7 @@ use rustc::middle::stability; use rustc::session::config::get_unstable_features_setting; use rustc_front::hir; -use clean::{self, SelfTy}; +use clean::{self, SelfTy, Attributes}; use doctree; use fold::DocFolder; use html::escape::Escape; @@ -104,6 +104,8 @@ pub struct Context { /// the source files are present in the html rendering, then this will be /// `true`. pub include_sources: bool, + /// The local file sources we've emitted and their respective url-paths. + pub local_sources: HashMap<PathBuf, String>, /// A flag, which when turned off, will render pages which redirect to the /// real location of an item. This is used to allow external links to /// publicly reused items to redirect to the right location. @@ -262,8 +264,6 @@ pub struct Cache { struct SourceCollector<'a> { cx: &'a mut Context, - /// Processed source-file paths - seen: HashSet<String>, /// Root destination to place all HTML output into dst: PathBuf, } @@ -374,7 +374,7 @@ fn init_ids() -> HashMap<String, usize> { "deref-methods", "implementations", "derived_implementations" - ].into_iter().map(|id| (String::from(*id), 1)).collect::<HashMap<_, _>>() + ].into_iter().map(|id| (String::from(*id), 1)).collect() } /// This method resets the local table of used ID attributes. This is typically @@ -423,6 +423,7 @@ pub fn run(mut krate: clean::Crate, playground_url: "".to_string(), }, include_sources: true, + local_sources: HashMap::new(), render_redirect_pages: false, issue_tracker_base_url: None, }; @@ -431,42 +432,38 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - let default: &[_] = &[]; - match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { - Some(attrs) => { - for attr in attrs { - match *attr { - clean::NameValue(ref x, ref s) - if "html_favicon_url" == *x => { - cx.layout.favicon = s.to_string(); - } - clean::NameValue(ref x, ref s) - if "html_logo_url" == *x => { - cx.layout.logo = s.to_string(); - } - clean::NameValue(ref x, ref s) - if "html_playground_url" == *x => { - cx.layout.playground_url = s.to_string(); - markdown::PLAYGROUND_KRATE.with(|slot| { - if slot.borrow().is_none() { - let name = krate.name.clone(); - *slot.borrow_mut() = Some(Some(name)); - } - }); - } - clean::NameValue(ref x, ref s) - if "issue_tracker_base_url" == *x => { - cx.issue_tracker_base_url = Some(s.to_string()); - } - clean::Word(ref x) - if "html_no_source" == *x => { - cx.include_sources = false; - } - _ => {} + if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list_def("doc")) { + for attr in attrs { + match *attr { + clean::NameValue(ref x, ref s) + if "html_favicon_url" == *x => { + cx.layout.favicon = s.to_string(); } + clean::NameValue(ref x, ref s) + if "html_logo_url" == *x => { + cx.layout.logo = s.to_string(); + } + clean::NameValue(ref x, ref s) + if "html_playground_url" == *x => { + cx.layout.playground_url = s.to_string(); + markdown::PLAYGROUND_KRATE.with(|slot| { + if slot.borrow().is_none() { + let name = krate.name.clone(); + *slot.borrow_mut() = Some(Some(name)); + } + }); + } + clean::NameValue(ref x, ref s) + if "issue_tracker_base_url" == *x => { + cx.issue_tracker_base_url = Some(s.to_string()); + } + clean::Word(ref x) + if "html_no_source" == *x => { + cx.include_sources = false; + } + _ => {} } } - None => {} } // Crawl the crate to build various caches used for the output @@ -770,11 +767,8 @@ fn render_sources(cx: &mut Context, try_err!(mkdir(&dst), &dst); let mut folder = SourceCollector { dst: dst, - seen: HashSet::new(), cx: cx, }; - // skip all invalid spans - folder.seen.insert("".to_string()); Ok(folder.fold_crate(krate)) } @@ -838,35 +832,26 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation { // Failing that, see if there's an attribute specifying where to find this // external crate - for attr in &e.attrs { - match *attr { - clean::List(ref x, ref list) if "doc" == *x => { - for attr in list { - match *attr { - clean::NameValue(ref x, ref s) - if "html_root_url" == *x => { - if s.ends_with("/") { - return Remote(s.to_string()); - } - return Remote(format!("{}/", s)); - } - _ => {} - } - } - } - _ => {} + e.attrs.list_def("doc").value("html_root_url").map(|url| { + let mut url = url.to_owned(); + if !url.ends_with("/") { + url.push('/') } - } - - // Well, at least we tried. - return Unknown; + Remote(url) + }).unwrap_or(Unknown) // Well, at least we tried. } impl<'a> DocFolder for SourceCollector<'a> { fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> { // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem - if self.cx.include_sources && !self.seen.contains(&item.source.filename) { + if self.cx.include_sources + // skip all invalid spans + && item.source.filename != "" + // macros from other libraries get special filenames which we can + // safely ignore + && !(item.source.filename.starts_with("<") + && item.source.filename.ends_with("macros>")) { // If it turns out that we couldn't read this file, then we probably // can't read any of the files (generating html output from json or @@ -884,7 +869,6 @@ impl<'a> DocFolder for SourceCollector<'a> { false } }; - self.seen.insert(item.source.filename.clone()); } self.fold_item_recur(item) @@ -895,19 +879,14 @@ impl<'a> SourceCollector<'a> { /// Renders the given filename into its corresponding HTML source file. fn emit_source(&mut self, filename: &str) -> io::Result<()> { let p = PathBuf::from(filename); + if self.cx.local_sources.contains_key(&p) { + // We've already emitted this source + return Ok(()); + } - // If we couldn't open this file, then just returns because it - // probably means that it's some standard library macro thing and we - // can't have the source to it anyway. let mut contents = Vec::new(); - match File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)) { - Ok(r) => r, - // macros from other libraries get special filenames which we can - // safely ignore - Err(..) if filename.starts_with("<") && - filename.ends_with("macros>") => return Ok(()), - Err(e) => return Err(e) - }; + try!(File::open(&p).and_then(|mut f| f.read_to_end(&mut contents))); + let contents = str::from_utf8(&contents).unwrap(); // Remove the utf-8 BOM if any @@ -920,16 +899,20 @@ impl<'a> SourceCollector<'a> { // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = String::from("../../"); + let mut href = String::new(); clean_srcpath(&self.cx.src_root, &p, false, |component| { cur.push(component); mkdir(&cur).unwrap(); root_path.push_str("../"); + href.push_str(component); + href.push('/'); }); - let mut fname = p.file_name().expect("source has no filename") .to_os_string(); fname.push(".html"); cur.push(&fname[..]); + href.push_str(&fname.to_string_lossy()); + let mut w = BufWriter::new(try!(File::create(&cur))); let title = format!("{} -- source", cur.file_name().unwrap() .to_string_lossy()); @@ -939,12 +922,13 @@ impl<'a> SourceCollector<'a> { ty: "source", root_path: &root_path, description: &desc, - keywords: get_basic_keywords(), + keywords: BASIC_KEYWORDS, }; try!(layout::render(&mut w, &self.cx.layout, &page, &(""), &Source(contents))); try!(w.flush()); - return Ok(()); + self.cx.local_sources.insert(p, href); + Ok(()) } } @@ -983,15 +967,12 @@ impl DocFolder for Cache { // Collect all the implementors of traits. if let clean::ImplItem(ref i) = item.inner { - match i.trait_ { - Some(clean::ResolvedPath{ did, .. }) => { - self.implementors.entry(did).or_insert(vec![]).push(Implementor { - def_id: item.def_id, - stability: item.stability.clone(), - impl_: i.clone(), - }); - } - Some(..) | None => {} + if let Some(clean::ResolvedPath{ did, .. }) = i.trait_ { + self.implementors.entry(did).or_insert(vec![]).push(Implementor { + def_id: item.def_id, + stability: item.stability.clone(), + impl_: i.clone(), + }); } } @@ -1051,6 +1032,9 @@ impl DocFolder for Cache { } }); + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. if item.def_id.index != CRATE_DEF_INDEX { self.search_index.push(IndexItem { ty: shortty(&item), @@ -1075,13 +1059,14 @@ impl DocFolder for Cache { } // Keep track of the fully qualified path for this item. - let pushed = if item.name.is_some() { - let n = item.name.as_ref().unwrap(); - if !n.is_empty() { + let pushed = match item.name { + Some(ref n) if !n.is_empty() => { self.stack.push(n.to_string()); true - } else { false } - } else { false }; + } + _ => false, + }; + match item.inner { clean::StructItem(..) | clean::EnumItem(..) | clean::TypedefItem(..) | clean::TraitItem(..) | @@ -1150,60 +1135,40 @@ impl DocFolder for Cache { // Once we've recursively found all the generics, then hoard off all the // implementations elsewhere - let ret = match self.fold_item_recur(item) { - Some(item) => { - match item { - clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { - // extract relevant documentation for this impl - let dox = match attrs.into_iter().find(|a| { - match *a { - clean::NameValue(ref x, _) - if "doc" == *x => { - true - } - _ => false - } - }) { - Some(clean::NameValue(_, dox)) => Some(dox), - Some(..) | None => None, - }; - - // Figure out the id of this impl. This may map to a - // primitive rather than always to a struct/enum. - let did = match i.for_ { - clean::ResolvedPath { did, .. } | - clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - Some(did) - } - - ref t => { - t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).map(|n| { - let id = t.to_def_index(); - DefId { krate: *n, index: id } - }) - }) - } - }; - - if let Some(did) = did { - self.impls.entry(did).or_insert(vec![]).push(Impl { - impl_: i, - dox: dox, - stability: item.stability.clone(), - }); - } + let ret = self.fold_item_recur(item).and_then(|item| { + if let clean::Item { attrs, inner: clean::ImplItem(i), .. } = item { + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + let did = match i.for_ { + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + Some(did) + } - None + ref t => { + t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).map(|n| { + let id = t.to_def_index(); + DefId { krate: *n, index: id } + }) + }) } + }; - i => Some(i), + if let Some(did) = did { + self.impls.entry(did).or_insert(vec![]).push(Impl { + impl_: i, + dox: attrs.value("doc").map(|s|s.to_owned()), + stability: item.stability.clone(), + }); } + None + } else { + Some(item) } - i => i, - }; + }); if pushed { self.stack.pop().unwrap(); } if parent_pushed { self.parent_stack.pop().unwrap(); } @@ -1301,11 +1266,7 @@ impl Context { } title.push_str(" - Rust"); let tyname = shortty(it).to_static_str(); - let is_crate = match it.inner { - clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true, - _ => false - }; - let desc = if is_crate { + let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", cx.layout.krate) } else { @@ -1459,7 +1420,7 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn href(&self, cx: &Context) -> Option<String> { + fn href(&self) -> Option<String> { let href = if self.item.source.loline == self.item.source.hiline { format!("{}", self.item.source.loline) } else { @@ -1492,25 +1453,13 @@ impl<'a> Item<'a> { // know the span, so we plow forward and generate a proper url. The url // has anchors for the line numbers that we're linking to. } else if self.item.def_id.is_local() { - let mut path = Vec::new(); - clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename), - true, |component| { - path.push(component.to_string()); - }); - - // If the span points into an external macro the - // source-file will be bogus, i.e `<foo macros>` - let filename = &self.item.source.filename; - if !(filename.starts_with("<") && filename.ends_with("macros>")) { - Some(format!("{root}src/{krate}/{path}.html#{href}", - root = self.cx.root_path, - krate = self.cx.layout.krate, - path = path.join("/"), - href = href)) - } else { - None - } - + self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| { + format!("{root}src/{krate}/{path}.html#{href}", + root = self.cx.root_path, + krate = self.cx.layout.krate, + path = path, + href = href) + }) // If this item is not part of the local crate, then things get a little // trickier. We don't actually know the span of the external item, but // we know that the documentation on the other end knows the span! @@ -1590,13 +1539,10 @@ impl<'a> fmt::Display for Item<'a> { // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if self.cx.include_sources && !is_primitive { - match self.href(self.cx) { - Some(l) => { - try!(write!(fmt, "<a id='src-{}' class='srclink' \ - href='{}' title='{}'>[src]</a>", - self.item.def_id.index.as_usize(), l, "goto source code")); - } - None => {} + if let Some(l) = self.href() { + try!(write!(fmt, "<a id='src-{}' class='srclink' \ + href='{}' title='{}'>[src]</a>", + self.item.def_id.index.as_usize(), l, "goto source code")); } } @@ -1810,7 +1756,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Option<String> { - let mut result = item.stability.as_ref().and_then(|stab| { + item.stability.as_ref().and_then(|stab| { let reason = if show_reason && !stab.reason.is_empty() { format!(": {}", stab.reason) } else { @@ -1845,10 +1791,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio }; Some(format!("<em class='stab {}'>{}</em>", item.stability_class(), text)) - }); - - if result.is_none() { - result = item.deprecation.as_ref().and_then(|depr| { + }).or_else(|| { + item.deprecation.as_ref().and_then(|depr| { let note = if show_reason && !depr.note.is_empty() { format!(": {}", depr.note) } else { @@ -1862,10 +1806,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio let text = format!("Deprecated{}{}", since, Markdown(¬e)); Some(format!("<em class='stab deprecated'>{}</em>", text)) - }); - } - - result + }) + }) } struct Initializer<'a>(&'a str); @@ -1945,18 +1887,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, bounds, WhereClause(&t.generics))); - let types = t.items.iter().filter(|m| { - match m.inner { clean::AssociatedTypeItem(..) => true, _ => false } - }).collect::<Vec<_>>(); - let consts = t.items.iter().filter(|m| { - match m.inner { clean::AssociatedConstItem(..) => true, _ => false } - }).collect::<Vec<_>>(); - let required = t.items.iter().filter(|m| { - match m.inner { clean::TyMethodItem(_) => true, _ => false } - }).collect::<Vec<_>>(); - let provided = t.items.iter().filter(|m| { - match m.inner { clean::MethodItem(_) => true, _ => false } - }).collect::<Vec<_>>(); + let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); + let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); + let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>(); + let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>(); if t.items.is_empty() { try!(write!(w, "{{ }}")); @@ -2117,17 +2051,12 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, fn render_stability_since_raw<'a>(w: &mut fmt::Formatter, ver: Option<&'a str>, containing_ver: Option<&'a str>) -> fmt::Result { - if containing_ver != ver { - match ver { - Some(v) => - if v.len() > 0 { - try!(write!(w, "<span class=\"since\">{}</span>", - v)) - }, - None => {} + if let Some(v) = ver { + if containing_ver != ver && v.len() > 0 { + try!(write!(w, "<span class=\"since\">{}</span>", + v)) } } - Ok(()) } @@ -2298,43 +2227,33 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>", name = variant.name.as_ref().unwrap())); try!(document(w, cx, variant)); - match variant.inner { - clean::VariantItem(ref var) => { - match var.kind { - clean::StructVariant(ref s) => { - let fields = s.fields.iter().filter(|f| { - match f.inner { - clean::StructFieldItem(ref t) => match *t { - clean::HiddenStructField => false, - clean::TypedStructField(..) => true, - }, - _ => false, - } - }); - try!(write!(w, "<h3 class='fields'>Fields</h3>\n - <table>")); - for field in fields { - try!(write!(w, "<tr><td \ - id='variant.{v}.field.{f}'>\ - <code>{f}</code></td><td>", - v = variant.name.as_ref().unwrap(), - f = field.name.as_ref().unwrap())); - try!(document(w, cx, field)); - try!(write!(w, "</td></tr>")); - } - try!(write!(w, "</table>")); - } - _ => () + + use clean::{Variant, StructVariant}; + if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner { + let fields = s.fields.iter().filter(|f| { + match f.inner { + clean::StructFieldItem(clean::TypedStructField(..)) => true, + _ => false, } + }); + try!(write!(w, "<h3 class='fields'>Fields</h3>\n + <table>")); + for field in fields { + try!(write!(w, "<tr><td \ + id='variant.{v}.field.{f}'>\ + <code>{f}</code></td><td>", + v = variant.name.as_ref().unwrap(), + f = field.name.as_ref().unwrap())); + try!(document(w, cx, field)); + try!(write!(w, "</td></tr>")); } - _ => () + try!(write!(w, "</table>")); } try!(write!(w, "</td><td>")); try!(render_stability_since(w, variant, it)); try!(write!(w, "</td></tr>")); } try!(write!(w, "</table>")); - } try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)); Ok(()) @@ -2365,9 +2284,8 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, VisSpace(it.visibility), if structhead {"struct "} else {""}, it.name.as_ref().unwrap())); - match g { - Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))), - None => {} + if let Some(g) = g { + try!(write!(w, "{}{}", *g, WhereClause(g))) } match ty { doctree::Plain => { @@ -2461,7 +2379,7 @@ fn render_assoc_items(w: &mut fmt::Formatter, } } if let AssocItemRender::DerefFor { .. } = what { - return Ok(()) + return Ok(()); } if !traits.is_empty() { let deref_impl = traits.iter().find(|t| { @@ -2542,10 +2460,17 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi link: AssocItemLink, render_static: bool, outer_version: Option<&str>) -> fmt::Result { let name = item.name.as_ref().unwrap(); + + let is_static = match item.inner { + clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic, + clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic, + _ => false + }; + match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods - if !is_static_method(item) || render_static { + if !is_static || render_static { let id = derive_id(format!("method.{}", name)); try!(write!(w, "<h4 id='{}' class='{}'>", id, shortty(item))); try!(render_stability_since_raw(w, item.stable_since(), outer_version)); @@ -2581,22 +2506,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi _ => panic!("can't make docs for trait item with name {:?}", item.name) } - return if let AssocItemLink::Anchor = link { - if is_static_method(item) && !render_static { - Ok(()) - } else { + match link { + AssocItemLink::Anchor if !is_static || render_static => { document(w, cx, item) - } - } else { - Ok(()) - }; - - fn is_static_method(item: &clean::Item) -> bool { - match item.inner { - clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic, - clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic, - _ => false - } + }, + _ => Ok(()), } } @@ -2614,9 +2528,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi outer_version: Option<&str>) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); - match i.items.iter().find(|m| { m.name == n }) { - Some(..) => continue, - None => {} + if i.items.iter().find(|m| { m.name == n }).is_some() { + continue; } try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static, @@ -2632,7 +2545,6 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ { if let Some(t) = cache().traits.get(&did) { try!(render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version)); - } } try!(write!(w, "</div>")); @@ -2676,7 +2588,7 @@ impl<'a> fmt::Display for Sidebar<'a> { try!(write!(fmt, "</p>")); // sidebar refers to the enclosing module, not this module - let relpath = if shortty(it) == ItemType::Module { "../" } else { "" }; + let relpath = if it.is_mod() { "../" } else { "" }; try!(write!(fmt, "<script>window.sidebarCurrent = {{\ name: '{name}', \ @@ -2734,12 +2646,10 @@ fn item_primitive(w: &mut fmt::Formatter, cx: &Context, render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn get_basic_keywords() -> &'static str { - "rust, rustlang, rust-lang" -} +const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; fn make_item_keywords(it: &clean::Item) -> String { - format!("{}, {}", get_basic_keywords(), it.name.as_ref().unwrap()) + format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) } fn get_index_search_type(item: &clean::Item, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ffb15d157b0..21df784b098 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -43,7 +43,7 @@ extern crate rustc_back; extern crate rustc_front; extern crate rustc_metadata; extern crate serialize; -extern crate syntax; +#[macro_use] extern crate syntax; extern crate test as testing; extern crate rustc_unicode; #[macro_use] extern crate log; @@ -94,6 +94,8 @@ pub mod visit_ast; pub mod test; mod flock; +use clean::Attributes; + type Pass = (&'static str, // name fn(clean::Crate) -> plugins::PluginResult, // fn &'static str); // description @@ -107,6 +109,8 @@ const PASSES: &'static [Pass] = &[ "concatenates all document attributes into one document attribute"), ("strip-private", passes::strip_private, "strips all private items from a crate which cannot be seen externally"), + ("strip-priv-imports", passes::strip_priv_imports, + "strips all private import statements (`use`, `extern crate`) from a crate"), ]; const DEFAULT_PASSES: &'static [&'static str] = &[ @@ -283,19 +287,15 @@ pub fn main_args(args: &[String]) -> isize { info!("going to format"); match matches.opt_str("w").as_ref().map(|s| &**s) { Some("html") | None => { - match html::render::run(krate, &external_html, - output.unwrap_or(PathBuf::from("doc")), - passes.into_iter().collect()) { - Ok(()) => {} - Err(e) => panic!("failed to generate documentation: {}", e), - } + html::render::run(krate, &external_html, + output.unwrap_or(PathBuf::from("doc")), + passes.into_iter().collect()) + .expect("failed to generate documentation") } Some("json") => { - match json_output(krate, json_plugins, - output.unwrap_or(PathBuf::from("doc.json"))) { - Ok(()) => {} - Err(e) => panic!("failed to write json: {}", e), - } + json_output(krate, json_plugins, + output.unwrap_or(PathBuf::from("doc.json"))) + .expect("failed to write json") } Some(s) => { println!("unknown output format: {}", s); @@ -332,18 +332,10 @@ fn parse_externs(matches: &getopts::Matches) -> Result<core::Externs, String> { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); - let name = match parts.next() { - Some(s) => s, - None => { - return Err("--extern value must not be empty".to_string()); - } - }; - let location = match parts.next() { - Some(s) => s, - None => { - return Err("--extern value must be of the format `foo=bar`".to_string()); - } - }; + let name = try!(parts.next().ok_or("--extern value must not be empty".to_string())); + let location = try!(parts.next() + .ok_or("--extern value must be of the format `foo=bar`" + .to_string())); let name = name.to_string(); externs.entry(name).or_insert(vec![]).push(location.to_string()); } @@ -391,32 +383,25 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. - match krate.module.as_ref().unwrap().doc_list() { - Some(nested) => { - for inner in nested { - match *inner { - clean::Word(ref x) - if "no_default_passes" == *x => { - default_passes = false; - } - clean::NameValue(ref x, ref value) - if "passes" == *x => { - for pass in value.split_whitespace() { - passes.push(pass.to_string()); - } - } - clean::NameValue(ref x, ref value) - if "plugins" == *x => { - for p in value.split_whitespace() { - plugins.push(p.to_string()); - } - } - _ => {} + for attr in krate.module.as_ref().unwrap().attrs.list_def("doc") { + match *attr { + clean::Word(ref w) if "no_default_passes" == *w => { + default_passes = false; + }, + clean::NameValue(ref name, ref value) => { + let sink = match &name[..] { + "passes" => &mut passes, + "plugins" => &mut plugins, + _ => continue, + }; + for p in value.split_whitespace() { + sink.push(p.to_string()); } } + _ => (), } - None => {} } + if default_passes { for name in DEFAULT_PASSES.iter().rev() { passes.insert(0, name.to_string()); @@ -448,17 +433,16 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche // Run everything! info!("Executing passes/plugins"); let (krate, json) = pm.run_plugins(krate); - return Output { krate: krate, json_plugins: json, passes: passes, }; + Output { krate: krate, json_plugins: json, passes: passes } } /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result<Output, String> { let mut bytes = Vec::new(); - match File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) { - Ok(_) => {} - Err(e) => return Err(format!("couldn't open {}: {}", input, e)), - }; + if let Err(e) = File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) { + return Err(format!("couldn't open {}: {}", input, e)) + } match json::from_reader(&mut &bytes[..]) { Err(s) => Err(format!("{:?}", s)), Ok(Json::Object(obj)) => { @@ -507,21 +491,13 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> , json.insert("schema".to_string(), Json::String(SCHEMA_VERSION.to_string())); let plugins_json = res.into_iter() .filter_map(|opt| { - match opt { - None => None, - Some((string, json)) => { - Some((string.to_string(), json)) - } - } + opt.map(|(string, json)| (string.to_string(), json)) }).collect(); // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode // straight to the Rust JSON representation. let crate_json_str = format!("{}", json::as_json(&krate)); - let crate_json = match json::from_str(&crate_json_str) { - Ok(j) => j, - Err(e) => panic!("Rust generated JSON is invalid: {:?}", e) - }; + let crate_json = json::from_str(&crate_json_str).expect("Rust generated JSON is invalid"); json.insert("crate".to_string(), crate_json); json.insert("plugins".to_string(), Json::Object(plugins_json)); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 957957eaec6..2eb82dec6da 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -16,7 +16,7 @@ use std::string::String; use std::usize; use rustc_front::hir; -use clean; +use clean::{self, Attributes}; use clean::Item; use plugins; use fold; @@ -33,7 +33,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { } impl<'a> fold::DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option<Item> { - if i.is_hidden_from_doc() { + if i.attrs.list_def("doc").has_word("hidden") { debug!("found one in strip_hidden; removing"); self.stripped.insert(i.def_id); @@ -106,7 +106,7 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { retained: &mut retained, access_levels: &access_levels, }; - krate = stripper.fold_crate(krate); + krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); } // strip all private implementations of traits @@ -144,12 +144,6 @@ impl<'a> fold::DocFolder for Stripper<'a> { } } - clean::ExternCrateItem(..) | clean::ImportItem(_) => { - if i.visibility != Some(hir::Public) { - return None - } - } - clean::StructFieldItem(..) => { if i.visibility != Some(hir::Public) { return Some(clean::Item { @@ -170,6 +164,9 @@ impl<'a> fold::DocFolder for Stripper<'a> { return None; } } + // handled in the `strip-priv-imports` pass + clean::ExternCrateItem(..) | clean::ImportItem(_) => {} + clean::DefaultImplItem(..) | clean::ImplItem(..) => {} // tymethods/macros have no control over privacy @@ -205,22 +202,19 @@ impl<'a> fold::DocFolder for Stripper<'a> { self.fold_item_recur(i) }; - match i { - Some(i) => { - match i.inner { - // emptied modules/impls have no need to exist - clean::ModuleItem(ref m) - if m.items.is_empty() && - i.doc_value().is_none() => None, - clean::ImplItem(ref i) if i.items.is_empty() => None, - _ => { - self.retained.insert(i.def_id); - Some(i) - } + i.and_then(|i| { + match i.inner { + // emptied modules/impls have no need to exist + clean::ModuleItem(ref m) + if m.items.is_empty() && + i.doc_value().is_none() => None, + clean::ImplItem(ref i) if i.items.is_empty() => None, + _ => { + self.retained.insert(i.def_id); + Some(i) } } - None => None, - } + }) } } @@ -242,12 +236,26 @@ impl<'a> fold::DocFolder for ImplStripper<'a> { } } +// This stripper discards all private import statements (`use`, `extern crate`) +struct ImportStripper; +impl fold::DocFolder for ImportStripper { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match i.inner { + clean::ExternCrateItem(..) | + clean::ImportItem(..) if i.visibility != Some(hir::Public) => None, + _ => self.fold_item_recur(i) + } + } +} + +pub fn strip_priv_imports(krate: clean::Crate) -> plugins::PluginResult { + (ImportStripper.fold_crate(krate), None) +} pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult { struct CommentCleaner; impl fold::DocFolder for CommentCleaner { - fn fold_item(&mut self, i: Item) -> Option<Item> { - let mut i = i; + fn fold_item(&mut self, mut i: Item) -> Option<Item> { let mut avec: Vec<clean::Attribute> = Vec::new(); for attr in &i.attrs { match attr { @@ -271,17 +279,14 @@ pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult { pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { struct Collapser; impl fold::DocFolder for Collapser { - fn fold_item(&mut self, i: Item) -> Option<Item> { + fn fold_item(&mut self, mut i: Item) -> Option<Item> { let mut docstr = String::new(); - let mut i = i; for attr in &i.attrs { - match *attr { - clean::NameValue(ref x, ref s) - if "doc" == *x => { + if let clean::NameValue(ref x, ref s) = *attr { + if "doc" == *x { docstr.push_str(s); docstr.push('\n'); - }, - _ => () + } } } let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 39550488a9e..6294b676651 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -91,7 +91,7 @@ pub fn run(input: &str, let mut cfg = config::build_configuration(&sess); cfg.extend(config::parse_cfgspecs(cfgs.clone())); - let krate = driver::phase_1_parse_input(&sess, cfg, &input); + let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "rustdoc-test", None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); @@ -121,9 +121,8 @@ pub fn run(input: &str, let mut v = RustdocVisitor::new(&ctx, None); v.visit(ctx.map.krate()); let mut krate = v.clean(&ctx); - match crate_name { - Some(name) => krate.name = name, - None => {} + if let Some(name) = crate_name { + krate.name = name; } let (krate, _) = passes::collapse_docs(krate); let (krate, _) = passes::unindent_comments(krate); @@ -334,13 +333,10 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, // Don't inject `extern crate std` because it's already injected by the // compiler. if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") { - match cratename { - Some(cratename) => { - if s.contains(cratename) { - prog.push_str(&format!("extern crate {};\n", cratename)); - } + if let Some(cratename) = cratename { + if s.contains(cratename) { + prog.push_str(&format!("extern crate {};\n", cratename)); } - None => {} } } if dont_insert_main || s.contains("fn main") { @@ -476,12 +472,7 @@ impl DocFolder for Collector { _ => typename_if_impl(&item) }; - let pushed = if let Some(name) = current_name { - self.names.push(name); - true - } else { - false - }; + let pushed = current_name.map(|name| self.names.push(name)).is_some(); if let Some(doc) = item.doc_value() { self.cnt = 0; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ba389bc42b7..bc6b4f83984 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -263,13 +263,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let name = renamed.unwrap_or(item.name); match item.node { hir::ItemExternCrate(ref p) => { - let path = match *p { - None => None, - Some(x) => Some(x.to_string()), - }; om.extern_crates.push(ExternCrate { name: name, - path: path, + path: p.map(|x|x.to_string()), vis: item.vis, attrs: item.attrs.clone(), whence: item.span, diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 587d1d42258..031a9b8bec2 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on ASCII strings and characters +//! Operations on ASCII strings and characters. #![stable(feature = "rust1", since = "1.0.0")] @@ -169,8 +169,6 @@ pub trait AsciiExt { /// # Examples /// /// ``` - /// #![feature(ascii)] - /// /// use std::ascii::AsciiExt; /// /// let ascii: String = "a".to_owned(); @@ -179,7 +177,7 @@ pub trait AsciiExt { /// /// assert_eq!(upper, "A"); /// ``` - #[unstable(feature = "ascii", issue = "27809")] + #[stable(feature = "into_ascii", since = "1.8.0")] fn into_ascii_uppercase(self) -> Self::Owned where Self: Sized { self.to_ascii_uppercase() } @@ -192,8 +190,6 @@ pub trait AsciiExt { /// # Examples /// /// ``` - /// #![feature(ascii)] - /// /// use std::ascii::AsciiExt; /// /// let ascii: String = "A".to_owned(); @@ -202,7 +198,7 @@ pub trait AsciiExt { /// /// assert_eq!(lower, "a"); /// ``` - #[unstable(feature = "ascii", issue = "27809")] + #[stable(feature = "into_ascii", since = "1.8.0")] fn into_ascii_lowercase(self) -> Self::Owned where Self: Sized { self.to_ascii_lowercase() } @@ -210,7 +206,7 @@ pub trait AsciiExt { /// Implement `into_ascii_lowercase` and `into_ascii_uppercase` without memory allocation, /// defer other methods to `str`. -#[unstable(feature = "ascii", issue = "27809")] +#[stable(feature = "into_ascii", since = "1.8.0")] impl AsciiExt for String { type Owned = Self; @@ -242,7 +238,7 @@ impl AsciiExt for String { /// Implement `into_ascii_lowercase` and `into_ascii_uppercase` without memory allocation, /// defer other methods to `[u8]`. -#[unstable(feature = "ascii", issue = "27809")] +#[stable(feature = "into_ascii", since = "1.8.0")] impl AsciiExt for Vec<u8> { type Owned = Self; diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c60ec4d3655..1c8375479ca 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -28,7 +28,7 @@ fn main() { } if target.contains("unknown-linux") { - if target.contains("musl") && target.contains("x86_64") { + if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { println!("cargo:rustc-link-lib=static=unwind"); } else { println!("cargo:rustc-link-lib=dl"); diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index badbba21d55..6b88d498b10 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Filesystem manipulation operations +//! Filesystem manipulation operations. //! //! This module contains basic methods to manipulate the contents of the local //! filesystem. All methods in this module represent cross-platform filesystem @@ -22,7 +22,6 @@ use ffi::OsString; use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; -use sys_common::io::read_to_end_uninitialized; use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; use vec::Vec; use time::SystemTime; @@ -351,7 +350,7 @@ impl Read for File { self.inner.read(buf) } fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { - unsafe { read_to_end_uninitialized(self, buf) } + self.inner.read_to_end(buf) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -372,6 +371,9 @@ impl<'a> Read for &'a File { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.inner.read_to_end(buf) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for &'a File { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index cd2d5e52462..25309a785c4 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,7 +18,6 @@ use io::lazy::Lazy; use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; -use sys_common::io::{read_to_end_uninitialized}; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use thread::LocalKeyState; @@ -78,6 +77,9 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.0.read_to_end(buf) + } } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -116,6 +118,12 @@ impl<R: io::Read> io::Read for Maybe<R> { Maybe::Fake => Ok(0) } } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + match *self { + Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0), + Maybe::Fake => Ok(0) + } + } } fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> { @@ -294,7 +302,7 @@ impl<'a> Read for StdinLock<'a> { self.inner.read(buf) } fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { - unsafe { read_to_end_uninitialized(self, buf) } + self.inner.read_to_end(buf) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e062f9040af..d3a0295c835 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -232,6 +232,7 @@ #![feature(fnbox)] #![feature(heap_api)] #![feature(hashmap_hasher)] +#![feature(inclusive_range)] #![feature(int_error_internals)] #![feature(into_cow)] #![feature(lang_items)] @@ -246,7 +247,6 @@ #![feature(optin_builtin_traits)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(range_inclusive)] #![feature(raw)] #![feature(repr_simd)] #![feature(reflect_marker)] @@ -281,7 +281,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #[cfg(test)] extern crate test; -#[cfg(test)] #[macro_use] extern crate log; // We want to reexport a few macros from core but libcore has already been // imported by the compiler (via our #[no_std] attribute) In this case we just diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index d241cd032ed..39adda1066a 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -173,18 +173,6 @@ macro_rules! select { }) } -// When testing the standard library, we link to the liblog crate to get the -// logging macros. In doing so, the liblog crate was linked against the real -// version of libstd, and uses a different std::fmt module than the test crate -// uses. To get around this difference, we redefine the log!() macro here to be -// just a dumb version of what it should be. -#[cfg(test)] -macro_rules! log { - ($lvl:expr, $($args:tt)*) => ( - if log_enabled!($lvl) { println!($($args)*) } - ) -} - #[cfg(test)] macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 68075af61cf..9c8ff44c704 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -121,6 +121,8 @@ impl Ipv4Addr { } /// Returns true if the address appears to be globally routable. + /// See [iana-ipv4-special-registry][ipv4-sr]. + /// [ipv4-sr]: http://goo.gl/RaZ7lg /// /// The following return false: /// @@ -129,9 +131,10 @@ impl Ipv4Addr { /// - the link-local address (169.254.0.0/16) /// - the broadcast address (255.255.255.255/32) /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) + /// - the unspecified address (0.0.0.0) pub fn is_global(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() + !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() } /// Returns true if this is a multicast address. @@ -725,22 +728,22 @@ mod tests { } // address unspec loopbk privt linloc global multicast brdcast doc - check(&[0, 0, 0, 0], true, false, false, false, true, false, false, false); - check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); - check(&[1, 0, 0, 0], false, false, false, false, true, false, false, false); - check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); - check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); - check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); - check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); - check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); - check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); - check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); - check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); - check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); - check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); - check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); - check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); - check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); + check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false); + check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); + check(&[1, 0, 0, 0], false, false, false, false, true, false, false, false); + check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); + check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); + check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); + check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); + check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); + check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); + check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); + check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); + check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); } #[test] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index f8e3b58bb3e..414696413f4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -14,7 +14,6 @@ use io::prelude::*; use fmt; use io; use net::{ToSocketAddrs, SocketAddr, Shutdown}; -use sys_common::io::read_to_end_uninitialized; use sys_common::net as net_imp; use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; @@ -269,7 +268,7 @@ impl TcpStream { impl Read for TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { - unsafe { read_to_end_uninitialized(self, buf) } + self.0.read_to_end(buf) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -281,7 +280,7 @@ impl Write for TcpStream { impl<'a> Read for &'a TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { - unsafe { read_to_end_uninitialized(self, buf) } + self.0.read_to_end(buf) } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs new file mode 100644 index 00000000000..8056ce4fdc4 --- /dev/null +++ b/src/libstd/os/emscripten/fs.rs @@ -0,0 +1,128 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use libc; + +use fs::Metadata; +use sys_common::AsInner; + +#[allow(deprecated)] +use os::emscripten::raw; + +/// OS-specific extension methods for `fs::Metadata` +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned `stat` are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated(since = "1.8.0", + reason = "deprecated in favor of the accessor \ + methods of this trait")] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { + &*(self.as_inner().as_inner() as *const libc::stat64 + as *const raw::stat) + } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/src/libstd/os/emscripten/mod.rs b/src/libstd/os/emscripten/mod.rs new file mode 100644 index 00000000000..8ec44b9fae4 --- /dev/null +++ b/src/libstd/os/emscripten/mod.rs @@ -0,0 +1,16 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Linux-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/src/libstd/os/emscripten/raw.rs b/src/libstd/os/emscripten/raw.rs new file mode 100644 index 00000000000..9da400a6913 --- /dev/null +++ b/src/libstd/os/emscripten/raw.rs @@ -0,0 +1,80 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Emscripten-specific raw type definitions +//! This is basically exactly the same as the linux definitions, +//! except using the musl-specific stat64 structure in liblibc. + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated(since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions")] +#![allow(deprecated)] + +use os::raw::{c_long, c_short, c_uint, c_ulong}; + +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; + +#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = c_ulong; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long; + +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: c_short, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __st_ino: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, +} diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index e15c8d67a8a..a91d251fc12 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! OS-specific functionality +//! OS-specific functionality. #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, bad_style)] @@ -31,10 +31,6 @@ pub use sys::ext as windows; #[cfg(target_os = "netbsd")] pub mod netbsd; #[cfg(target_os = "openbsd")] pub mod openbsd; #[cfg(target_os = "solaris")] pub mod solaris; - -// Emscripten is just like linux -#[cfg(target_os = "emscripten")] -#[path = "linux/mod.rs"] -pub mod emscripten; +#[cfg(target_os = "emscripten")] pub mod emscripten; pub mod raw; diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index ebd299efa78..f4cd319f064 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The Rust Prelude +//! The Rust Prelude. //! //! Rust comes with a variety of things in its standard library. However, if //! you had to manually import every single thing that you used, it would be diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 839287d1321..24e35b87bf2 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -370,7 +370,7 @@ mod prim_slice { } /// // story has nineteen bytes /// assert_eq!(19, len); /// -/// // We can re-build a str out of ptr and len. This is all unsafe becuase +/// // We can re-build a str out of ptr and len. This is all unsafe because /// // we are responsible for making sure the two components are valid: /// let s = unsafe { /// // First, we build a &[u8]... diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 8db8ad324be..5813d82a315 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -20,10 +20,9 @@ use fmt; use io; use path::Path; use str; -use sys::pipe::AnonPipe; +use sys::pipe::{read2, AnonPipe}; use sys::process as imp; use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -use thread::{self, JoinHandle}; /// Representation of a running or exited child process. /// @@ -134,6 +133,9 @@ impl Read for ChildStdout { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.inner.read_to_end(buf) + } } impl AsInner<AnonPipe> for ChildStdout { @@ -161,6 +163,9 @@ impl Read for ChildStderr { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.inner.read_to_end(buf) + } } impl AsInner<AnonPipe> for ChildStderr { @@ -289,7 +294,7 @@ impl Command { /// By default, stdin, stdout and stderr are inherited from the parent. #[stable(feature = "process", since = "1.0.0")] pub fn spawn(&mut self) -> io::Result<Child> { - self.inner.spawn(imp::Stdio::Inherit).map(Child::from_inner) + self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) } /// Executes the command as a child process, waiting for it to finish and @@ -312,7 +317,7 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result<Output> { - self.inner.spawn(imp::Stdio::MakePipe).map(Child::from_inner) + self.inner.spawn(imp::Stdio::MakePipe, false).map(Child::from_inner) .and_then(|p| p.wait_with_output()) } @@ -334,7 +339,8 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn status(&mut self) -> io::Result<ExitStatus> { - self.spawn().and_then(|mut p| p.wait()) + self.inner.spawn(imp::Stdio::Inherit, false).map(Child::from_inner) + .and_then(|mut p| p.wait()) } } @@ -496,24 +502,29 @@ impl Child { #[stable(feature = "process", since = "1.0.0")] pub fn wait_with_output(mut self) -> io::Result<Output> { drop(self.stdin.take()); - fn read<R>(mut input: R) -> JoinHandle<io::Result<Vec<u8>>> - where R: Read + Send + 'static - { - thread::spawn(move || { - let mut ret = Vec::new(); - input.read_to_end(&mut ret).map(|_| ret) - }) + + let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); + match (self.stdout.take(), self.stderr.take()) { + (None, None) => {} + (Some(mut out), None) => { + let res = out.read_to_end(&mut stdout); + res.unwrap(); + } + (None, Some(mut err)) => { + let res = err.read_to_end(&mut stderr); + res.unwrap(); + } + (Some(out), Some(err)) => { + let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); + res.unwrap(); + } } - let stdout = self.stdout.take().map(read); - let stderr = self.stderr.take().map(read); - let status = try!(self.wait()); - let stdout = stdout.and_then(|t| t.join().unwrap().ok()); - let stderr = stderr.and_then(|t| t.join().unwrap().ok()); + let status = try!(self.wait()); Ok(Output { status: status, - stdout: stdout.unwrap_or(Vec::new()), - stderr: stderr.unwrap_or(Vec::new()), + stdout: stdout, + stderr: stderr, }) } } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 9c9aa20eff5..1a42b091831 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Useful synchronization primitives +//! Useful synchronization primitives. //! //! This module contains useful safe and unsafe synchronization primitives. //! Most of the primitives in this module do not provide any sort of locking diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs index 3f70afe6ad7..c1e9782852a 100644 --- a/src/libstd/sys/common/libunwind.rs +++ b/src/libstd/sys/common/libunwind.rs @@ -106,9 +106,15 @@ pub type _Unwind_Exception_Cleanup_Fn = #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", target_os = "solaris", - all(target_os = "linux", target_env = "musl", not(target_arch = "x86_64"))), + all(target_os = "linux", + target_env = "musl", + not(target_arch = "x86"), + not(target_arch = "x86_64"))), link(name = "gcc_s"))] -#[cfg_attr(all(target_os = "linux", target_env = "musl", target_arch = "x86_64", not(test)), +#[cfg_attr(all(target_os = "linux", + target_env = "musl", + any(target_arch = "x86", target_arch = "x86_64"), + not(test)), link(name = "unwind", kind = "static"))] #[cfg_attr(any(target_os = "android", target_os = "openbsd"), link(name = "gcc"))] diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index ca4f6e19882..aa92e5be114 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -225,6 +225,10 @@ impl TcpStream { self.inner.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.inner.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; let ret = try!(cvt(unsafe { diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 299c6ec2731..8ec073858fd 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -8,12 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io; +#![unstable(reason = "not public", issue = "0", feature = "fd")] + +use prelude::v1::*; + +use io::{self, Read}; use libc::{self, c_int, size_t, c_void}; use mem; +use sync::atomic::{AtomicBool, Ordering}; use sys::cvt; use sys_common::AsInner; -use sync::atomic::{AtomicBool, Ordering}; +use sys_common::io::read_to_end_uninitialized; pub struct FileDesc { fd: c_int, @@ -42,6 +47,11 @@ impl FileDesc { Ok(ret as usize) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let mut me = self; + (&mut me).read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let ret = try!(cvt(unsafe { libc::write(self.fd, @@ -67,6 +77,20 @@ impl FileDesc { } } + pub fn set_nonblocking(&self, nonblocking: bool) { + unsafe { + let previous = libc::fcntl(self.fd, libc::F_GETFL); + debug_assert!(previous != -1); + let new = if nonblocking { + previous | libc::O_NONBLOCK + } else { + previous & !libc::O_NONBLOCK + }; + let ret = libc::fcntl(self.fd, libc::F_SETFL, new); + debug_assert!(ret != -1); + } + } + pub fn duplicate(&self) -> io::Result<FileDesc> { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This @@ -118,6 +142,16 @@ impl FileDesc { } } +impl<'a> Read for &'a FileDesc { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } +} + impl AsInner<c_int> for FileDesc { fn as_inner(&self) -> &c_int { &self.fd } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 250b1b015a0..3985a07470e 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -25,15 +25,19 @@ use sys::time::SystemTime; use sys::{cvt, cvt_r}; use sys_common::{AsInner, FromInner}; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "emscripten"))] use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; #[cfg(target_os = "android")] use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off64_t, ftruncate64, lseek64, dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", target_os = "android")))] +#[cfg(not(any(target_os = "linux", + target_os = "emscripten", + target_os = "android")))] use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64}; -#[cfg(not(any(target_os = "linux", target_os = "solaris")))] +#[cfg(not(any(target_os = "linux", + target_os = "emscripten", + target_os = "solaris")))] use libc::{readdir_r as readdir64_r}; pub struct File(FileDesc); @@ -482,6 +486,10 @@ impl File { self.0.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.0.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 8785da51986..acf501d5fda 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -116,6 +116,10 @@ impl Socket { self.0.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.0.read_to_end(buf) + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 667f0f9e6bf..e5cb3761001 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; + +use cmp; use io; use libc::{self, c_int}; +use mem; use sys::cvt_r; use sys::fd::FileDesc; @@ -57,6 +61,10 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.0.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -64,3 +72,54 @@ impl AnonPipe { pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } + +pub fn read2(p1: AnonPipe, + v1: &mut Vec<u8>, + p2: AnonPipe, + v2: &mut Vec<u8>) -> io::Result<()> { + // Set both pipes into nonblocking mode as we're gonna be reading from both + // in the `select` loop below, and we wouldn't want one to block the other! + let p1 = p1.into_fd(); + let p2 = p2.into_fd(); + p1.set_nonblocking(true); + p2.set_nonblocking(true); + + let max = cmp::max(p1.raw(), p2.raw()); + loop { + // wait for either pipe to become readable using `select` + try!(cvt_r(|| unsafe { + let mut read: libc::fd_set = mem::zeroed(); + libc::FD_SET(p1.raw(), &mut read); + libc::FD_SET(p2.raw(), &mut read); + libc::select(max + 1, &mut read, 0 as *mut _, 0 as *mut _, + 0 as *mut _) + })); + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + let read = |fd: &FileDesc, dst: &mut Vec<u8>| { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) || + e.raw_os_error() == Some(libc::EAGAIN) { + Ok(false) + } else { + Err(e) + } + } + } + }; + if try!(read(&p1, v1)) { + p2.set_nonblocking(false); + return p2.read_to_end(v2).map(|_| ()); + } + if try!(read(&p2, v2)) { + p1.set_nonblocking(false); + return p1.read_to_end(v1).map(|_| ()); + } + } +} diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 28475f50ce6..47b0ff42f93 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -216,7 +216,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn spawn(&mut self, default: Stdio) + pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; @@ -225,7 +225,7 @@ impl Command { "nul byte found in provided data")); } - let (ours, theirs) = try!(self.setup_io(default)); + let (ours, theirs) = try!(self.setup_io(default, needs_stdin)); let (input, output) = try!(sys::pipe::anon_pipe()); let pid = unsafe { @@ -298,7 +298,7 @@ impl Command { "nul byte found in provided data") } - match self.setup_io(default) { + match self.setup_io(default, true) { Ok((_, theirs)) => unsafe { self.do_exec(theirs) }, Err(e) => e, } @@ -408,8 +408,11 @@ impl Command { } - fn setup_io(&self, default: Stdio) -> io::Result<(StdioPipes, ChildPipes)> { - let stdin = self.stdin.as_ref().unwrap_or(&default); + fn setup_io(&self, default: Stdio, needs_stdin: bool) + -> io::Result<(StdioPipes, ChildPipes)> { + let null = Stdio::Null; + let default_stdin = if needs_stdin {&default} else {&null}; + let stdin = self.stdin.as_ref().unwrap_or(default_stdin); let stdout = self.stdout.as_ref().unwrap_or(&default); let stderr = self.stderr.as_ref().unwrap_or(&default); let (their_stdin, our_stdin) = try!(stdin.to_child_stdio(true)); @@ -648,7 +651,7 @@ mod tests { cmd.stdin(Stdio::MakePipe); cmd.stdout(Stdio::MakePipe); - let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null)); + let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); let stdin_write = pipes.stdin.take().unwrap(); let stdout_read = pipes.stdout.take().unwrap(); diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index ccbb14677c7..37d1d9a969e 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; + use io; use libc; use sys::fd::FileDesc; @@ -25,6 +27,13 @@ impl Stdin { fd.into_raw(); ret } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let fd = FileDesc::new(libc::STDIN_FILENO); + let ret = fd.read_to_end(buf); + fd.into_raw(); + ret + } } impl Stdout { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 472ffdf9e1d..002ffc7c868 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -12,6 +12,7 @@ #![allow(bad_style)] #![cfg_attr(test, allow(dead_code))] +#![unstable(issue = "0", feature = "windows_c")] use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,}; use os::raw::{c_char, c_ulonglong}; @@ -181,6 +182,7 @@ pub const ERROR_PATH_NOT_FOUND: DWORD = 3; pub const ERROR_ACCESS_DENIED: DWORD = 5; pub const ERROR_INVALID_HANDLE: DWORD = 6; pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_HANDLE_EOF: DWORD = 38; pub const ERROR_BROKEN_PIPE: DWORD = 109; pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; @@ -188,6 +190,7 @@ pub const ERROR_ALREADY_EXISTS: DWORD = 183; pub const ERROR_NO_DATA: DWORD = 232; pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; pub const ERROR_OPERATION_ABORTED: DWORD = 995; +pub const ERROR_IO_PENDING: DWORD = 997; pub const ERROR_TIMEOUT: DWORD = 0x5B4; pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; @@ -292,6 +295,14 @@ pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND; +pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; +pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; +pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000; +pub const PIPE_WAIT: DWORD = 0x00000000; +pub const PIPE_TYPE_BYTE: DWORD = 0x00000000; +pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; +pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; + #[repr(C)] #[cfg(target_arch = "x86")] pub struct WSADATA { @@ -913,10 +924,6 @@ extern "system" { nOutBufferSize: DWORD, lpBytesReturned: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL; - pub fn CreatePipe(hReadPipe: LPHANDLE, - hWritePipe: LPHANDLE, - lpPipeAttributes: LPSECURITY_ATTRIBUTES, - nSize: DWORD) -> BOOL; pub fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: extern "system" fn(*mut c_void) @@ -1129,6 +1136,29 @@ extern "system" { OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); + + pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCWSTR) -> HANDLE; + pub fn WaitForMultipleObjects(nCount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD) -> DWORD; + pub fn CreateNamedPipeW(lpName: LPCWSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES) + -> HANDLE; + pub fn CancelIo(handle: HANDLE) -> BOOL; + pub fn GetOverlappedResult(hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + bWait: BOOL) -> BOOL; } // Functions that aren't available on Windows XP, but we still use them and just diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 95fb1e7c600..624fef097fc 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; use io::prelude::*; use os::windows::prelude::*; @@ -312,6 +313,10 @@ impl File { self.handle.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.handle.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.handle.write(buf) } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 47676a927f6..1396d670902 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -8,14 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![unstable(issue = "0", feature = "windows_handle")] + +use prelude::v1::*; + use cmp; -use io::ErrorKind; +use io::{ErrorKind, Read}; use io; use mem; use ops::Deref; use ptr; use sys::c; use sys::cvt; +use sys_common::io::read_to_end_uninitialized; use u32; /// An owned container for `HANDLE` object, closing them on Drop. @@ -39,6 +44,20 @@ impl Handle { Handle(RawHandle::new(handle)) } + pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> { + unsafe { + let event = c::CreateEventW(0 as *mut _, + manual as c::BOOL, + init as c::BOOL, + 0 as *const _); + if event.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(Handle::new(event)) + } + } + } + pub fn into_raw(self) -> c::HANDLE { let ret = self.raw(); mem::forget(self); @@ -87,6 +106,64 @@ impl RawHandle { } } + pub unsafe fn read_overlapped(&self, + buf: &mut [u8], + overlapped: *mut c::OVERLAPPED) + -> io::Result<Option<usize>> { + let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let mut amt = 0; + let res = cvt({ + c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, + len, &mut amt, overlapped) + }); + match res { + Ok(_) => Ok(Some(amt as usize)), + Err(e) => { + if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) { + Ok(None) + } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { + Ok(Some(0)) + } else { + Err(e) + } + } + } + } + + pub fn overlapped_result(&self, + overlapped: *mut c::OVERLAPPED, + wait: bool) -> io::Result<usize> { + unsafe { + let mut bytes = 0; + let wait = if wait {c::TRUE} else {c::FALSE}; + let res = cvt({ + c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait) + }); + match res { + Ok(_) => Ok(bytes as usize), + Err(e) => { + if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) || + e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) { + Ok(0) + } else { + Err(e) + } + } + } + } + } + + pub fn cancel_io(&self) -> io::Result<()> { + unsafe { + cvt(c::CancelIo(self.raw())).map(|_| ()) + } + } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let mut me = self; + (&mut me).read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let mut amt = 0; // WriteFile takes a DWORD (u32) for the length so it only supports @@ -111,3 +188,13 @@ impl RawHandle { Ok(Handle::new(ret)) } } + +impl<'a> Read for &'a RawHandle { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } +} diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index dfa44a651e6..bb3c79c5a84 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![unstable(issue = "0", feature = "windows_net")] + +use prelude::v1::*; + use cmp; -use io; +use io::{self, Read}; use libc::{c_int, c_void, c_ulong}; use mem; use net::{SocketAddr, Shutdown}; @@ -20,6 +24,7 @@ use sync::Once; use sys::c; use sys; use sys_common::{self, AsInner, FromInner, IntoInner}; +use sys_common::io::read_to_end_uninitialized; use sys_common::net; use time::Duration; @@ -142,6 +147,11 @@ impl Socket { } } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let mut me = self; + (&mut me).read_to_end(buf) + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> { let timeout = match dur { @@ -206,6 +216,17 @@ impl Socket { } } +#[unstable(reason = "not public", issue = "0", feature = "fd_read")] +impl<'a> Read for &'a Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } +} + impl Drop for Socket { fn drop(&mut self) { let _ = unsafe { c::closesocket(self.0) }; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index aec41885f3b..fbe38d76e95 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -8,10 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; +use os::windows::prelude::*; + +use ffi::OsStr; +use path::Path; use io; -use ptr; -use sys::cvt; +use mem; +use rand::{self, Rng}; +use slice; use sys::c; +use sys::fs::{File, OpenOptions}; use sys::handle::Handle; //////////////////////////////////////////////////////////////////////////////// @@ -23,14 +30,76 @@ pub struct AnonPipe { } pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - let mut reader = c::INVALID_HANDLE_VALUE; - let mut writer = c::INVALID_HANDLE_VALUE; - try!(cvt(unsafe { - c::CreatePipe(&mut reader, &mut writer, ptr::null_mut(), 0) - })); - let reader = Handle::new(reader); - let writer = Handle::new(writer); - Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer })) + // Note that we specifically do *not* use `CreatePipe` here because + // unfortunately the anonymous pipes returned do not support overlapped + // operations. + // + // Instead, we create a "hopefully unique" name and create a named pipe + // which has overlapped operations enabled. + // + // Once we do this, we connect do it as usual via `CreateFileW`, and then we + // return those reader/writer halves. + unsafe { + let reader; + let mut name; + let mut tries = 0; + loop { + tries += 1; + let key: u64 = rand::thread_rng().gen(); + name = format!(r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", + c::GetCurrentProcessId(), + key); + let wide_name = OsStr::new(&name) + .encode_wide() + .chain(Some(0)) + .collect::<Vec<_>>(); + + let handle = c::CreateNamedPipeW(wide_name.as_ptr(), + c::PIPE_ACCESS_INBOUND | + c::FILE_FLAG_FIRST_PIPE_INSTANCE | + c::FILE_FLAG_OVERLAPPED, + c::PIPE_TYPE_BYTE | + c::PIPE_READMODE_BYTE | + c::PIPE_WAIT | + c::PIPE_REJECT_REMOTE_CLIENTS, + 1, + 4096, + 4096, + 0, + 0 as *mut _); + + // We pass the FILE_FLAG_FIRST_PIPE_INSTANCE flag above, and we're + // also just doing a best effort at selecting a unique name. If + // ERROR_ACCESS_DENIED is returned then it could mean that we + // accidentally conflicted with an already existing pipe, so we try + // again. + // + // Don't try again too much though as this could also perhaps be a + // legit error. + if handle == c::INVALID_HANDLE_VALUE { + let err = io::Error::last_os_error(); + if tries < 10 && + err.raw_os_error() == Some(c::ERROR_ACCESS_DENIED as i32) { + continue + } + return Err(err) + } + reader = Handle::new(handle); + break + } + + // Connect to the named pipe we just created in write-only mode (also + // overlapped for async I/O below). + let mut opts = OpenOptions::new(); + opts.write(true); + opts.read(false); + opts.share_mode(0); + opts.attributes(c::FILE_FLAG_OVERLAPPED); + let writer = try!(File::open(Path::new(&name), &opts)); + let writer = AnonPipe { inner: writer.into_handle() }; + + Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer.into_handle() })) + } } impl AnonPipe { @@ -41,7 +110,193 @@ impl AnonPipe { self.inner.read(buf) } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + self.inner.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.inner.write(buf) } } + +pub fn read2(p1: AnonPipe, + v1: &mut Vec<u8>, + p2: AnonPipe, + v2: &mut Vec<u8>) -> io::Result<()> { + let p1 = p1.into_handle(); + let p2 = p2.into_handle(); + + let mut p1 = try!(AsyncPipe::new(p1, v1)); + let mut p2 = try!(AsyncPipe::new(p2, v2)); + let objs = [p1.event.raw(), p2.event.raw()]; + + // In a loop we wait for either pipe's scheduled read operation to complete. + // If the operation completes with 0 bytes, that means EOF was reached, in + // which case we just finish out the other pipe entirely. + // + // Note that overlapped I/O is in general super unsafe because we have to + // be careful to ensure that all pointers in play are valid for the entire + // duration of the I/O operation (where tons of operations can also fail). + // The destructor for `AsyncPipe` ends up taking care of most of this. + loop { + let res = unsafe { + c::WaitForMultipleObjects(2, objs.as_ptr(), c::FALSE, c::INFINITE) + }; + if res == c::WAIT_OBJECT_0 { + if !try!(p1.result()) || !try!(p1.schedule_read()) { + return p2.finish() + } + } else if res == c::WAIT_OBJECT_0 + 1 { + if !try!(p2.result()) || !try!(p2.schedule_read()) { + return p1.finish() + } + } else { + return Err(io::Error::last_os_error()) + } + } +} + +struct AsyncPipe<'a> { + pipe: Handle, + event: Handle, + overlapped: Box<c::OVERLAPPED>, // needs a stable address + dst: &'a mut Vec<u8>, + state: State, +} + +#[derive(PartialEq, Debug)] +enum State { + NotReading, + Reading, + Read(usize), +} + +impl<'a> AsyncPipe<'a> { + fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> { + // Create an event which we'll use to coordinate our overlapped + // opreations, this event will be used in WaitForMultipleObjects + // and passed as part of the OVERLAPPED handle. + // + // Note that we do a somewhat clever thing here by flagging the + // event as being manually reset and setting it initially to the + // signaled state. This means that we'll naturally fall through the + // WaitForMultipleObjects call above for pipes created initially, + // and the only time an even will go back to "unset" will be once an + // I/O operation is successfully scheduled (what we want). + let event = try!(Handle::new_event(true, true)); + let mut overlapped: Box<c::OVERLAPPED> = unsafe { + Box::new(mem::zeroed()) + }; + overlapped.hEvent = event.raw(); + Ok(AsyncPipe { + pipe: pipe, + overlapped: overlapped, + event: event, + dst: dst, + state: State::NotReading, + }) + } + + /// Executes an overlapped read operation. + /// + /// Must not currently be reading, and returns whether the pipe is currently + /// at EOF or not. If the pipe is not at EOF then `result()` must be called + /// to complete the read later on (may block), but if the pipe is at EOF + /// then `result()` should not be called as it will just block forever. + fn schedule_read(&mut self) -> io::Result<bool> { + assert_eq!(self.state, State::NotReading); + let amt = unsafe { + let slice = slice_to_end(self.dst); + try!(self.pipe.read_overlapped(slice, &mut *self.overlapped)) + }; + + // If this read finished immediately then our overlapped event will + // remain signaled (it was signaled coming in here) and we'll progress + // down to the method below. + // + // Otherwise the I/O operation is scheduled and the system set our event + // to not signaled, so we flag ourselves into the reading state and move + // on. + self.state = match amt { + Some(0) => return Ok(false), + Some(amt) => State::Read(amt), + None => State::Reading, + }; + Ok(true) + } + + /// Wait for the result of the overlapped operation previously executed. + /// + /// Takes a parameter `wait` which indicates if this pipe is currently being + /// read whether the function should block waiting for the read to complete. + /// + /// Return values: + /// + /// * `true` - finished any pending read and the pipe is not at EOF (keep + /// going) + /// * `false` - finished any pending read and pipe is at EOF (stop issuing + /// reads) + fn result(&mut self) -> io::Result<bool> { + let amt = match self.state { + State::NotReading => return Ok(true), + State::Reading => { + try!(self.pipe.overlapped_result(&mut *self.overlapped, true)) + } + State::Read(amt) => amt, + }; + self.state = State::NotReading; + unsafe { + let len = self.dst.len(); + self.dst.set_len(len + amt); + } + Ok(amt != 0) + } + + /// Finishes out reading this pipe entirely. + /// + /// Waits for any pending and schedule read, and then calls `read_to_end` + /// if necessary to read all the remaining information. + fn finish(&mut self) -> io::Result<()> { + while try!(self.result()) && try!(self.schedule_read()) { + // ... + } + Ok(()) + } +} + +impl<'a> Drop for AsyncPipe<'a> { + fn drop(&mut self) { + match self.state { + State::Reading => {} + _ => return, + } + + // If we have a pending read operation, then we have to make sure that + // it's *done* before we actually drop this type. The kernel requires + // that the `OVERLAPPED` and buffer pointers are valid for the entire + // I/O operation. + // + // To do that, we call `CancelIo` to cancel any pending operation, and + // if that succeeds we wait for the overlapped result. + // + // If anything here fails, there's not really much we can do, so we leak + // the buffer/OVERLAPPED pointers to ensure we're at least memory safe. + if self.pipe.cancel_io().is_err() || self.result().is_err() { + let buf = mem::replace(self.dst, Vec::new()); + let overlapped = Box::new(unsafe { mem::zeroed() }); + let overlapped = mem::replace(&mut self.overlapped, overlapped); + mem::forget((buf, overlapped)); + } + } +} + +unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] { + if v.capacity() == 0 { + v.reserve(16); + } + if v.capacity() == v.len() { + v.reserve(1); + } + slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), + v.capacity() - v.len()) +} diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index fa118be6fe6..524c932eed4 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -123,7 +123,7 @@ impl Command { self.stderr = Some(stderr); } - pub fn spawn(&mut self, default: Stdio) + pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { // To have the spawning semantics of unix/windows stay the same, we need // to read the *child's* PATH if one is provided. See #15149 for more @@ -181,7 +181,9 @@ impl Command { stdout: None, stderr: None, }; - let stdin = self.stdin.as_ref().unwrap_or(&default); + let null = Stdio::Null; + let default_stdin = if needs_stdin {&default} else {&null}; + let stdin = self.stdin.as_ref().unwrap_or(default_stdin); let stdout = self.stdout.as_ref().unwrap_or(&default); let stderr = self.stderr.as_ref().unwrap_or(&default); let stdin = try!(stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)); diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 1cd05b61d25..5883904c21d 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![unstable(issue = "0", feature = "windows_stdio")] + use prelude::v1::*; use io::prelude::*; @@ -18,6 +20,7 @@ use sync::Mutex; use sys::c; use sys::cvt; use sys::handle::Handle; +use sys_common::io::read_to_end_uninitialized; pub struct NoClose(Option<Handle>); @@ -113,6 +116,22 @@ impl Stdin { // MemReader shouldn't error here since we just filled it utf8.read(buf) } + + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { + let mut me = self; + (&mut me).read_to_end(buf) + } +} + +#[unstable(reason = "not public", issue = "0", feature = "fd_read")] +impl<'a> Read for &'a Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } } impl Stdout { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 981ba1e36e9..6a923c8c094 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Native threads +//! Native threads. //! //! ## The threading model //! diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 23bb6fd141a..a8bea2da833 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -458,7 +458,7 @@ pub struct WhereEqPredicate { /// The set of MetaItems that define the compilation environment of the crate, /// used to drive conditional compilation -pub type CrateConfig = Vec<P<MetaItem>> ; +pub type CrateConfig = Vec<P<MetaItem>>; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Crate { @@ -886,6 +886,15 @@ impl fmt::Debug for Expr { } } +/// Limit types of a range (inclusive or exclusive) +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum RangeLimits { + /// Inclusive at the beginning, exclusive at the end + HalfOpen, + /// Inclusive at the beginning and end + Closed, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ExprKind { /// A `box x` expression. @@ -974,8 +983,8 @@ pub enum ExprKind { TupField(P<Expr>, Spanned<usize>), /// An indexing operation (`foo[2]`) Index(P<Expr>, P<Expr>), - /// A range (`1..2`, `1..`, or `..2`) - Range(Option<P<Expr>>, Option<P<Expr>>), + /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`) + Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits), /// Variable reference, possibly containing `::` and/or type /// parameters, e.g. foo::bar::<baz>. @@ -1013,6 +1022,9 @@ pub enum ExprKind { /// No-op: used solely so we can pretty-print faithfully Paren(P<Expr>), + + /// `expr?` + Try(P<Expr>), } /// The explicit Self type in a "qualified path". The actual diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e8098cfff45..f5794f7219b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1519,7 +1519,7 @@ mod tests { let crate_ast = parse::parse_crate_from_source_str( "<test>".to_string(), src, - Vec::new(), &sess); + Vec::new(), &sess).unwrap(); // should fail: let mut gated_cfgs = vec![]; let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); @@ -1535,7 +1535,7 @@ mod tests { let crate_ast = parse::parse_crate_from_source_str( "<test>".to_string(), src, - Vec::new(), &sess); + Vec::new(), &sess).unwrap(); let mut gated_cfgs = vec![]; let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); expand_crate(ecx, vec![], vec![], crate_ast); @@ -1549,7 +1549,7 @@ mod tests { let crate_ast = parse::parse_crate_from_source_str( "<test>".to_string(), src, - Vec::new(), &sess); + Vec::new(), &sess).unwrap(); let mut gated_cfgs = vec![]; let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs); expand_crate(ecx, vec![], vec![], crate_ast); diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index d0eaa89e4ae..38da478b5ed 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -18,12 +18,12 @@ use parse::token::*; use parse::token; use ptr::P; -/// Quasiquoting works via token trees. +/// Quasiquoting works via token trees. /// -/// This is registered as a set of expression syntax extension called quote! -/// that lifts its argument token-tree to an AST representing the -/// construction of the same token tree, with token::SubstNt interpreted -/// as antiquotes (splices). +/// This is registered as a set of expression syntax extension called quote! +/// that lifts its argument token-tree to an AST representing the +/// construction of the same token tree, with token::SubstNt interpreted +/// as antiquotes (splices). pub mod rt { use ast; @@ -319,34 +319,36 @@ pub mod rt { } impl<'a> ExtParseUtils for ExtCtxt<'a> { - fn parse_item(&self, s: String) -> P<ast::Item> { - parse::parse_item_from_source_str( + panictry!(parse::parse_item_from_source_str( "<quote expansion>".to_string(), s, self.cfg(), - self.parse_sess()).expect("parse error") + self.parse_sess())).expect("parse error") } fn parse_stmt(&self, s: String) -> ast::Stmt { - parse::parse_stmt_from_source_str("<quote expansion>".to_string(), - s, - self.cfg(), - self.parse_sess()).expect("parse error") + panictry!(parse::parse_stmt_from_source_str( + "<quote expansion>".to_string(), + s, + self.cfg(), + self.parse_sess())).expect("parse error") } fn parse_expr(&self, s: String) -> P<ast::Expr> { - parse::parse_expr_from_source_str("<quote expansion>".to_string(), - s, - self.cfg(), - self.parse_sess()) + panictry!(parse::parse_expr_from_source_str( + "<quote expansion>".to_string(), + s, + self.cfg(), + self.parse_sess())) } fn parse_tts(&self, s: String) -> Vec<TokenTree> { - parse::parse_tts_from_source_str("<quote expansion>".to_string(), - s, - self.cfg(), - self.parse_sess()) + panictry!(parse::parse_tts_from_source_str( + "<quote expansion>".to_string(), + s, + self.cfg(), + self.parse_sess())) } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3f2fb2d3d17..14a3f93738a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -241,7 +241,13 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status ("cfg_target_thread_local", "1.7.0", Some(29594), Active), // rustc internal - ("abi_vectorcall", "1.7.0", None, Active) + ("abi_vectorcall", "1.7.0", None, Active), + + // a...b and ...b + ("inclusive_range_syntax", "1.7.0", Some(28237), Active), + + // `expr?` + ("question_mark", "1.9.0", Some(31436), Active) ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -549,6 +555,7 @@ pub struct Features { pub allow_placement_in: bool, pub allow_box: bool, pub allow_pushpop_unsafe: bool, + pub allow_inclusive_range: bool, pub simd_ffi: bool, pub unmarked_api: bool, /// spans of #![feature] attrs for stable language features. for error reporting @@ -566,6 +573,7 @@ pub struct Features { pub staged_api: bool, pub stmt_expr_attributes: bool, pub deprecated: bool, + pub question_mark: bool, } impl Features { @@ -583,6 +591,7 @@ impl Features { allow_placement_in: false, allow_box: false, allow_pushpop_unsafe: false, + allow_inclusive_range: false, simd_ffi: false, unmarked_api: false, declared_stable_lang_features: Vec::new(), @@ -598,6 +607,7 @@ impl Features { staged_api: false, stmt_expr_attributes: false, deprecated: false, + question_mark: false, } } } @@ -991,6 +1001,14 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { self.gate_feature("type_ascription", e.span, "type ascription is experimental"); } + ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => { + self.gate_feature("inclusive_range_syntax", + e.span, + "inclusive range syntax is experimental"); + } + ast::ExprKind::Try(..) => { + self.gate_feature("question_mark", e.span, "the `?` operator is not stable"); + } _ => {} } visit::walk_expr(self, e); @@ -1177,6 +1195,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler, allow_placement_in: cx.has_feature("placement_in_syntax"), allow_box: cx.has_feature("box_syntax"), allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), + allow_inclusive_range: cx.has_feature("inclusive_range_syntax"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), declared_stable_lang_features: accepted_features, @@ -1192,6 +1211,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler, staged_api: cx.has_feature("staged_api"), stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"), deprecated: cx.has_feature("deprecated"), + question_mark: cx.has_feature("question_mark"), } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d75e8f796ae..9056103d300 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1273,9 +1273,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Index(el, er) => { ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er)) } - ExprKind::Range(e1, e2) => { + ExprKind::Range(e1, e2, lim) => { ExprKind::Range(e1.map(|x| folder.fold_expr(x)), - e2.map(|x| folder.fold_expr(x))) + e2.map(|x| folder.fold_expr(x)), + lim) } ExprKind::Path(qself, path) => { let qself = qself.map(|QSelf { ty, position }| { @@ -1331,7 +1332,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu fields.move_map(|x| folder.fold_field(x)), maybe_expr.map(|x| folder.fold_expr(x))) }, - ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex)) + ExprKind::Paren(ex) => ExprKind::Paren(folder.fold_expr(ex)), + ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), }, span: folder.new_span(span), attrs: attrs.map_thin_attrs(|v| fold_attrs(v, folder)), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d7d3e576a61..04a3cf096ba 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -38,6 +38,7 @@ extern crate term; extern crate libc; #[macro_use] extern crate log; #[macro_use] #[no_link] extern crate rustc_bitflags; +extern crate rustc_unicode; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index e336c98f03c..629edced804 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -15,7 +15,7 @@ use codemap::{BytePos, CharPos, CodeMap, Pos}; use errors; use parse::lexer::is_block_doc_comment; use parse::lexer::{StringReader, TokenAndSpan}; -use parse::lexer::{is_whitespace, Reader}; +use parse::lexer::{is_pattern_whitespace, Reader}; use parse::lexer; use print::pprust; use str::char_at; @@ -153,7 +153,7 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec<Comment>) { } fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec<Comment>) { - while is_whitespace(rdr.curr) && !rdr.is_eof() { + while is_pattern_whitespace(rdr.curr) && !rdr.is_eof() { if rdr.col == CharPos(0) && rdr.curr_is('\n') { push_blank_line_comment(rdr, &mut *comments); } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 3183dfbd954..a5cb5c7117e 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -16,6 +16,7 @@ use ext::tt::transcribe::tt_next_token; use parse::token::str_to_ident; use parse::token; use str::char_at; +use rustc_unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; @@ -546,10 +547,10 @@ impl<'a> StringReader<'a> { let c = self.scan_comment(); debug!("scanning a comment {:?}", c); c - } - c if is_whitespace(Some(c)) => { + }, + c if is_pattern_whitespace(Some(c)) => { let start_bpos = self.last_pos; - while is_whitespace(self.curr) { + while is_pattern_whitespace(self.curr) { self.bump(); } let c = Some(TokenAndSpan { @@ -1440,7 +1441,7 @@ impl<'a> StringReader<'a> { } fn consume_whitespace(&mut self) { - while is_whitespace(self.curr) && !self.is_eof() { + while is_pattern_whitespace(self.curr) && !self.is_eof() { self.bump(); } } @@ -1465,7 +1466,7 @@ impl<'a> StringReader<'a> { } fn consume_non_eol_whitespace(&mut self) { - while is_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() { + while is_pattern_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() { self.bump(); } } @@ -1596,11 +1597,10 @@ impl<'a> StringReader<'a> { } } -pub fn is_whitespace(c: Option<char>) -> bool { - match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace - ' ' | '\n' | '\t' | '\r' => true, - _ => false, - } +// This tests the character for the unicode property 'PATTERN_WHITE_SPACE' which +// is guaranteed to be forward compatible. http://unicode.org/reports/tr31/#R3 +pub fn is_pattern_whitespace(c: Option<char>) -> bool { + c.map_or(false, Pattern_White_Space) } fn in_range(c: Option<char>, lo: char, hi: char) -> bool { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1ec2479058c..ea5d6739e6d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -71,95 +71,97 @@ impl ParseSess { // uses a HOF to parse anything, and <source> includes file and // source_str. -pub fn parse_crate_from_file( - input: &Path, - cfg: ast::CrateConfig, - sess: &ParseSess -) -> ast::Crate { +pub fn parse_crate_from_file<'a>(input: &Path, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, ast::Crate> { let mut parser = new_parser_from_file(sess, cfg, input); - abort_if_errors(parser.parse_crate_mod(), &parser) + parser.parse_crate_mod() } -pub fn parse_crate_attrs_from_file( - input: &Path, - cfg: ast::CrateConfig, - sess: &ParseSess -) -> Vec<ast::Attribute> { +pub fn parse_crate_attrs_from_file<'a>(input: &Path, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, Vec<ast::Attribute>> { let mut parser = new_parser_from_file(sess, cfg, input); - abort_if_errors(parser.parse_inner_attributes(), &parser) + parser.parse_inner_attributes() } -pub fn parse_crate_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> ast::Crate { +pub fn parse_crate_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, ast::Crate> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - panictry!(p.parse_crate_mod()) + p.parse_crate_mod() } -pub fn parse_crate_attrs_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> Vec<ast::Attribute> { +pub fn parse_crate_attrs_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, Vec<ast::Attribute>> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - panictry!(p.parse_inner_attributes()) + p.parse_inner_attributes() } -pub fn parse_expr_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> P<ast::Expr> { +pub fn parse_expr_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, P<ast::Expr>> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - panictry!(p.parse_expr()) + p.parse_expr() } -pub fn parse_item_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> Option<P<ast::Item>> { +/// Parses an item. +/// +/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err` +/// when a syntax error occurred. +pub fn parse_item_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, Option<P<ast::Item>>> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - panictry!(p.parse_item()) + p.parse_item() } -pub fn parse_meta_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> P<ast::MetaItem> { +pub fn parse_meta_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, P<ast::MetaItem>> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - panictry!(p.parse_meta_item()) + p.parse_meta_item() } -pub fn parse_stmt_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> Option<ast::Stmt> { +pub fn parse_stmt_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, Option<ast::Stmt>> { let mut p = new_parser_from_source_str( sess, cfg, name, source ); - panictry!(p.parse_stmt()) + p.parse_stmt() } // Warning: This parses with quote_depth > 0, which is not the default. -pub fn parse_tts_from_source_str(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &ParseSess) - -> Vec<ast::TokenTree> { +pub fn parse_tts_from_source_str<'a>(name: String, + source: String, + cfg: ast::CrateConfig, + sess: &'a ParseSess) + -> PResult<'a, Vec<ast::TokenTree>> { let mut p = new_parser_from_source_str( sess, cfg, @@ -168,7 +170,7 @@ pub fn parse_tts_from_source_str(name: String, ); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. - panictry!(p.parse_all_token_trees()) + p.parse_all_token_trees() } // Create a new parser from a source string @@ -265,20 +267,6 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, p } - -fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T { - match result { - Ok(c) => { - c - } - Err(mut e) => { - e.emit(); - p.abort_if_errors(); - unreachable!(); - } - } -} - /// Parse a string representing a character literal into its final form. /// Rather than just accepting/rejecting a given literal, unescapes it as /// well. Can take any slice prefixed by a character escape. Returns the @@ -1078,19 +1066,21 @@ mod tests { let name = "<source>".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 item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess) + .unwrap().unwrap(); let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); assert_eq!(&doc[..], "/// 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 item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess) + .unwrap().unwrap(); let docs = item.attrs.iter().filter(|a| &*a.name() == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); 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 item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap().unwrap(); let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); assert_eq!(&doc[..], "/** doc comment\n * with CRLF */"); } @@ -1099,7 +1089,7 @@ mod tests { fn ttdelim_span() { let sess = ParseSess::new(); let expr = parse::parse_expr_from_source_str("foo".to_string(), - "foo!( fn main() { body } )".to_string(), vec![], &sess); + "foo!( fn main() { body } )".to_string(), vec![], &sess).unwrap(); let tts = match expr.node { ast::ExprKind::Mac(ref mac) => mac.node.tts.clone(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e166a367219..5884be40150 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -20,7 +20,7 @@ use ast::{BlockCheckMode, CaptureBy}; use ast::{Constness, Crate, CrateConfig}; use ast::{Decl, DeclKind}; use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf}; -use ast::{Expr, ExprKind}; +use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{Ident, ImplItem, Item, ItemKind}; @@ -99,13 +99,6 @@ pub enum BoundParsingMode { Modified, } -/// `pub` should be parsed in struct fields and not parsed in variant fields -#[derive(Clone, Copy, PartialEq)] -pub enum ParsePub { - Yes, - No, -} - #[derive(Clone, Copy, PartialEq)] pub enum SemiColonMode { Break, @@ -2059,9 +2052,10 @@ impl<'a> Parser<'a> { pub fn mk_range(&mut self, start: Option<P<Expr>>, - end: Option<P<Expr>>) + end: Option<P<Expr>>, + limits: RangeLimits) -> ast::ExprKind { - ExprKind::Range(start, end) + ExprKind::Range(start, end, limits) } pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::ExprKind { @@ -2533,6 +2527,12 @@ impl<'a> Parser<'a> { let mut e = e0; let mut hi; loop { + // expr? + while self.eat(&token::Question) { + let hi = self.span.hi; + e = self.mk_expr(lo, hi, ExprKind::Try(e), None); + } + // expr.f if self.eat(&token::Dot) { match self.token { @@ -2899,14 +2899,13 @@ impl<'a> Parser<'a> { LhsExpr::AttributesParsed(attrs) => Some(attrs), _ => None, }; - if self.token == token::DotDot { + if self.token == token::DotDot || self.token == token::DotDotDot { return self.parse_prefix_range_expr(attrs); } else { try!(self.parse_prefix_expr(attrs)) } }; - if self.expr_is_complete(&lhs) { // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 return Ok(lhs); @@ -2945,32 +2944,32 @@ impl<'a> Parser<'a> { ExprKind::Type(lhs, rhs), None); continue } else if op == AssocOp::DotDot { - // If we didn’t have to handle `x..`, it would be pretty easy to generalise - // it to the Fixity::None code. - // - // We have 2 alternatives here: `x..y` and `x..` The other two variants are - // handled with `parse_prefix_range_expr` call above. - let rhs = if self.is_at_start_of_range_notation_rhs() { - let rhs = self.parse_assoc_expr_with(op.precedence() + 1, - LhsExpr::NotYetParsed); - match rhs { - Ok(e) => Some(e), - Err(mut e) => { - e.cancel(); - None - } + // If we didn’t have to handle `x..`, it would be pretty easy to generalise + // it to the Fixity::None code. + // + // We have 2 alternatives here: `x..y` and `x..` The other two variants are + // handled with `parse_prefix_range_expr` call above. + let rhs = if self.is_at_start_of_range_notation_rhs() { + let rhs = self.parse_assoc_expr_with(op.precedence() + 1, + LhsExpr::NotYetParsed); + match rhs { + Ok(e) => Some(e), + Err(mut e) => { + e.cancel(); + None } - } else { - None - }; - let (lhs_span, rhs_span) = (lhs_span, if let Some(ref x) = rhs { - x.span - } else { - cur_op_span - }); - let r = self.mk_range(Some(lhs), rhs); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None); - break + } + } else { + None + }; + let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs { + x.span + } else { + cur_op_span + }); + let r = self.mk_range(Some(lhs), rhs, RangeLimits::HalfOpen); + lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, None); + break } let rhs = try!(match op.fixity() { @@ -2986,8 +2985,8 @@ impl<'a> Parser<'a> { this.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed) }), - // We currently have no non-associative operators that are not handled above by - // the special cases. The code is here only for future convenience. + // the only operator handled here is `...` (the other non-associative operators are + // special-cased above) Fixity::None => self.with_res( restrictions - Restrictions::RESTRICTION_STMT_EXPR, |this| { @@ -3028,6 +3027,11 @@ impl<'a> Parser<'a> { let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(lhs_span.lo, rhs_span.hi, aopexpr, None) } + AssocOp::DotDotDot => { + let (lhs_span, rhs_span) = (lhs.span, rhs.span); + let r = self.mk_range(Some(lhs), Some(rhs), RangeLimits::Closed); + self.mk_expr(lhs_span.lo, rhs_span.hi, r, None) + } AssocOp::As | AssocOp::Colon | AssocOp::DotDot => { self.bug("As, Colon or DotDot branch reached") } @@ -3059,18 +3063,19 @@ impl<'a> Parser<'a> { } } - /// Parse prefix-forms of range notation: `..expr` and `..` + /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr` fn parse_prefix_range_expr(&mut self, already_parsed_attrs: Option<ThinAttributes>) -> PResult<'a, P<Expr>> { - debug_assert!(self.token == token::DotDot); + debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); + let tok = self.token.clone(); let attrs = try!(self.parse_or_use_outer_attributes(already_parsed_attrs)); let lo = self.span.lo; let mut hi = self.span.hi; self.bump(); let opt_end = if self.is_at_start_of_range_notation_rhs() { - // RHS must be parsed with more associativity than DotDot. - let next_prec = AssocOp::from_token(&token::DotDot).unwrap().precedence() + 1; + // RHS must be parsed with more associativity than the dots. + let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1; Some(try!(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) .map(|x|{ @@ -3080,7 +3085,13 @@ impl<'a> Parser<'a> { } else { None }; - let r = self.mk_range(None, opt_end); + let r = self.mk_range(None, + opt_end, + if tok == token::DotDot { + RangeLimits::HalfOpen + } else { + RangeLimits::Closed + }); Ok(self.mk_expr(lo, hi, r, attrs)) } @@ -5093,20 +5104,17 @@ impl<'a> Parser<'a> { VariantData::Unit(ast::DUMMY_NODE_ID) } else { // If we see: `struct Foo<T> where T: Copy { ... }` - VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)), - ast::DUMMY_NODE_ID) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) } // No `where` so: `struct Foo<T>;` } else if self.eat(&token::Semi) { VariantData::Unit(ast::DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::Yes)), - ast::DUMMY_NODE_ID) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { - let body = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::Yes)), - ast::DUMMY_NODE_ID); + let body = VariantData::Tuple(try!(self.parse_tuple_struct_body()), ast::DUMMY_NODE_ID); generics.where_clause = try!(self.parse_where_clause()); try!(self.expect(&token::Semi)); body @@ -5119,13 +5127,11 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Struct(vdata, generics), None)) } - pub fn parse_record_struct_body(&mut self, - parse_pub: ParsePub) - -> PResult<'a, Vec<StructField>> { + pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { while self.token != token::CloseDelim(token::Brace) { - fields.push(try!(self.parse_struct_decl_field(parse_pub))); + fields.push(try!(self.parse_struct_decl_field())); } self.bump(); @@ -5139,9 +5145,7 @@ impl<'a> Parser<'a> { Ok(fields) } - pub fn parse_tuple_struct_body(&mut self, - parse_pub: ParsePub) - -> PResult<'a, Vec<StructField>> { + pub fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { // This is the case where we find `struct Foo<T>(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function let fields = try!(self.parse_unspanned_seq( @@ -5152,13 +5156,7 @@ impl<'a> Parser<'a> { let attrs = try!(p.parse_outer_attributes()); let lo = p.span.lo; let struct_field_ = ast::StructField_ { - kind: UnnamedField ( - if parse_pub == ParsePub::Yes { - try!(p.parse_visibility()) - } else { - Visibility::Inherited - } - ), + kind: UnnamedField(try!(p.parse_visibility())), id: ast::DUMMY_NODE_ID, ty: try!(p.parse_ty_sum()), attrs: attrs, @@ -5193,15 +5191,11 @@ impl<'a> Parser<'a> { } /// Parse an element of a struct definition - fn parse_struct_decl_field(&mut self, parse_pub: ParsePub) -> PResult<'a, StructField> { + fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = try!(self.parse_outer_attributes()); if self.eat_keyword(keywords::Pub) { - if parse_pub == ParsePub::No { - let span = self.last_span; - self.span_err(span, "`pub` is not allowed here"); - } return self.parse_single_struct_field(Visibility::Public, attrs); } @@ -5567,11 +5561,11 @@ impl<'a> Parser<'a> { if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; - struct_def = VariantData::Struct(try!(self.parse_record_struct_body(ParsePub::No)), + struct_def = VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID); } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; - struct_def = VariantData::Tuple(try!(self.parse_tuple_struct_body(ParsePub::No)), + struct_def = VariantData::Tuple(try!(self.parse_tuple_struct_body()), ast::DUMMY_NODE_ID); } else if self.eat(&token::Eq) { disr_expr = Some(try!(self.parse_expr())); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 6593b3ea532..294cbf35895 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -196,7 +196,7 @@ impl Token { BinOp(Or) => true, // in lambda syntax OrOr => true, // in lambda syntax AndAnd => true, // double borrow - DotDot => true, // range notation + DotDot | DotDotDot => true, // range notation ModSep => true, Interpolated(NtExpr(..)) => true, Interpolated(NtIdent(..)) => true, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b4e08d65a0a..2cfed1f82f7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2163,11 +2163,15 @@ impl<'a> State<'a> { try!(self.print_expr(&index)); try!(word(&mut self.s, "]")); } - ast::ExprKind::Range(ref start, ref end) => { + ast::ExprKind::Range(ref start, ref end, limits) => { if let &Some(ref e) = start { try!(self.print_expr(&e)); } - try!(word(&mut self.s, "..")); + if limits == ast::RangeLimits::HalfOpen { + try!(word(&mut self.s, "..")); + } else { + try!(word(&mut self.s, "...")); + } if let &Some(ref e) = end { try!(self.print_expr(&e)); } @@ -2273,6 +2277,10 @@ impl<'a> State<'a> { try!(self.print_inner_attributes_inline(attrs)); try!(self.print_expr(&e)); try!(self.pclose()); + }, + ast::ExprKind::Try(ref e) => { + try!(self.print_expr(e)); + try!(word(&mut self.s, "?")) } } try!(self.ann.post(self, NodeExpr(expr))); diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 6fb81bb6a76..df4eb1c9ed7 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -61,6 +61,8 @@ pub enum AssocOp { As, /// `..` range DotDot, + /// `...` range + DotDotDot, /// `:` Colon, } @@ -102,6 +104,7 @@ impl AssocOp { Token::AndAnd => Some(LAnd), Token::OrOr => Some(LOr), Token::DotDot => Some(DotDot), + Token::DotDotDot => Some(DotDotDot), Token::Colon => Some(Colon), _ if t.is_keyword(keywords::As) => Some(As), _ => None @@ -147,7 +150,7 @@ impl AssocOp { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, LAnd => 6, LOr => 5, - DotDot => 4, + DotDot | DotDotDot => 4, Inplace => 3, Assign | AssignOp(_) => 2, } @@ -162,7 +165,7 @@ impl AssocOp { As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, - DotDot => Fixity::None + DotDot | DotDotDot => Fixity::None } } @@ -171,7 +174,8 @@ impl AssocOp { match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | - ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | Colon => false + ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | + DotDot | DotDotDot | Colon => false } } @@ -181,7 +185,7 @@ impl AssocOp { Assign | AssignOp(_) | Inplace => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | - LOr | DotDot | Colon => false + LOr | DotDot | DotDotDot | Colon => false } } @@ -206,7 +210,7 @@ impl AssocOp { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Inplace | Assign | AssignOp(_) | As | DotDot | Colon => None + Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None } } } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index b0f4c2dcba5..8358af69b66 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -10,11 +10,11 @@ use ast; use parse::{ParseSess,PResult,filemap_to_tts}; -use parse::new_parser_from_source_str; +use parse::{lexer, new_parser_from_source_str}; use parse::parser::Parser; use parse::token; use ptr::P; -use str::char_at; +use std::iter::Peekable; /// Map a string to tts, using a made-up filename: pub fn string_to_tts(source_str: String) -> Vec<ast::TokenTree> { @@ -87,69 +87,62 @@ pub fn strs_to_idents(ids: Vec<&str> ) -> Vec<ast::Ident> { /// Does the given string match the pattern? whitespace in the first string /// may be deleted or replaced with other whitespace to match the pattern. -/// this function is Unicode-ignorant; fortunately, the careful design of -/// UTF-8 mitigates this ignorance. In particular, this function only collapses -/// sequences of \n, \r, ' ', and \t, but it should otherwise tolerate Unicode -/// chars. Unsurprisingly, it doesn't do NKF-normalization(?). +/// This function is relatively Unicode-ignorant; fortunately, the careful design +/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?). pub fn matches_codepattern(a : &str, b : &str) -> bool { - let mut idx_a = 0; - let mut idx_b = 0; + let mut a_iter = a.chars().peekable(); + let mut b_iter = b.chars().peekable(); + loop { - if idx_a == a.len() && idx_b == b.len() { - return true; - } - else if idx_a == a.len() {return false;} - else if idx_b == b.len() { - // maybe the stuff left in a is all ws? - if is_whitespace(char_at(a, idx_a)) { - return scan_for_non_ws_or_end(a,idx_a) == a.len(); - } else { - return false; + let (a, b) = match (a_iter.peek(), b_iter.peek()) { + (None, None) => return true, + (None, _) => return false, + (Some(&a), None) => { + if is_pattern_whitespace(a) { + break // trailing whitespace check is out of loop for borrowck + } else { + return false + } } - } - // ws in both given and pattern: - else if is_whitespace(char_at(a, idx_a)) - && is_whitespace(char_at(b, idx_b)) { - idx_a = scan_for_non_ws_or_end(a,idx_a); - idx_b = scan_for_non_ws_or_end(b,idx_b); - } - // ws in given only: - else if is_whitespace(char_at(a, idx_a)) { - idx_a = scan_for_non_ws_or_end(a,idx_a); - } - // *don't* silently eat ws in expected only. - else if char_at(a, idx_a) == char_at(b, idx_b) { - idx_a += 1; - idx_b += 1; - } - else { - return false; + (Some(&a), Some(&b)) => (a, b) + }; + + if is_pattern_whitespace(a) && is_pattern_whitespace(b) { + // skip whitespace for a and b + scan_for_non_ws_or_end(&mut a_iter); + scan_for_non_ws_or_end(&mut b_iter); + } else if is_pattern_whitespace(a) { + // skip whitespace for a + scan_for_non_ws_or_end(&mut a_iter); + } else if a == b { + a_iter.next(); + b_iter.next(); + } else { + return false } } + + // check if a has *only* trailing whitespace + a_iter.all(is_pattern_whitespace) } -/// Given a string and an index, return the first usize >= idx -/// that is a non-ws-char or is outside of the legal range of -/// the string. -fn scan_for_non_ws_or_end(a : &str, idx: usize) -> usize { - let mut i = idx; - let len = a.len(); - while (i < len) && (is_whitespace(char_at(a, i))) { - i += 1; +/// Advances the given peekable `Iterator` until it reaches a non-whitespace character +fn scan_for_non_ws_or_end<I: Iterator<Item= char>>(iter: &mut Peekable<I>) { + while lexer::is_pattern_whitespace(iter.peek().cloned()) { + iter.next(); } - i } -/// Copied from lexer. -pub fn is_whitespace(c: char) -> bool { - return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +pub fn is_pattern_whitespace(c: char) -> bool { + lexer::is_pattern_whitespace(Some(c)) } #[cfg(test)] mod tests { use super::*; - #[test] fn eqmodws() { + #[test] + fn eqmodws() { assert_eq!(matches_codepattern("",""),true); assert_eq!(matches_codepattern("","a"),false); assert_eq!(matches_codepattern("a",""),false); @@ -160,5 +153,22 @@ mod tests { assert_eq!(matches_codepattern("a b","a b"),true); assert_eq!(matches_codepattern("ab","a b"),false); assert_eq!(matches_codepattern("a b","ab"),true); + assert_eq!(matches_codepattern(" a b","ab"),true); + } + + #[test] + fn pattern_whitespace() { + assert_eq!(matches_codepattern("","\x0C"), false); + assert_eq!(matches_codepattern("a b ","a \u{0085}\n\t\r b"),true); + assert_eq!(matches_codepattern("a b","a \u{0085}\n\t\r b "),false); + } + + #[test] + fn non_pattern_whitespace() { + // These have the property 'White_Space' but not 'Pattern_White_Space' + assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); + assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); + assert_eq!(matches_codepattern("\u{205F}a b","ab"), false); + assert_eq!(matches_codepattern("a \u{3000}b","ab"), false); } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f26610b8b8d..25aee09e26c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -763,7 +763,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } - ExprKind::Range(ref start, ref end) => { + ExprKind::Range(ref start, ref end, _) => { walk_list!(visitor, visit_expr, start); walk_list!(visitor, visit_expr, end); } @@ -793,6 +793,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(&output.expr) } } + ExprKind::Try(ref subexpression) => { + visitor.visit_expr(subexpression) + } } visitor.visit_expr_post(expression) diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml index 96a84496b9c..ecbd5a9c0f5 100644 --- a/src/libtest/Cargo.toml +++ b/src/libtest/Cargo.toml @@ -11,4 +11,3 @@ crate-type = ["dylib", "rlib"] [dependencies] getopts = { path = "../libgetopts" } term = { path = "../libterm" } -serialize = { path = "../libserialize" } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 7536ab9c5af..11d2a3e65c8 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -42,8 +42,6 @@ #![feature(staged_api)] extern crate getopts; -extern crate serialize; -extern crate serialize as rustc_serialize; extern crate term; extern crate libc; @@ -56,7 +54,6 @@ use self::NamePadding::*; use self::OutputLocation::*; use stats::Stats; -use serialize::Encodable; use std::boxed::FnBox; use term::Terminal; @@ -215,7 +212,7 @@ pub struct TestDescAndFn { pub testfn: TestFn, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Copy)] +#[derive(Clone, PartialEq, Debug, Copy)] pub struct Metric { value: f64, noise: f64, diff --git a/src/test/auxiliary/empty.rs b/src/test/auxiliary/empty.rs new file mode 100644 index 00000000000..30669470522 --- /dev/null +++ b/src/test/auxiliary/empty.rs @@ -0,0 +1,9 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. diff --git a/src/test/auxiliary/issue13507.rs b/src/test/auxiliary/issue13507.rs index 78d0394a6e5..4cb846b5186 100644 --- a/src/test/auxiliary/issue13507.rs +++ b/src/test/auxiliary/issue13507.rs @@ -14,26 +14,26 @@ pub mod testtypes { use std::any::TypeId; pub fn type_ids() -> Vec<TypeId> { - let mut ids = vec!(); - ids.push(TypeId::of::<FooNil>()); - ids.push(TypeId::of::<FooBool>()); - ids.push(TypeId::of::<FooInt>()); - ids.push(TypeId::of::<FooUint>()); - ids.push(TypeId::of::<FooFloat>()); - ids.push(TypeId::of::<FooEnum>()); - ids.push(TypeId::of::<FooUniq>()); - ids.push(TypeId::of::<FooPtr>()); - ids.push(TypeId::of::<&'static FooTrait>()); - ids.push(TypeId::of::<FooStruct>()); - ids.push(TypeId::of::<FooTuple>()); - ids + vec![ + TypeId::of::<FooBool>(), + TypeId::of::<FooInt>(), + TypeId::of::<FooUint>(), + TypeId::of::<FooFloat>(), + TypeId::of::<FooStr>(), + TypeId::of::<FooArray>(), + TypeId::of::<FooSlice>(), + TypeId::of::<FooBox>(), + TypeId::of::<FooPtr>(), + TypeId::of::<FooRef>(), + TypeId::of::<FooFnPtr>(), + TypeId::of::<FooNil>(), + TypeId::of::<FooTuple>(), + TypeId::of::<FooTrait>(), + TypeId::of::<FooStruct>(), + TypeId::of::<FooEnum>() + ] } - // Tests ty_nil - pub type FooNil = (); - - // Skipping ty_bot - // Tests TyBool pub type FooBool = bool; @@ -49,25 +49,26 @@ pub mod testtypes { // Tests TyFloat (does not test all variants of FloatTy) pub type FooFloat = f64; - // For TyStr, what kind of string should I use? &'static str? String? Raw str? + // Tests TyStr + pub type FooStr = str; - // Tests TyEnum - pub enum FooEnum { - VarA(usize), - VarB(usize, usize) - } + // Tests TyArray + pub type FooArray = [u8; 1]; - // Tests TyBox (of u8) - pub type FooUniq = Box<u8>; + // Tests TySlice + pub type FooSlice = [u8]; - // As with TyStr, what type should be used for TyArray? + // Tests TyBox (of u8) + pub type FooBox = Box<u8>; // Tests TyRawPtr pub type FooPtr = *const u8; - // Skipping TyRef + // Tests TyRef + pub type FooRef = &'static u8; - // Skipping TyBareFn (how do you get a bare function type, rather than proc or closure?) + // Tests TyFnPtr + pub type FooFnPtr = fn(u8) -> bool; // Tests TyTrait pub trait FooTrait { @@ -80,14 +81,17 @@ pub mod testtypes { foo_field: usize } + // Tests TyEnum + pub enum FooEnum { + VarA(usize), + VarB(usize, usize) + } + // Tests TyTuple + pub type FooNil = (); pub type FooTuple = (u8, i8, bool); - // Skipping ty_param - - // Skipping ty_self - - // Skipping ty_self + // Skipping TyParam // Skipping TyInfer diff --git a/src/test/compile-fail/derive-no-std-not-supported.rs b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs index 01c81a8bbce..01c81a8bbce 100644 --- a/src/test/compile-fail/derive-no-std-not-supported.rs +++ b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs index d36293a484d..d36293a484d 100644 --- a/src/test/compile-fail/dropck_tarena_cycle_checked.rs +++ b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs diff --git a/src/test/compile-fail/dropck_tarena_unsound_drop.rs b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs index 6cbed34c7ad..6cbed34c7ad 100644 --- a/src/test/compile-fail/dropck_tarena_unsound_drop.rs +++ b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs diff --git a/src/test/compile-fail/duplicate_entry_error.rs b/src/test/compile-fail/duplicate_entry_error.rs index d39553a7267..ad5ea291599 100644 --- a/src/test/compile-fail/duplicate_entry_error.rs +++ b/src/test/compile-fail/duplicate_entry_error.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test for issue #31788 +// note-pattern: first defined in crate `std`. -// error-pattern: duplicate entry for `panic_fmt`, first definition found in `std` +// Test for issue #31788 and E0152 #![feature(lang_items)] #[lang = "panic_fmt"] fn panic_fmt() -> ! { +//~^ ERROR: duplicate lang item found: `panic_fmt`. loop {} } diff --git a/src/test/compile-fail/feature-gate-try-operator.rs b/src/test/compile-fail/feature-gate-try-operator.rs new file mode 100644 index 00000000000..184aa63b234 --- /dev/null +++ b/src/test/compile-fail/feature-gate-try-operator.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! id { + ($e:expr) => { $e } +} + +fn main() { + id!(x?); //~ error: the `?` operator is not stable (see issue #31436) + //~^ help: add #![feature(question_mark)] to the crate attributes to enable + y?; //~ error: the `?` operator is not stable (see issue #31436) + //~^ help: add #![feature(question_mark)] to the crate attributes to enable +} diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs index 5015810ff47..2fbd1ddb1e6 100644 --- a/src/test/compile-fail/fn-item-type.rs +++ b/src/test/compile-fail/fn-item-type.rs @@ -11,23 +11,37 @@ // Test that the types of distinct fn items are not compatible by // default. See also `run-pass/fn-item-type-*.rs`. -fn foo(x: isize) -> isize { x * 2 } -fn bar(x: isize) -> isize { x * 4 } +fn foo<T>(x: isize) -> isize { x * 2 } +fn bar<T>(x: isize) -> isize { x * 4 } fn eq<T>(x: T, y: T) { } +trait Foo { fn foo() { /* this is a default fn */ } } +impl<T> Foo for T { /* `foo` is still default here */ } + fn main() { - let f = if true { foo } else { bar }; - //~^ ERROR if and else have incompatible types - //~| expected `fn(isize) -> isize {foo}` - //~| found `fn(isize) -> isize {bar}` - //~| expected fn item, - //~| found a different fn item - - eq(foo, bar); + eq(foo::<u8>, bar::<u8>); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo}` - //~| found `fn(isize) -> isize {bar}` + //~| expected `fn(isize) -> isize {foo::<u8>}` + //~| found `fn(isize) -> isize {bar::<u8>}` //~| expected fn item //~| found a different fn item + + eq(foo::<u8>, foo::<i8>); + //~^ ERROR mismatched types + //~| expected `fn(isize) -> isize {foo::<u8>}` + //~| found `fn(isize) -> isize {foo::<i8>}` + + eq(bar::<String>, bar::<Vec<u8>>); + //~^ ERROR mismatched types + //~| expected `fn(isize) -> isize {bar::<collections::string::String>}` + //~| found `fn(isize) -> isize {bar::<collections::vec::Vec<u8>>}` + //~| expected struct `collections::string::String` + //~| found struct `collections::vec::Vec` + + // Make sure we distinguish between trait methods correctly. + eq(<u8 as Foo>::foo, <u16 as Foo>::foo); + //~^ ERROR mismatched types + //~| expected `fn() {Foo::foo}` + //~| found `fn() {Foo::foo}` } diff --git a/src/test/compile-fail/invalid-intrinsic.rs b/src/test/compile-fail/invalid-intrinsic.rs new file mode 100644 index 00000000000..2aa2546cb9f --- /dev/null +++ b/src/test/compile-fail/invalid-intrinsic.rs @@ -0,0 +1,16 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] +extern "rust-intrinsic" { + pub static breakpoint : unsafe extern "rust-intrinsic" fn(); + //~^ ERROR intrinsic has wrong type +} +fn main() { unsafe { breakpoint(); } } \ No newline at end of file diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index f907be161fa..e1fe2d06993 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -17,7 +17,7 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types -//~| expected `[_#0i; 2]` +//~| expected `[_#1i; 2]` //~| found `[_#7t; 0]` //~| expected an array with a fixed size of 2 elements //~| found one with 0 elements diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs index 83e52216be2..787eb7a3b88 100644 --- a/src/test/compile-fail/issue-17728.rs +++ b/src/test/compile-fail/issue-17728.rs @@ -107,7 +107,7 @@ impl Debug for Player { } fn str_to_direction(to_parse: &str) -> RoomDirection { - match to_parse { + match to_parse { //~ ERROR match arms have incompatible types "w" | "west" => RoomDirection::West, "e" | "east" => RoomDirection::East, "n" | "north" => RoomDirection::North, @@ -116,7 +116,7 @@ fn str_to_direction(to_parse: &str) -> RoomDirection { "out" => RoomDirection::Out, "up" => RoomDirection::Up, "down" => RoomDirection::Down, - _ => None //~ ERROR mismatched types + _ => None //~ NOTE match arm with an incompatible type } } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 256c5d8e6f7..9143a226a24 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -21,5 +21,5 @@ impl<A> vec_monad<A> for Vec<A> { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope + //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope } diff --git a/src/test/parse-fail/struct-variant-no-pub.rs b/src/test/compile-fail/issue-30730.rs index 1824e32c425..82804bb7474 100644 --- a/src/test/parse-fail/struct-variant-no-pub.rs +++ b/src/test/compile-fail/issue-30730.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,12 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -enum Foo { - Bar { - pub a: isize //~ ERROR: `pub` is not allowed here - } -} - +#![deny(warnings)] //~ NOTE: lint level defined here +use std::thread; //~ ERROR: unused import fn main() {} diff --git a/src/test/compile-fail/issue-31561.rs b/src/test/compile-fail/issue-31561.rs new file mode 100644 index 00000000000..f8645c4d3a7 --- /dev/null +++ b/src/test/compile-fail/issue-31561.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Thing { + Foo(u8), + Bar, + Baz +} + +fn main() { + let Thing::Foo(y) = Thing::Foo(1); + //~^ ERROR refutable pattern in local binding: `Bar` not covered +} diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index 0fee48a8c6c..3aab953eb79 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -12,6 +12,8 @@ #![deny(unused_assignments)] #![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] +use std::ops::AddAssign; + fn f1(x: isize) { //~^ ERROR unused variable: `x` } @@ -100,5 +102,49 @@ fn f5c() { } } +struct View<'a>(&'a mut [i32]); + +impl<'a> AddAssign<i32> for View<'a> { + fn add_assign(&mut self, rhs: i32) { + for lhs in self.0.iter_mut() { + *lhs += rhs; + } + } +} + +fn f6() { + let mut array = [1, 2, 3]; + let mut v = View(&mut array); + + // ensure an error shows up for x even if lhs of an overloaded add assign + + let x; + //~^ ERROR variable `x` is assigned to, but never used + + *({ + x = 0; //~ ERROR value assigned to `x` is never read + &mut v + }) += 1; +} + + +struct MutRef<'a>(&'a mut i32); + +impl<'a> AddAssign<i32> for MutRef<'a> { + fn add_assign(&mut self, rhs: i32) { + *self.0 += rhs; + } +} + +fn f7() { + let mut a = 1; + { + // `b` does not trigger unused_variables + let mut b = MutRef(&mut a); + b += 1; + } + drop(a); +} + fn main() { } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index b839902c683..e4ab5829f41 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -13,7 +13,7 @@ pub fn main() { // Mixed types. let _ = 0u32..10i32; - //~^ ERROR start and end of range have incompatible types + //~^ ERROR mismatched types // Bool => does not implement iterator. for i in false..true {} diff --git a/src/test/compile-fail/range-2.rs b/src/test/compile-fail/range-2.rs index c9053328572..94967693ecf 100644 --- a/src/test/compile-fail/range-2.rs +++ b/src/test/compile-fail/range-2.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,8 +12,10 @@ pub fn main() { let r = { - &42..&42 - //~^ ERROR borrowed value does not live long enough - //~^^ ERROR borrowed value does not live long enough + let a = 42; + let b = 42; + &a..&b + //~^ ERROR `a` does not live long enough + //~^^ ERROR `b` does not live long enough }; } diff --git a/src/test/compile-fail/range_inclusive_gate.rs b/src/test/compile-fail/range_inclusive_gate.rs new file mode 100644 index 00000000000..deac152ec85 --- /dev/null +++ b/src/test/compile-fail/range_inclusive_gate.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure that #![feature(inclusive_range)] is required. + +#![feature(inclusive_range_syntax)] +// #![feature(inclusive_range)] + +pub fn main() { + let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ... { use std::intrinsics; 2 }; + //~^ ERROR use of unstable library feature 'inclusive_range' + //~^^ ERROR core_intrinsics + //~^^^ ERROR core_intrinsics + //~^^^^ WARN unused_imports + //~^^^^^ WARN unused_imports +} + + diff --git a/src/test/compile-fail/trait-privacy.rs b/src/test/compile-fail/trait-privacy.rs index a0d0014a064..5f9e8ba6c0a 100644 --- a/src/test/compile-fail/trait-privacy.rs +++ b/src/test/compile-fail/trait-privacy.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] +#![feature(rustc_attrs, get_type_id)] #![allow(dead_code)] mod foo { @@ -26,5 +26,10 @@ fn g() { ().f(); // Check that this does not trigger a privacy error } +fn f() { + let error = ::std::thread::spawn(|| {}).join().unwrap_err(); + error.get_type_id(); // Regression test for #21670 +} + #[rustc_error] fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs new file mode 100644 index 00000000000..3eae76f9492 --- /dev/null +++ b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs @@ -0,0 +1,51 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +unsafe fn foo() -> (isize, *const (), Option<fn()>) { + let i = mem::transmute(bar); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + let p = mem::transmute(foo); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + let of = mem::transmute(main); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + (i, p, of) +} + +unsafe fn bar() { + mem::transmute::<_, *mut ()>(foo); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + mem::transmute::<_, fn()>(bar); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + // No error if a coercion would otherwise occur. + mem::transmute::<fn(), usize>(main); + + // Error, still, if the resulting type is not pointer-sized. + mem::transmute::<_, u8>(main); + //~^ ERROR transmute called with differently sized types +} + +fn main() { + unsafe { + foo(); + bar(); + } +} diff --git a/src/test/compile-fail/useless-pub.rs b/src/test/compile-fail/useless-pub.rs index fb6cdf7fa59..268b937c291 100644 --- a/src/test/compile-fail/useless-pub.rs +++ b/src/test/compile-fail/useless-pub.rs @@ -18,4 +18,11 @@ impl E for A { pub fn foo(&self) {} //~ ERROR: unnecessary visibility } +enum Foo { + V1 { pub f: i32 }, //~ ERROR unnecessary visibility qualifier + //| NOTE visibility qualifiers have no effect on variant fields + V2(pub i32), //~ ERROR unnecessary visibility qualifier + //| NOTE visibility qualifiers have no effect on variant fields +} + fn main() {} diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 94055450bc6..1d5ebdbae3e 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -22,7 +22,7 @@ fn main() { let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types //~| expected `unsafe extern "C" fn(isize, u8)` - //~| found `unsafe extern "C" fn(isize, u8, ...)` + //~| found `unsafe extern "C" fn(isize, u8, ...) {foo}` //~| expected non-variadic fn //~| found variadic function diff --git a/src/test/parse-fail/issue-19096.rs b/src/test/parse-fail/issue-19096.rs index 0d9a111045a..6ba0fb5f15b 100644 --- a/src/test/parse-fail/issue-19096.rs +++ b/src/test/parse-fail/issue-19096.rs @@ -12,5 +12,5 @@ fn main() { let t = (42, 42); - t.0::<isize>; //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `::` + t.0::<isize>; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `::` } diff --git a/src/test/parse-fail/issue-3036.rs b/src/test/parse-fail/issue-3036.rs index 1946e984e5d..229b12136fc 100644 --- a/src/test/parse-fail/issue-3036.rs +++ b/src/test/parse-fail/issue-3036.rs @@ -15,4 +15,4 @@ fn main() { let x = 3 -} //~ ERROR: expected one of `.`, `;`, or an operator, found `}` +} //~ ERROR: expected one of `.`, `;`, `?`, or an operator, found `}` diff --git a/src/test/parse-fail/macros-no-semicolon.rs b/src/test/parse-fail/macros-no-semicolon.rs index 5931631ccee..1c55d70f607 100644 --- a/src/test/parse-fail/macros-no-semicolon.rs +++ b/src/test/parse-fail/macros-no-semicolon.rs @@ -12,6 +12,6 @@ fn main() { assert_eq!(1, 2) - assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert_eq` + assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq` println!("hello"); } diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index b99d0493ff7..37b66601e70 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,7 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - ; //~ ERROR expected one of `.`, `{`, or an operator, found `;` + ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` println!("{}", foo) } diff --git a/src/test/parse-fail/range-3.rs b/src/test/parse-fail/range-3.rs index 284cdb8c653..95aa71b0cdf 100644 --- a/src/test/parse-fail/range-3.rs +++ b/src/test/parse-fail/range-3.rs @@ -14,5 +14,5 @@ pub fn main() { let r = 1..2..3; - //~^ ERROR expected one of `.`, `;`, or an operator, found `..` + //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` } diff --git a/src/test/parse-fail/range-4.rs b/src/test/parse-fail/range-4.rs index 69898612771..4500df116a2 100644 --- a/src/test/parse-fail/range-4.rs +++ b/src/test/parse-fail/range-4.rs @@ -14,5 +14,5 @@ pub fn main() { let r = ..1..2; - //~^ ERROR expected one of `.`, `;`, or an operator, found `..` + //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` } diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs new file mode 100644 index 00000000000..5fd6f1834e0 --- /dev/null +++ b/src/test/parse-fail/range_inclusive.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure that inclusive ranges with no end point don't parse. + +#![feature(inclusive_range_syntax, inclusive_range)] + +pub fn main() { + for _ in 1... {} +} //~ ERROR expected one of + diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs new file mode 100644 index 00000000000..021b6dd3e26 --- /dev/null +++ b/src/test/parse-fail/range_inclusive_gate.rs @@ -0,0 +1,74 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure that #![feature(inclusive_range_syntax)] is required. + +// #![feature(inclusive_range_syntax, inclusive_range)] + +macro_rules! m { + () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental +} + +#[cfg(nope)] +fn f() {} +#[cfg(not(nope))] +fn f() { + for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental +} + +#[cfg(nope)] +macro_rules! n { () => {} } +#[cfg(not(nope))] +macro_rules! n { + () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental +} + +macro_rules! o { + () => {{ + #[cfg(nope)] + fn g() {} + #[cfg(not(nope))] + fn g() { + for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + } + + g(); + }} +} + +#[cfg(nope)] +macro_rules! p { () => {} } +#[cfg(not(nope))] +macro_rules! p { + () => {{ + #[cfg(nope)] + fn h() {} + #[cfg(not(nope))] + fn h() { + for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + } + + h(); + }} +} + +pub fn main() { + for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + for _ in ...10 {} //~ ERROR inclusive range syntax is experimental + + f(); // not allowed in cfg'ed functions + + m!(); // not allowed in macros + n!(); // not allowed in cfg'ed macros + o!(); // not allowed in macros that output cfgs + p!(); // not allowed in cfg'ed macros that output cfgs +} + + diff --git a/src/test/parse-fail/raw-str-unbalanced.rs b/src/test/parse-fail/raw-str-unbalanced.rs index ce8960edde1..5c09f68970b 100644 --- a/src/test/parse-fail/raw-str-unbalanced.rs +++ b/src/test/parse-fail/raw-str-unbalanced.rs @@ -12,5 +12,5 @@ static s: &'static str = r#" - "## //~ ERROR expected one of `.`, `;`, or an operator, found `#` + "## //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `#` ; diff --git a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs index ab9ff7ac19e..301bd0e8b1c 100644 --- a/src/test/parse-fail/removed-syntax-mut-vec-expr.rs +++ b/src/test/parse-fail/removed-syntax-mut-vec-expr.rs @@ -13,5 +13,5 @@ fn f() { let v = [mut 1, 2, 3, 4]; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `]`, `{`, or an operator, found `1` + //~^^ ERROR expected one of `!`, `,`, `.`, `::`, `;`, `?`, `]`, `{`, or an operator, found `1` } diff --git a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs index ea686aeb6e0..2f637cf0b4e 100644 --- a/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs +++ b/src/test/parse-fail/removed-syntax-uniq-mut-expr.rs @@ -13,5 +13,5 @@ fn f() { let a_box = box mut 42; //~^ ERROR expected identifier, found keyword `mut` - //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `{`, or an operator, found `42` + //~^^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `42` } diff --git a/src/test/parse-fail/removed-syntax-with-1.rs b/src/test/parse-fail/removed-syntax-with-1.rs index e9de52c013b..156b172a944 100644 --- a/src/test/parse-fail/removed-syntax-with-1.rs +++ b/src/test/parse-fail/removed-syntax-with-1.rs @@ -18,5 +18,5 @@ fn removed_with() { let a = S { foo: (), bar: () }; let b = S { foo: () with a }; - //~^ ERROR expected one of `,`, `.`, `}`, or an operator, found `with` + //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with` } diff --git a/src/test/parse-fail/struct-literal-in-for.rs b/src/test/parse-fail/struct-literal-in-for.rs index e57298f7280..93098455560 100644 --- a/src/test/parse-fail/struct-literal-in-for.rs +++ b/src/test/parse-fail/struct-literal-in-for.rs @@ -23,7 +23,7 @@ impl Foo { fn main() { for x in Foo { x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{` + }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` println!("yo"); } } diff --git a/src/test/parse-fail/struct-literal-in-if.rs b/src/test/parse-fail/struct-literal-in-if.rs index 6bf41b7a450..db6a360a567 100644 --- a/src/test/parse-fail/struct-literal-in-if.rs +++ b/src/test/parse-fail/struct-literal-in-if.rs @@ -23,7 +23,7 @@ impl Foo { fn main() { if Foo { x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{` + }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` println!("yo"); } } diff --git a/src/test/parse-fail/struct-literal-in-match-discriminant.rs b/src/test/parse-fail/struct-literal-in-match-discriminant.rs index 679f4542824..7038cc798c4 100644 --- a/src/test/parse-fail/struct-literal-in-match-discriminant.rs +++ b/src/test/parse-fail/struct-literal-in-match-discriminant.rs @@ -20,6 +20,6 @@ fn main() { } { Foo { x: x - } => {} //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `=>` + } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` } } diff --git a/src/test/parse-fail/struct-literal-in-while.rs b/src/test/parse-fail/struct-literal-in-while.rs index b388aac2c54..75e4eb3de07 100644 --- a/src/test/parse-fail/struct-literal-in-while.rs +++ b/src/test/parse-fail/struct-literal-in-while.rs @@ -23,7 +23,7 @@ impl Foo { fn main() { while Foo { x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `{` + }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` println!("yo"); } } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 835f7fc96c6..0347631aeb3 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -86,8 +86,10 @@ pub fn id<T>(x: T) -> T { (x as T) } pub fn use_id() { let _ = ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id})(([(1 as i32), (2 as i32), - (3 as i32)] as [i32; 3])) as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), + (2 as i32), + (3 as i32)] as + [i32; 3])) as [i32; 3]); } fn main() { } diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 13cbdfe24d6..29063c5a607 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -18,7 +18,7 @@ extern crate rustc_front; extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_resolve; -extern crate syntax; +#[macro_use] extern crate syntax; use std::ffi::{CStr, CString}; use std::mem::transmute; @@ -230,7 +230,7 @@ fn compile_program(input: &str, sysroot: PathBuf) let id = "input".to_string(); - let krate = driver::phase_1_parse_input(&sess, cfg, &input); + let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) .expect("phase_2 returned `None`"); diff --git a/src/test/run-pass/conditional-debug-macro-off.rs b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs index c6beb5ba358..c6beb5ba358 100644 --- a/src/test/run-pass/conditional-debug-macro-off.rs +++ b/src/test/run-pass-fulldeps/conditional-debug-macro-off.rs diff --git a/src/test/run-pass/deprecated-derive.rs b/src/test/run-pass-fulldeps/deprecated-derive.rs index 69a7f888bbe..69a7f888bbe 100644 --- a/src/test/run-pass/deprecated-derive.rs +++ b/src/test/run-pass-fulldeps/deprecated-derive.rs diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass-fulldeps/derive-no-std.rs index 78e9da001f7..78e9da001f7 100644 --- a/src/test/run-pass/derive-no-std.rs +++ b/src/test/run-pass-fulldeps/derive-no-std.rs diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs index 328cc134f3b..328cc134f3b 100644 --- a/src/test/run-pass/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-cell-refcell.rs index 6e5eb86c584..6e5eb86c584 100644 --- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-cell-refcell.rs diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass-fulldeps/deriving-global.rs index 10e8ddc41f3..10e8ddc41f3 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass-fulldeps/deriving-global.rs diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs index db30bfbf747..db30bfbf747 100644 --- a/src/test/run-pass/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass-fulldeps/dropck_tarena_sound_drop.rs diff --git a/src/test/run-pass/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs index 8d19209208d..8d19209208d 100644 --- a/src/test/run-pass/empty-struct-braces-derive.rs +++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs diff --git a/src/test/run-pass/extern-mod-syntax.rs b/src/test/run-pass-fulldeps/extern-mod-syntax.rs index 37404ee7e69..37404ee7e69 100644 --- a/src/test/run-pass/extern-mod-syntax.rs +++ b/src/test/run-pass-fulldeps/extern-mod-syntax.rs diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs index 9da04f72355..9da04f72355 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass-fulldeps/issue-11881.rs diff --git a/src/test/run-pass/issue-14021.rs b/src/test/run-pass-fulldeps/issue-14021.rs index 907967d115d..907967d115d 100644 --- a/src/test/run-pass/issue-14021.rs +++ b/src/test/run-pass-fulldeps/issue-14021.rs diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass-fulldeps/issue-15924.rs index 0c208773884..0c208773884 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass-fulldeps/issue-15924.rs diff --git a/src/test/run-pass/issue-24972.rs b/src/test/run-pass-fulldeps/issue-24972.rs index ae7eb84d3e8..ae7eb84d3e8 100644 --- a/src/test/run-pass/issue-24972.rs +++ b/src/test/run-pass-fulldeps/issue-24972.rs diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass-fulldeps/issue-2804.rs index a2b4e218a07..a2b4e218a07 100644 --- a/src/test/run-pass/issue-2804.rs +++ b/src/test/run-pass-fulldeps/issue-2804.rs diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass-fulldeps/issue-4016.rs index bc3fa162e02..bc3fa162e02 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass-fulldeps/issue-4016.rs diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass-fulldeps/issue-4036.rs index ae7bb8a6842..ae7bb8a6842 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass-fulldeps/issue-4036.rs diff --git a/src/test/run-pass/logging-enabled-debug.rs b/src/test/run-pass-fulldeps/logging-enabled-debug.rs index 3ae4884ce47..3ae4884ce47 100644 --- a/src/test/run-pass/logging-enabled-debug.rs +++ b/src/test/run-pass-fulldeps/logging-enabled-debug.rs diff --git a/src/test/run-pass/logging-enabled.rs b/src/test/run-pass-fulldeps/logging-enabled.rs index 2975835a271..2975835a271 100644 --- a/src/test/run-pass/logging-enabled.rs +++ b/src/test/run-pass-fulldeps/logging-enabled.rs diff --git a/src/test/run-pass/logging-right-crate.rs b/src/test/run-pass-fulldeps/logging-right-crate.rs index 7caeeb40124..7caeeb40124 100644 --- a/src/test/run-pass/logging-right-crate.rs +++ b/src/test/run-pass-fulldeps/logging-right-crate.rs diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass-fulldeps/logging-separate-lines.rs index 09759326afd..09759326afd 100644 --- a/src/test/run-pass/logging-separate-lines.rs +++ b/src/test/run-pass-fulldeps/logging-separate-lines.rs diff --git a/src/test/run-pass/placement-new-arena.rs b/src/test/run-pass-fulldeps/placement-new-arena.rs index 7ac624e6814..7ac624e6814 100644 --- a/src/test/run-pass/placement-new-arena.rs +++ b/src/test/run-pass-fulldeps/placement-new-arena.rs diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass-fulldeps/regions-mock-tcx.rs index ed3cec465ef..ed3cec465ef 100644 --- a/src/test/run-pass/regions-mock-tcx.rs +++ b/src/test/run-pass-fulldeps/regions-mock-tcx.rs diff --git a/src/test/run-pass/rust-log-filter.rs b/src/test/run-pass-fulldeps/rust-log-filter.rs index 306d24e3177..306d24e3177 100644 --- a/src/test/run-pass/rust-log-filter.rs +++ b/src/test/run-pass-fulldeps/rust-log-filter.rs diff --git a/src/test/run-pass/augmented-assignments.rs b/src/test/run-pass/augmented-assignments.rs index 8c9ebcd274a..3ed9e8548dc 100644 --- a/src/test/run-pass/augmented-assignments.rs +++ b/src/test/run-pass/augmented-assignments.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![deny(unused_assignments)] + use std::mem; use std::ops::{ AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, Index, MulAssign, RemAssign, @@ -27,6 +29,8 @@ impl Slice { } } +struct View<'a>(&'a mut [i32]); + fn main() { let mut x = Int(1); @@ -78,6 +82,12 @@ fn main() { assert_eq!(array[0], 1); assert_eq!(array[1], 2); assert_eq!(array[2], 3); + + // sized indirection + // check that this does *not* trigger the unused_assignments lint + let mut array = [0, 1, 2]; + let mut view = View(&mut array); + view += 1; } impl AddAssign for Int { @@ -159,3 +169,11 @@ impl AddAssign<i32> for Slice { } } } + +impl<'a> AddAssign<i32> for View<'a> { + fn add_assign(&mut self, rhs: i32) { + for lhs in self.0.iter_mut() { + *lhs += rhs; + } + } +} diff --git a/src/test/run-pass/coerce-unify.rs b/src/test/run-pass/coerce-unify.rs new file mode 100644 index 00000000000..3d690146931 --- /dev/null +++ b/src/test/run-pass/coerce-unify.rs @@ -0,0 +1,77 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that coercions can unify if-else, match arms and array elements. + +// Try to construct if-else chains, matches and arrays out of given expressions. +macro_rules! check { + ($last:expr $(, $rest:expr)+) => { + // Last expression comes first because of whacky ifs and matches. + let _ = $(if false { $rest })else+ else { $last }; + + let _ = match 0 { $(_ if false => $rest,)+ _ => $last }; + + let _ = [$($rest,)+ $last]; + } +} + +// Check all non-uniform cases of 2 and 3 expressions of 2 types. +macro_rules! check2 { + ($a:expr, $b:expr) => { + check!($a, $b); + check!($b, $a); + + check!($a, $a, $b); + check!($a, $b, $a); + check!($a, $b, $b); + + check!($b, $a, $a); + check!($b, $a, $b); + check!($b, $b, $a); + } +} + +// Check all non-uniform cases of 2 and 3 expressions of 3 types. +macro_rules! check3 { + ($a:expr, $b:expr, $c:expr) => { + // Delegate to check2 for cases where a type repeats. + check2!($a, $b); + check2!($b, $c); + check2!($a, $c); + + // Check the remaining cases, i.e. permutations of ($a, $b, $c). + check!($a, $b, $c); + check!($a, $c, $b); + check!($b, $a, $c); + check!($b, $c, $a); + check!($c, $a, $b); + check!($c, $b, $a); + } +} + +use std::mem::size_of; + +fn foo() {} +fn bar() {} + +pub fn main() { + check3!(foo, bar, foo as fn()); + check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize); + + let s = String::from("bar"); + check2!("foo", &s); + + let a = [1, 2, 3]; + let v = vec![1, 2, 3]; + check2!(&a[..], &v); + + // Make sure in-array coercion still works. + let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)]; +} diff --git a/src/test/run-pass/empty-type-parameter-list.rs b/src/test/run-pass/empty-type-parameter-list.rs new file mode 100644 index 00000000000..7af2844d564 --- /dev/null +++ b/src/test/run-pass/empty-type-parameter-list.rs @@ -0,0 +1,33 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that empty type parameter list (<>) is synonymous with +// no type parameters at all + +struct S<>; +trait T<> {} +enum E<> { V } +impl<> T<> for S<> {} +impl T for E {} +fn foo<>() {} +fn bar() {} + +fn main() { + let _ = S; + let _ = S::<>; + let _ = E::V; + let _ = E::<>::V; + foo(); + foo::<>(); + + // Test that we can supply <> to non generic things + bar::<>(); + let _: i32<>; +} diff --git a/src/test/run-pass/enum-clike-ffi-as-int.rs b/src/test/run-pass/enum-clike-ffi-as-int.rs index 8be3634c88a..fdaad9e1fab 100644 --- a/src/test/run-pass/enum-clike-ffi-as-int.rs +++ b/src/test/run-pass/enum-clike-ffi-as-int.rs @@ -25,16 +25,17 @@ #[repr(u32)] enum Foo { - A = 0, - B = 23 + A = 0, + B = 23 } #[inline(never)] extern "C" fn foo(_x: usize) -> Foo { Foo::B } pub fn main() { - unsafe { - let f: extern "C" fn(usize) -> u32 = ::std::mem::transmute(foo); - assert_eq!(f(0xDEADBEEF), Foo::B as u32); - } + unsafe { + let f: extern "C" fn(usize) -> u32 = + ::std::mem::transmute(foo as extern "C" fn(usize) -> Foo); + assert_eq!(f(0xDEADBEEF), Foo::B as u32); + } } diff --git a/src/test/run-pass/fn-item-type-zero-sized.rs b/src/test/run-pass/fn-item-type-zero-sized.rs new file mode 100644 index 00000000000..5fdaf083d07 --- /dev/null +++ b/src/test/run-pass/fn-item-type-zero-sized.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that fn item types are zero-sized. + +use std::mem::{size_of, size_of_val}; + +fn main() { + assert_eq!(size_of_val(&main), 0); + + let (a, b) = (size_of::<u8>, size_of::<u16>); + assert_eq!(size_of_val(&a), 0); + assert_eq!(size_of_val(&b), 0); + assert_eq!((a(), b()), (1, 2)); +} diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 91ec3e85404..084b7a166cd 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -19,23 +19,29 @@ use issue13507::testtypes; use std::any::TypeId; pub fn type_ids() -> Vec<TypeId> { - let mut ids = vec!(); - ids.push(TypeId::of::<testtypes::FooNil>()); - ids.push(TypeId::of::<testtypes::FooBool>()); - ids.push(TypeId::of::<testtypes::FooInt>()); - ids.push(TypeId::of::<testtypes::FooUint>()); - ids.push(TypeId::of::<testtypes::FooFloat>()); - ids.push(TypeId::of::<testtypes::FooEnum>()); - ids.push(TypeId::of::<testtypes::FooUniq>()); - ids.push(TypeId::of::<testtypes::FooPtr>()); - ids.push(TypeId::of::<&'static testtypes::FooTrait>()); - ids.push(TypeId::of::<testtypes::FooStruct>()); - ids.push(TypeId::of::<testtypes::FooTuple>()); - ids + use issue13507::testtypes::*; + vec![ + TypeId::of::<FooBool>(), + TypeId::of::<FooInt>(), + TypeId::of::<FooUint>(), + TypeId::of::<FooFloat>(), + TypeId::of::<FooStr>(), + TypeId::of::<FooArray>(), + TypeId::of::<FooSlice>(), + TypeId::of::<FooBox>(), + TypeId::of::<FooPtr>(), + TypeId::of::<FooRef>(), + TypeId::of::<FooFnPtr>(), + TypeId::of::<FooNil>(), + TypeId::of::<FooTuple>(), + TypeId::of::<FooTrait>(), + TypeId::of::<FooStruct>(), + TypeId::of::<FooEnum>() + ] } pub fn main() { - let othercrate = testtypes::type_ids(); + let othercrate = issue13507::testtypes::type_ids(); let thiscrate = type_ids(); assert_eq!(thiscrate, othercrate); } diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs index 93953e3f58a..67baf2f9c49 100644 --- a/src/test/run-pass/mir_refs_correct.rs +++ b/src/test/run-pass/mir_refs_correct.rs @@ -204,48 +204,41 @@ fn t24() -> fn(u8) -> S { C4 } -fn main(){ - unsafe { - assert_eq!(t1()(), regular()); - - assert!(::std::mem::transmute::<_, *mut ()>(t2()) == - ::std::mem::transmute::<_, *mut ()>(E::U)); - assert!(::std::mem::transmute::<_, *mut ()>(t3()) == - ::std::mem::transmute::<_, *mut ()>(S)); - - assert_eq!(t4()(), S::hey()); - let s = S(42); - assert_eq!(t5()(&s), <S as X>::hoy(&s)); - - - assert_eq!(t6()(), ext::regular_fn()); - assert!(::std::mem::transmute::<_, *mut ()>(t7()) == - ::std::mem::transmute::<_, *mut ()>(ext::E::U)); - assert!(::std::mem::transmute::<_, *mut ()>(t8()) == - ::std::mem::transmute::<_, *mut ()>(ext::S)); - - assert_eq!(t9()(), ext::S::hey()); - let sext = ext::S(6); - assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext)); - - let p = parametric::<u8>; - assert!(::std::mem::transmute::<_, *mut ()>(t11()) == - ::std::mem::transmute::<_, *mut ()>(p)); - - assert_eq!(t12(), C); - assert_eq!(t13(), C2); - assert_eq!(t13_2(), C3); - - assert_eq!(t14()(), <S as X>::hoy2()); - assert_eq!(t15()(&s), S::hey2(&s)); - assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32)); - assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64)); - assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64)); - assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32)); - assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38)); - assert_eq!(t21(), Unit); - assert_eq!(t22(), None); - assert_eq!(t23(), (CEnum::A, CEnum::B)); - assert_eq!(t24(), C4); - } +fn main() { + assert_eq!(t1()(), regular()); + + assert_eq!(t2() as *mut (), E::U as *mut ()); + assert_eq!(t3() as *mut (), S as *mut ()); + + assert_eq!(t4()(), S::hey()); + let s = S(42); + assert_eq!(t5()(&s), <S as X>::hoy(&s)); + + + assert_eq!(t6()(), ext::regular_fn()); + assert_eq!(t7() as *mut (), ext::E::U as *mut ()); + assert_eq!(t8() as *mut (), ext::S as *mut ()); + + assert_eq!(t9()(), ext::S::hey()); + let sext = ext::S(6); + assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext)); + + let p = parametric::<u8>; + assert_eq!(t11() as *mut (), p as *mut ()); + + assert_eq!(t12(), C); + assert_eq!(t13(), C2); + assert_eq!(t13_2(), C3); + + assert_eq!(t14()(), <S as X>::hoy2()); + assert_eq!(t15()(&s), S::hey2(&s)); + assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32)); + assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64)); + assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64)); + assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32)); + assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38)); + assert_eq!(t21(), Unit); + assert_eq!(t22(), None); + assert_eq!(t23(), (CEnum::A, CEnum::B)); + assert_eq!(t24(), C4); } diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index 224111900d6..2b7cf6c6682 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -24,13 +24,14 @@ use std::mem; #[inline(never)] -extern "C" fn foo<'a>(x: &'a isize) -> Option<&'a isize> { Some(x) } +extern "C" fn foo(x: &isize) -> Option<&isize> { Some(x) } static FOO: isize = 0xDEADBEE; pub fn main() { unsafe { - let f: for<'a> extern "C" fn(&'a isize) -> &'a isize = mem::transmute(foo); + let f: extern "C" fn(&isize) -> &isize = + mem::transmute(foo as extern "C" fn(&isize) -> Option<&isize>); assert_eq!(*f(&FOO), FOO); } } diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index cfd3bb49f34..dffdcfe0af5 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -12,8 +12,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::{option, mem}; - // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, // which "says that a destructor applied to an object built from a constructor // behaves as expected". -- http://coq.inria.fr/doc/Reference-Manual006.html @@ -43,9 +41,9 @@ macro_rules! check_option { check_option!($e, $T, |ptr| assert_eq!(*ptr, $e)); }}; ($e:expr, $T:ty, |$v:ident| $chk:expr) => {{ - assert!(option::Option::None::<$T>.is_none()); + assert!(None::<$T>.is_none()); let e = $e; - let s_ = option::Option::Some::<$T>(e); + let s_ = Some::<$T>(e); let $v = s_.as_ref().unwrap(); $chk }} @@ -78,9 +76,8 @@ pub fn main() { check_type!(&17, &isize); check_type!(box 18, Box<isize>); check_type!("foo".to_string(), String); - check_type!(vec!(20, 22), Vec<isize> ); - let mint: usize = unsafe { mem::transmute(main) }; + check_type!(vec!(20, 22), Vec<isize>); check_type!(main, fn(), |pthing| { - assert_eq!(mint, unsafe { mem::transmute(*pthing) }) + assert_eq!(main as fn(), *pthing as fn()) }); } diff --git a/src/test/run-pass/parser-unicode-whitespace.rs b/src/test/run-pass/parser-unicode-whitespace.rs new file mode 100644 index 00000000000..837bb8339e1 --- /dev/null +++ b/src/test/run-pass/parser-unicode-whitespace.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Beware editing: it has numerous whitespace characters which are important. +// It contains one ranges from the 'PATTERN_WHITE_SPACE' property outlined in +// http://unicode.org/Public/UNIDATA/PropList.txt +// +// The characters in the first expression of the assertion can be generated +// from: "4\u{0C}+\n\t\r7\t*\u{20}2\u{85}/\u{200E}3\u{200F}*\u{2028}2\u{2029}" +pub fn main() { +assert_eq!(4+ + +7 * 2 /3* 2 , 4 + 7 * 2 / 3 * 2); +} diff --git a/src/test/run-pass/range.rs b/src/test/run-pass/range.rs index 24261772add..4c249bbe1f7 100644 --- a/src/test/run-pass/range.rs +++ b/src/test/run-pass/range.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -44,6 +44,7 @@ pub fn main() { let _ = 0_usize..4+4-3; let _ = 0..foo(); + let _ = { &42..&100 }; // references to literals are OK let _ = ..42_usize; // Test we can use two different types with a common supertype. diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs new file mode 100644 index 00000000000..07233a43b88 --- /dev/null +++ b/src/test/run-pass/range_inclusive.rs @@ -0,0 +1,129 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test inclusive range syntax. + +#![feature(inclusive_range_syntax, inclusive_range, step_by)] + +use std::ops::{RangeInclusive, RangeToInclusive}; + +fn foo() -> isize { 42 } + +// Test that range syntax works in return statements +fn return_range_to() -> RangeToInclusive<i32> { return ...1; } + +pub fn main() { + let mut count = 0; + for i in 0_usize...10 { + assert!(i >= 0 && i <= 10); + count += i; + } + assert_eq!(count, 55); + + let mut count = 0; + let mut range = 0_usize...10; + for i in range { + assert!(i >= 0 && i <= 10); + count += i; + } + assert_eq!(count, 55); + + let mut count = 0; + for i in (0_usize...10).step_by(2) { + assert!(i >= 0 && i <= 10 && i % 2 == 0); + count += i; + } + assert_eq!(count, 30); + + let _ = 0_usize...4+4-3; + let _ = 0...foo(); + + let _ = { &42...&100 }; // references to literals are OK + let _ = ...42_usize; + + // Test we can use two different types with a common supertype. + let x = &42; + { + let y = 42; + let _ = x...&y; + } + + // test collection indexing + let vec = (0...10).collect::<Vec<_>>(); + let slice: &[_] = &*vec; + let string = String::from("hello world"); + let stir = "hello world"; + + assert_eq!(&vec[3...6], &[3, 4, 5, 6]); + assert_eq!(&vec[ ...6], &[0, 1, 2, 3, 4, 5, 6]); + + assert_eq!(&slice[3...6], &[3, 4, 5, 6]); + assert_eq!(&slice[ ...6], &[0, 1, 2, 3, 4, 5, 6]); + + assert_eq!(&string[3...6], "lo w"); + assert_eq!(&string[ ...6], "hello w"); + + assert_eq!(&stir[3...6], "lo w"); + assert_eq!(&stir[ ...6], "hello w"); + + // test the size hints and emptying + let mut long = 0...255u8; + let mut short = 42...42; + assert_eq!(long.size_hint(), (256, Some(256))); + assert_eq!(short.size_hint(), (1, Some(1))); + long.next(); + short.next(); + assert_eq!(long.size_hint(), (255, Some(255))); + assert_eq!(short.size_hint(), (0, Some(0))); + assert_eq!(short, RangeInclusive::Empty { at: 42 }); + + assert_eq!(long.len(), 255); + assert_eq!(short.len(), 0); + + // test iterating backwards + assert_eq!(long.next_back(), Some(255)); + assert_eq!(long.next_back(), Some(254)); + assert_eq!(long.next_back(), Some(253)); + assert_eq!(long.next(), Some(1)); + assert_eq!(long.next(), Some(2)); + assert_eq!(long.next_back(), Some(252)); + for i in 3...251 { + assert_eq!(long.next(), Some(i)); + } + assert_eq!(long, RangeInclusive::Empty { at: 251 }); + + // check underflow + let mut narrow = 1...0; + assert_eq!(narrow.next_back(), None); + assert_eq!(narrow, RangeInclusive::Empty { at: 0 }); + let mut zero = 0u8...0; + assert_eq!(zero.next_back(), Some(0)); + assert_eq!(zero.next_back(), None); + assert_eq!(zero, RangeInclusive::Empty { at: 0 }); + let mut high = 255u8...255; + assert_eq!(high.next_back(), Some(255)); + assert_eq!(high.next_back(), None); + assert_eq!(high, RangeInclusive::Empty { at: 255 }); + + // what happens if you have a nonsense range? + let mut nonsense = 10...5; + assert_eq!(nonsense.next(), None); + assert_eq!(nonsense, RangeInclusive::Empty { at: 10 }); + + // conversion + assert_eq!(0...9, (0..10).into()); + assert_eq!(0...0, (0..1).into()); + assert_eq!(RangeInclusive::Empty { at: 1 }, (1..0).into()); + + // output + assert_eq!(format!("{:?}", 0...10), "0...10"); + assert_eq!(format!("{:?}", ...10), "...10"); + assert_eq!(format!("{:?}", long), "[empty range @ 251]"); +} diff --git a/src/test/run-pass/range_inclusive_gate.rs b/src/test/run-pass/range_inclusive_gate.rs new file mode 100644 index 00000000000..5e0ec19d6b3 --- /dev/null +++ b/src/test/run-pass/range_inclusive_gate.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you only need the syntax gate if you don't mention the structs. + +#![feature(inclusive_range_syntax)] + +fn main() { + let mut count = 0; + for i in 0_usize...10 { + assert!(i >= 0 && i <= 10); + count += i; + } + assert_eq!(count, 55); +} + diff --git a/src/test/run-pass/transmute-from-fn-item-types.rs b/src/test/run-pass/transmute-from-fn-item-types.rs new file mode 100644 index 00000000000..574a90e2ad6 --- /dev/null +++ b/src/test/run-pass/transmute-from-fn-item-types.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(transmute_from_fn_item_types)] + +use std::mem; + +fn main() { + unsafe { + let u = mem::transmute(main); + let p = mem::transmute(main); + let f = mem::transmute(main); + let tuple: (usize, *mut (), fn()) = (u, p, f); + assert_eq!(mem::transmute::<_, [usize; 3]>(tuple), [main as usize; 3]); + + mem::transmute::<_, usize>(main); + mem::transmute::<_, *mut ()>(main); + mem::transmute::<_, fn()>(main); + } +} diff --git a/src/test/run-pass/try-operator-hygiene.rs b/src/test/run-pass/try-operator-hygiene.rs new file mode 100644 index 00000000000..233c03df4e5 --- /dev/null +++ b/src/test/run-pass/try-operator-hygiene.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// `expr?` expands to: +// +// match expr { +// Ok(val) => val, +// Err(err) => return From::from(err), +// } +// +// This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and +// `err` bindings that may be in scope. + +#![feature(question_mark)] + +use std::num::ParseIntError; + +fn main() { + assert_eq!(parse(), Ok(1)); +} + +fn parse() -> Result<i32, ParseIntError> { + const val: char = 'a'; + const err: char = 'b'; + + Ok("1".parse::<i32>()?) +} diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs new file mode 100644 index 00000000000..de5ccf09c59 --- /dev/null +++ b/src/test/run-pass/try-operator.rs @@ -0,0 +1,200 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(question_mark)] + +use std::fs::File; +use std::io::{Read, self}; +use std::num::ParseIntError; +use std::str::FromStr; + +fn on_method() -> Result<i32, ParseIntError> { + Ok("1".parse::<i32>()? + "2".parse::<i32>()?) +} + +fn in_chain() -> Result<String, ParseIntError> { + Ok("3".parse::<i32>()?.to_string()) +} + +fn on_call() -> Result<i32, ParseIntError> { + fn parse<T: FromStr>(s: &str) -> Result<T, T::Err> { + s.parse() + } + + Ok(parse("4")?) +} + +fn nested() -> Result<i32, ParseIntError> { + Ok("5".parse::<i32>()?.to_string().parse()?) +} + +fn on_path() -> Result<i32, ParseIntError> { + let x = "6".parse::<i32>(); + + Ok(x?) +} + +fn on_macro() -> Result<i32, ParseIntError> { + macro_rules! id { + ($e:expr) => { $e } + } + + Ok(id!("7".parse::<i32>())?) +} + +fn on_parens() -> Result<i32, ParseIntError> { + let x = "8".parse::<i32>(); + + Ok((x)?) +} + +fn on_block() -> Result<i32, ParseIntError> { + let x = "9".parse::<i32>(); + + Ok({x}?) +} + +fn on_field() -> Result<i32, ParseIntError> { + struct Pair<A, B> { a: A, b: B } + + let x = Pair { a: "10".parse::<i32>(), b: 0 }; + + Ok(x.a?) +} + +fn on_tuple_field() -> Result<i32, ParseIntError> { + let x = ("11".parse::<i32>(), 0); + + Ok(x.0?) +} + +fn on_try() -> Result<i32, ParseIntError> { + let x = "12".parse::<i32>().map(|i| i.to_string().parse::<i32>()); + + Ok(x??) +} + +fn on_binary_op() -> Result<i32, ParseIntError> { + let x = 13 - "14".parse::<i32>()?; + let y = "15".parse::<i32>()? - 16; + let z = "17".parse::<i32>()? - "18".parse::<i32>()?; + + Ok(x + y + z) +} + +fn on_index() -> Result<i32, ParseIntError> { + let x = [19]; + let y = "0".parse::<usize>(); + + Ok(x[y?]) +} + +fn on_args() -> Result<i32, ParseIntError> { + fn sub(x: i32, y: i32) -> i32 { x - y } + + let x = "20".parse(); + let y = "21".parse(); + + Ok(sub(x?, y?)) +} + +fn on_if() -> Result<i32, ParseIntError> { + Ok(if true { + "22".parse::<i32>() + } else { + "23".parse::<i32>() + }?) +} + +fn on_if_let() -> Result<i32, ParseIntError> { + Ok(if let Ok(..) = "24".parse::<i32>() { + "25".parse::<i32>() + } else { + "26".parse::<i32>() + }?) +} + +fn on_match() -> Result<i32, ParseIntError> { + Ok(match "27".parse::<i32>() { + Err(..) => "28".parse::<i32>(), + Ok(..) => "29".parse::<i32>(), + }?) +} + +fn tight_binding() -> Result<bool, ()> { + fn ok<T>(x: T) -> Result<T, ()> { Ok(x) } + + let x = ok(true); + Ok(!x?) +} + +// just type check +fn merge_error() -> Result<i32, Error> { + let mut s = String::new(); + + File::open("foo.txt")?.read_to_string(&mut s)?; + + Ok(s.parse::<i32>()? + 1) +} + +fn main() { + assert_eq!(Ok(3), on_method()); + + assert_eq!(Ok("3".to_string()), in_chain()); + + assert_eq!(Ok(4), on_call()); + + assert_eq!(Ok(5), nested()); + + assert_eq!(Ok(6), on_path()); + + assert_eq!(Ok(7), on_macro()); + + assert_eq!(Ok(8), on_parens()); + + assert_eq!(Ok(9), on_block()); + + assert_eq!(Ok(10), on_field()); + + assert_eq!(Ok(11), on_tuple_field()); + + assert_eq!(Ok(12), on_try()); + + assert_eq!(Ok(-3), on_binary_op()); + + assert_eq!(Ok(19), on_index()); + + assert_eq!(Ok(-1), on_args()); + + assert_eq!(Ok(22), on_if()); + + assert_eq!(Ok(25), on_if_let()); + + assert_eq!(Ok(29), on_match()); + + assert_eq!(Ok(false), tight_binding()); +} + +enum Error { + Io(io::Error), + Parse(ParseIntError), +} + +impl From<io::Error> for Error { + fn from(e: io::Error) -> Error { + Error::Io(e) + } +} + +impl From<ParseIntError> for Error { + fn from(e: ParseIntError) -> Error { + Error::Parse(e) + } +} diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs index 97c37bbc1ed..266a3089194 100644 --- a/src/test/rustdoc/issue-15347.rs +++ b/src/test/rustdoc/issue-15347.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags:--no-defaults --passes "collapse-docs" --passes "unindent-comments" +// compile-flags:--no-defaults --passes collapse-docs --passes unindent-comments // @has issue_15347/fn.foo.html #[doc(hidden)] diff --git a/src/test/rustdoc/issue-27104.rs b/src/test/rustdoc/issue-27104.rs new file mode 100644 index 00000000000..5fa093d8f29 --- /dev/null +++ b/src/test/rustdoc/issue-27104.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--no-defaults --passes strip-priv-imports +// aux-build:empty.rs +// ignore-cross-compile + +// @has issue_27104/index.html +// @!has - 'extern crate std' +// @!has - 'use std::prelude::' + +// @has - 'pub extern crate empty' +pub extern crate empty; |
