diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py index 78427a6360a9f..daf21670b3339 100644 --- a/src/ci/cpu-usage-over-time.py +++ b/src/ci/cpu-usage-over-time.py @@ -30,23 +30,8 @@ # the second column is always zero. # # Once you've downloaded a file there's various ways to plot it and visualize -# it. For command line usage you can use a script like so: -# -# set timefmt '%Y-%m-%dT%H:%M:%S' -# set xdata time -# set ylabel "Idle CPU %" -# set xlabel "Time" -# set datafile sep ',' -# set term png -# set output "printme.png" -# set grid -# builder = "i686-apple" -# plot "cpu-".builder.".csv" using 1:2 with lines title builder -# -# Executed as `gnuplot < ./foo.plot` it will generate a graph called -# `printme.png` which you can then open up. If you know how to improve this -# script or the viewing process that would be much appreciated :) (or even if -# you know how to automate it!) +# it. For command line usage you use the `src/etc/cpu-usage-over-time-plot.sh` +# script in this repository. import datetime import sys diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 1994cf491889b..0e38e2865d893 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -132,7 +132,7 @@ The advantages over a simple `fn(&str) -> u32` are: In addition to procedural macros, you can define new [`derive`](../../reference/attributes/derive.md)-like attributes and other kinds of extensions. See `Registry::register_syntax_extension` and the -`SyntaxExtension` enum. For a more involved macro example, see +`SyntaxExtension` struct. For a more involved macro example, see [`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs). diff --git a/src/etc/cpu-usage-over-time-plot.sh b/src/etc/cpu-usage-over-time-plot.sh new file mode 100755 index 0000000000000..724a21c3fc269 --- /dev/null +++ b/src/etc/cpu-usage-over-time-plot.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# A small script to help visualizing CPU usage over time data collected on CI +# using `gnuplot`. +# +# This script is expected to be called with two arguments. The first is the full +# commit SHA of the build you're interested in, and the second is the name of +# the builder. For example: +# +# ./src/etc/cpu-usage-over-time-plot.sh e699ea096fcc2fc9ce8e8bcf884e11496a31cc9f i686-mingw-1 +# +# That will generate `$builder.png` in the current directory which you can open +# up to see a hopefully pretty graph. +# +# Improvements to this script are greatly appreciated! + +set -ex + +bucket=rust-lang-ci-evalazure +commit=$1 +builder=$2 + +curl -O https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv + +gnuplot <<-EOF +reset +set timefmt '%Y-%m-%dT%H:%M:%S' +set xdata time +set ylabel "CPU Usage %" +set xlabel "Time" +set datafile sep ',' +set term png size 3000,1000 +set output "$builder.png" +set grid + +f(x) = mean_y +fit f(x) 'cpu-$builder.csv' using 1:(100-\$2) via mean_y + +set label 1 gprintf("Average = %g%%", mean_y) center font ",18" +set label 1 at graph 0.50, 0.25 +set xtics rotate by 45 offset -2,-2.4 300 +set ytics 10 +set boxwidth 0.5 + +plot \\ + mean_y with lines linetype 1 linecolor rgb "#ff0000" title "average", \\ + "cpu-$builder.csv" using 1:(100-\$2) with points pointtype 7 pointsize 0.4 title "$builder", \\ + "" using 1:(100-\$2) smooth bezier linewidth 3 title "bezier" +EOF diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 030f4f1d12cc8..1bfb852424d63 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,6 +100,7 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![cfg_attr(not(bootstrap), feature(transparent_unions))] #![feature(unboxed_closures)] #![feature(unsized_locals)] #![feature(untagged_unions)] diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index eeff9d0303a3b..28e1e22ba7ff2 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -172,7 +172,7 @@ use crate::mem::ManuallyDrop; /// /// # Layout /// -/// `MaybeUninit` is guaranteed to have the same size and alignment as `T`: +/// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as `T`: /// /// ```rust /// use std::mem::{MaybeUninit, size_of, align_of}; @@ -191,9 +191,23 @@ use crate::mem::ManuallyDrop; /// assert_eq!(size_of::>(), 1); /// assert_eq!(size_of::>>(), 2); /// ``` +/// +/// If `T` is FFI-safe, then so is `MaybeUninit`. +/// +/// While `MaybeUninit` is `#[repr(transparent)]` (indicating it guarantees the same size, +/// alignment, and ABI as `T`), this does *not* change any of the previous caveats. `Option` and +/// `Option>` may still have different sizes, and types containing a field of type +/// `T` may be laid out (and sized) differently than if that field were `MaybeUninit`. +/// `MaybeUninit` is a union type, and `#[repr(transparent)]` on unions is unstable (see [the +/// tracking issue](https://github.com/rust-lang/rust/issues/60405)). Over time, the exact +/// guarantees of `#[repr(transparent)]` on unions may evolve, and `MaybeUninit` may or may not +/// remain `#[repr(transparent)]`. That said, `MaybeUninit` will *always* guarantee that it has +/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that +/// guarantee may evolve. #[allow(missing_debug_implementations)] #[stable(feature = "maybe_uninit", since = "1.36.0")] #[derive(Copy)] +#[cfg_attr(not(bootstrap), repr(transparent))] pub union MaybeUninit { uninit: (), value: ManuallyDrop, diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 213e57a3b37c2..a7750edbb6f48 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -330,7 +330,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprKind::DropTemps(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Field(ref e, _) | - hir::ExprKind::Yield(ref e) | + hir::ExprKind::Yield(ref e, _) | hir::ExprKind::Repeat(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index e29a373ec3b76..8d7e51d1ea6c0 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1089,7 +1089,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(expr) } } - ExprKind::Yield(ref subexpression) => { + ExprKind::Yield(ref subexpression, _) => { visitor.visit_expr(subexpression); } ExprKind::Lit(_) | ExprKind::Err => {} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c4f7b78a133c1..60b099b0fed12 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,14 +62,14 @@ use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned}; +use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned}; use syntax::source_map::CompilerDesugaringKind::IfTemporary; use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::{self, Token}; use syntax::visit::{self, Visitor}; -use syntax_pos::{DUMMY_SP, edition, Span}; +use syntax_pos::{DUMMY_SP, Span}; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -95,8 +95,7 @@ pub struct LoweringContext<'a> { modules: BTreeMap, - is_generator: bool, - is_async_body: bool, + generator_kind: Option, /// Used to get the current `fn`'s def span to point to when using `await` /// outside of an `async fn`. @@ -142,6 +141,9 @@ pub struct LoweringContext<'a> { current_hir_id_owner: Vec<(DefIndex, u32)>, item_local_id_counters: NodeMap, node_id_to_hir_id: IndexVec, + + allow_try_trait: Option>, + allow_gen_future: Option>, } pub trait Resolver { @@ -261,12 +263,13 @@ pub fn lower_crate( current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), - is_generator: false, - is_async_body: false, + generator_kind: None, current_item: None, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), + allow_try_trait: Some([sym::try_trait][..].into()), + allow_gen_future: Some([sym::gen_future][..].into()), }.lower_crate(krate) } @@ -790,18 +793,49 @@ impl<'a> LoweringContext<'a> { }) } - fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { - if self.is_generator && self.is_async_body { - span_err!( - self.sess, - value.span, - E0727, - "`async` generators are not yet supported", - ); - self.sess.abort_if_errors(); + fn generator_movability_for_fn( + &mut self, + decl: &ast::FnDecl, + fn_decl_span: Span, + generator_kind: Option, + movability: Movability, + ) -> Option { + match generator_kind { + Some(hir::GeneratorKind::Gen) => { + if !decl.inputs.is_empty() { + span_err!( + self.sess, + fn_decl_span, + E0628, + "generators cannot have explicit arguments" + ); + self.sess.abort_if_errors(); + } + Some(match movability { + Movability::Movable => hir::GeneratorMovability::Movable, + Movability::Static => hir::GeneratorMovability::Static, + }) + }, + Some(hir::GeneratorKind::Async) => { + bug!("non-`async` closure body turned `async` during lowering"); + }, + None => { + if movability == Movability::Static { + span_err!( + self.sess, + fn_decl_span, + E0697, + "closures cannot be static" + ); + } + None + }, } + } + + fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { let body = hir::Body { - is_generator: self.is_generator || self.is_async_body, + generator_kind: self.generator_kind, arguments, value, }; @@ -848,14 +882,10 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: Option>, ) -> Span { let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(source_map::ExpnInfo { - call_site: span, + mark.set_expn_info(ExpnInfo { def_site: Some(span), - format: source_map::CompilerDesugaring(reason), allow_internal_unstable, - allow_internal_unsafe: false, - local_inner_macros: false, - edition: edition::Edition::from_session(), + ..ExpnInfo::default(source_map::CompilerDesugaring(reason), span, self.sess.edition()) }); span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } @@ -1142,7 +1172,7 @@ impl<'a> LoweringContext<'a> { }; let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); let body_id = self.lower_fn_body(&ast_decl, |this| { - this.is_async_body = true; + this.generator_kind = Some(hir::GeneratorKind::Async); body(this) }); let generator = hir::Expr { @@ -1156,7 +1186,7 @@ impl<'a> LoweringContext<'a> { let unstable_span = self.mark_span_with_reason( CompilerDesugaringKind::Async, span, - Some(vec![sym::gen_future].into()), + self.allow_gen_future.clone(), ); let gen_future = self.expr_std_path( unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new()); @@ -1167,12 +1197,10 @@ impl<'a> LoweringContext<'a> { &mut self, f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), ) -> hir::BodyId { - let prev_is_generator = mem::replace(&mut self.is_generator, false); - let prev_is_async_body = mem::replace(&mut self.is_async_body, false); + let prev_gen_kind = self.generator_kind.take(); let (arguments, result) = f(self); let body_id = self.record_body(arguments, result); - self.is_generator = prev_is_generator; - self.is_async_body = prev_is_async_body; + self.generator_kind = prev_gen_kind; body_id } @@ -4382,7 +4410,7 @@ impl<'a> LoweringContext<'a> { let unstable_span = this.mark_span_with_reason( CompilerDesugaringKind::TryBlock, body.span, - Some(vec![sym::try_trait].into()), + this.allow_try_trait.clone(), ); let mut block = this.lower_block(body, true).into_inner(); let tail = block.expr.take().map_or_else( @@ -4475,37 +4503,18 @@ impl<'a> LoweringContext<'a> { self.with_new_scopes(|this| { this.current_item = Some(fn_decl_span); - let mut is_generator = false; + let mut generator_kind = None; let body_id = this.lower_fn_body(decl, |this| { let e = this.lower_expr(body); - is_generator = this.is_generator; + generator_kind = this.generator_kind; e }); - let generator_option = if is_generator { - if !decl.inputs.is_empty() { - span_err!( - this.sess, - fn_decl_span, - E0628, - "generators cannot have explicit arguments" - ); - this.sess.abort_if_errors(); - } - Some(match movability { - Movability::Movable => hir::GeneratorMovability::Movable, - Movability::Static => hir::GeneratorMovability::Static, - }) - } else { - if movability == Movability::Static { - span_err!( - this.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ); - } - None - }; + let generator_option = this.generator_movability_for_fn( + &decl, + fn_decl_span, + generator_kind, + movability, + ); hir::ExprKind::Closure( this.lower_capture_clause(capture_clause), fn_decl, @@ -4677,12 +4686,26 @@ impl<'a> LoweringContext<'a> { } ExprKind::Yield(ref opt_expr) => { - self.is_generator = true; + match self.generator_kind { + Some(hir::GeneratorKind::Gen) => {}, + Some(hir::GeneratorKind::Async) => { + span_err!( + self.sess, + e.span, + E0727, + "`async` generators are not yet supported", + ); + self.sess.abort_if_errors(); + }, + None => { + self.generator_kind = Some(hir::GeneratorKind::Gen); + } + } let expr = opt_expr .as_ref() .map(|x| self.lower_expr(x)) .unwrap_or_else(|| self.expr_unit(e.span)); - hir::ExprKind::Yield(P(expr)) + hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield) } ExprKind::Err => hir::ExprKind::Err, @@ -4968,13 +4991,13 @@ impl<'a> LoweringContext<'a> { let unstable_span = self.mark_span_with_reason( CompilerDesugaringKind::QuestionMark, e.span, - Some(vec![sym::try_trait].into()), + self.allow_try_trait.clone(), ); let try_span = self.sess.source_map().end_point(e.span); let try_span = self.mark_span_with_reason( CompilerDesugaringKind::QuestionMark, try_span, - Some(vec![sym::try_trait].into()), + self.allow_try_trait.clone(), ); // `Try::into_result()` @@ -5754,19 +5777,23 @@ impl<'a> LoweringContext<'a> { // yield (); // } // } - if !self.is_async_body { - let mut err = struct_span_err!( - self.sess, - await_span, - E0728, - "`await` is only allowed inside `async` functions and blocks" - ); - err.span_label(await_span, "only allowed inside `async` functions and blocks"); - if let Some(item_sp) = self.current_item { - err.span_label(item_sp, "this is not `async`"); + match self.generator_kind { + Some(hir::GeneratorKind::Async) => {}, + Some(hir::GeneratorKind::Gen) | + None => { + let mut err = struct_span_err!( + self.sess, + await_span, + E0728, + "`await` is only allowed inside `async` functions and blocks" + ); + err.span_label(await_span, "only allowed inside `async` functions and blocks"); + if let Some(item_sp) = self.current_item { + err.span_label(item_sp, "this is not `async`"); + } + err.emit(); + return hir::ExprKind::Err; } - err.emit(); - return hir::ExprKind::Err; } let span = self.mark_span_with_reason( CompilerDesugaringKind::Await, @@ -5776,7 +5803,7 @@ impl<'a> LoweringContext<'a> { let gen_future_span = self.mark_span_with_reason( CompilerDesugaringKind::Await, await_span, - Some(vec![sym::gen_future].into()), + self.allow_gen_future.clone(), ); // let mut pinned = ; @@ -5864,7 +5891,7 @@ impl<'a> LoweringContext<'a> { let unit = self.expr_unit(span); let yield_expr = P(self.expr( span, - hir::ExprKind::Yield(P(unit)), + hir::ExprKind::Yield(P(unit), hir::YieldSource::Await), ThinVec::new(), )); self.stmt(span, hir::StmtKind::Expr(yield_expr)) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index a88eeaa5ee276..69bd4d3f1f6a3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1306,7 +1306,7 @@ pub struct BodyId { /// /// - an `arguments` array containing the `(x, y)` pattern /// - a `value` containing the `x + y` expression (maybe wrapped in a block) -/// - `is_generator` would be false +/// - `generator_kind` would be `None` /// /// All bodies have an **owner**, which can be accessed via the HIR /// map using `body_owner_def_id()`. @@ -1314,7 +1314,7 @@ pub struct BodyId { pub struct Body { pub arguments: HirVec, pub value: Expr, - pub is_generator: bool, + pub generator_kind: Option, } impl Body { @@ -1325,6 +1325,26 @@ impl Body { } } +/// The type of source expression that caused this generator to be created. +// Not `IsAsync` because we want to eventually add support for `AsyncGen` +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable, + RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum GeneratorKind { + /// An `async` block or function. + Async, + /// A generator literal created via a `yield` inside a closure. + Gen, +} + +impl fmt::Display for GeneratorKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + GeneratorKind::Async => "`async` object", + GeneratorKind::Gen => "generator", + }) + } +} + #[derive(Copy, Clone, Debug)] pub enum BodyOwnerKind { /// Functions and methods. @@ -1531,8 +1551,8 @@ pub enum ExprKind { /// /// The final span is the span of the argument block `|...|`. /// - /// This may also be a generator literal, indicated by the final boolean, - /// in that case there is an `GeneratorClause`. + /// This may also be a generator literal or an `async block` as indicated by the + /// `Option`. Closure(CaptureClause, P, BodyId, Span, Option), /// A block (e.g., `'label: { ... }`). Block(P, Option