diff options
| author | bors <bors@rust-lang.org> | 2022-01-31 08:12:10 +0000 | 
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-01-31 08:12:10 +0000 | 
| commit | 415c9f95884caebd0be9b837ef0885d1ffde1b9b (patch) | |
| tree | dee55224d2f23cc0bfd794554c76228daa36046e /compiler/rustc_builtin_macros/src | |
| parent | bb549e5afe8f23258606649cc3a2d8b8a51ef63a (diff) | |
| parent | 4757a931cd69f57ab3e1d823ffa44b18c37e1223 (diff) | |
| download | rust-415c9f95884caebd0be9b837ef0885d1ffde1b9b.tar.gz rust-415c9f95884caebd0be9b837ef0885d1ffde1b9b.zip | |
Auto merge of #93499 - matthiaskrgr:rollup-icdex11, r=matthiaskrgr
Rollup of 8 pull requests
Successful merges:
 - #93395 (Improve suggestion for escaping reserved keywords)
 - #93403 (review the total_cmp documentation)
 - #93461 (Accommodate yield points in the format_args expansion)
 - #93462 (Document `SystemTime` platform precision)
 - #93471 (unix: Use metadata for `DirEntry::file_type` fallback)
 - #93480 (Remove deprecated and unstable slice_partition_at_index functions)
 - #93485 (core: Remove some redundant {}s from the sorting code)
 - #93494 (kmc-solid: Inherit the calling task's base priority in `Thread::new`)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/format.rs | 55 | 
1 files changed, 51 insertions, 4 deletions
| diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 41b56cca1dc..aaa6580acc6 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -4,6 +4,7 @@ use Position::*; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; +use rustc_ast::visit::{self, Visitor}; use rustc_ast::{token, BlockCheckMode, UnsafeSource}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; @@ -788,17 +789,31 @@ impl<'a, 'b> Context<'a, 'b> { // the order provided to fmt::Arguments. When arguments are repeated, we // want the expression evaluated only once. // - // Thus in the not nicely ordered case we emit the following instead: + // Further, if any arg _after the first one_ contains a yield point such + // as `await` or `yield`, the above short form is inconvenient for the + // caller because it would keep a temporary of type ArgumentV1 alive + // across the yield point. ArgumentV1 can't implement Send since it + // holds a type-erased arbitrary type. + // + // Thus in the not nicely ordered case, and in the yielding case, we + // emit the following instead: // // match (&$arg0, &$arg1, …) { // args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …] // } // // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty. + // This more verbose representation ensures that all arguments are + // evaluated a single time each, in the order written by the programmer, + // and that the surrounding future/generator (if any) is Send whenever + // possible. + let no_need_for_match = + nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e)); + for (arg_index, arg_ty) in fmt_arg_index_and_ty { let e = &mut original_args[arg_index]; let span = e.span; - let arg = if nicely_ordered { + let arg = if no_need_for_match { let expansion_span = e.span.with_ctxt(self.macsp.ctxt()); // The indices are strictly ordered so e has not been taken yet. self.ecx.expr_addr_of(expansion_span, P(e.take())) @@ -814,10 +829,10 @@ impl<'a, 'b> Context<'a, 'b> { let args_array = self.ecx.expr_vec(self.macsp, fmt_args); let args_slice = self.ecx.expr_addr_of( self.macsp, - if nicely_ordered { + if no_need_for_match { args_array } else { - // In the !nicely_ordered case, none of the exprs were moved + // In the !no_need_for_match case, none of the exprs were moved // away in the previous loop. // // This uses the arg span for `&arg` so that borrowck errors @@ -1226,3 +1241,35 @@ pub fn expand_preparsed_format_args( cx.into_expr() } + +fn may_contain_yield_point(e: &ast::Expr) -> bool { + struct MayContainYieldPoint(bool); + + impl Visitor<'_> for MayContainYieldPoint { + fn visit_expr(&mut self, e: &ast::Expr) { + if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { + self.0 = true; + } else { + visit::walk_expr(self, e); + } + } + + fn visit_mac_call(&mut self, _: &ast::MacCall) { + self.0 = true; + } + + fn visit_attribute(&mut self, _: &ast::Attribute) { + // Conservatively assume this may be a proc macro attribute in + // expression position. + self.0 = true; + } + + fn visit_item(&mut self, _: &ast::Item) { + // Do not recurse into nested items. + } + } + + let mut visitor = MayContainYieldPoint(false); + visitor.visit_expr(e); + visitor.0 +} | 
