From c04d86deeb6d23d8ee4b31abda92bb84c1d17897 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 29 Jan 2018 11:07:11 +0100 Subject: [PATCH 01/25] Work around LLVM OCAML binding installation failure --- src/bootstrap/native.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 3f30756a568ce..bb482813a23fe 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,6 +155,7 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); From 4d92fe2bb07a12368b6bb981d08f12f4a446a4d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 8 Feb 2018 16:26:43 -0800 Subject: [PATCH 02/25] Fix span bug. --- src/libsyntax/parse/parser.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc3745fc4a3ee..c7de0a75817c5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2630,8 +2630,7 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot_span = self.prev_span; - hi = self.span; + let idx_span = self.span; self.bump(); let invalid_msg = "invalid tuple or struct index"; @@ -2646,9 +2645,8 @@ impl<'a> Parser<'a> { n.to_string()); err.emit(); } - let id = respan(dot_span.to(hi), n); - let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo.to(hi), field, ThinVec::new()); + let field = self.mk_tup_field(e, respan(idx_span, n)); + e = self.mk_expr(lo.to(idx_span), field, ThinVec::new()); } None => { let prev_span = self.prev_span; From 4f8049a2b00c46cb1ac77cabaaf716895f185afe Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 01:47:18 -0800 Subject: [PATCH 03/25] Add Range[Inclusive]::is_empty During the RFC, it was discussed that figuring out whether a range is empty was subtle, and thus there should be a clear and obvious way to do it. It can't just be ExactSizeIterator::is_empty (also unstable) because not all ranges are ExactSize -- not even Range or RangeInclusive. --- src/libcore/iter/traits.rs | 2 +- src/libcore/ops/range.rs | 36 ++++++++++++++++++++++++++++++++++-- src/libcore/tests/iter.rs | 4 ++-- src/libcore/tests/lib.rs | 1 + src/libcore/tests/ops.rs | 24 ++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index be4889f24877c..860742d9eab60 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -706,7 +706,7 @@ pub trait ExactSizeIterator: Iterator { /// ``` /// #![feature(exact_size_is_empty)] /// - /// let mut one_element = 0..1; + /// let mut one_element = std::iter::once(0); /// assert!(!one_element.is_empty()); /// /// assert_eq!(one_element.next(), Some(0)); diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb69..102e08362cb4c 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -92,7 +92,6 @@ impl fmt::Debug for Range { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> Range { /// Returns `true` if `item` is contained in the range. /// @@ -109,9 +108,26 @@ impl> Range { /// assert!(!(3..3).contains(3)); /// assert!(!(3..2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { (self.start <= item) && (item < self.end) } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty)] + /// + /// assert!(!(3..5).is_empty()); + /// assert!( (3..3).is_empty()); + /// assert!( (3..2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start < self.end) + } } /// A range only bounded inclusively below (`start..`). @@ -280,7 +296,6 @@ impl fmt::Debug for RangeInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// @@ -298,9 +313,26 @@ impl> RangeInclusive { /// assert!( (3..=3).contains(3)); /// assert!(!(3..=2).contains(3)); /// ``` + #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } + + /// Returns `true` if the range contains no items. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// assert!(!(3..=5).is_empty()); + /// assert!(!(3..=3).is_empty()); + /// assert!( (3..=2).is_empty()); + /// ``` + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + pub fn is_empty(&self) -> bool { + !(self.start <= self.end) + } } /// A range only bounded inclusively above (`..=end`). diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index b2a5243d5e67b..062b6d4126e2c 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1427,9 +1427,9 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); + assert_eq!(ExactSizeIterator::is_empty(&r), true); assert_eq!(r, 1..=0); // We may not want to document/promise this detail } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c32452f84635..91b4f02594bc3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -29,6 +29,7 @@ #![feature(iter_rfold)] #![feature(nonzero)] #![feature(pattern)] +#![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 9d2fa1abff658..68a692b24a3fb 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -68,3 +68,27 @@ fn test_range_inclusive() { assert_eq!(r.size_hint(), (0, Some(0))); assert_eq!(r.next(), None); } + + +#[test] +fn test_range_is_empty() { + use core::f32::*; + + assert!(!(0.0 .. 10.0).is_empty()); + assert!( (-0.0 .. 0.0).is_empty()); + assert!( (10.0 .. 0.0).is_empty()); + + assert!(!(NEG_INFINITY .. INFINITY).is_empty()); + assert!( (EPSILON .. NAN).is_empty()); + assert!( (NAN .. EPSILON).is_empty()); + assert!( (NAN .. NAN).is_empty()); + + assert!(!(0.0 ..= 10.0).is_empty()); + assert!(!(-0.0 ..= 0.0).is_empty()); + assert!( (10.0 ..= 0.0).is_empty()); + + assert!(!(NEG_INFINITY ..= INFINITY).is_empty()); + assert!( (EPSILON ..= NAN).is_empty()); + assert!( (NAN ..= EPSILON).is_empty()); + assert!( (NAN ..= NAN).is_empty()); +} \ No newline at end of file From 7fe182fdfe01e01dd899962cc8dbaea63f422c9c Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 02:11:04 -0800 Subject: [PATCH 04/25] Fix tidy --- src/libcore/tests/ops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 68a692b24a3fb..bed08f86d72c1 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -91,4 +91,4 @@ fn test_range_is_empty() { assert!( (EPSILON ..= NAN).is_empty()); assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); -} \ No newline at end of file +} From b5cb393cf5b4a65fb99d8b1e43450fb87567788b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 17:54:27 -0800 Subject: [PATCH 05/25] Use is_empty in range iteration exhaustion tests --- src/libcore/ops/range.rs | 18 ++++++++++++ src/libcore/tests/iter.rs | 61 +++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 102e08362cb4c..cce593ee208b6 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -262,6 +262,13 @@ impl> RangeTo { /// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. /// +/// This iterator is [fused], but the specific values of `start` and `end` after +/// iteration has finished are **unspecified** other than that [`.is_empty()`] +/// will return `true` once no more values will be produced. +/// +/// [fused]: ../iter/trait.FusedIterator.html +/// [`.is_empty()`]: #method.is_empty +/// /// # Examples /// /// ``` @@ -329,6 +336,17 @@ impl> RangeInclusive { /// assert!(!(3..=3).is_empty()); /// assert!( (3..=2).is_empty()); /// ``` + /// + /// This method returns `true` after iteration has finished: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// let mut r = 3..=5; + /// for _ in r.by_ref() {} + /// // Precise field values are unspecified here + /// assert!(r.is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 062b6d4126e2c..d8c9dcd866486 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1322,42 +1322,84 @@ fn test_range() { (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))); } +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + #[test] fn test_range_inclusive_exhaustion() { let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.next(), Some(10)); assert_eq!(r.next(), Some(11)); assert_eq!(r.next(), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.next_back(), Some(12)); assert_eq!(r.next_back(), Some(11)); assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1..=0); + assert!(r.is_empty()); + assert_eq!(r.next(), None); let mut r = 100..=10; assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); assert_eq!(r, 100..=10); let mut r = 100..=10; assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); assert_eq!(r, 100..=10); } @@ -1427,10 +1469,11 @@ fn test_range_inclusive_nth() { assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); assert_eq!(ExactSizeIterator::is_empty(&r), false); assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); assert_eq!(ExactSizeIterator::is_empty(&r), true); - assert_eq!(r, 1..=0); // We may not want to document/promise this detail } #[test] @@ -1514,11 +1557,11 @@ fn test_range_inclusive_folds() { let mut it = 10..=20; assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); let mut it = 10..=20; assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165)); - assert_eq!(it, 1..=0); + assert!(it.is_empty()); } #[test] From 6f70a11a831992fe86a935a0d649d3aa6b16dc50 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 9 Feb 2018 18:01:12 -0800 Subject: [PATCH 06/25] range_is_empty tracking issue is #48111 --- src/libcore/ops/range.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index cce593ee208b6..4e4d334752370 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -124,7 +124,7 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) } @@ -347,7 +347,7 @@ impl> RangeInclusive { /// // Precise field values are unspecified here /// assert!(r.is_empty()); /// ``` - #[unstable(feature = "range_is_empty", reason = "recently added", issue = "123456789")] + #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start <= self.end) } From 0cccd9aca51e3fe2952633b34c4c877539d1113d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Feb 2018 14:57:08 +0100 Subject: [PATCH 07/25] Show better warning for trying to cast non-u8 scalar to char --- src/librustc_lint/types.rs | 17 +++++++++++++++++ src/test/ui/cast_char.rs | 20 ++++++++++++++++++++ src/test/ui/cast_char.stderr | 20 ++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/cast_char.rs create mode 100644 src/test/ui/cast_char.stderr diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e7e4119b9999b..f734f3182a931 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,6 +11,7 @@ #![allow(non_snake_case)] use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{self, LayoutOf}; @@ -176,6 +177,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => bug!(), }; if lit_val < min || lit_val > max { + let parent_id = cx.tcx.hir.get_parent_node(e.id); + if let hir_map::NodeExpr(parent_expr) = cx.tcx.hir.get(parent_id) { + if let hir::ExprCast(..) = parent_expr.node { + if let ty::TyChar = cx.tables.expr_ty(parent_expr).sty { + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + parent_expr.span, + "only u8 can be casted into char"); + err.span_suggestion(parent_expr.span, + &"use a char literal instead", + format!("'\\u{{{:X}}}'", lit_val)); + err.emit(); + return + } + } + } cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs new file mode 100644 index 0000000000000..cd8ade5e51a1b --- /dev/null +++ b/src/test/ui/cast_char.rs @@ -0,0 +1,20 @@ +// 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. + +#![deny(overflowing_literals)] + +fn main() { + const XYZ: char = 0x1F888 as char; + //~^ ERROR only u8 can be casted into char + const XY: char = 129160 as char; + //~^ ERROR only u8 can be casted into char + const ZYX: char = '\u{01F888}'; + println!("{}", XYZ); +} diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr new file mode 100644 index 0000000000000..e42a38dace9d2 --- /dev/null +++ b/src/test/ui/cast_char.stderr @@ -0,0 +1,20 @@ +error: only u8 can be casted into char + --> $DIR/cast_char.rs:14:23 + | +14 | const XYZ: char = 0x1F888 as char; + | ^^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + | +note: lint level defined here + --> $DIR/cast_char.rs:11:9 + | +11 | #![deny(overflowing_literals)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: only u8 can be casted into char + --> $DIR/cast_char.rs:16:22 + | +16 | const XY: char = 129160 as char; + | ^^^^^^^^^^^^^^ help: use a char literal instead: `'/u{1F888}'` + +error: aborting due to 2 previous errors + From 14f488ee7d05c39b8d6ea2855da274157555df0b Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 19:22:04 +0300 Subject: [PATCH 08/25] Whitelist pclmul x86 feature flag Relevant `stdsimd` [issue](https://github.com/rust-lang-nursery/stdsimd/issues/318). --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 843231d376f6c..f719562b47647 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", + "xsaves\0", "aes\0", "pclmul\0" "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 877272ba066dd81d9d920b851d0300bb3e7ee2b3 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sat, 10 Feb 2018 20:07:37 +0300 Subject: [PATCH 09/25] typo fix --- src/librustc_trans/llvm_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index f719562b47647..21def37e5e6e5 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -88,7 +88,7 @@ const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bm "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0" + "xsaves\0", "aes\0", "pclmul\0", "avx512bw\0", "avx512cd\0", "avx512dq\0", "avx512er\0", "avx512f\0", "avx512ifma\0", From 3c01dea03e1b4ffbcb665a68bcf228c02497ecdc Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 10 Feb 2018 21:29:10 +0100 Subject: [PATCH 10/25] Add comment about the problem, and use provided path if available --- src/bootstrap/native.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bb482813a23fe..108b0159dce74 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -155,11 +155,18 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_OCAML_INSTALL_PATH", "usr/lib/ocaml") .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + // By default, LLVM will automatically find OCaml and, if it finds it, + // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults + // to /usr/bin/ocaml. + // This causes problem for non-root builds of Rust. Side-step the issue + // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs + // in the prefix. + cfg.define("LLVM_OCAML_INSTALL_PATH", + env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space From 45d5a420ada9c11f61347fd4c63c7f0234adaea7 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 10 Feb 2018 21:20:42 +0000 Subject: [PATCH 11/25] Correct a few stability attributes --- src/libcore/num/mod.rs | 6 +++--- src/libcore/ptr.rs | 4 ++-- src/libcore/time.rs | 4 ++-- src/libstd/io/cursor.rs | 2 +- src/libstd/path.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c7775..21d4a486b9833 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe662..b266771b818e5 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25b2..b8d0719b9b992 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5baf..76bcb5fedc94a 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949ede..e03a182653e5a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874a8..f8dbc4d0f4532 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -538,7 +538,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) From 8be306840f89b92ee49d2c0fae2b189c45706b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:27:21 +0300 Subject: [PATCH 12/25] added conversion from Rust feature to LLVM feature --- src/librustc_trans/attributes.rs | 5 ++- src/librustc_trans/llvm_util.rs | 72 +++++++++++++++++--------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 6c8088375c4b0..8309c91ab2573 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -142,7 +142,7 @@ pub fn provide(providers: &mut Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|c| c.to_str().unwrap().to_string()) + .map(|c| c.to_string()) .collect()) }; @@ -212,7 +212,8 @@ fn from_target_feature( let value = value.as_str(); for feature in value.split(',') { if whitelist.contains(feature) { - target_features.push(format!("+{}", feature)); + let llvm_feature = llvm_util::to_llvm_feature(feature); + target_features.push(format!("+{}", llvm_feature)); continue } diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 21def37e5e6e5..61eefb32e099a 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -79,45 +79,54 @@ unsafe fn configure_llvm(sess: &Session) { // detection code will walk past the end of the feature array, // leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"]; - -const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"]; - -const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", - "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", - "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", - "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0", - "xsave\0", "xsaveopt\0", "xsavec\0", - "xsaves\0", "aes\0", "pclmul\0", - "avx512bw\0", "avx512cd\0", - "avx512dq\0", "avx512er\0", - "avx512f\0", "avx512ifma\0", - "avx512pf\0", "avx512vbmi\0", - "avx512vl\0", "avx512vpopcntdq\0", - "mmx\0", "fxsr\0"]; - -const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"]; - -const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0", - "power8-altivec\0", "power9-altivec\0", - "power8-vector\0", "power9-vector\0", - "vsx\0"]; - -const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"]; +const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"]; + +const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"]; + +const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse", + "sse2", "sse3", "sse4.1", "sse4.2", + "ssse3", "tbm", "lzcnt", "popcnt", + "sse4a", "rdrnd", "rdseed", "fma", + "xsave", "xsaveopt", "xsavec", + "xsaves", "aes", "pclmulqdq", + "avx512bw", "avx512cd", + "avx512dq", "avx512er", + "avx512f", "avx512ifma", + "avx512pf", "avx512vbmi", + "avx512vl", "avx512vpopcntdq", + "mmx", "fxsr"]; + +const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"]; + +const POWERPC_WHITELIST: &'static [&'static str] = &["altivec", + "power8-altivec", "power9-altivec", + "power8-vector", "power9-vector", + "vsx"]; + +const MIPS_WHITELIST: &'static [&'static str] = &["msa"]; + +pub fn to_llvm_feature(s: &str) -> &str { + match s { + "pclmulqdq" => "pclmul", + s => s, + } +} pub fn target_features(sess: &Session) -> Vec { let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); let mut features = Vec::new(); - for feat in whitelist { - if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } { - features.push(Symbol::intern(feat.to_str().unwrap())); + for feature in whitelist { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { + features.push(Symbol::intern(feature)); } } features } -pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { +pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { let whitelist = match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, @@ -126,10 +135,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> { "mips" | "mips64" => MIPS_WHITELIST, "powerpc" | "powerpc64" => POWERPC_WHITELIST, _ => &[], - }; - whitelist.iter().map(|m| { - CStr::from_bytes_with_nul(m.as_bytes()).unwrap() - }).collect() + } } pub fn print_version() { From c97aa0911785fc1c1306b38e978093b3153666ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 02:36:22 +0300 Subject: [PATCH 13/25] iterator instead loop --- src/librustc_trans/llvm_util.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 61eefb32e099a..8839129f3f88e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -113,17 +113,15 @@ pub fn to_llvm_feature(s: &str) -> &str { } pub fn target_features(sess: &Session) -> Vec { - let whitelist = target_feature_whitelist(sess); let target_machine = create_target_machine(sess); - let mut features = Vec::new(); - for feature in whitelist { - let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); - if unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } { - features.push(Symbol::intern(feature)); - } - } - features + target_feature_whitelist(sess) + .iter() + .filter(|feature| { + let llvm_feature = to_llvm_feature(feature); + let ptr = CString::new(llvm_feature).as_ptr(); + unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + }) + .map(Symbol::intern).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { From 161e8ffda79d25ef7a570bf0c0d884201267c6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 11 Feb 2018 00:56:24 +0100 Subject: [PATCH 14/25] typo: correct endianess to endianness (this also changes function names!) --- src/librustc_mir/interpret/memory.rs | 32 ++++++++++++++-------------- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c49..7cc4ba8489525 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { self.tcx.data_layout.pointer_size.bytes() } - pub fn endianess(&self) -> layout::Endian { + pub fn endianness(&self) -> layout::Endian { self.tcx.data_layout.endian } @@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! @@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } // Now we do the actual reading let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 + read_target_int(endianness, bytes).unwrap() as u128 } else { - read_target_uint(endianess, bytes).unwrap() + read_target_uint(endianness, bytes).unwrap() }; // See if we got a pointer if size != self.pointer_size() { @@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { @@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); + write_target_int(endianness, dst, bytes as i128).unwrap(); } else { - write_target_uint(endianess, dst, bytes).unwrap(); + write_target_uint(endianness, dst, bytes).unwrap(); } } @@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } //////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess +// Methods to access integers in the target endianness //////////////////////////////////////////////////////////////////////////////// fn write_target_uint( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_uint128::(data, len), layout::Endian::Big => target.write_uint128::(data, len), } } fn write_target_int( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: i128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_int128::(data, len), layout::Endian::Big => target.write_int128::(data, len), } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ecf68f29d6f1f..a760922115aef 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1023,7 +1023,7 @@ impl f32 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 29ba7d0dac635..6f34f176a9711 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -978,7 +978,7 @@ impl f64 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how From 7c6adb475abef794cc6b81f6a21094f3257ee37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 11 Feb 2018 03:27:04 +0300 Subject: [PATCH 15/25] fixed errors --- src/librustc_trans/llvm_util.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 8839129f3f88e..1f921513fe628 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -14,7 +14,7 @@ use llvm; use rustc::session::Session; use rustc::session::config::PrintRequest; use libc::c_int; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; @@ -118,14 +118,14 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).as_ptr(); + let ptr = CString::new(llvm_feature).unwrap().as_ptr(); unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } }) - .map(Symbol::intern).collect() + .map(|feature| Symbol::intern(feature)).collect() } pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] { - let whitelist = match &*sess.target.target.arch { + match &*sess.target.target.arch { "arm" => ARM_WHITELIST, "aarch64" => AARCH64_WHITELIST, "x86" | "x86_64" => X86_WHITELIST, From 22b0489f80dae5242f19c4ce892b50d3685dbf82 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 10 Feb 2018 16:32:05 -0800 Subject: [PATCH 16/25] Add the emptiness condition to the docs; add a PartialOrd example with NAN --- src/libcore/ops/range.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 4e4d334752370..8a45444f1ab0c 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -60,7 +60,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -124,6 +124,17 @@ impl> Range { /// assert!( (3..3).is_empty()); /// assert!( (3..2).is_empty()); /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..5.0).is_empty()); + /// assert!( (3.0..NAN).is_empty()); + /// assert!( (NAN..5.0).is_empty()); + /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { !(self.start < self.end) @@ -260,7 +271,7 @@ impl> RangeTo { /// An range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. +/// and `x <= end`. It is empty unless `start <= end`. /// /// This iterator is [fused], but the specific values of `start` and `end` after /// iteration has finished are **unspecified** other than that [`.is_empty()`] @@ -337,6 +348,17 @@ impl> RangeInclusive { /// assert!( (3..=2).is_empty()); /// ``` /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_is_empty,inclusive_range_syntax)] + /// + /// use std::f32::NAN; + /// assert!(!(3.0..=5.0).is_empty()); + /// assert!( (3.0..=NAN).is_empty()); + /// assert!( (NAN..=5.0).is_empty()); + /// ``` + /// /// This method returns `true` after iteration has finished: /// /// ``` From bf69b0feed33f40ddbef2940b9a3d99845982153 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 26 Jan 2018 03:14:20 +0800 Subject: [PATCH 17/25] Upgrade the Travis CI macOS images for testing from Xcode 8.3 to 9.2. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1007aad925d96..280da05699506 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto - env: > @@ -70,7 +70,7 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 os: osx - osx_image: xcode8.3 + osx_image: xcode9.2 if: branch = auto # OSX builders producing releases. These do not run the full test suite and From a003cb7cd7d619a5553c5c99e4ee7ce185a1608c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 8 Feb 2018 16:26:33 -0800 Subject: [PATCH 18/25] Add test. --- src/test/run-pass/hygiene/issue-47312.rs | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/run-pass/hygiene/issue-47312.rs diff --git a/src/test/run-pass/hygiene/issue-47312.rs b/src/test/run-pass/hygiene/issue-47312.rs new file mode 100644 index 0000000000000..5e83f3808d8cc --- /dev/null +++ b/src/test/run-pass/hygiene/issue-47312.rs @@ -0,0 +1,30 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro)] +#![allow(unused)] + +mod foo { + pub macro m($s:tt, $i:tt) { + $s.$i + } +} + +mod bar { + struct S(i32); + fn f() { + let s = S(0); + ::foo::m!(s, 0); + } +} + +fn main() {} From c2a31dee835c2312a9e527b1f9ea1b77c24beeab Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 11 Feb 2018 15:57:07 +0300 Subject: [PATCH 19/25] Dangling pointer fix --- src/librustc_trans/llvm_util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 1f921513fe628..b25562252e72e 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -118,8 +118,8 @@ pub fn target_features(sess: &Session) -> Vec { .iter() .filter(|feature| { let llvm_feature = to_llvm_feature(feature); - let ptr = CString::new(llvm_feature).unwrap().as_ptr(); - unsafe { llvm::LLVMRustHasFeature(target_machine, ptr) } + let cstr = CString::new(llvm_feature).unwrap(); + unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } }) .map(|feature| Symbol::intern(feature)).collect() } From bd426f1d69ec8371d86e06382e96e9ed842f3933 Mon Sep 17 00:00:00 2001 From: Jason Schein Date: Sun, 11 Feb 2018 17:54:44 -0800 Subject: [PATCH 20/25] Update ops range example to avoid confusion between indexes and values. --- src/libcore/ops/range.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 3f573f7c7eb69..a80699c0f5afd 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -68,11 +68,11 @@ impl fmt::Debug for RangeFull { /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); /// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// let arr = ['a', 'b', 'c', 'd']; +/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']); +/// assert_eq!(arr[ ..3], ['a', 'b', 'c', ]); +/// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); +/// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] From f7cabc6550f23d8a761abf737763a0375a0ac41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 11 Feb 2018 22:10:35 -0800 Subject: [PATCH 21/25] Continue parsing function after finding `...` arg When encountering a variadic argument in a function definition that doesn't accept it, if immediately after there's a closing paren, continue parsing as normal. Otherwise keep current behavior of emitting error and stopping. --- src/libsyntax/parse/parser.rs | 21 +++++++++++++++----- src/test/ui/invalid-variadic-function.rs | 13 ++++++++++++ src/test/ui/invalid-variadic-function.stderr | 14 +++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/invalid-variadic-function.rs create mode 100644 src/test/ui/invalid-variadic-function.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc3745fc4a3ee..ac582627f88fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4859,19 +4859,30 @@ impl<'a> Parser<'a> { |p| { if p.token == token::DotDotDot { p.bump(); + variadic = true; if allow_variadic { if p.token != token::CloseDelim(token::Paren) { let span = p.span; p.span_err(span, "`...` must be last in argument list for variadic function"); } + Ok(None) } else { - let span = p.span; - p.span_err(span, - "only foreign functions are allowed to be variadic"); + let span = p.prev_span; + if p.token == token::CloseDelim(token::Paren) { + // continue parsing to present any further errors + p.struct_span_err( + span, + "only foreign functions are allowed to be variadic" + ).emit(); + Ok(Some(dummy_arg(span))) + } else { + // this function definition looks beyond recovery, stop parsing + p.span_err(span, + "only foreign functions are allowed to be variadic"); + Ok(None) + } } - variadic = true; - Ok(None) } else { match p.parse_arg_general(named_args) { Ok(arg) => Ok(Some(arg)), diff --git a/src/test/ui/invalid-variadic-function.rs b/src/test/ui/invalid-variadic-function.rs new file mode 100644 index 0000000000000..3d421e00b08e4 --- /dev/null +++ b/src/test/ui/invalid-variadic-function.rs @@ -0,0 +1,13 @@ +// 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. + +extern "C" fn foo(x: u8, ...); +//~^ ERROR only foreign functions are allowed to be variadic +//~| ERROR expected one of `->`, `where`, or `{`, found `;` diff --git a/src/test/ui/invalid-variadic-function.stderr b/src/test/ui/invalid-variadic-function.stderr new file mode 100644 index 0000000000000..15a908b3f00f2 --- /dev/null +++ b/src/test/ui/invalid-variadic-function.stderr @@ -0,0 +1,14 @@ +error: only foreign functions are allowed to be variadic + --> $DIR/invalid-variadic-function.rs:11:26 + | +11 | extern "C" fn foo(x: u8, ...); + | ^^^ + +error: expected one of `->`, `where`, or `{`, found `;` + --> $DIR/invalid-variadic-function.rs:11:30 + | +11 | extern "C" fn foo(x: u8, ...); + | ^ expected one of `->`, `where`, or `{` here + +error: aborting due to 2 previous errors + From 0f16eee013aa64108a1b1ca8fa9f9cf263635071 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 21:21:02 -0800 Subject: [PATCH 22/25] rustc: Add the ability to not run dsymutil This commit adds the ability for rustc to not run `dsymutil` by default on OSX. A new codegen option, `-Z run-dsymutil=no`, was added to specify that `dsymutil` should *not* run and instead the compiler should unconditionally keep the object files around in a compilation if necessary for debug information. cc #47240 --- src/librustc/session/config.rs | 2 ++ src/librustc_trans/back/link.rs | 58 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5b8092e86da04..1f40c2db45397 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1320,6 +1320,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "The epoch to build Rust with. Newer epochs may include features that require breaking changes. The default epoch is 2015 (the first epoch). Crates compiled with different epochs can be linked together."), + run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], + "run `dsymutil` and delete intermediate object files"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index f050edcd513b9..4fe294a790fc4 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -166,7 +166,9 @@ pub(crate) fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() { + if sess.opts.output_types.should_trans() && + !preserve_objects_for_their_debuginfo(sess) + { for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { remove(sess, obj); } @@ -190,6 +192,52 @@ pub(crate) fn link_binary(sess: &Session, out_filenames } +/// Returns a boolean indicating whether we should preserve the object files on +/// the filesystem for their debug information. This is often useful with +/// split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { + // If the objects don't have debuginfo there's nothing to preserve. + if sess.opts.debuginfo == NoDebugInfo { + return false + } + + // If we're only producing artifacts that are archives, no need to preserve + // the objects as they're losslessly contained inside the archives. + let output_linked = sess.crate_types.borrow() + .iter() + .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib); + if !output_linked { + return false + } + + // If we're on OSX then the equivalent of split dwarf is turned on by + // default. The final executable won't actually have any debug information + // except it'll have pointers to elsewhere. Historically we've always run + // `dsymutil` to "link all the dwarf together" but this is actually sort of + // a bummer for incremental compilation! (the whole point of split dwarf is + // that you don't do this sort of dwarf link). + // + // Basically as a result this just means that if we're on OSX and we're + // *not* running dsymutil then the object files are the only source of truth + // for debug information, so we must preserve them. + if sess.target.target.options.is_like_osx { + match sess.opts.debugging_opts.run_dsymutil { + // dsymutil is not being run, preserve objects + Some(false) => return true, + + // dsymutil is being run, no need to preserve the objects + Some(true) => return false, + + // The default historical behavior was to always run dsymutil, so + // we're preserving that temporarily, but we're likely to switch the + // default soon. + None => return false, + } + } + + false +} + fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf { let out_filename = outputs.single_output_file.clone() .unwrap_or(outputs @@ -736,8 +784,12 @@ fn link_natively(sess: &Session, // On macOS, debuggers need this utility to get run to do some munging of - // the symbols - if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo { + // the symbols. Note, though, that if the object files are being preserved + // for their debug information there's no need for us to run dsymutil. + if sess.target.target.options.is_like_osx && + sess.opts.debuginfo != NoDebugInfo && + !preserve_objects_for_their_debuginfo(sess) + { match Command::new("dsymutil").arg(out_filename).output() { Ok(..) => {} Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)), From 43e8ac27d9bf645b66a15f762be6969e9fe16285 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 08:38:46 -0800 Subject: [PATCH 23/25] rustc: Persist LLVM's `Linker` in Fat LTO This commit updates our Fat LTO logic to tweak our custom wrapper around LLVM's "link modules" functionality. Previously whenever the `LLVMRustLinkInExternalBitcode` function was called it would call LLVM's `Linker::linkModules` wrapper. Internally this would crate an instance of a `Linker` which internally creates an instance of an `IRMover`. Unfortunately for us the creation of `IRMover` is somewhat O(n) with the input module. This means that every time we linked a module it was O(n) with respect to the entire module we had built up! Now the modules we build up during LTO are quite large, so this quickly started creating an O(n^2) problem for us! Discovered in #48025 it turns out this has always been a problem and we just haven't noticed it. It became particularly worse recently though due to most libraries having 16x more object files than they previously did (1 -> 16). This commit fixes this performance issue by preserving the `Linker` instance across all links into the main LLVM module. This means we only create one `IRMover` and allows LTO to progress much speedier. From the `cargo-cache` project in #48025 a **full build** locally when from 5m15s to 2m24s. Looking at the timing logs each object file was linked in in single-digit millisecond rather than hundreds, clearly being a nice improvement! Closes #48025 --- src/librustc_llvm/build.rs | 1 + src/librustc_llvm/ffi.rs | 10 ++++- src/librustc_trans/back/lto.rs | 40 +++++++++++++++---- src/rustllvm/Linker.cpp | 72 ++++++++++++++++++++++++++++++++++ src/rustllvm/RustWrapper.cpp | 40 ------------------- 5 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 src/rustllvm/Linker.cpp diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 49b93f3c7d6a2..54e3f544acb68 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -155,6 +155,7 @@ fn main() { cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") + .file("../rustllvm/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("rustllvm"); diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 99e43a2ddf98d..e71bef512cf06 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -444,6 +444,9 @@ pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; #[allow(missing_copy_implementations)] pub enum OperandBundleDef_opaque {} pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; +#[allow(missing_copy_implementations)] +pub enum Linker_opaque {} +pub type LinkerRef = *mut Linker_opaque; pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); @@ -1608,7 +1611,6 @@ extern "C" { pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool; pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t); pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); @@ -1724,4 +1726,10 @@ extern "C" { CU2: *mut *mut c_void); pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void); pub fn LLVMRustThinLTORemoveAvailableExternally(M: ModuleRef); + + pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef; + pub fn LLVMRustLinkerAdd(linker: LinkerRef, + bytecode: *const c_char, + bytecode_len: usize) -> bool; + pub fn LLVMRustLinkerFree(linker: LinkerRef); } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 9ff5bcf7a33ca..a33270380196f 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -247,22 +247,20 @@ fn fat_lto(cgcx: &CodegenContext, // know much about the memory management here so we err on the side of being // save and persist everything with the original module. let mut serialized_bitcode = Vec::new(); + let mut linker = Linker::new(llmod); for (bc_decoded, name) in serialized_modules { info!("linking {:?}", name); - time(cgcx.time_passes, &format!("ll link {:?}", name), || unsafe { + time(cgcx.time_passes, &format!("ll link {:?}", name), || { let data = bc_decoded.data(); - if llvm::LLVMRustLinkInExternalBitcode(llmod, - data.as_ptr() as *const libc::c_char, - data.len() as libc::size_t) { - Ok(()) - } else { + linker.add(&data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - Err(write::llvm_err(&diag_handler, msg)) - } + write::llvm_err(&diag_handler, msg) + }) })?; timeline.record(&format!("link {:?}", name)); serialized_bitcode.push(bc_decoded); } + drop(linker); cgcx.save_temp_bitcode(&module, "lto.input"); // Internalize everything that *isn't* in our whitelist to help strip out @@ -289,6 +287,32 @@ fn fat_lto(cgcx: &CodegenContext, }]) } +struct Linker(llvm::LinkerRef); + +impl Linker { + fn new(llmod: ModuleRef) -> Linker { + unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } + } + + fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + unsafe { + if llvm::LLVMRustLinkerAdd(self.0, + bytecode.as_ptr() as *const libc::c_char, + bytecode.len()) { + Ok(()) + } else { + Err(()) + } + } + } +} + +impl Drop for Linker { + fn drop(&mut self) { + unsafe { llvm::LLVMRustLinkerFree(self.0); } + } +} + /// Prepare "thin" LTO to get run on these modules. /// /// The general structure of ThinLTO is quite different from the structure of diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp new file mode 100644 index 0000000000000..534e4b910902e --- /dev/null +++ b/src/rustllvm/Linker.cpp @@ -0,0 +1,72 @@ +// 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. + +#include "llvm/Linker/Linker.h" + +#include "rustllvm.h" + +using namespace llvm; + +struct RustLinker { + Linker L; + LLVMContext &Ctx; + + RustLinker(Module &M) : + L(M), + Ctx(M.getContext()) + {} +}; + +extern "C" RustLinker* +LLVMRustLinkerNew(LLVMModuleRef DstRef) { + Module *Dst = unwrap(DstRef); + + auto Ret = llvm::make_unique(*Dst); + return Ret.release(); +} + +extern "C" void +LLVMRustLinkerFree(RustLinker *L) { + delete L; +} + +extern "C" bool +LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { + std::unique_ptr Buf = + MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); + +#if LLVM_VERSION_GE(4, 0) + Expected> SrcOrError = + llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx); + if (!SrcOrError) { + LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); + return false; + } + + auto Src = std::move(*SrcOrError); +#else + ErrorOr> Src = + llvm::getLazyBitcodeModule(std::move(Buf), L->Ctx); + if (!Src) { + LLVMRustSetLastError(Src.getError().message().c_str()); + return false; + } +#endif + +#if LLVM_VERSION_GE(4, 0) + if (L->L.linkInModule(std::move(Src))) { +#else + if (L->L.linkInModule(std::move(Src.get()))) { +#endif + LLVMRustSetLastError(""); + return false; + } + return true; +} diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4dfc4029d75dc..27d5496f57628 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -916,46 +916,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC, - size_t Len) { - Module *Dst = unwrap(DstRef); - - std::unique_ptr Buf = - MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); - -#if LLVM_VERSION_GE(4, 0) - Expected> SrcOrError = - llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), Dst->getContext()); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return false; - } - - auto Src = std::move(*SrcOrError); -#else - ErrorOr> Src = - llvm::getLazyBitcodeModule(std::move(Buf), Dst->getContext()); - if (!Src) { - LLVMRustSetLastError(Src.getError().message().c_str()); - return false; - } -#endif - - std::string Err; - - raw_string_ostream Stream(Err); - DiagnosticPrinterRawOStream DP(Stream); -#if LLVM_VERSION_GE(4, 0) - if (Linker::linkModules(*Dst, std::move(Src))) { -#else - if (Linker::linkModules(*Dst, std::move(Src.get()))) { -#endif - LLVMRustSetLastError(Err.c_str()); - return false; - } - return true; -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The From 4c658f76c1b51ced4f6c30ea37441c4141659b93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Feb 2018 10:46:31 -0800 Subject: [PATCH 24/25] Update compiletest's `read2` function This was originally copied over from Cargo and Cargo has since [been updated][update] so let's pull in the fixes here too! [update]: https://github.com/rust-lang/cargo/pull/5030 --- src/tools/compiletest/src/read2.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 1d8816c7db132..486c0d81e3f40 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -58,9 +58,12 @@ mod imp { fds[0].events = libc::POLLIN; fds[1].fd = err_pipe.as_raw_fd(); fds[1].events = libc::POLLIN; - loop { + let mut nfds = 2; + let mut errfd = 1; + + while nfds > 0 { // wait for either pipe to become readable using `select` - let r = unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) }; + let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) }; if r == -1 { let err = io::Error::last_os_error(); if err.kind() == io::ErrorKind::Interrupted { @@ -86,19 +89,20 @@ mod imp { } } }; - if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { - out_done = true; - } - data(true, &mut out, out_done); - if !err_done && fds[1].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { + if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? { err_done = true; + nfds -= 1; } data(false, &mut err, err_done); - - if out_done && err_done { - return Ok(()) + if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? { + out_done = true; + fds[0].fd = err_pipe.as_raw_fd(); + errfd = 0; + nfds -= 1; } + data(true, &mut out, out_done); } + Ok(()) } } From f237e9e2e74dfd5b223589f6254c80e8a69b724e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Mon, 12 Feb 2018 12:28:32 -0700 Subject: [PATCH 25/25] Remove allocation from width of character function. --- src/libsyntax/codemap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3601b9ba8a8c1..ff6f32fc3be0b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -690,14 +690,16 @@ impl CodeMap { return 1; } + let src = local_begin.fm.external_src.borrow(); + // We need to extend the snippet to the end of the src rather than to end_index so when // searching forwards for boundaries we've got somewhere to search. let snippet = if let Some(ref src) = local_begin.fm.src { let len = src.len(); - (&src[start_index..len]).to_string() - } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() { + (&src[start_index..len]) + } else if let Some(src) = src.get_source() { let len = src.len(); - (&src[start_index..len]).to_string() + (&src[start_index..len]) } else { return 1; };