about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-20 22:35:56 +0000
committerbors <bors@rust-lang.org>2024-04-20 22:35:56 +0000
commit453ceafce32ef8108c604bca5e165ab41d3d6d8c (patch)
tree291ff8649c049bbc4d4c1d73d99158e869f672e1 /compiler
parentdbce3b43b6cb34dd3ba12c3ec6f708fe68e9c3df (diff)
parentc72cfdd46fff49c382d3834b4f0e48d75aedb970 (diff)
downloadrust-453ceafce32ef8108c604bca5e165ab41d3d6d8c.tar.gz
rust-453ceafce32ef8108c604bca5e165ab41d3d6d8c.zip
Auto merge of #124208 - jieyouxu:rollup-gbgpu4u, r=jieyouxu
Rollup of 10 pull requests

Successful merges:

 - #123379 (Print note with closure signature on type mismatch)
 - #123967 (static_mut_refs: use raw pointers to remove the remaining FIXME)
 - #123976 (Use fake libc in core test)
 - #123986 (lint-docs: Add redirects for renamed lints.)
 - #124053 (coverage: Branch coverage tests for lazy boolean operators)
 - #124071 (Add llvm-bitcode-linker to build manifest)
 - #124103 (Improve std::fs::Metadata Debug representation)
 - #124132 (llvm RustWrapper: explain OpBundlesIndirect argument type)
 - #124191 (Give a name to each distinct manipulation of pretty-printer FixupContext)
 - #124196 (mir-opt tests: rename unit-test -> test-mir-pass)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs25
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs226
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/fixup.rs149
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs15
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs6
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs19
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp3
9 files changed, 213 insertions, 234 deletions
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 293e65ce872..2c176828c84 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -3,11 +3,12 @@
 //! Note that HIR pretty printing is layered on top of this crate.
 
 mod expr;
+mod fixup;
 mod item;
 
 use crate::pp::Breaks::{Consistent, Inconsistent};
 use crate::pp::{self, Breaks};
-use crate::pprust::state::expr::FixupContext;
+use crate::pprust::state::fixup::FixupContext;
 use ast::TraitBoundModifiers;
 use rustc_ast::attr::AttrIdGenerator;
 use rustc_ast::ptr::P;
@@ -15,7 +16,6 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
 use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{Comment, CommentStyle};
-use rustc_ast::util::parser;
 use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
 use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
 use rustc_ast::{GenericArg, GenericBound, SelfKind};
@@ -1252,22 +1252,14 @@ impl<'a> State<'a> {
             ast::StmtKind::Item(item) => self.print_item(item),
             ast::StmtKind::Expr(expr) => {
                 self.space_if_not_bol();
-                self.print_expr_outer_attr_style(
-                    expr,
-                    false,
-                    FixupContext { stmt: true, ..FixupContext::default() },
-                );
+                self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
                 if classify::expr_requires_semi_to_be_stmt(expr) {
                     self.word(";");
                 }
             }
             ast::StmtKind::Semi(expr) => {
                 self.space_if_not_bol();
-                self.print_expr_outer_attr_style(
-                    expr,
-                    false,
-                    FixupContext { stmt: true, ..FixupContext::default() },
-                );
+                self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
                 self.word(";");
             }
             ast::StmtKind::Empty => {
@@ -1319,11 +1311,7 @@ impl<'a> State<'a> {
                 ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => {
                     self.maybe_print_comment(st.span.lo());
                     self.space_if_not_bol();
-                    self.print_expr_outer_attr_style(
-                        expr,
-                        false,
-                        FixupContext { stmt: true, ..FixupContext::default() },
-                    );
+                    self.print_expr_outer_attr_style(expr, false, FixupContext::new_stmt());
                     self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
                 }
                 _ => self.print_stmt(st),
@@ -1367,8 +1355,7 @@ impl<'a> State<'a> {
         self.word_space("=");
         self.print_expr_cond_paren(
             expr,
-            fixup.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
-                || parser::needs_par_as_let_scrutinee(expr.precedence().order()),
+            fixup.needs_par_as_let_scrutinee(expr),
             FixupContext::default(),
         );
     }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 6eff70410cb..4cbdc9f256d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,10 +1,10 @@
 use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::fixup::FixupContext;
 use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 use ast::{ForLoopKind, MatchKind};
 use itertools::{Itertools, Position};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
-use rustc_ast::util::classify;
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode};
@@ -14,78 +14,6 @@ use rustc_ast::{
 };
 use std::fmt::Write;
 
-#[derive(Copy, Clone, Debug)]
-pub(crate) struct FixupContext {
-    /// Print expression such that it can be parsed back as a statement
-    /// consisting of the original expression.
-    ///
-    /// The effect of this is for binary operators in statement position to set
-    /// `leftmost_subexpression_in_stmt` when printing their left-hand operand.
-    ///
-    /// ```ignore (illustrative)
-    /// (match x {}) - 1;  // match needs parens when LHS of binary operator
-    ///
-    /// match x {};  // not when its own statement
-    /// ```
-    pub stmt: bool,
-
-    /// This is the difference between:
-    ///
-    /// ```ignore (illustrative)
-    /// (match x {}) - 1;  // subexpression needs parens
-    ///
-    /// let _ = match x {} - 1;  // no parens
-    /// ```
-    ///
-    /// There are 3 distinguishable contexts in which `print_expr` might be
-    /// called with the expression `$match` as its argument, where `$match`
-    /// represents an expression of kind `ExprKind::Match`:
-    ///
-    ///   - stmt=false leftmost_subexpression_in_stmt=false
-    ///
-    ///     Example: `let _ = $match - 1;`
-    ///
-    ///     No parentheses required.
-    ///
-    ///   - stmt=false leftmost_subexpression_in_stmt=true
-    ///
-    ///     Example: `$match - 1;`
-    ///
-    ///     Must parenthesize `($match)`, otherwise parsing back the output as a
-    ///     statement would terminate the statement after the closing brace of
-    ///     the match, parsing `-1;` as a separate statement.
-    ///
-    ///   - stmt=true leftmost_subexpression_in_stmt=false
-    ///
-    ///     Example: `$match;`
-    ///
-    ///     No parentheses required.
-    pub leftmost_subexpression_in_stmt: bool,
-
-    /// This is the difference between:
-    ///
-    /// ```ignore (illustrative)
-    /// if let _ = (Struct {}) {}  // needs parens
-    ///
-    /// match () {
-    ///     () if let _ = Struct {} => {}  // no parens
-    /// }
-    /// ```
-    pub parenthesize_exterior_struct_lit: bool,
-}
-
-/// The default amount of fixing is minimal fixing. Fixups should be turned on
-/// in a targeted fashion where needed.
-impl Default for FixupContext {
-    fn default() -> Self {
-        FixupContext {
-            stmt: false,
-            leftmost_subexpression_in_stmt: false,
-            parenthesize_exterior_struct_lit: false,
-        }
-    }
-}
-
 impl<'a> State<'a> {
     fn print_else(&mut self, els: Option<&ast::Expr>) {
         if let Some(_else) = els {
@@ -136,9 +64,7 @@ impl<'a> State<'a> {
     /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
     /// `if cond { ... }`.
     fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
-        let fixup =
-            FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() };
-        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup)
+        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), FixupContext::new_cond())
     }
 
     /// Does `expr` need parentheses when printed in a condition position?
@@ -310,15 +236,7 @@ impl<'a> State<'a> {
         // because the latter is valid syntax but with the incorrect meaning.
         // It's a match-expression followed by tuple-expression, not a function
         // call.
-        self.print_expr_maybe_paren(
-            func,
-            prec,
-            FixupContext {
-                stmt: false,
-                leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
-                ..fixup
-            },
-        );
+        self.print_expr_maybe_paren(func, prec, fixup.leftmost_subexpression());
 
         self.print_call_post(args)
     }
@@ -387,33 +305,17 @@ impl<'a> State<'a> {
             _ => left_prec,
         };
 
-        self.print_expr_maybe_paren(
-            lhs,
-            left_prec,
-            FixupContext {
-                stmt: false,
-                leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt,
-                ..fixup
-            },
-        );
+        self.print_expr_maybe_paren(lhs, left_prec, fixup.leftmost_subexpression());
 
         self.space();
         self.word_space(op.node.as_str());
 
-        self.print_expr_maybe_paren(
-            rhs,
-            right_prec,
-            FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
-        );
+        self.print_expr_maybe_paren(rhs, right_prec, fixup.subsequent_subexpression());
     }
 
     fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
         self.word(op.as_str());
-        self.print_expr_maybe_paren(
-            expr,
-            parser::PREC_PREFIX,
-            FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
-        );
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup.subsequent_subexpression());
     }
 
     fn print_expr_addr_of(
@@ -431,11 +333,7 @@ impl<'a> State<'a> {
                 self.print_mutability(mutability, true);
             }
         }
-        self.print_expr_maybe_paren(
-            expr,
-            parser::PREC_PREFIX,
-            FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
-        );
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup.subsequent_subexpression());
     }
 
     pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
@@ -470,8 +368,7 @@ impl<'a> State<'a> {
         //
         // Same applies to a small set of other expression kinds which eagerly
         // terminate a statement which opens with them.
-        let needs_par =
-            fixup.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr);
+        let needs_par = fixup.would_cause_statement_boundary(expr);
         if needs_par {
             self.popen();
             fixup = FixupContext::default();
@@ -519,16 +416,7 @@ impl<'a> State<'a> {
             }
             ast::ExprKind::Cast(expr, ty) => {
                 let prec = AssocOp::As.precedence() as i8;
-                self.print_expr_maybe_paren(
-                    expr,
-                    prec,
-                    FixupContext {
-                        stmt: false,
-                        leftmost_subexpression_in_stmt: fixup.stmt
-                            || fixup.leftmost_subexpression_in_stmt,
-                        ..fixup
-                    },
-                );
+                self.print_expr_maybe_paren(expr, prec, fixup.leftmost_subexpression());
                 self.space();
                 self.word_space("as");
                 self.print_type(ty);
@@ -660,70 +548,34 @@ impl<'a> State<'a> {
                 self.print_block_with_attrs(blk, attrs);
             }
             ast::ExprKind::Await(expr, _) => {
-                // Same fixups as ExprKind::MethodCall.
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
                 self.word(".await");
             }
             ast::ExprKind::Assign(lhs, rhs, _) => {
-                // Same fixups as ExprKind::Binary.
                 let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(
-                    lhs,
-                    prec + 1,
-                    FixupContext {
-                        stmt: false,
-                        leftmost_subexpression_in_stmt: fixup.stmt
-                            || fixup.leftmost_subexpression_in_stmt,
-                        ..fixup
-                    },
-                );
+                self.print_expr_maybe_paren(lhs, prec + 1, fixup.leftmost_subexpression());
                 self.space();
                 self.word_space("=");
-                self.print_expr_maybe_paren(
-                    rhs,
-                    prec,
-                    FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
-                );
+                self.print_expr_maybe_paren(rhs, prec, fixup.subsequent_subexpression());
             }
             ast::ExprKind::AssignOp(op, lhs, rhs) => {
-                // Same fixups as ExprKind::Binary.
                 let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(
-                    lhs,
-                    prec + 1,
-                    FixupContext {
-                        stmt: false,
-                        leftmost_subexpression_in_stmt: fixup.stmt
-                            || fixup.leftmost_subexpression_in_stmt,
-                        ..fixup
-                    },
-                );
+                self.print_expr_maybe_paren(lhs, prec + 1, fixup.leftmost_subexpression());
                 self.space();
                 self.word(op.node.as_str());
                 self.word_space("=");
-                self.print_expr_maybe_paren(
-                    rhs,
-                    prec,
-                    FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
-                );
+                self.print_expr_maybe_paren(rhs, prec, fixup.subsequent_subexpression());
             }
             ast::ExprKind::Field(expr, ident) => {
-                // Same fixups as ExprKind::MethodCall.
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup);
                 self.word(".");
                 self.print_ident(*ident);
             }
             ast::ExprKind::Index(expr, index, _) => {
-                // Same fixups as ExprKind::Call.
                 self.print_expr_maybe_paren(
                     expr,
                     parser::PREC_POSTFIX,
-                    FixupContext {
-                        stmt: false,
-                        leftmost_subexpression_in_stmt: fixup.stmt
-                            || fixup.leftmost_subexpression_in_stmt,
-                        ..fixup
-                    },
+                    fixup.leftmost_subexpression(),
                 );
                 self.word("[");
                 self.print_expr(index, FixupContext::default());
@@ -736,31 +588,14 @@ impl<'a> State<'a> {
                 // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
                 let fake_prec = AssocOp::LOr.precedence() as i8;
                 if let Some(e) = start {
-                    self.print_expr_maybe_paren(
-                        e,
-                        fake_prec,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: fixup.stmt
-                                || fixup.leftmost_subexpression_in_stmt,
-                            ..fixup
-                        },
-                    );
+                    self.print_expr_maybe_paren(e, fake_prec, fixup.leftmost_subexpression());
                 }
                 match limits {
                     ast::RangeLimits::HalfOpen => self.word(".."),
                     ast::RangeLimits::Closed => self.word("..="),
                 }
                 if let Some(e) = end {
-                    self.print_expr_maybe_paren(
-                        e,
-                        fake_prec,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: false,
-                            ..fixup
-                        },
-                    );
+                    self.print_expr_maybe_paren(e, fake_prec, fixup.subsequent_subexpression());
                 }
             }
             ast::ExprKind::Underscore => self.word("_"),
@@ -777,11 +612,7 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(
                         expr,
                         parser::PREC_JUMP,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: false,
-                            ..fixup
-                        },
+                        fixup.subsequent_subexpression(),
                     );
                 }
             }
@@ -799,11 +630,7 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(
                         expr,
                         parser::PREC_JUMP,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: false,
-                            ..fixup
-                        },
+                        fixup.subsequent_subexpression(),
                     );
                 }
             }
@@ -816,11 +643,7 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(
                         expr,
                         parser::PREC_JUMP,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: false,
-                            ..fixup
-                        },
+                        fixup.subsequent_subexpression(),
                     );
                 }
             }
@@ -830,7 +653,7 @@ impl<'a> State<'a> {
                 self.print_expr_maybe_paren(
                     result,
                     parser::PREC_JUMP,
-                    FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup },
+                    fixup.subsequent_subexpression(),
                 );
             }
             ast::ExprKind::InlineAsm(a) => {
@@ -884,16 +707,11 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(
                         expr,
                         parser::PREC_JUMP,
-                        FixupContext {
-                            stmt: false,
-                            leftmost_subexpression_in_stmt: false,
-                            ..fixup
-                        },
+                        fixup.subsequent_subexpression(),
                     );
                 }
             }
             ast::ExprKind::Try(e) => {
-                // Same fixups as ExprKind::MethodCall.
                 self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup);
                 self.word("?")
             }
@@ -961,7 +779,7 @@ impl<'a> State<'a> {
                 }
                 _ => {
                     self.end(); // Close the ibox for the pattern.
-                    self.print_expr(body, FixupContext { stmt: true, ..FixupContext::default() });
+                    self.print_expr(body, FixupContext::new_stmt());
                     self.word(",");
                 }
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
new file mode 100644
index 00000000000..d21cb82f83b
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
@@ -0,0 +1,149 @@
+use rustc_ast::util::{classify, parser};
+use rustc_ast::Expr;
+
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct FixupContext {
+    /// Print expression such that it can be parsed back as a statement
+    /// consisting of the original expression.
+    ///
+    /// The effect of this is for binary operators in statement position to set
+    /// `leftmost_subexpression_in_stmt` when printing their left-hand operand.
+    ///
+    /// ```ignore (illustrative)
+    /// (match x {}) - 1;  // match needs parens when LHS of binary operator
+    ///
+    /// match x {};  // not when its own statement
+    /// ```
+    stmt: bool,
+
+    /// This is the difference between:
+    ///
+    /// ```ignore (illustrative)
+    /// (match x {}) - 1;  // subexpression needs parens
+    ///
+    /// let _ = match x {} - 1;  // no parens
+    /// ```
+    ///
+    /// There are 3 distinguishable contexts in which `print_expr` might be
+    /// called with the expression `$match` as its argument, where `$match`
+    /// represents an expression of kind `ExprKind::Match`:
+    ///
+    ///   - stmt=false leftmost_subexpression_in_stmt=false
+    ///
+    ///     Example: `let _ = $match - 1;`
+    ///
+    ///     No parentheses required.
+    ///
+    ///   - stmt=false leftmost_subexpression_in_stmt=true
+    ///
+    ///     Example: `$match - 1;`
+    ///
+    ///     Must parenthesize `($match)`, otherwise parsing back the output as a
+    ///     statement would terminate the statement after the closing brace of
+    ///     the match, parsing `-1;` as a separate statement.
+    ///
+    ///   - stmt=true leftmost_subexpression_in_stmt=false
+    ///
+    ///     Example: `$match;`
+    ///
+    ///     No parentheses required.
+    leftmost_subexpression_in_stmt: bool,
+
+    /// This is the difference between:
+    ///
+    /// ```ignore (illustrative)
+    /// if let _ = (Struct {}) {}  // needs parens
+    ///
+    /// match () {
+    ///     () if let _ = Struct {} => {}  // no parens
+    /// }
+    /// ```
+    parenthesize_exterior_struct_lit: bool,
+}
+
+/// The default amount of fixing is minimal fixing. Fixups should be turned on
+/// in a targeted fashion where needed.
+impl Default for FixupContext {
+    fn default() -> Self {
+        FixupContext {
+            stmt: false,
+            leftmost_subexpression_in_stmt: false,
+            parenthesize_exterior_struct_lit: false,
+        }
+    }
+}
+
+impl FixupContext {
+    /// Create the initial fixup for printing an expression in statement
+    /// position.
+    ///
+    /// This is currently also used for printing an expression as a match-arm,
+    /// but this is incorrect and leads to over-parenthesizing.
+    pub fn new_stmt() -> Self {
+        FixupContext { stmt: true, ..FixupContext::default() }
+    }
+
+    /// Create the initial fixup for printing an expression as the "condition"
+    /// of an `if` or `while`. There are a few other positions which are
+    /// grammatically equivalent and also use this, such as the iterator
+    /// expression in `for` and the scrutinee in `match`.
+    pub fn new_cond() -> Self {
+        FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() }
+    }
+
+    /// Transform this fixup into the one that should apply when printing the
+    /// leftmost subexpression of the current expression.
+    ///
+    /// The leftmost subexpression is any subexpression that has the same first
+    /// token as the current expression, but has a different last token.
+    ///
+    /// For example in `$a + $b` and `$a.method()`, the subexpression `$a` is a
+    /// leftmost subexpression.
+    ///
+    /// Not every expression has a leftmost subexpression. For example neither
+    /// `-$a` nor `[$a]` have one.
+    pub fn leftmost_subexpression(self) -> Self {
+        FixupContext {
+            stmt: false,
+            leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
+            ..self
+        }
+    }
+
+    /// Transform this fixup into the one that should apply when printing any
+    /// subexpression that is neither a leftmost subexpression nor surrounded in
+    /// delimiters.
+    ///
+    /// This is for any subexpression that has a different first token than the
+    /// current expression, and is not surrounded by a paren/bracket/brace. For
+    /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
+    /// `$a.f($b)`.
+    pub fn subsequent_subexpression(self) -> Self {
+        FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..self }
+    }
+
+    /// Determine whether parentheses are needed around the given expression to
+    /// head off an unintended statement boundary.
+    ///
+    /// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has
+    /// examples.
+    pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool {
+        self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr)
+    }
+
+    /// Determine whether parentheses are needed around the given `let`
+    /// scrutinee.
+    ///
+    /// In `if let _ = $e {}`, some examples of `$e` that would need parentheses
+    /// are:
+    ///
+    ///   - `Struct {}.f()`, because otherwise the `{` would be misinterpreted
+    ///     as the opening of the if's then-block.
+    ///
+    ///   - `true && false`, because otherwise this would be misinterpreted as a
+    ///     "let chain".
+    pub fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
+        self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
+            || parser::needs_par_as_let_scrutinee(expr.precedence().order())
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 13f27c1c95c..10886aace53 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -1,5 +1,5 @@
 use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::expr::FixupContext;
+use crate::pprust::state::fixup::FixupContext;
 use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 
 use ast::StaticItem;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 8b0b9123ac7..efa4be7e15a 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -1,4 +1,13 @@
-#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
+#![feature(
+    no_core,
+    lang_items,
+    never_type,
+    linkage,
+    extern_types,
+    thread_local,
+    repr_simd,
+    raw_ref_op
+)]
 #![no_core]
 #![allow(dead_code, non_camel_case_types, internal_features)]
 
@@ -112,9 +121,7 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
-#[allow(static_mut_refs)]
-static NUM_REF: &'static u8 = unsafe { &NUM };
+static NUM_REF: &'static u8 = unsafe { &*&raw const NUM };
 
 unsafe fn zeroed<T>() -> T {
     let mut uninit = MaybeUninit { uninit: () };
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index add77880716..5a7ddc4cd7f 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -2,7 +2,7 @@
 
 #![feature(
     no_core, unboxed_closures, start, lang_items, never_type, linkage,
-    extern_types, thread_local
+    extern_types, thread_local, raw_ref_op
 )]
 #![no_core]
 #![allow(dead_code, internal_features, non_camel_case_types)]
@@ -99,9 +99,7 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
-#[allow(static_mut_refs)]
-static NUM_REF: &'static u8 = unsafe { &NUM };
+static NUM_REF: &'static u8 = unsafe { &* &raw const NUM };
 
 macro_rules! assert {
     ($e:expr) => {
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 5d345e788e9..a17e0da47a5 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -730,7 +730,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
     } }
 
     #[rustc_lint_diagnostics]
-    fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
+    pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
         self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
         self
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 29c9f08a166..fdae9d84b5f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -61,7 +61,7 @@ use crate::traits::{
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString,
-    ErrorGuaranteed, IntoDiagArg,
+    ErrorGuaranteed, IntoDiagArg, StringPart,
 };
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -1917,6 +1917,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     );
                     if !is_simple_error || terr.must_include_note() {
                         diag.note_expected_found(&expected_label, expected, &found_label, found);
+
+                        if let Some(ty::Closure(_, args)) =
+                            exp_found.map(|expected_type_found| expected_type_found.found.kind())
+                        {
+                            diag.highlighted_note(vec![
+                                StringPart::normal("closure has signature: `"),
+                                StringPart::highlighted(
+                                    self.tcx
+                                        .signature_unclosure(
+                                            args.as_closure().sig(),
+                                            rustc_hir::Unsafety::Normal,
+                                        )
+                                        .to_string(),
+                                ),
+                                StringPart::normal("`"),
+                            ]);
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 2a9de499622..565bdc3af03 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1522,6 +1522,7 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
   delete Bundle;
 }
 
+// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
 extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                                           LLVMValueRef *Args, unsigned NumArgs,
                                           OperandBundleDef **OpBundlesIndirect,
@@ -1601,6 +1602,7 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B,
       unwrap(Dst), unwrap(Val), unwrap(Size), MaybeAlign(DstAlign), IsVolatile));
 }
 
+// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
 extern "C" LLVMValueRef
 LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                     LLVMValueRef *Args, unsigned NumArgs,
@@ -1623,6 +1625,7 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                                       Name));
 }
 
+// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
 extern "C" LLVMValueRef
 LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                     LLVMBasicBlockRef DefaultDest,