about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-03 16:16:52 +0000
committerbors <bors@rust-lang.org>2024-04-03 16:16:52 +0000
commit703dc9ce64d9b31a239a7280d9b5f9ddd85ffed6 (patch)
treec39cc52942d7e2c3871c4fbd22dbba1356176583
parentceab6128fa48a616bfd3e3adf4bc80133b8ee223 (diff)
parent658c8f73677696ff2f37ea1cbd5d667d2562ccbf (diff)
downloadrust-703dc9ce64d9b31a239a7280d9b5f9ddd85ffed6.tar.gz
rust-703dc9ce64d9b31a239a7280d9b5f9ddd85ffed6.zip
Auto merge of #123416 - matthiaskrgr:rollup-j85wj05, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #123209 (Add section to sanitizer doc for `-Zexternal-clangrt`)
 - #123342 (x.py test: remove no-op --skip flag)
 - #123382 (Assert `FnDef` kind)
 - #123386 (Set `CARGO` instead of `PATH` for Rust Clippy)
 - #123393 (rustc_ast: Update `P<T>` docs to reflect mutable status.)
 - #123394 (Postfix match fixes)
 - #123412 (Output URLs of CI artifacts to GitHub summary)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/ptr.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_middle/src/thir.rs3
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs6
-rw-r--r--compiler/rustc_mir_build/src/errors.rs23
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs57
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs1
-rw-r--r--src/bootstrap/src/core/builder.rs13
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/bootstrap/src/core/config/flags.rs3
-rwxr-xr-xsrc/ci/scripts/upload-artifacts.sh14
-rw-r--r--src/doc/unstable-book/src/compiler-flags/external-clangrt.md6
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md15
-rw-r--r--src/etc/completions/x.py.fish2
-rw-r--r--src/etc/completions/x.py.ps12
-rw-r--r--src/etc/completions/x.py.sh10
-rw-r--r--src/etc/completions/x.py.zsh2
-rw-r--r--tests/ui/match/postfix-match/match-after-as.rs7
-rw-r--r--tests/ui/match/postfix-match/match-after-as.stderr28
20 files changed, 148 insertions, 69 deletions
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 0140fb752bf..e22a523dbc3 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -1,6 +1,6 @@
 //! The AST pointer.
 //!
-//! Provides `P<T>`, a frozen owned smart pointer.
+//! Provides [`P<T>`][struct@P], an owned smart pointer.
 //!
 //! # Motivations and benefits
 //!
@@ -8,18 +8,14 @@
 //!   passes (e.g., one may be able to bypass the borrow checker with a shared
 //!   `ExprKind::AddrOf` node taking a mutable borrow).
 //!
-//! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
-//!   (unless it contains an `Unsafe` interior, but that may be denied later).
-//!   This mainly prevents mistakes, but also enforces a kind of "purity".
-//!
 //! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
 //!   the latter even when the input and output types differ (as it would be the
 //!   case with arenas or a GADT AST using type parameters to toggle features).
 //!
-//! * **Maintainability**: `P<T>` provides a fixed interface - `Deref`,
-//!   `and_then` and `map` - which can remain fully functional even if the
-//!   implementation changes (using a special thread-local heap, for example).
-//!   Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
+//! * **Maintainability**: `P<T>` provides an interface, which can remain fully
+//!   functional even if the implementation changes (using a special thread-local
+//!   heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy
+//!   and mostly automated.
 
 use std::fmt::{self, Debug, Display};
 use std::ops::{Deref, DerefMut};
@@ -29,6 +25,8 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 /// An owned smart pointer.
+///
+/// See the [module level documentation][crate::ptr] for details.
 pub struct P<T: ?Sized> {
     ptr: Box<T>,
 }
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 722def2563c..9d7deebac48 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -474,9 +474,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             VariantData::Unit(..) | VariantData::Struct { .. } => {
                 tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity()
             }
-            VariantData::Tuple(..) => {
+            VariantData::Tuple(_, _, ctor) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
-                Ty::new_fn_def(tcx, def_id.to_def_id(), args)
+                Ty::new_fn_def(tcx, ctor.to_def_id(), args)
             }
         },
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 05f6fbbbfa3..95e8509c2d3 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,7 +12,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BindingAnnotation, ByRef, RangeEnd};
+use rustc_hir::{BindingAnnotation, ByRef, MatchSource, RangeEnd};
 use rustc_index::newtype_index;
 use rustc_index::IndexVec;
 use rustc_middle::middle::region;
@@ -358,6 +358,7 @@ pub enum ExprKind<'tcx> {
         scrutinee: ExprId,
         scrutinee_hir_id: hir::HirId,
         arms: Box<[ArmId]>,
+        match_source: MatchSource,
     },
     /// A block.
     Block {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index b5e619f1e2a..ba0898e07c2 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -11,7 +11,7 @@ use crate::ty::{
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use crate::ty::{List, ParamEnv};
-use hir::def::DefKind;
+use hir::def::{CtorKind, DefKind};
 use rustc_data_structures::captures::Captures;
 use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan};
 use rustc_hir as hir;
@@ -1677,6 +1677,10 @@ impl<'tcx> Ty<'tcx> {
         def_id: DefId,
         args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
     ) -> Ty<'tcx> {
+        debug_assert_matches!(
+            tcx.def_kind(def_id),
+            DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn)
+        );
         let args = tcx.check_and_mk_args(def_id, args);
         Ty::new(tcx, FnDef(def_id, args))
     }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 848da56f981..26f10fdd333 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -456,8 +456,8 @@ pub enum UnusedUnsafeEnclosing {
 
 pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
     pub cx: &'m RustcPatCtxt<'p, 'tcx>,
-    pub expr_span: Span,
-    pub span: Span,
+    pub scrut_span: Span,
+    pub braces_span: Option<Span>,
     pub ty: Ty<'tcx>,
 }
 
@@ -465,7 +465,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
     fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> {
         let mut diag =
             Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty);
-        diag.span(self.span);
+        diag.span(self.scrut_span);
         diag.code(E0004);
         let peeled_ty = self.ty.peel_refs();
         diag.arg("ty", self.ty);
@@ -502,26 +502,19 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo
             }
         }
 
-        let mut suggestion = None;
         let sm = self.cx.tcx.sess.source_map();
-        if self.span.eq_ctxt(self.expr_span) {
+        if let Some(braces_span) = self.braces_span {
             // Get the span for the empty match body `{}`.
-            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.scrut_span)
+            {
                 (format!("\n{snippet}"), "    ")
             } else {
                 (" ".to_string(), "")
             };
-            suggestion = Some((
-                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
-                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}",),
-            ));
-        }
-
-        if let Some((span, sugg)) = suggestion {
             diag.span_suggestion_verbose(
-                span,
+                braces_span,
                 fluent::mir_build_suggestion,
-                sugg,
+                format!(" {{{indentation}{more}_ => todo!(),{indentation}}}"),
                 Applicability::HasPlaceholders,
             );
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 1e508ffc1e7..c697e16217b 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -716,10 +716,11 @@ impl<'tcx> Cx<'tcx> {
                 then: self.mirror_expr(then),
                 else_opt: else_opt.map(|el| self.mirror_expr(el)),
             },
-            hir::ExprKind::Match(discr, arms, _) => ExprKind::Match {
+            hir::ExprKind::Match(discr, arms, match_source) => ExprKind::Match {
                 scrutinee: self.mirror_expr(discr),
                 scrutinee_hir_id: discr.hir_id,
                 arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
+                match_source,
             },
             hir::ExprKind::Loop(body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 3a688a14dd5..a3e6c2abc51 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -144,16 +144,8 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
                 });
                 return;
             }
-            ExprKind::Match { scrutinee, scrutinee_hir_id, box ref arms } => {
-                let source = match ex.span.desugaring_kind() {
-                    Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar,
-                    Some(DesugaringKind::QuestionMark) => {
-                        hir::MatchSource::TryDesugar(scrutinee_hir_id)
-                    }
-                    Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar,
-                    _ => hir::MatchSource::Normal,
-                };
-                self.check_match(scrutinee, arms, source, ex.span);
+            ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
+                self.check_match(scrutinee, arms, match_source, ex.span);
             }
             ExprKind::Let { box ref pat, expr } => {
                 self.check_let(pat, Some(expr), ex.span);
@@ -505,8 +497,41 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                     None,
                 );
             } else {
+                // span after scrutinee, or after `.match`. That is, the braces, arms,
+                // and any whitespace preceding the braces.
+                let braces_span = match source {
+                    hir::MatchSource::Normal => scrut
+                        .span
+                        .find_ancestor_in_same_ctxt(expr_span)
+                        .map(|scrut_span| scrut_span.shrink_to_hi().with_hi(expr_span.hi())),
+                    hir::MatchSource::Postfix => {
+                        // This is horrendous, and we should deal with it by just
+                        // stashing the span of the braces somewhere (like in the match source).
+                        scrut.span.find_ancestor_in_same_ctxt(expr_span).and_then(|scrut_span| {
+                            let sm = self.tcx.sess.source_map();
+                            let brace_span = sm.span_extend_to_next_char(scrut_span, '{', true);
+                            if sm.span_to_snippet(sm.next_point(brace_span)).as_deref() == Ok("{") {
+                                let sp = brace_span.shrink_to_hi().with_hi(expr_span.hi());
+                                // We also need to extend backwards for whitespace
+                                sm.span_extend_prev_while(sp, |c| c.is_whitespace()).ok()
+                            } else {
+                                None
+                            }
+                        })
+                    }
+                    hir::MatchSource::ForLoopDesugar
+                    | hir::MatchSource::TryDesugar(_)
+                    | hir::MatchSource::AwaitDesugar
+                    | hir::MatchSource::FormatArgs => None,
+                };
                 self.error = Err(report_non_exhaustive_match(
-                    &cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
+                    &cx,
+                    self.thir,
+                    scrut.ty,
+                    scrut.span,
+                    witnesses,
+                    arms,
+                    braces_span,
                 ));
             }
         }
@@ -929,7 +954,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     sp: Span,
     witnesses: Vec<WitnessPat<'p, 'tcx>>,
     arms: &[ArmId],
-    expr_span: Span,
+    braces_span: Option<Span>,
 ) -> ErrorGuaranteed {
     let is_empty_match = arms.is_empty();
     let non_empty_enum = match scrut_ty.kind() {
@@ -941,8 +966,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     if is_empty_match && !non_empty_enum {
         return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty {
             cx,
-            expr_span,
-            span: sp,
+            scrut_span: sp,
+            braces_span,
             ty: scrut_ty,
         });
     }
@@ -1028,7 +1053,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     let mut suggestion = None;
     let sm = cx.tcx.sess.source_map();
     match arms {
-        [] if sp.eq_ctxt(expr_span) => {
+        [] if let Some(braces_span) = braces_span => {
             // Get the span for the empty match body `{}`.
             let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
                 (format!("\n{snippet}"), "    ")
@@ -1036,7 +1061,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
                 (" ".to_string(), "")
             };
             suggestion = Some((
-                sp.shrink_to_hi().with_hi(expr_span.hi()),
+                braces_span,
                 format!(" {{{indentation}{more}{suggested_arm},{indentation}}}",),
             ));
         }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 18fb858c84c..012285e4644 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -860,6 +860,7 @@ impl<'a> Parser<'a> {
                     ExprKind::MethodCall(_) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_, _) => "`.await`",
+                    ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
                     ExprKind::Err(_) => return Ok(with_postfix),
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
                 }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index c051b818328..0cce5130f64 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1194,20 +1194,11 @@ impl<'a> Builder<'a> {
     }
 
     pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> Command {
-        let initial_sysroot_bin = self.initial_rustc.parent().unwrap();
-        // Set PATH to include the sysroot bin dir so clippy can find cargo.
-        // FIXME: once rust-clippy#11944 lands on beta, set `CARGO` directly instead.
-        let path = t!(env::join_paths(
-            // The sysroot comes first in PATH to avoid using rustup's cargo.
-            std::iter::once(PathBuf::from(initial_sysroot_bin))
-                .chain(env::split_paths(&t!(env::var("PATH"))))
-        ));
-
         if run_compiler.stage == 0 {
             // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
             let cargo_clippy = self.build.config.download_clippy();
             let mut cmd = Command::new(cargo_clippy);
-            cmd.env("PATH", &path);
+            cmd.env("CARGO", &self.initial_cargo);
             return cmd;
         }
 
@@ -1227,7 +1218,7 @@ impl<'a> Builder<'a> {
 
         let mut cmd = Command::new(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
-        cmd.env("PATH", path);
+        cmd.env("CARGO", &self.initial_cargo);
         cmd
     }
 
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 0f977640559..178df633cec 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -599,7 +599,6 @@ mod dist {
             pass: None,
             run: None,
             only_modified: false,
-            skip: vec![],
             extra_checks: None,
         };
 
@@ -664,7 +663,6 @@ mod dist {
             no_fail_fast: false,
             doc: true,
             no_doc: false,
-            skip: vec![],
             bless: false,
             force_rerun: false,
             compare_mode: None,
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 7262b785ee0..a66f743a1c5 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -339,9 +339,6 @@ pub enum Subcommand {
         #[arg(long)]
         /// run all tests regardless of failure
         no_fail_fast: bool,
-        #[arg(long, value_name = "SUBSTRING")]
-        /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times
-        skip: Vec<PathBuf>,
         #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
         /// extra arguments to be passed for the test tool being used
         /// (e.g. libtest, compiletest or rustdoc)
diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh
index 9755edb6dce..c9c85ec20b4 100755
--- a/src/ci/scripts/upload-artifacts.sh
+++ b/src/ci/scripts/upload-artifacts.sh
@@ -45,3 +45,17 @@ deploy_url="s3://${DEPLOY_BUCKET}/${deploy_dir}/$(ciCommit)"
 
 retry aws s3 cp --storage-class INTELLIGENT_TIERING \
     --no-progress --recursive --acl public-read "${upload_dir}" "${deploy_url}"
+
+access_url="https://ci-artifacts.rust-lang.org/${deploy_dir}/$(ciCommit)"
+
+# Output URLs to the uploaded artifacts to GitHub summary (if it is available)
+# to make them easily accessible.
+if [ -n "${GITHUB_STEP_SUMMARY}" ]
+then
+  echo "# CI artifacts" >> "${GITHUB_STEP_SUMMARY}"
+
+  for filename in "${upload_dir}"/*.xz; do
+    filename=`basename "${filename}"`
+    echo "- [${filename}](${access_url}/${filename})" >> "${GITHUB_STEP_SUMMARY}"
+  done
+fi
diff --git a/src/doc/unstable-book/src/compiler-flags/external-clangrt.md b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
new file mode 100644
index 00000000000..76b78d733e5
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/external-clangrt.md
@@ -0,0 +1,6 @@
+# `external-clangrt`
+
+This option controls whether the compiler links in its own runtime library for
+[sanitizers](./sanitizer.md). Passing this flag makes the compiler *not* link
+its own library. For more information, see the section in the sanitizers doc on
+[working with other languages.](./sanitizer.md#working-with-other-languages)
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index c8fd154a00e..72b44e002b4 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -45,6 +45,9 @@ To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
 `-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
 `-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
 `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
+If you're working with other languages that are also instrumented with sanitizers,
+you might need the `external-clangrt` flag. See the section on
+[working with other languages](#working-with-other-languages).
 
 Example:
 ```shell
@@ -853,6 +856,18 @@ functionality][build-std].
 
 [build-std]: ../../cargo/reference/unstable.html#build-std
 
+# Working with other languages
+
+Sanitizers rely on compiler runtime libraries to function properly. Rust links
+in its own compiler runtime which might conflict with runtimes required by
+languages such as C++. Since Rust's runtime doesn't always contain the symbols
+required by C++ instrumented code, you might need to skip linking it so another
+runtime can be linked instead.
+
+A separate unstable option `-Zexternal-clangrt` can be used to make rustc skip
+linking the compiler runtime for the sanitizer. This will require you to link
+in an external runtime, such as from clang instead.
+
 # Build scripts and procedural macros
 
 Use of sanitizers together with build scripts and procedural macros is
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 9fc95fd09ba..c95516494ae 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -261,7 +261,6 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-generate -
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d 'Enable BOLT link flags'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
 complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')'
-complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r
 complete -c x.py -n "__fish_seen_subcommand_from test" -l extra-checks -d 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)' -r
@@ -274,6 +273,7 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l build -d 'build target
 complete -c x.py -n "__fish_seen_subcommand_from test" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l exclude -d 'build paths to exclude' -r -F
+complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'build paths to skip' -r -F
 complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-error-format -r -f
 complete -c x.py -n "__fish_seen_subcommand_from test" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
 complete -c x.py -n "__fish_seen_subcommand_from test" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 6359b7ff086..8e505afaf75 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -333,7 +333,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             break
         }
         'x.py;test' {
-            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times')
             [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests')
             [CompletionResult]::new('--extra-checks', 'extra-checks', [CompletionResultType]::ParameterName, 'comma-separated list of other files types to check (accepts py, py:lint, py:fmt, shell)')
@@ -346,6 +345,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
+            [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip')
             [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format')
             [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure')
             [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index e1436dcde67..742f61f1622 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -1625,16 +1625,12 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
             fi
             case "${prev}" in
-                --skip)
-                    COMPREPLY=($(compgen -f "${cur}"))
-                    return 0
-                    ;;
                 --test-args)
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
@@ -1683,6 +1679,10 @@ _x.py() {
                     COMPREPLY=($(compgen -f "${cur}"))
                     return 0
                     ;;
+                --skip)
+                    COMPREPLY=($(compgen -f "${cur}"))
+                    return 0
+                    ;;
                 --rustc-error-format)
                     COMPREPLY=("${cur}")
                     return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index ea7e4ba6758..eec610629a1 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -335,7 +335,6 @@ _arguments "${_arguments_options[@]}" \
 ;;
 (test)
 _arguments "${_arguments_options[@]}" \
-'*--skip=[skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times]:SUBSTRING:_files' \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \
 '*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \
 '--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \
@@ -348,6 +347,7 @@ _arguments "${_arguments_options[@]}" \
 '--host=[host targets to build]:HOST:( )' \
 '--target=[target targets to build]:TARGET:( )' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
+'*--skip=[build paths to skip]:PATH:_files' \
 '--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \
 '--on-fail=[command to run on failure]:CMD:_cmdstring' \
 '--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \
diff --git a/tests/ui/match/postfix-match/match-after-as.rs b/tests/ui/match/postfix-match/match-after-as.rs
new file mode 100644
index 00000000000..7c648bfcf03
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.rs
@@ -0,0 +1,7 @@
+#![feature(postfix_match)]
+
+fn main() {
+    1 as i32.match {};
+    //~^ ERROR cast cannot be followed by a postfix match
+    //~| ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/match/postfix-match/match-after-as.stderr b/tests/ui/match/postfix-match/match-after-as.stderr
new file mode 100644
index 00000000000..68e4762b8d9
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.stderr
@@ -0,0 +1,28 @@
+error: cast cannot be followed by a postfix match
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+help: try surrounding the expression in parentheses
+   |
+LL |     (1 as i32).match {};
+   |     +        +
+
+error[E0004]: non-exhaustive patterns: type `i32` is non-empty
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     1 as i32.match {
+LL +         _ => todo!(),
+LL ~     };
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.