From adaaeeaee341d9cc4472afc8287704dd5cea521e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 30 Mar 2018 16:10:05 +0200 Subject: [PATCH 01/12] Add missing anchor for union type fields --- src/librustdoc/html/render.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ff6cc56e5b4f5..38696bb71493d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2801,10 +2801,15 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "

Fields

")?; for (field, ty) in fields { - write!(w, "{name}: {ty} + let name = field.name.as_ref().expect("union field name"); + let id = format!("{}.{}", ItemType::StructField, name); + write!(w, "\ + \ + \ ", + id = id, + name = name, shortty = ItemType::StructField, - name = field.name.as_ref().unwrap(), ty = ty)?; if let Some(stability_class) = field.stability_class() { write!(w, "", From d0eeb291dddb99ad6f2aedafa5355556b40e483f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 30 Mar 2018 14:20:16 +0200 Subject: [PATCH 02/12] Add support for variant and types fields for intra links --- src/librustdoc/clean/mod.rs | 25 +++++++++++++++++++++--- src/test/rustdoc/struct-field.rs | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/struct-field.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3a79c14f4ec2a..bff22292cc0a4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1013,8 +1013,7 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option let ty = cx.resolver.borrow_mut() .with_scope(*id, |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, - &path, false) + resolver.resolve_str_path_error(DUMMY_SP, &path, false) })?; match ty.def { Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => { @@ -1029,7 +1028,27 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option }; Ok((ty.def, Some(format!("{}.{}", out, item_name)))) } else { - Err(()) + let is_enum = match ty.def { + Def::Enum(_) => true, + _ => false, + }; + let elem = if is_enum { + cx.tcx.adt_def(did).all_fields().find(|item| item.name == item_name) + } else { + cx.tcx.adt_def(did) + .non_enum_variant() + .fields + .iter() + .find(|item| item.name == item_name) + }; + if let Some(item) = elem { + Ok((ty.def, + Some(format!("{}.{}", + if is_enum { "variant" } else { "structfield" }, + item.name)))) + } else { + Err(()) + } } } Def::Trait(did) => { diff --git a/src/test/rustdoc/struct-field.rs b/src/test/rustdoc/struct-field.rs new file mode 100644 index 0000000000000..c5016bac7d394 --- /dev/null +++ b/src/test/rustdoc/struct-field.rs @@ -0,0 +1,33 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/struct.Foo.html#structfield.bar"]' 'Foo::bar' +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/union.Bar.html#structfield.foo"]' 'Bar::foo' +// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/enum.Uniooon.html#X.v"]' 'Uniooon::X' + +//! Test with [Foo::bar], [Bar::foo], [Uniooon::X] + +pub struct Foo { + pub bar: usize, +} + +pub union Bar { + pub foo: u32, +} + +pub enum Uniooon { + F, + X, + Y, +} From fb7deda27419eae61da3cbf5a5b1b4f51ae16d04 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 30 Mar 2018 23:06:05 -0700 Subject: [PATCH 03/12] Add #[must_use] to a few standard library methods Chosen to start a precedent of using it on ones that are potentially-expensive and where using it for side effects is particularly discouraged. Discuss :) --- src/liballoc/borrow.rs | 1 + src/libcore/clone.rs | 1 + src/libcore/iter/iterator.rs | 1 + src/librustc_mir/build/mod.rs | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index acae0daa86b6b..c6741ddb822d5 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -59,6 +59,7 @@ pub trait ToOwned { /// let vv: Vec = v.to_owned(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "cloning is often expensive and is not expected to have side effects"] fn to_owned(&self) -> Self::Owned; /// Uses borrowed data to replace owned data, usually by cloning. diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index d25f498b99efe..c175ae15d28fe 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -105,6 +105,7 @@ pub trait Clone : Sized { /// assert_eq!("Hello", hello.clone()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "cloning is often expensive and is not expected to have side effects"] fn clone(&self) -> Self; /// Performs copy-assignment from `source`. diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 31f77f92435d8..42fd90512923b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1368,6 +1368,7 @@ pub trait Iterator { /// [`Result`]: ../../std/result/enum.Result.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] fn collect>(self) -> B where Self: Sized { FromIterator::from_iter(self) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8494c043f90fc..6f5fcc9e421cc 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -317,7 +317,7 @@ newtype_index!(ScopeId); /// macro (and methods below) makes working with `BlockAnd` much more /// convenient. -#[must_use] // if you don't use one of these results, you're leaving a dangling edge +#[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd(BasicBlock, T); trait BlockAndExtension { From 8f9ec1cb06524a483b1bfc81c9912ebb7d46cb52 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 2 Apr 2018 00:14:44 +0300 Subject: [PATCH 04/12] avoid IdxSets containing garbage above the universe length This makes sure that all bits in each IdxSet between the universe length and the end of the word are all zero instead of being in an indeterminate state. This fixes a crash with RUST_LOG=rustc_mir, and is probably a good idea anyway. --- src/librustc_data_structures/indexed_set.rs | 74 ++++++++++++++++++++- src/librustc_mir/dataflow/impls/mod.rs | 4 +- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 7ab6a2691488e..c9495587c4687 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -121,7 +121,9 @@ impl IdxSetBuf { /// Creates set holding every element whose index falls in range 0..universe_size. pub fn new_filled(universe_size: usize) -> Self { - Self::new(!0, universe_size) + let mut result = Self::new(!0, universe_size); + result.trim_to(universe_size); + result } /// Creates set holding no elements. @@ -168,6 +170,36 @@ impl IdxSet { } } + /// Sets all elements up to `universe_size` + pub fn set_up_to(&mut self, universe_size: usize) { + for b in &mut self.bits { + *b = !0; + } + self.trim_to(universe_size); + } + + /// Clear all elements above `universe_size`. + fn trim_to(&mut self, universe_size: usize) { + let word_bits = mem::size_of::() * 8; + + // `trim_block` is the first block where some bits have + // to be cleared. + let trim_block = universe_size / word_bits; + + // all the blocks above it have to be completely cleared. + if trim_block < self.bits.len() { + for b in &mut self.bits[trim_block+1..] { + *b = 0; + } + + // at that block, the `universe_size % word_bits` lsbs + // should remain. + let remaining_bits = universe_size % word_bits; + let mask = (1< bool { self.bits.clear_bit(elem.index()) @@ -252,3 +284,43 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> { } } } + +#[test] +fn test_trim_to() { + use std::cmp; + + for i in 0..256 { + let mut idx_buf: IdxSetBuf = IdxSetBuf::new_filled(128); + idx_buf.trim_to(i); + + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..cmp::min(i, 128)).collect(); + assert_eq!(elems, expected); + } +} + +#[test] +fn test_set_up_to() { + for i in 0..128 { + for mut idx_buf in + vec![IdxSetBuf::new_empty(128), IdxSetBuf::new_filled(128)] + .into_iter() + { + idx_buf.set_up_to(i); + + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..i).collect(); + assert_eq!(elems, expected); + } + } +} + +#[test] +fn test_new_filled() { + for i in 0..128 { + let mut idx_buf = IdxSetBuf::new_filled(i); + let elems: Vec = idx_buf.iter().collect(); + let expected: Vec = (0..i).collect(); + assert_eq!(elems, expected); + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index c5f5492cd2c2c..287640439c0e8 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> // sets on_entry bits for Arg places fn start_block_effect(&self, entry_set: &mut IdxSet) { // set all bits to 1 (uninit) before gathering counterevidence - for e in entry_set.words_mut() { *e = !0; } + entry_set.set_up_to(self.bits_per_block()); drop_flag_effects_for_function_entry( self.tcx, self.mir, self.mdpe, @@ -443,7 +443,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc // sets on_entry bits for Arg places fn start_block_effect(&self, entry_set: &mut IdxSet) { - for e in entry_set.words_mut() { *e = 0; } + entry_set.clear(); drop_flag_effects_for_function_entry( self.tcx, self.mir, self.mdpe, From cc939ac345091327b23f807b7d1f6a7c75c03f36 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 30 Mar 2018 16:10:47 +0900 Subject: [PATCH 05/12] Add vec![ptr::null{,_mut}(); n] optimization, like vec![0; n] vec![0; n], via implementations of SpecFromElem, has an optimization that uses with_capacity_zeroed instead of with_capacity, which will use calloc instead of malloc, and avoid an extra memset. This adds the same optimization for vec![ptr::null(); n] and vec![ptr::null_mut(); n], assuming their bit value is 0 (which is true on all currently supported platforms). This does so by adding an intermediate trait IsZero, which looks very much like nonzero::Zeroable, but that one is on the way out, and doesn't apply to pointers anyways. Adding such a trait allows to avoid repeating the logic using with_capacity_zeroed or with_capacity, or making the macro more complex to support generics. --- src/liballoc/vec.rs | 79 ++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2eedb964f88ba..512c74d9d7704 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1567,40 +1567,67 @@ impl SpecFromElem for u8 { } } -macro_rules! impl_spec_from_elem { +impl SpecFromElem for T { + #[inline] + fn from_elem(elem: T, n: usize) -> Vec { + if elem.is_zero() { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + let mut v = Vec::with_capacity(n); + v.extend_with(n, ExtendElement(elem)); + v + } +} + +unsafe trait IsZero { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} + +macro_rules! impl_is_zero { ($t: ty, $is_zero: expr) => { - impl SpecFromElem for $t { + unsafe impl IsZero for $t { #[inline] - fn from_elem(elem: $t, n: usize) -> Vec<$t> { - if $is_zero(elem) { - return Vec { - buf: RawVec::with_capacity_zeroed(n), - len: n, - } - } - let mut v = Vec::with_capacity(n); - v.extend_with(n, ExtendElement(elem)); - v + fn is_zero(&self) -> bool { + $is_zero(*self) } } - }; + } } -impl_spec_from_elem!(i8, |x| x == 0); -impl_spec_from_elem!(i16, |x| x == 0); -impl_spec_from_elem!(i32, |x| x == 0); -impl_spec_from_elem!(i64, |x| x == 0); -impl_spec_from_elem!(i128, |x| x == 0); -impl_spec_from_elem!(isize, |x| x == 0); +impl_is_zero!(i8, |x| x == 0); +impl_is_zero!(i16, |x| x == 0); +impl_is_zero!(i32, |x| x == 0); +impl_is_zero!(i64, |x| x == 0); +impl_is_zero!(i128, |x| x == 0); +impl_is_zero!(isize, |x| x == 0); -impl_spec_from_elem!(u16, |x| x == 0); -impl_spec_from_elem!(u32, |x| x == 0); -impl_spec_from_elem!(u64, |x| x == 0); -impl_spec_from_elem!(u128, |x| x == 0); -impl_spec_from_elem!(usize, |x| x == 0); +impl_is_zero!(u16, |x| x == 0); +impl_is_zero!(u32, |x| x == 0); +impl_is_zero!(u64, |x| x == 0); +impl_is_zero!(u128, |x| x == 0); +impl_is_zero!(usize, |x| x == 0); + +impl_is_zero!(f32, |x: f32| x.to_bits() == 0); +impl_is_zero!(f64, |x: f64| x.to_bits() == 0); + +unsafe impl IsZero for *const T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} + +unsafe impl IsZero for *mut T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} -impl_spec_from_elem!(f32, |x: f32| x.to_bits() == 0); -impl_spec_from_elem!(f64, |x: f64| x.to_bits() == 0); //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec From 0df837f79289819f9b671b67d4e63dfe5c80d419 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 2 Apr 2018 10:44:38 +0900 Subject: [PATCH 06/12] Add vec!['\0'; n] optimization, like vec![0; n] Similarly to vec![ptr::null{,_mut}(); n] in previous change, this adds the optimization for vec!['\0'; n]. --- src/liballoc/vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 512c74d9d7704..515b79e5acdc7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1611,6 +1611,8 @@ impl_is_zero!(u64, |x| x == 0); impl_is_zero!(u128, |x| x == 0); impl_is_zero!(usize, |x| x == 0); +impl_is_zero!(char, |x| x == '\0'); + impl_is_zero!(f32, |x: f32| x.to_bits() == 0); impl_is_zero!(f64, |x: f64| x.to_bits() == 0); From fb5b5f52488d3f149c5a6c72b4842d400a872043 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 26 Mar 2018 19:19:25 -0300 Subject: [PATCH 07/12] Refactor inner function into closure. So we can cut some params by using stuff from the environment. --- src/librustc_typeck/check/mod.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 187f220f7f830..b7eef6c5d0b77 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2532,16 +2532,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); - fn parameter_count_error<'tcx>(sess: &Session, - sp: Span, - expr_sp: Span, - expected_count: usize, - arg_count: usize, - error_code: &str, - variadic: bool, - def_span: Option, - sugg_unit: bool) { - let mut err = sess.struct_span_err_with_code(sp, + let param_count_error = |expected_count: usize, + arg_count: usize, + error_code: &str, + variadic: bool, + sugg_unit: bool| { + let mut err = tcx.sess.struct_span_err_with_code(sp, &format!("this function takes {}{} parameter{} but {} parameter{} supplied", if variadic {"at least "} else {""}, expected_count, @@ -2550,11 +2546,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if arg_count == 1 {" was"} else {"s were"}), DiagnosticId::Error(error_code.to_owned())); - if let Some(def_s) = def_span.map(|sp| sess.codemap().def_span(sp)) { + if let Some(def_s) = def_span.map(|sp| tcx.sess.codemap().def_span(sp)) { err.span_label(def_s, "defined here"); } if sugg_unit { - let sugg_span = sess.codemap().end_point(expr_sp); + let sugg_span = tcx.sess.codemap().end_point(expr_sp); // remove closing `)` from the span let sugg_span = sugg_span.shrink_to_lo(); err.span_suggestion( @@ -2568,14 +2564,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if expected_count == 1 {""} else {"s"})); } err.emit(); - } + }; let formal_tys = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::TyTuple(arg_types) if arg_types.len() != args.len() => { - parameter_count_error(tcx.sess, sp, expr_sp, arg_types.len(), args.len(), - "E0057", false, def_span, false); + param_count_error(arg_types.len(), args.len(), "E0057", false, false); expected_arg_tys = &[]; self.err_args(args.len()) } @@ -2603,8 +2598,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { - parameter_count_error(tcx.sess, sp, expr_sp, expected_arg_count, - supplied_arg_count, "E0060", true, def_span, false); + param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); expected_arg_tys = &[]; self.err_args(supplied_arg_count) } @@ -2617,8 +2611,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { false }; - parameter_count_error(tcx.sess, sp, expr_sp, expected_arg_count, - supplied_arg_count, "E0061", false, def_span, sugg_unit); + param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); + expected_arg_tys = &[]; self.err_args(supplied_arg_count) }; From be25e7858c0aba0ed18e0149f9176f2be07cc6d5 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 27 Mar 2018 08:25:31 -0300 Subject: [PATCH 08/12] Remove single use helper function. --- src/librustc_typeck/check/mod.rs | 13 +------------ src/librustc_typeck/check/op.rs | 6 +++--- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b7eef6c5d0b77..e19bd9610e4a2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2829,18 +2829,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_expr_coercable_to_type(&self, expr: &'gcx hir::Expr, expected: Ty<'tcx>) -> Ty<'tcx> { - self.check_expr_coercable_to_type_with_needs(expr, expected, Needs::None) - } - - fn check_expr_coercable_to_type_with_needs(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>, - needs: Needs) - -> Ty<'tcx> { - let ty = self.check_expr_with_expectation_and_needs( - expr, - ExpectHasType(expected), - needs); + let ty = self.check_expr_with_hint(expr, expected); self.demand_coerce(expr, ty, expected) } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index faebb370a6c46..e74d774745b58 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -174,9 +174,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // trait matching creating lifetime constraints that are too strict. // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. - let lhs_ty = self.check_expr_coercable_to_type_with_needs(lhs_expr, - self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)), - lhs_needs); + let lhs_ty = self.check_expr_with_needs(lhs_expr, lhs_needs); + let fresh_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)); + let lhs_ty = self.demand_coerce(lhs_expr, lhs_ty, fresh_var); let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); // NB: As we have not yet type-checked the RHS, we don't have the From 6511ef3c00c80d96dbfa04ba761526d3a948dbaf Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 27 Mar 2018 11:27:02 -0300 Subject: [PATCH 09/12] Simplify code around expected argument types. --- src/librustc_typeck/check/mod.rs | 95 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e19bd9610e4a2..27b74f1fb3700 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2508,7 +2508,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp: Span, expr_sp: Span, fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], + mut expected_arg_tys: &[Ty<'tcx>], args: &'gcx [hir::Expr], variadic: bool, tuple_arguments: TupleArgumentsFlag, @@ -2529,7 +2529,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); } - let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); let param_count_error = |expected_count: usize, @@ -2616,6 +2615,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected_arg_tys = &[]; self.err_args(supplied_arg_count) }; + // If there is no expectation, expect formal_tys. + let expected_arg_tys = if !expected_arg_tys.is_empty() { + expected_arg_tys + } else { + &formal_tys + }; debug!("check_argument_types: formal_tys={:?}", formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>()); @@ -2667,23 +2672,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The special-cased logic below has three functions: // 1. Provide as good of an expected type as possible. - let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(self, ty) - }); + let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - let checked_ty = self.check_expr_with_expectation( - &arg, - expected.unwrap_or(ExpectHasType(formal_ty))); + let checked_ty = self.check_expr_with_expectation(&arg, expected); // 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(self)); - self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); + let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); + self.demand_coerce(&arg, checked_ty, coerce_ty); // 3. Relate the expected type and the formal one, // if the expected type was used for the coercion. - coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); + self.demand_suptype(arg.span, formal_ty, coerce_ty); } } @@ -2878,45 +2879,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { formal_args: &[Ty<'tcx>]) -> Vec> { let formal_ret = self.resolve_type_vars_with_obligations(formal_ret); - let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { - self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); - - // FIXME(#27336) can't use ? here, Try::from_error doesn't default - // to identity so the resulting type is not constrained. - match ures { - Ok(ok) => { - // Process any obligations locally as much as - // we can. We don't care if some things turn - // out unconstrained or ambiguous, as we're - // just trying to get hints here. - self.save_and_restore_in_snapshot_flag(|_| { - let mut fulfill = TraitEngine::new(self.tcx); - for obligation in ok.obligations { - fulfill.register_predicate_obligation(self, obligation); - } - fulfill.select_where_possible(self) - }).map_err(|_| ())?; - } - Err(_) => return Err(()), + let ret_ty = match expected_ret.only_has_type(self) { + Some(ret) => ret, + None => return Vec::new() + }; + let expect_args = self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = self.misc(call_span); + let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); + + // FIXME(#27336) can't use ? here, Try::from_error doesn't default + // to identity so the resulting type is not constrained. + match ures { + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + self.save_and_restore_in_snapshot_flag(|_| { + let mut fulfill = TraitEngine::new(self.tcx); + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }).map_err(|_| ())?; } + Err(_) => return Err(()), + } - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| { - self.resolve_type_vars_if_possible(ty) - }).collect()) - }).ok() - }).unwrap_or(vec![]); + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| { + self.resolve_type_vars_if_possible(ty) + }).collect()) + }).unwrap_or(Vec::new()); debug!("expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", formal_args, formal_ret, - expected_args, expected_ret); - expected_args + expect_args, expected_ret); + expect_args } // Checks a method call. From a2a0f21ba1d2d0d54e8a34d39d7435cbb4efe7e9 Mon Sep 17 00:00:00 2001 From: Rolf van de Krol Date: Mon, 2 Apr 2018 21:48:56 +0200 Subject: [PATCH 10/12] Fix typo --- src/libstd/io/buffered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index cefff2f143ce7..3e9ae261ab649 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -180,7 +180,7 @@ impl BufReader { /// /// # Examples /// - /// ```no_ru + /// ```no_run /// # #![feature(bufreader_buffer)] /// use std::io::{BufReader, BufRead}; /// use std::fs::File; From 58217edd2fbb9f51b5838c6da97ef8dc4bfdef33 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 2 Apr 2018 17:21:37 -0700 Subject: [PATCH 11/12] run-pass/attr-stmt-expr: expand test cases --- .../proc-macro/attr-stmt-expr.rs | 14 +++++++++++++- .../proc-macro/auxiliary/attr-stmt-expr.rs | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs index 082dd63992968..98316c62ef135 100644 --- a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs +++ b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs @@ -14,7 +14,8 @@ #![feature(proc_macro, stmt_expr_attributes)] extern crate attr_stmt_expr; -use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr}; +use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr, + no_output, noop}; fn print_str(string: &'static str) { // macros are handled a bit differently @@ -29,6 +30,17 @@ fn main() { #[expect_print_stmt] println!("{}", string); + let _: () = { + #[no_output] + "Hello, world!" + }; + + let _: &'static str = #[noop] "Hello, world!"; + + let _: &'static str = { + #[noop] "Hello, world!" + }; + #[expect_expr] print_str("string") } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-stmt-expr.rs index 189e6bbd00dba..972368b7b532a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-stmt-expr.rs @@ -44,3 +44,18 @@ pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert_eq!(item.to_string(), "println!(\"{}\" , string)"); item } + +#[proc_macro_attribute] +pub fn no_output(attr: TokenStream, item: TokenStream) -> TokenStream { + assert!(attr.to_string().is_empty()); + assert!(!item.to_string().is_empty()); + "".parse().unwrap() + +} + +#[proc_macro_attribute] +pub fn noop(attr: TokenStream, item: TokenStream) -> TokenStream { + assert!(attr.to_string().is_empty()); + assert!(!item.to_string().is_empty()); + item +} From 9ab5788e0e73d1d7edbc025627e34bb8d4fa9bdd Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 2 Apr 2018 19:34:06 -0600 Subject: [PATCH 12/12] Fix "since" version for getpid feature. It was stabilized right before the beta branch was cut for 1.26.0. See https://github.com/rust-lang/rust/pull/49523#issuecomment-377996315 --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index b463a6d88fe8e..40bc84f4bc104 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1426,7 +1426,7 @@ pub fn abort() -> ! { /// ``` /// /// -#[stable(feature = "getpid", since = "1.27.0")] +#[stable(feature = "getpid", since = "1.26.0")] pub fn id() -> u32 { ::sys::os::getpid() }