about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-22 17:46:57 +0000
committerbors <bors@rust-lang.org>2022-08-22 17:46:57 +0000
commita7851767419e56280110fe2859bbc15d5cbdd468 (patch)
tree41cc6602b9a79136876c87b4f6945d50bc8d48a2
parente0dc8d78019ca924203fe153ff0af7f64f68cb5d (diff)
parent4ed8fa47592ade04e388bc527c26d09c651b6455 (diff)
downloadrust-a7851767419e56280110fe2859bbc15d5cbdd468.tar.gz
rust-a7851767419e56280110fe2859bbc15d5cbdd468.zip
Auto merge of #100881 - Dylan-DPC:rollup-q9rr658, r=Dylan-DPC
Rollup of 8 pull requests

Successful merges:

 - #98200 (Expand potential inner `Or` pattern for THIR)
 - #99770 (Make some const prop mir-opt tests `unit-test`s)
 - #99957 (Rework Ipv6Addr::is_global to check for global reachability rather than global scope - rebase)
 - #100331 (Guarantee `try_reserve` preserves the contents on error)
 - #100336 (Fix two const_trait_impl issues)
 - #100713 (Convert diagnostics in parser/expr to SessionDiagnostic)
 - #100820 (Use pointer `is_aligned*` methods)
 - #100872 (Add guarantee that Vec::default() does not alloc)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl109
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs23
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs343
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs426
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs12
-rw-r--r--library/alloc/src/collections/binary_heap.rs3
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs3
-rw-r--r--library/alloc/src/string.rs3
-rw-r--r--library/alloc/src/vec/into_iter.rs2
-rw-r--r--library/alloc/src/vec/mod.rs5
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/alloc/tests/thin_box.rs8
-rw-r--r--library/core/src/intrinsics.rs2
-rw-r--r--library/std/src/ffi/os_str.rs3
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/net/ip.rs204
-rw-r--r--library/std/src/net/ip/tests.rs98
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/alloc.rs4
-rw-r--r--library/std/src/sys_common/wtf8.rs3
-rw-r--r--src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/aggregate.rs1
-rw-r--r--src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff7
-rw-r--r--src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff7
-rw-r--r--src/test/mir-opt/const_prop/array_index.rs1
-rw-r--r--src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff10
-rw-r--r--src/test/mir-opt/const_prop/bad_op_div_by_zero.rs1
-rw-r--r--src/test/mir-opt/const_prop/boolean_identities.rs1
-rw-r--r--src/test/mir-opt/const_prop/boxes.main.ConstProp.diff7
-rw-r--r--src/test/mir-opt/const_prop/boxes.rs1
-rw-r--r--src/test/mir-opt/const_prop/cast.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/cast.rs1
-rw-r--r--src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/checked_add.rs1
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff6
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs1
-rw-r--r--src/test/mir-opt/const_prop/control-flow-simplification.rs7
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/discriminant.rs1
-rw-r--r--src/test/mir-opt/const_prop/indirect.main.ConstProp.diff4
-rw-r--r--src/test/mir-opt/const_prop/indirect.rs1
-rw-r--r--src/test/mir-opt/const_prop/issue-66971.rs1
-rw-r--r--src/test/mir-opt/const_prop/issue-67019.rs1
-rw-r--r--src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mult_by_zero.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_no_prop.rs1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs1
-rw-r--r--src/test/mir-opt/const_prop/optimizes_into_variable.rs1
-rw-r--r--src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff4
-rw-r--r--src/test/mir-opt/const_prop/read_immutable_static.rs1
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.rs1
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.or3.stderr11
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.or4.stderr11
-rw-r--r--src/test/ui/or-patterns/inner-or-pat.rs73
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs29
65 files changed, 1050 insertions, 425 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 2d378013dd0..3b37a393846 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -41,3 +41,112 @@ parser_switch_mut_let_order =
 parser_missing_let_before_mut = missing keyword
 parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
 parser_use_let_not_var = write `let` instead of `var` to introduce a new variable
+
+parser_invalid_comparison_operator = invalid comparison operator `{$invalid}`
+    .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
+    .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+
+parser_invalid_logical_operator = `{$incorrect}` is not a logical operator
+    .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+    .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
+    .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+
+parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
+    .suggestion = use `!` to perform bitwise not
+
+parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier
+    .suggestion = use `!` to perform logical negation
+
+parser_malformed_loop_label = malformed loop label
+    .suggestion = use the correct loop label format
+
+parser_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
+    .suggestion = remove the lifetime annotation
+    .label = annotated with lifetime here
+
+parser_field_expression_with_generic = field expressions cannot have generic arguments
+
+parser_macro_invocation_with_qualified_path = macros cannot use qualified paths
+
+parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+
+parser_require_colon_after_labeled_expression = labeled expression must be followed by `:`
+    .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
+    .label = the label
+    .suggestion = add `:` after the label
+
+parser_do_catch_syntax_removed = found removed `do catch` syntax
+    .note = following RFC #2388, the new non-placeholder syntax is `try`
+    .suggestion = replace with the new syntax
+
+parser_float_literal_requires_integer_part = float literals must have an integer part
+    .suggestion = must have an integer part
+
+parser_invalid_int_literal_width = invalid width `{$width}` for integer literal
+    .help = valid widths are 8, 16, 32, 64 and 128
+
+parser_invalid_num_literal_base_prefix = invalid base prefix for number literal
+    .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+    .suggestion = try making the prefix lowercase
+
+parser_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+    .label = invalid suffix `{$suffix}`
+    .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parser_invalid_float_literal_width = invalid width `{$width}` for float literal
+    .help = valid widths are 32 and 64
+
+parser_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+    .label = invalid suffix `{$suffix}`
+    .help = valid suffixes are `f32` and `f64`
+
+parser_int_literal_too_large = integer literal is too large
+
+parser_missing_semicolon_before_array = expected `;`, found `[`
+    .suggestion = consider adding `;` here
+
+parser_invalid_block_macro_segment = cannot use a `block` macro fragment here
+    .label = the `block` fragment is within this context
+
+parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition
+    .add_then_block = add a block here
+    .condition_possibly_unfinished = this binary operation is possibly unfinished
+
+parser_if_expression_missing_condition = missing condition for `if` expression
+    .condition_label = expected condition here
+    .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
+
+parser_expected_expression_found_let = expected expression, found `let` statement
+
+parser_expected_else_block = expected `{"{"}`, found {$first_tok}
+    .label = expected an `if` or a block after this `else`
+    .suggestion = add an `if` if this is the condition of a chained `else if` statement
+
+parser_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
+    .branch_label = the attributes are attached to this branch
+    .ctx_label = the branch belongs to this `{$ctx}`
+    .suggestion = remove the attributes
+
+parser_missing_in_in_for_loop = missing `in` in `for` loop
+    .use_in_not_of = try using `in` here instead
+    .add_in = try adding `in` here
+
+parser_missing_comma_after_match_arm = expected `,` following `match` arm
+    .suggestion = missing a comma here to end this `match` arm
+
+parser_catch_after_try = keyword `catch` cannot follow a `try` block
+    .help = try using `match` on the result of the `try` block instead
+
+parser_comma_after_base_struct = cannot use a comma after the base struct
+    .note = the base struct must always be the last field
+    .suggestion = remove this comma
+
+parser_eq_field_init = expected `:`, found `=`
+    .suggestion = replace equals symbol with a colon
+
+parser_dotdotdot = unexpected token: `...`
+    .suggest_exclusive_range = use `..` for an exclusive range
+    .suggest_inclusive_range = or `..=` for an inclusive range
+
+parser_left_arrow_operator = unexpected token: `<-`
+    .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 0a660ef30c8..443626d14b9 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
 #[derive(Clone)]
-struct PatStack<'p, 'tcx> {
-    pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
+pub(crate) struct PatStack<'p, 'tcx> {
+    pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
@@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         })
     }
 
+    // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix.
+    fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) {
+        if !self.is_empty() && self.head().is_or_pat() {
+            for pat in self.head().iter_fields() {
+                let mut new_patstack = PatStack::from_pattern(pat);
+                new_patstack.pats.extend_from_slice(&self.pats[1..]);
+                if !new_patstack.is_empty() && new_patstack.head().is_or_pat() {
+                    new_patstack.expand_and_extend(matrix);
+                } else if !new_patstack.is_empty() {
+                    matrix.push(new_patstack);
+                }
+            }
+        }
+    }
+
     /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
     ///
     /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
@@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
 /// A 2D matrix.
 #[derive(Clone)]
 pub(super) struct Matrix<'p, 'tcx> {
-    patterns: Vec<PatStack<'p, 'tcx>>,
+    pub patterns: Vec<PatStack<'p, 'tcx>>,
 }
 
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
@@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
-            self.patterns.extend(row.expand_or_pat());
+            row.expand_and_extend(self);
         } else {
             self.patterns.push(row);
         }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index d7facb29714..2c9f9a2c2c2 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -363,6 +363,349 @@ pub enum InvalidVariableDeclarationSub {
     UseLetNotVar(#[primary_span] Span),
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_comparison_operator)]
+pub(crate) struct InvalidComparisonOperator {
+    #[primary_span]
+    pub span: Span,
+    pub invalid: String,
+    #[subdiagnostic]
+    pub sub: InvalidComparisonOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidComparisonOperatorSub {
+    #[suggestion_short(
+        parser::use_instead,
+        applicability = "machine-applicable",
+        code = "{correct}"
+    )]
+    Correctable {
+        #[primary_span]
+        span: Span,
+        invalid: String,
+        correct: String,
+    },
+    #[label(parser::spaceship_operator_invalid)]
+    Spaceship(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_logical_operator)]
+#[note]
+pub(crate) struct InvalidLogicalOperator {
+    #[primary_span]
+    pub span: Span,
+    pub incorrect: String,
+    #[subdiagnostic]
+    pub sub: InvalidLogicalOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidLogicalOperatorSub {
+    #[suggestion_short(
+        parser::use_amp_amp_for_conjunction,
+        applicability = "machine-applicable",
+        code = "&&"
+    )]
+    Conjunction(#[primary_span] Span),
+    #[suggestion_short(
+        parser::use_pipe_pipe_for_disjunction,
+        applicability = "machine-applicable",
+        code = "||"
+    )]
+    Disjunction(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::tilde_is_not_unary_operator)]
+pub(crate) struct TildeAsUnaryOperator(
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_not)]
+pub(crate) struct NotAsNegationOperator {
+    #[primary_span]
+    pub negated: Span,
+    pub negated_desc: String,
+    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    pub not: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::malformed_loop_label)]
+pub(crate) struct MalformedLoopLabel {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
+    pub span: Span,
+    pub correct_label: Ident,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::lifetime_in_borrow_expression)]
+pub(crate) struct LifetimeInBorrowExpression {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[label]
+    pub lifetime_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::field_expression_with_generic)]
+pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::macro_invocation_with_qualified_path)]
+pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_label)]
+pub(crate) struct UnexpectedTokenAfterLabel(
+    #[primary_span]
+    #[label(parser::unexpected_token_after_label)]
+    pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::require_colon_after_labeled_expression)]
+#[note]
+pub(crate) struct RequireColonAfterLabeledExpression {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub label: Span,
+    #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+    pub label_end: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::do_catch_syntax_removed)]
+#[note]
+pub(crate) struct DoCatchSyntaxRemoved {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "try")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::float_literal_requires_integer_part)]
+pub(crate) struct FloatLiteralRequiresIntegerPart {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
+    pub span: Span,
+    pub correct: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_int_literal_width)]
+#[help]
+pub(crate) struct InvalidIntLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_base_prefix)]
+#[note]
+pub(crate) struct InvalidNumLiteralBasePrefix {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
+    pub span: Span,
+    pub fixed: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_suffix)]
+#[help]
+pub(crate) struct InvalidNumLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_width)]
+#[help]
+pub(crate) struct InvalidFloatLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_suffix)]
+#[help]
+pub(crate) struct InvalidFloatLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::int_literal_too_large)]
+pub(crate) struct IntLiteralTooLarge {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_semicolon_before_array)]
+pub(crate) struct MissingSemicolonBeforeArray {
+    #[primary_span]
+    pub open_delim: Span,
+    #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+    pub semicolon: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_block_macro_segment)]
+pub(crate) struct InvalidBlockMacroSegment {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub context: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_then_block)]
+pub(crate) struct IfExpressionMissingThenBlock {
+    #[primary_span]
+    pub if_span: Span,
+    #[subdiagnostic]
+    pub sub: IfExpressionMissingThenBlockSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum IfExpressionMissingThenBlockSub {
+    #[help(parser::condition_possibly_unfinished)]
+    UnfinishedCondition(#[primary_span] Span),
+    #[help(parser::add_then_block)]
+    AddThenBlock(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_condition)]
+pub(crate) struct IfExpressionMissingCondition {
+    #[primary_span]
+    #[label(parser::condition_label)]
+    pub if_span: Span,
+    #[label(parser::block_label)]
+    pub block_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_expression_found_let)]
+pub(crate) struct ExpectedExpressionFoundLet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_else_block)]
+pub(crate) struct ExpectedElseBlock {
+    #[primary_span]
+    pub first_tok_span: Span,
+    pub first_tok: String,
+    #[label]
+    pub else_span: Span,
+    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+    pub condition_start: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+pub(crate) struct OuterAttributeNotAllowedOnIfElse {
+    #[primary_span]
+    pub last: Span,
+
+    #[label(parser::branch_label)]
+    pub branch_span: Span,
+
+    #[label(parser::ctx_label)]
+    pub ctx_span: Span,
+    pub ctx: String,
+
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub attributes: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_in_in_for_loop)]
+pub(crate) struct MissingInInForLoop {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MissingInInForLoopSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum MissingInInForLoopSub {
+    // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
+    #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+    InNotOf(#[primary_span] Span),
+    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+    AddIn(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_comma_after_match_arm)]
+pub(crate) struct MissingCommaAfterMatchArm {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = ",")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::catch_after_try)]
+#[help]
+pub(crate) struct CatchAfterTry {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::comma_after_base_struct)]
+#[note]
+pub(crate) struct CommaAfterBaseStruct {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion_short(applicability = "machine-applicable", code = "")]
+    pub comma: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::eq_field_init)]
+pub(crate) struct EqFieldInit {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = ":")]
+    pub eq: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::dotdotdot)]
+pub(crate) struct DotDotDot {
+    #[primary_span]
+    #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+    #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::left_arrow_operator)]
+pub(crate) struct LeftArrowOperator {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9fb9199231f..17117cbc8fb 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,4 +1,14 @@
-use super::diagnostics::SnapshotParser;
+use super::diagnostics::{
+    CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
+    ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
+    FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
+    IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
+    InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
+    LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
+    MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
+    NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression,
+    SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
+};
 use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
@@ -6,6 +16,11 @@ use super::{
     SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
+use crate::parser::diagnostics::{
+    IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
+    InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
+    MissingCommaAfterMatchArm,
+};
 
 use core::mem;
 use rustc_ast::ptr::P;
@@ -20,9 +35,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, Diagnostic, PResult};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::SessionDiagnostic;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
@@ -216,15 +232,18 @@ impl<'a> Parser<'a> {
                     AssocOp::Equal => "==",
                     AssocOp::NotEqual => "!=",
                     _ => unreachable!(),
-                };
-                self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`"))
-                    .span_suggestion_short(
-                        sp,
-                        &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
-                        sugg,
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                }
+                .into();
+                let invalid = format!("{}=", &sugg);
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: invalid.clone(),
+                    sub: InvalidComparisonOperatorSub::Correctable {
+                        span: sp,
+                        invalid,
+                        correct: sugg,
+                    },
+                });
                 self.bump();
             }
 
@@ -234,14 +253,15 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.struct_span_err(sp, "invalid comparison operator `<>`")
-                    .span_suggestion_short(
-                        sp,
-                        "`<>` is not a valid comparison operator, use `!=`",
-                        "!=",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: "<>".into(),
+                    sub: InvalidComparisonOperatorSub::Correctable {
+                        span: sp,
+                        invalid: "<>".into(),
+                        correct: "!=".into(),
+                    },
+                });
                 self.bump();
             }
 
@@ -251,12 +271,11 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.struct_span_err(sp, "invalid comparison operator `<=>`")
-                    .span_label(
-                        sp,
-                        "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
-                    )
-                    .emit();
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: "<=>".into(),
+                    sub: InvalidComparisonOperatorSub::Spaceship(sp),
+                });
                 self.bump();
             }
 
@@ -430,11 +449,19 @@ impl<'a> Parser<'a> {
             }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) => {
-                self.error_bad_logical_op("and", "&&", "conjunction");
+                self.sess.emit_err(InvalidLogicalOperator {
+                    span: self.token.span,
+                    incorrect: "and".into(),
+                    sub: InvalidLogicalOperatorSub::Conjunction(self.token.span),
+                });
                 (AssocOp::LAnd, span)
             }
             (None, Some((Ident { name: sym::or, span }, false))) => {
-                self.error_bad_logical_op("or", "||", "disjunction");
+                self.sess.emit_err(InvalidLogicalOperator {
+                    span: self.token.span,
+                    incorrect: "or".into(),
+                    sub: InvalidLogicalOperatorSub::Disjunction(self.token.span),
+                });
                 (AssocOp::LOr, span)
             }
             _ => return None,
@@ -442,19 +469,6 @@ impl<'a> Parser<'a> {
         Some(source_map::respan(span, op))
     }
 
-    /// Error on `and` and `or` suggesting `&&` and `||` respectively.
-    fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) {
-        self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator"))
-            .span_suggestion_short(
-                self.token.span,
-                &format!("use `{good}` to perform logical {english}"),
-                good,
-                Applicability::MachineApplicable,
-            )
-            .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators")
-            .emit();
-    }
-
     /// Checks if this expression is a successfully parsed statement.
     fn expr_is_complete(&self, e: &Expr) -> bool {
         self.restrictions.contains(Restrictions::STMT_EXPR)
@@ -619,14 +633,7 @@ impl<'a> Parser<'a> {
 
     // Recover on `!` suggesting for bitwise negation instead.
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        self.struct_span_err(lo, "`~` cannot be used as a unary operator")
-            .span_suggestion_short(
-                lo,
-                "use `!` to perform bitwise not",
-                "!",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(TildeAsUnaryOperator(lo));
 
         self.parse_unary_expr(lo, UnOp::Not)
     }
@@ -652,20 +659,14 @@ impl<'a> Parser<'a> {
     /// Recover on `not expr` in favor of `!expr`.
     fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         // Emit the error...
-        let not_token = self.look_ahead(1, |t| t.clone());
-        self.struct_span_err(
-            not_token.span,
-            &format!("unexpected {} after identifier", super::token_descr(&not_token)),
-        )
-        .span_suggestion_short(
+        let negated_token = self.look_ahead(1, |t| t.clone());
+        self.sess.emit_err(NotAsNegationOperator {
+            negated: negated_token.span,
+            negated_desc: super::token_descr(&negated_token),
             // Span the `not` plus trailing whitespace to avoid
             // trailing whitespace after the `!` in our suggestion
-            self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)),
-            "use `!` to perform logical negation",
-            "!",
-            Applicability::MachineApplicable,
-        )
-        .emit();
+            not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
+        });
 
         // ...and recover!
         self.parse_unary_expr(lo, UnOp::Not)
@@ -725,14 +726,10 @@ impl<'a> Parser<'a> {
                         match self.parse_labeled_expr(label, false) {
                             Ok(expr) => {
                                 type_err.cancel();
-                                self.struct_span_err(label.ident.span, "malformed loop label")
-                                    .span_suggestion(
-                                        label.ident.span,
-                                        "use the correct loop label format",
-                                        label.ident,
-                                        Applicability::MachineApplicable,
-                                    )
-                                    .emit();
+                                self.sess.emit_err(MalformedLoopLabel {
+                                    span: label.ident.span,
+                                    correct_label: label.ident,
+                                });
                                 return Ok(expr);
                             }
                             Err(err) => {
@@ -910,15 +907,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
-        self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes")
-            .span_label(lt_span, "annotated with lifetime here")
-            .span_suggestion(
-                lt_span,
-                "remove the lifetime annotation",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
     /// Parse `mut?` or `raw [ const | mut ]`.
@@ -1272,11 +1261,7 @@ impl<'a> Parser<'a> {
         } else {
             // Field access `expr.f`
             if let Some(args) = segment.args {
-                self.struct_span_err(
-                    args.span(),
-                    "field expressions cannot have generic arguments",
-                )
-                .emit();
+                self.sess.emit_err(FieldExpressionWithGeneric(args.span()));
             }
 
             let span = lo.to(self.prev_token.span);
@@ -1489,7 +1474,7 @@ impl<'a> Parser<'a> {
         let (span, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
             if qself.is_some() {
-                self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+                self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span));
             }
             let lo = path.span;
             let mac = P(MacCall {
@@ -1535,11 +1520,11 @@ impl<'a> Parser<'a> {
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
-            let msg = "expected `while`, `for`, `loop` or `{` after a label";
-            self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
+            self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
+            // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
 
             let mut err = self.struct_span_err(self.token.span, msg);
@@ -1604,25 +1589,16 @@ impl<'a> Parser<'a> {
         }?;
 
         if !ate_colon && consume_colon {
-            self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
+            self.sess.emit_err(RequireColonAfterLabeledExpression {
+                span: expr.span,
+                label: lo,
+                label_end: lo.shrink_to_hi(),
+            });
         }
 
         Ok(expr)
     }
 
-    fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) {
-        self.struct_span_err(span, "labeled expression must be followed by `:`")
-            .span_label(lo, "the label")
-            .span_suggestion_short(
-                lo.shrink_to_hi(),
-                "add `:` after the label",
-                ": ",
-                Applicability::MachineApplicable,
-            )
-            .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
-            .emit();
-    }
-
     /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
     fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
@@ -1630,16 +1606,8 @@ impl<'a> Parser<'a> {
         self.bump(); // `do`
         self.bump(); // `catch`
 
-        let span_dc = lo.to(self.prev_token.span);
-        self.struct_span_err(span_dc, "found removed `do catch` syntax")
-            .span_suggestion(
-                span_dc,
-                "replace with the new syntax",
-                "try",
-                Applicability::MachineApplicable,
-            )
-            .note("following RFC #2388, the new non-placeholder syntax is `try`")
-            .emit();
+        let span = lo.to(self.prev_token.span);
+        self.sess.emit_err(DoCatchSyntaxRemoved { span });
 
         self.parse_try_block(lo)
     }
@@ -1834,14 +1802,10 @@ impl<'a> Parser<'a> {
     }
 
     fn error_float_lits_must_have_int_part(&self, token: &Token) {
-        self.struct_span_err(token.span, "float literals must have an integer part")
-            .span_suggestion(
-                token.span,
-                "must have an integer part",
-                pprust::token_to_string(token),
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+            span: token.span,
+            correct: pprust::token_to_string(token).into_owned(),
+        });
     }
 
     fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
@@ -1883,28 +1847,11 @@ impl<'a> Parser<'a> {
                 let suf = suf.as_str();
                 if looks_like_width_suffix(&['i', 'u'], &suf) {
                     // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
-                    self.struct_span_err(span, &msg)
-                        .help("valid widths are 8, 16, 32, 64 and 128")
-                        .emit();
+                    self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
                 } else if let Some(fixed) = fix_base_capitalisation(suf) {
-                    let msg = "invalid base prefix for number literal";
-
-                    self.struct_span_err(span, msg)
-                        .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
-                        .span_suggestion(
-                            span,
-                            "try making the prefix lowercase",
-                            fixed,
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
                 } else {
-                    let msg = format!("invalid suffix `{suf}` for number literal");
-                    self.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{suf}`"))
-                        .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")
-                        .emit();
+                    self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
                 }
             }
             LitError::InvalidFloatSuffix => {
@@ -1912,14 +1859,10 @@ impl<'a> Parser<'a> {
                 let suf = suf.as_str();
                 if looks_like_width_suffix(&['f'], suf) {
                     // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
-                    self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit();
+                    self.sess
+                        .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
                 } else {
-                    let msg = format!("invalid suffix `{suf}` for float literal");
-                    self.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{suf}`"))
-                        .help("valid suffixes are `f32` and `f64`")
-                        .emit();
+                    self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
                 }
             }
             LitError::NonDecimalFloat(base) => {
@@ -1934,7 +1877,7 @@ impl<'a> Parser<'a> {
                     .emit();
             }
             LitError::IntTooLarge => {
-                self.struct_span_err(span, "integer literal is too large").emit();
+                self.sess.emit_err(IntLiteralTooLarge { span });
             }
         }
     }
@@ -2046,14 +1989,10 @@ impl<'a> Parser<'a> {
                         .span_to_snippet(snapshot.token.span)
                         .map_or(false, |snippet| snippet == "]") =>
                 {
-                    let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
-                    err.span_suggestion_verbose(
-                        prev_span.shrink_to_hi(),
-                        "consider adding `;` here",
-                        ';',
-                        Applicability::MaybeIncorrect,
-                    );
-                    return Err(err);
+                    return Err(MissingSemicolonBeforeArray {
+                        open_delim: open_delim_span,
+                        semicolon: prev_span.shrink_to_hi(),
+                    }.into_diagnostic(self.sess));
                 }
                 Ok(_) => (),
                 Err(err) => err.cancel(),
@@ -2080,9 +2019,10 @@ impl<'a> Parser<'a> {
         }
 
         if self.token.is_whole_block() {
-            self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here")
-                .span_label(lo.to(self.token.span), "the `block` fragment is within this context")
-                .emit();
+            self.sess.emit_err(InvalidBlockMacroSegment {
+                span: self.token.span,
+                context: lo.to(self.token.span),
+            });
         }
 
         let (attrs, blk) = self.parse_block_common(lo, blk_mode)?;
@@ -2252,11 +2192,19 @@ impl<'a> Parser<'a> {
             let block = match &mut cond.kind {
                 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
                     if let ExprKind::Block(_, None) = right.kind => {
-                        this.error_missing_if_then_block(lo, cond_span.shrink_to_lo().to(*binop_span), true).emit();
+                        self.sess.emit_err(IfExpressionMissingThenBlock {
+                            if_span: lo,
+                            sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
+                                cond_span.shrink_to_lo().to(*binop_span)
+                            ),
+                        });
                         std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
                     },
                 ExprKind::Block(_, None) => {
-                    this.error_missing_if_cond(lo, cond_span).emit();
+                    self.sess.emit_err(IfExpressionMissingCondition {
+                        if_span: self.sess.source_map().next_point(lo),
+                        block_span: self.sess.source_map().start_point(cond_span),
+                    });
                     std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
                 }
                 _ => {
@@ -2274,7 +2222,10 @@ impl<'a> Parser<'a> {
             if let Some(block) = recover_block_from_condition(self) {
                 block
             } else {
-                self.error_missing_if_then_block(lo, cond_span, false).emit();
+                self.sess.emit_err(IfExpressionMissingThenBlock {
+                    if_span: lo,
+                    sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
+                });
                 self.mk_block_err(cond_span.shrink_to_hi())
             }
         } else {
@@ -2302,39 +2253,6 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
     }
 
-    fn error_missing_if_then_block(
-        &self,
-        if_span: Span,
-        cond_span: Span,
-        is_unfinished: bool,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = self.struct_span_err(
-            if_span,
-            "this `if` expression is missing a block after the condition",
-        );
-        if is_unfinished {
-            err.span_help(cond_span, "this binary operation is possibly unfinished");
-        } else {
-            err.span_help(cond_span.shrink_to_hi(), "add a block here");
-        }
-        err
-    }
-
-    fn error_missing_if_cond(
-        &self,
-        lo: Span,
-        span: Span,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let next_span = self.sess.source_map().next_point(lo);
-        let mut err = self.struct_span_err(next_span, "missing condition for `if` expression");
-        err.span_label(next_span, "expected condition here");
-        err.span_label(
-            self.sess.source_map().start_point(span),
-            "if this block is the condition of the `if` expression, then it must be followed by another block"
-        );
-        err
-    }
-
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
         self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
@@ -2350,8 +2268,7 @@ impl<'a> Parser<'a> {
             TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
         );
         if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
-            self.struct_span_err(self.token.span, "expected expression, found `let` statement")
-                .emit();
+            self.sess.emit_err(ExpectedExpressionFoundLet { span: self.token.span });
         }
 
         self.bump(); // Eat `let` token
@@ -2389,15 +2306,12 @@ impl<'a> Parser<'a> {
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
                         && classify::expr_requires_semi_to_be_stmt(&cond) =>
                 {
-                    self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
-                        .span_label(else_span, "expected an `if` or a block after this `else`")
-                        .span_suggestion(
-                            cond.span.shrink_to_lo(),
-                            "add an `if` if this is the condition of a chained `else if` statement",
-                            "if ",
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    self.sess.emit_err(ExpectedElseBlock {
+                        first_tok_span,
+                        first_tok,
+                        else_span,
+                        condition_start: cond.span.shrink_to_lo(),
+                    });
                     self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
                 }
                 Err(e) => {
@@ -2422,16 +2336,18 @@ impl<'a> Parser<'a> {
         branch_span: Span,
         attrs: &[ast::Attribute],
     ) {
-        let (span, last) = match attrs {
+        let (attributes, last) = match attrs {
             [] => return,
             [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
         };
         let ctx = if is_ctx_else { "else" } else { "if" };
-        self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
-            .span_label(branch_span, "the attributes are attached to this branch")
-            .span_label(ctx_span, format!("the branch belongs to this `{ctx}`"))
-            .span_suggestion(span, "remove the attributes", "", Applicability::MachineApplicable)
-            .emit();
+        self.sess.emit_err(OuterAttributeNotAllowedOnIfElse {
+            last,
+            branch_span,
+            ctx_span,
+            ctx: ctx.to_string(),
+            attributes,
+        });
     }
 
     /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
@@ -2465,23 +2381,16 @@ impl<'a> Parser<'a> {
     }
 
     fn error_missing_in_for_loop(&mut self) {
-        let (span, msg, sugg) = if self.token.is_ident_named(sym::of) {
+        let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
             // Possibly using JS syntax (#75311).
             let span = self.token.span;
             self.bump();
-            (span, "try using `in` here instead", "in")
+            (span, MissingInInForLoopSub::InNotOf)
         } else {
-            (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ")
+            (self.prev_token.span.between(self.token.span), MissingInInForLoopSub::AddIn)
         };
-        self.struct_span_err(span, "missing `in` in `for` loop")
-            .span_suggestion_short(
-                span,
-                msg,
-                sugg,
-                // Has been misleading, at least in the past (closed Issue #48492).
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+
+        self.sess.emit_err(MissingInInForLoop { span, sub: sub(span) });
     }
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
@@ -2787,17 +2696,9 @@ impl<'a> Parser<'a> {
                                 .is_ok();
                             if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
                                 err.cancel();
-                                this.struct_span_err(
-                                    hi.shrink_to_hi(),
-                                    "expected `,` following `match` arm",
-                                )
-                                .span_suggestion(
-                                    hi.shrink_to_hi(),
-                                    "missing a comma here to end this `match` arm",
-                                    ",",
-                                    Applicability::MachineApplicable,
-                                )
-                                .emit();
+                                this.sess.emit_err(MissingCommaAfterMatchArm {
+                                    span: hi.shrink_to_hi(),
+                                });
                                 return Ok(true);
                             }
                         }
@@ -2827,13 +2728,7 @@ impl<'a> Parser<'a> {
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         if self.eat_keyword(kw::Catch) {
-            let mut error = self.struct_span_err(
-                self.prev_token.span,
-                "keyword `catch` cannot follow a `try` block",
-            );
-            error.help("try using `match` on the result of the `try` block instead");
-            error.emit();
-            Err(error)
+            Err(CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.sess))
         } else {
             let span = span_lo.to(body.span);
             self.sess.gated_spans.gate(sym::try_blocks, span);
@@ -3082,18 +2977,10 @@ impl<'a> Parser<'a> {
         if self.token != token::Comma {
             return;
         }
-        self.struct_span_err(
-            span.to(self.prev_token.span),
-            "cannot use a comma after the base struct",
-        )
-        .span_suggestion_short(
-            self.token.span,
-            "remove this comma",
-            "",
-            Applicability::MachineApplicable,
-        )
-        .note("the base struct must always be the last field")
-        .emit();
+        self.sess.emit_err(CommaAfterBaseStruct {
+            span: span.to(self.prev_token.span),
+            comma: self.token.span,
+        });
         self.recover_stmt();
     }
 
@@ -3139,43 +3026,18 @@ impl<'a> Parser<'a> {
             return;
         }
 
-        self.struct_span_err(self.token.span, "expected `:`, found `=`")
-            .span_suggestion(
-                field_name.span.shrink_to_hi().to(self.token.span),
-                "replace equals symbol with a colon",
-                ":",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(EqFieldInit {
+            span: self.token.span,
+            eq: field_name.span.shrink_to_hi().to(self.token.span),
+        });
     }
 
     fn err_dotdotdot_syntax(&self, span: Span) {
-        self.struct_span_err(span, "unexpected token: `...`")
-            .span_suggestion(
-                span,
-                "use `..` for an exclusive range",
-                "..",
-                Applicability::MaybeIncorrect,
-            )
-            .span_suggestion(
-                span,
-                "or `..=` for an inclusive range",
-                "..=",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(DotDotDot { span });
     }
 
     fn err_larrow_operator(&self, span: Span) {
-        self.struct_span_err(span, "unexpected token: `<-`")
-            .span_suggestion(
-                span,
-                "if you meant to write a comparison against a negative value, add a \
-             space in between `<` and `-`",
-                "< -",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(LeftArrowOperator { span });
     }
 
     fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index b4b6fe8eead..ed653f0f9c8 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -69,9 +69,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
     ) {
         let cause =
             traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc));
+        // for a type to be WF, we do not need to check if const trait predicates satisfy.
+        let param_env = self.param_env.without_const();
         self.ocx.register_obligation(traits::Obligation::new(
             cause,
-            self.param_env,
+            param_env,
             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()),
         ));
     }
@@ -1449,7 +1451,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
     let wf_obligations =
         iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
-            traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp)
+            traits::wf::predicate_obligations(
+                infcx,
+                wfcx.param_env.without_const(),
+                wfcx.body_id,
+                p,
+                sp,
+            )
         });
 
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 197e7aaaccf..4583bc9a158 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -1010,7 +1010,8 @@ impl<T> BinaryHeap<T> {
     /// current length. The allocator may reserve more space to speculatively
     /// avoid frequent allocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 57ab74e0159..347a938fd0c 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -794,7 +794,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// in the given deque. The collection may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 7bee894d3e4..e28ace4795f 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1080,7 +1080,8 @@ impl String {
     /// current length. The allocator may reserve more space to speculatively
     /// avoid frequent allocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index e02ad391a59..4351548811d 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -148,7 +148,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
 
     #[inline]
     fn next(&mut self) -> Option<T> {
-        if self.ptr as *const _ == self.end {
+        if self.ptr == self.end {
             None
         } else if mem::size_of::<T>() == 0 {
             // purposefully don't use 'ptr.offset' because for
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index cea943602f7..2c786fd511e 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -875,7 +875,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// in the given `Vec<T>`. The collection may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
@@ -2927,6 +2928,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
 #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
 impl<T> const Default for Vec<T> {
     /// Creates an empty `Vec<T>`.
+    ///
+    /// The vector will not allocate until elements are pushed onto it.
     fn default() -> Vec<T> {
         Vec::new()
     }
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index d83cd29ddba..99bfb2a45ed 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -38,6 +38,7 @@
 #![feature(const_str_from_utf8)]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(panic_update_hook)]
+#![feature(pointer_is_aligned)]
 #![feature(slice_flatten)]
 #![feature(thin_box)]
 #![feature(bench_black_box)]
diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs
index 368aa564f94..e008b0cc357 100644
--- a/library/alloc/tests/thin_box.rs
+++ b/library/alloc/tests/thin_box.rs
@@ -48,11 +48,11 @@ fn verify_aligned<T>(ptr: *const T) {
     // practice these checks are mostly just smoke-detectors for an extremely
     // broken `ThinBox` impl, since it's an extremely subtle piece of code.
     let ptr = core::hint::black_box(ptr);
-    let align = core::mem::align_of::<T>();
     assert!(
-        (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(),
-        "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}",
-        core::any::type_name::<T>(),
+        ptr.is_aligned() && !ptr.is_null(),
+        "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}",
+        ty = core::any::type_name::<T>(),
+        align = core::mem::align_of::<T>(),
     );
 }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 3d7b875eac1..441d2382686 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2139,7 +2139,7 @@ pub(crate) use assert_unsafe_precondition;
 /// Checks whether `ptr` is properly aligned with respect to
 /// `align_of::<T>()`.
 pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
-    !ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0
+    !ptr.is_null() && ptr.is_aligned()
 }
 
 /// Checks whether the regions of memory starting at `src` and `dst` of size
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index a0a5c003d28..80ed34157e6 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -290,7 +290,8 @@ impl OsString {
     /// in the given `OsString`. The string may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns `Ok(())`.
-    /// Does nothing if capacity is already sufficient.
+    /// Does nothing if capacity is already sufficient. This method preserves
+    /// the contents even if an error occurs.
     ///
     /// See the main `OsString` documentation information about encoding and capacity units.
     ///
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5029023121f..71bbf4317e0 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -296,6 +296,7 @@
 #![feature(panic_can_unwind)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(pointer_is_aligned)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
 #![feature(provide_any)]
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 189754a161e..6004810655e 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -620,25 +620,31 @@ impl Ipv4Addr {
         matches!(self.octets(), [169, 254, ..])
     }
 
-    /// Returns [`true`] if the address appears to be globally routable.
-    /// See [iana-ipv4-special-registry][ipv4-sr].
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
+    ///
+    /// Most IPv4 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
     ///
-    /// The following return [`false`]:
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
     ///
-    /// - private addresses (see [`Ipv4Addr::is_private()`])
-    /// - the loopback address (see [`Ipv4Addr::is_loopback()`])
-    /// - the link-local address (see [`Ipv4Addr::is_link_local()`])
-    /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
-    /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
-    /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
-    ///   `0.0.0.0/8` block
-    /// - addresses reserved for future protocols, except
-    /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
-    /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`]
-    /// - addresses reserved for networking devices benchmarking (see
-    /// [`Ipv4Addr::is_benchmarking()`])
+    /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
+    /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
+    /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
+    /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
+    /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
+    /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
+    /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
+    /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
     ///
-    /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
+    ///
+    /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+    /// [unspecified address]: Ipv4Addr::UNSPECIFIED
+    /// [broadcast address]: Ipv4Addr::BROADCAST
+
     ///
     /// # Examples
     ///
@@ -647,71 +653,61 @@ impl Ipv4Addr {
     ///
     /// use std::net::Ipv4Addr;
     ///
-    /// // private addresses are not global
+    /// // Most IPv4 addresses are globally reachable:
+    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`0.0.0.0`)
+    /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
     /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
     /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
     /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
     ///
-    /// // the 0.0.0.0/8 block is not global
-    /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false);
-    /// // in particular, the unspecified address is not global
-    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
+    /// // Addresses in the shared address space (`100.64.0.0/10`)
+    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
     ///
-    /// // the loopback address is not global
-    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false);
+    /// // The loopback addresses (`127.0.0.0/8`)
+    /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
     ///
-    /// // link local addresses are not global
+    /// // Link-local addresses (`169.254.0.0/16`)
     /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
     ///
-    /// // the broadcast address is not global
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false);
-    ///
-    /// // the address space designated for documentation is not global
+    /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
     /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
     /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
     /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
     ///
-    /// // shared addresses are not global
-    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
-    ///
-    /// // addresses reserved for protocol assignment are not global
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false);
+    /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
+    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
     ///
-    /// // addresses reserved for future use are not global
+    /// // Reserved addresses (`240.0.0.0/4`)
     /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
     ///
-    /// // addresses reserved for network devices benchmarking are not global
-    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
+    /// // The broadcast address (`255.255.255.255`)
+    /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
     ///
-    /// // All the other addresses are global
-    /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true);
-    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+    /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
     #[unstable(feature = "ip", issue = "27709")]
     #[must_use]
     #[inline]
     pub const fn is_global(&self) -> bool {
-        // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
-        // globally routable addresses in the 192.0.0.0/24 range.
-        if u32::from_be_bytes(self.octets()) == 0xc0000009
-            || u32::from_be_bytes(self.octets()) == 0xc000000a
-        {
-            return true;
-        }
-        !self.is_private()
-            && !self.is_loopback()
-            && !self.is_link_local()
-            && !self.is_broadcast()
-            && !self.is_documentation()
-            && !self.is_shared()
+        !(self.octets()[0] == 0 // "This network"
+            || self.is_private()
+            || self.is_shared()
+            || self.is_loopback()
+            || self.is_link_local()
             // addresses reserved for future protocols (`192.0.0.0/24`)
-            && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
-            && !self.is_reserved()
-            && !self.is_benchmarking()
-            // Make sure the address is not in 0.0.0.0/8
-            && self.octets()[0] != 0
+            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
+            || self.is_documentation()
+            || self.is_benchmarking()
+            || self.is_reserved()
+            || self.is_broadcast())
     }
 
     /// Returns [`true`] if this address is part of the Shared Address Space defined in
@@ -1300,13 +1296,33 @@ impl Ipv6Addr {
         u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
     }
 
-    /// Returns [`true`] if the address appears to be globally routable.
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
     ///
-    /// The following return [`false`]:
+    /// Most IPv6 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
     ///
-    /// - the loopback address
-    /// - link-local and unique local unicast addresses
-    /// - interface-, link-, realm-, admin- and site-local multicast addresses
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
+    /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
+    /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
+    /// - IPv4-mapped addresses
+    /// - Addresses reserved for benchmarking
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
+    /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
+    /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
+    ///
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
+    ///
+    /// Note that an address having global scope is not the same as being globally reachable,
+    /// and there is no direct relation between the two concepts: There exist addresses with global scope
+    /// that are not globally reachable (for example unique local addresses),
+    /// and addresses that are globally reachable without having global scope
+    /// (multicast addresses with non-global scope).
+    ///
+    /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
+    /// [unspecified address]: Ipv6Addr::UNSPECIFIED
+    /// [loopback address]: Ipv6Addr::LOCALHOST
     ///
     /// # Examples
     ///
@@ -1315,20 +1331,65 @@ impl Ipv6Addr {
     ///
     /// use std::net::Ipv6Addr;
     ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
+    /// // Most IPv6 addresses are globally reachable:
+    /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`::`)
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // The loopback address (`::1`)
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
+    ///
+    /// // IPv4-mapped addresses (`::ffff:0:0/96`)
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
+    ///
+    /// // Addresses reserved for benchmarking (`2001:2::/48`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
+    ///
+    /// // Addresses reserved for documentation (`2001:db8::/32`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unique local addresses (`fc00::/7`)
+    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unicast addresses with link-local scope (`fe80::/10`)
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
     #[unstable(feature = "ip", issue = "27709")]
     #[must_use]
     #[inline]
     pub const fn is_global(&self) -> bool {
-        match self.multicast_scope() {
-            Some(Ipv6MulticastScope::Global) => true,
-            None => self.is_unicast_global(),
-            _ => false,
-        }
+        !(self.is_unspecified()
+            || self.is_loopback()
+            // IPv4-mapped Address (`::ffff:0:0/96`)
+            || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
+            // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
+            || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
+            // Discard-Only Address Block (`100::/64`)
+            || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
+            // IETF Protocol Assignments (`2001::/23`)
+            || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
+                && !(
+                    // Port Control Protocol Anycast (`2001:1::1`)
+                    u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
+                    // Traversal Using Relays around NAT Anycast (`2001:1::2`)
+                    || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
+                    // AMT (`2001:3::/32`)
+                    || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
+                    // AS112-v6 (`2001:4:112::/48`)
+                    || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
+                    // ORCHIDv2 (`2001:20::/28`)
+                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
+                ))
+            || self.is_documentation()
+            || self.is_unique_local()
+            || self.is_unicast_link_local())
     }
 
     /// Returns [`true`] if this is a unique local address (`fc00::/7`).
@@ -1525,6 +1586,7 @@ impl Ipv6Addr {
             && !self.is_unique_local()
             && !self.is_unspecified()
             && !self.is_documentation()
+            && !self.is_benchmarking()
     }
 
     /// Returns the address's multicast scope if the address is multicast.
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index c29509331d7..7c3430b2b21 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -321,15 +321,15 @@ fn ip_properties() {
     check!("fe80:ffff::");
     check!("febf:ffff::");
     check!("fec0::", global);
-    check!("ff01::", multicast);
-    check!("ff02::", multicast);
-    check!("ff03::", multicast);
-    check!("ff04::", multicast);
-    check!("ff05::", multicast);
-    check!("ff08::", multicast);
+    check!("ff01::", global | multicast);
+    check!("ff02::", global | multicast);
+    check!("ff03::", global | multicast);
+    check!("ff04::", global | multicast);
+    check!("ff05::", global | multicast);
+    check!("ff08::", global | multicast);
     check!("ff0e::", global | multicast);
     check!("2001:db8:85a3::8a2e:370:7334", doc);
-    check!("2001:2::ac32:23ff:21", global | benchmarking);
+    check!("2001:2::ac32:23ff:21", benchmarking);
     check!("102:304:506:708:90a:b0c:d0e:f10", global);
 }
 
@@ -609,6 +609,60 @@ fn ipv6_properties() {
 
     check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
 
+    check!(
+        "::ffff:127.0.0.1",
+        &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
+        unicast_global
+    );
+
+    check!(
+        "64:ff9b:1::",
+        &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_global
+    );
+
+    check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:1::1",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:1::2",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:3::",
+        &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:4:112::",
+        &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:20::",
+        &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:200::",
+        &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
     check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
 
     check!(
@@ -666,21 +720,37 @@ fn ipv6_properties() {
     check!(
         "ff01::",
         &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_interface_local
+        multicast_interface_local | global
     );
 
-    check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local);
+    check!(
+        "ff02::",
+        &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_link_local | global
+    );
 
-    check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local);
+    check!(
+        "ff03::",
+        &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_realm_local | global
+    );
 
-    check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local);
+    check!(
+        "ff04::",
+        &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_admin_local | global
+    );
 
-    check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local);
+    check!(
+        "ff05::",
+        &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_site_local | global
+    );
 
     check!(
         "ff08::",
         &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_organization_local
+        multicast_organization_local | global
     );
 
     check!(
@@ -698,7 +768,7 @@ fn ipv6_properties() {
     check!(
         "2001:2::ac32:23ff:21",
         &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
-        global | unicast_global | benchmarking
+        benchmarking
     );
 
     check!(
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index fe8392f78cd..5409bd1777c 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -117,7 +117,7 @@ pub unsafe trait UserSafe {
     /// * the pointer is null.
     /// * the pointed-to range is not in user memory.
     unsafe fn check_ptr(ptr: *const Self) {
-        let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) };
+        let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) };
 
         assert!(is_aligned(ptr as *const u8));
         assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
@@ -386,7 +386,7 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize)
         unsafe {
             copy_bytewise_to_userspace(src, dst, len);
         }
-    } else if len % 8 == 0 && dst as usize % 8 == 0 {
+    } else if len % 8 == 0 && dst.is_aligned_to(8) {
         // Copying 8-byte aligned quadwords: copy quad word per quad word
         unsafe {
             copy_quadwords(src, dst, len);
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 57fa4989358..33e20756163 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -236,7 +236,8 @@ impl Wtf8Buf {
     /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional`. Does nothing if
-    /// capacity is already sufficient.
+    /// capacity is already sufficient. This method preserves the contents even
+    /// if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
index 836443bf4d2..04378dbf374 100644
--- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
@@ -24,7 +24,7 @@
 +         _1 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
           StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+1:27: +1:28
           StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+1:28: +1:29
-          nop;                             // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/aggregate.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs
index 7a3b26a7317..493d0508a04 100644
--- a/src/test/mir-opt/const_prop/aggregate.rs
+++ b/src/test/mir-opt/const_prop/aggregate.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 
 // EMIT_MIR aggregate.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
index bb9abdd1020..439b2a3e16b 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:+1:31: +1:32
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:+1:31: +1:32
-          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
+-         _4 = Len(_2);                    // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
       }
   
       bb1: {
@@ -30,7 +31,7 @@
 +         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:+1:18: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/array_index.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/array_index.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/array_index.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/array_index.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
index bb9abdd1020..439b2a3e16b 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:+1:31: +1:32
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:+1:31: +1:32
-          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
+-         _4 = Len(_2);                    // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
       }
   
       bb1: {
@@ -30,7 +31,7 @@
 +         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:+1:18: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/array_index.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/array_index.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/array_index.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/array_index.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs
index 2c5254b5deb..d31c2827b4e 100644
--- a/src/test/mir-opt/const_prop/array_index.rs
+++ b/src/test/mir-opt/const_prop/array_index.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR array_index.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
index 45134a3fdff..bea32a67ef4 100644
--- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
@@ -24,10 +24,9 @@
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 -         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
--         assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
+          assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
@@ -38,14 +37,13 @@
 +         _5 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Div(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
+          _2 = Div(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
           StorageDead(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
-          nop;                             // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2
+          _0 = const ();                   // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:2: +3:2
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
index 6f39209b970..a6fd325ece0 100644
--- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/src/test/mir-opt/const_prop/boolean_identities.rs b/src/test/mir-opt/const_prop/boolean_identities.rs
index 57164e3e794..c7b609949cd 100644
--- a/src/test/mir-opt/const_prop/boolean_identities.rs
+++ b/src/test/mir-opt/const_prop/boolean_identities.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O -Zmir-opt-level=4
 
 // EMIT_MIR boolean_identities.test.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
index 73fdf140498..cb82a7bea14 100644
--- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
@@ -24,12 +24,11 @@
           StorageLive(_3);                 // scope 0 at $DIR/boxes.rs:+1:14: +1:22
 -         _4 = SizeOf(i32);                // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 -         _5 = AlignOf(i32);               // scope 2 at $DIR/boxes.rs:+1:14: +1:22
--         _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 +         _4 = const 4_usize;              // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 +         _5 = const 4_usize;              // scope 2 at $DIR/boxes.rs:+1:14: +1:22
-+         _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
+          _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/boxes.rs:12:14: 12:22
+                                           // + span: $DIR/boxes.rs:13:14: 13:22
                                            // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
@@ -53,7 +52,7 @@
   
       bb2: {
           StorageDead(_3);                 // scope 0 at $DIR/boxes.rs:+1:26: +1:27
-          nop;                             // scope 0 at $DIR/boxes.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/boxes.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/boxes.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/boxes.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs
index fea666a4455..d287830db5a 100644
--- a/src/test/mir-opt/const_prop/boxes.rs
+++ b/src/test/mir-opt/const_prop/boxes.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 // ignore-emscripten compiled with panic=abort by default
 // ignore-wasm32
diff --git a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
index 5698a612fe2..e040a4b3a53 100644
--- a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
@@ -19,7 +19,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/cast.rs:+3:9: +3:10
 -         _2 = const 42_u32 as u8 (Misc);  // scope 1 at $DIR/cast.rs:+3:13: +3:24
 +         _2 = const 42_u8;                // scope 1 at $DIR/cast.rs:+3:13: +3:24
-          nop;                             // scope 0 at $DIR/cast.rs:+0:11: +4:2
+          _0 = const ();                   // scope 0 at $DIR/cast.rs:+0:11: +4:2
           StorageDead(_2);                 // scope 1 at $DIR/cast.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/cast.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/cast.rs:+4:2: +4:2
diff --git a/src/test/mir-opt/const_prop/cast.rs b/src/test/mir-opt/const_prop/cast.rs
index 680cab00740..984086eda48 100644
--- a/src/test/mir-opt/const_prop/cast.rs
+++ b/src/test/mir-opt/const_prop/cast.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR cast.main.ConstProp.diff
 
 fn main() {
diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
index 5e33d054207..96d0d25664a 100644
--- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
@@ -20,7 +20,7 @@
       bb1: {
 -         _1 = move (_2.0: u32);           // scope 0 at $DIR/checked_add.rs:+1:18: +1:23
 +         _1 = const 2_u32;                // scope 0 at $DIR/checked_add.rs:+1:18: +1:23
-          nop;                             // scope 0 at $DIR/checked_add.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/checked_add.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/checked_add.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/checked_add.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs
index 08d59b6fbc3..b9860da4c82 100644
--- a/src/test/mir-opt/const_prop/checked_add.rs
+++ b/src/test/mir-opt/const_prop/checked_add.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
 // EMIT_MIR checked_add.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index c21b24591d8..2cb071deab1 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _3 = const FOO;                  // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:8:13: 8:16
                                            // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39
@@ -29,14 +29,14 @@
           _5 = _1;                         // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11
           _4 = read(move _5) -> bb1;       // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:9:5: 9:9
                                            // + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) }
       }
   
       bb1: {
           StorageDead(_5);                 // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:11: +3:12
           StorageDead(_4);                 // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:12: +3:13
-          nop;                             // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2
+          _0 = const ();                   // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:2: +4:2
       }
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
index 8bd68527f37..0a3dcbd380f 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 #[inline(never)]
 fn read(_: usize) { }
 
diff --git a/src/test/mir-opt/const_prop/control-flow-simplification.rs b/src/test/mir-opt/const_prop/control-flow-simplification.rs
index aa4ce19f620..7dbe8e7344b 100644
--- a/src/test/mir-opt/const_prop/control-flow-simplification.rs
+++ b/src/test/mir-opt/const_prop/control-flow-simplification.rs
@@ -1,10 +1,11 @@
+// unit-test: ConstProp
 // compile-flags: -Zmir-opt-level=1
 
-trait NeedsDrop:Sized{
-    const NEEDS:bool=std::mem::needs_drop::<Self>();
+trait NeedsDrop: Sized {
+    const NEEDS: bool = std::mem::needs_drop::<Self>();
 }
 
-impl<This> NeedsDrop for This{}
+impl<This> NeedsDrop for This {}
 
 // EMIT_MIR control_flow_simplification.hello.ConstProp.diff
 // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
index 5b4ecaa80f1..6b29bb59c40 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
@@ -44,7 +44,7 @@
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:+1:13: +1:68
           StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:+1:67: +1:68
           StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:+1:68: +1:69
-          nop;                             // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/discriminant.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
index 5b4ecaa80f1..6b29bb59c40 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
@@ -44,7 +44,7 @@
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:+1:13: +1:68
           StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:+1:67: +1:68
           StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:+1:68: +1:69
-          nop;                             // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/discriminant.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs
index 67538b3c7a5..fdd67ca8ac4 100644
--- a/src/test/mir-opt/const_prop/discriminant.rs
+++ b/src/test/mir-opt/const_prop/discriminant.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 
 // FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
index 2e1e32545a2..948bb7f56fe 100644
--- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
@@ -18,14 +18,14 @@
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
 +         _2 = const 2_u8;                 // scope 0 at $DIR/indirect.rs:+1:13: +1:25
 +         _3 = const (3_u8, false);        // scope 0 at $DIR/indirect.rs:+1:13: +1:29
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
       }
   
       bb1: {
 -         _1 = move (_3.0: u8);            // scope 0 at $DIR/indirect.rs:+1:13: +1:29
 +         _1 = const 3_u8;                 // scope 0 at $DIR/indirect.rs:+1:13: +1:29
           StorageDead(_2);                 // scope 0 at $DIR/indirect.rs:+1:28: +1:29
-          nop;                             // scope 0 at $DIR/indirect.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/indirect.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/indirect.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/indirect.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/indirect.rs b/src/test/mir-opt/const_prop/indirect.rs
index 37217ca8134..44916cbfe74 100644
--- a/src/test/mir-opt/const_prop/indirect.rs
+++ b/src/test/mir-opt/const_prop/indirect.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
 // EMIT_MIR indirect.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs
index 81eccae46b9..6ca03438ef3 100644
--- a/src/test/mir-opt/const_prop/issue-66971.rs
+++ b/src/test/mir-opt/const_prop/issue-66971.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
 // Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs
index c78b8b97178..ffc6fa1f290 100644
--- a/src/test/mir-opt/const_prop/issue-67019.rs
+++ b/src/test/mir-opt/const_prop/issue-67019.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
 // This used to ICE in const-prop
diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index b3d5980aa73..9d541dcabbb 100644
--- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -19,7 +19,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/issue-66971.rs:+1:21: +1:22
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23
                                            // mir::Constant
-                                           // + span: $DIR/issue-66971.rs:16:5: 16:11
+                                           // + span: $DIR/issue-66971.rs:17:5: 17:11
                                            // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index 8330b50529f..b79d814760d 100644
--- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -20,7 +20,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/issue-67019.rs:+1:18: +1:19
           _1 = test(move _2) -> bb1;       // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20
                                            // mir::Constant
-                                           // + span: $DIR/issue-67019.rs:11:5: 11:9
+                                           // + span: $DIR/issue-67019.rs:12:5: 12:9
                                            // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mult_by_zero.rs b/src/test/mir-opt/const_prop/mult_by_zero.rs
index b0ecdf1818e..c839f92f2ce 100644
--- a/src/test/mir-opt/const_prop/mult_by_zero.rs
+++ b/src/test/mir-opt/const_prop/mult_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O -Zmir-opt-level=4
 
 // EMIT_MIR mult_by_zero.test.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable.rs b/src/test/mir-opt/const_prop/mutable_variable.rs
index 801e7a9fcbb..cb01719dd77 100644
--- a/src/test/mir-opt/const_prop/mutable_variable.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
index e0b4b77bac4..d4ff8d89073 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
index 79ac497c783..9060f7e9bd3 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
index c678f7b0327..6eda503c1ee 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
@@ -16,7 +16,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:29: +1:34
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:29: 6:32
                                            // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
index 9bb62b8973c..cb59509ff10 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
index 4c2ba9a0998..eb3a7bc96d8 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
@@ -25,7 +25,7 @@
           StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
           _4 = const {alloc1: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // + span: $DIR/mutable_variable_no_prop.rs:10:13: 10:19
                                            // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) }
           _3 = (*_4);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
           _1 = move _3;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
index 4126fb3c68c..8c23c5fcf0f 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 static mut STATIC: u32 = 42;
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 5328792b323..4f205667be0 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -25,7 +25,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:6:13: 6:16
                                            // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
index 13f1b3f47f2..b077cfd3e0a 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.rs b/src/test/mir-opt/const_prop/optimizes_into_variable.rs
index 17265b7eb85..c0fbd2558cd 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.rs
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -C overflow-checks=on
 
 struct Point {
diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
index 89f43d75138..b9c283a5482 100644
--- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
           _3 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
                                            // mir::Constant
-                                           // + span: $DIR/read_immutable_static.rs:7:13: 7:16
+                                           // + span: $DIR/read_immutable_static.rs:8:13: 8:16
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
 -         _2 = (*_3);                      // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
 +         _2 = const 2_u8;                 // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
@@ -26,7 +26,7 @@
           StorageLive(_5);                 // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
           _5 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/read_immutable_static.rs:7:19: 7:22
+                                           // + span: $DIR/read_immutable_static.rs:8:19: 8:22
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
 -         _4 = (*_5);                      // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
 -         _1 = Add(move _2, move _4);      // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:22
diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs
index 8a5f12c6f3d..4f7afe6cad4 100644
--- a/src/test/mir-opt/const_prop/read_immutable_static.rs
+++ b/src/test/mir-opt/const_prop/read_immutable_static.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 static FOO: u8 = 2;
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index f0c89caeac6..84ec5c8bb1d 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -13,7 +13,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref_project.rs:5:6: 5:17
+                                           // + span: $DIR/ref_deref_project.rs:6:6: 6:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
index d2554028792..6f3a060a126 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
@@ -16,7 +16,7 @@
 -         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
 +         _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
 +                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
++                                          // + span: $DIR/ref_deref_project.rs:6:6: 6:17
 +                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs
index c7cc73651f6..659c11d9b0c 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.rs
+++ b/src/test/mir-opt/const_prop/ref_deref_project.rs
@@ -1,3 +1,4 @@
+// unit-test
 // EMIT_MIR ref_deref_project.main.PromoteTemps.diff
 // EMIT_MIR ref_deref_project.main.ConstProp.diff
 
diff --git a/src/test/ui/or-patterns/inner-or-pat.or3.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
new file mode 100644
index 00000000000..2236a38c37b
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/inner-or-pat.rs:38:54
+   |
+LL |     match x {
+   |           - this expression has type `&str`
+LL |         x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+   |                                                      ^^ expected `str`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/inner-or-pat.or4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
new file mode 100644
index 00000000000..058873ff5ff
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
@@ -0,0 +1,11 @@
+error[E0408]: variable `x` is not bound in all patterns
+  --> $DIR/inner-or-pat.rs:53:37
+   |
+LL |         (x @ "red" | (x @ "blue" |  "red")) => {
+   |                       -             ^^^^^ pattern doesn't bind `x`
+   |                       |
+   |                       variable not in all patterns
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs
new file mode 100644
index 00000000000..f4cf4b0c188
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.rs
@@ -0,0 +1,73 @@
+// revisions: or1 or2 or3 or4 or5
+// [or1] run-pass
+// [or2] run-pass
+// [or5] run-pass
+
+#![allow(unreachable_patterns)]
+#![allow(unused_variables)]
+#![allow(unused_parens)]
+#![allow(dead_code)]
+
+
+
+fn foo() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) |
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
+
+fn bar() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" | x @ "red")) => {
+        }
+        _ => (),
+    }
+}
+
+#[cfg(or3)]
+fn zot() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+        //[or3]~^ ERROR mismatched types
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
+
+
+#[cfg(or4)]
+fn hey() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" |  "red")) => {
+        //[or4]~^ variable `x` is not bound in all patterns
+        }
+        _ => (),
+    }
+}
+
+fn don() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+
+    match Foo::A {
+        | _foo @ (Foo::A | Foo::B) => {}
+        Foo::C => {}
+    };
+}
+
+fn main(){}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
new file mode 100644
index 00000000000..1004bb28c59
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
@@ -0,0 +1,29 @@
+// revisions: nn ny yn yy
+// check-pass
+#![feature(const_trait_impl, associated_type_defaults, const_mut_refs)]
+
+#[cfg_attr(any(yn, yy), const_trait)]
+pub trait Index {
+    type Output;
+}
+
+#[cfg_attr(any(ny, yy), const_trait)]
+pub trait IndexMut where Self: Index {
+    const C: <Self as Index>::Output;
+    type Assoc = <Self as Index>::Output;
+    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output;
+}
+
+impl Index for () { type Output = (); }
+
+impl const IndexMut for <() as Index>::Output {
+    const C: <Self as Index>::Output = ();
+    type Assoc = <Self as Index>::Output;
+    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
+        where <Self as Index>::Output:,
+    {}
+}
+
+const C: <() as Index>::Output = ();
+
+fn main() {}