about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-27 07:54:44 +0000
committerbors <bors@rust-lang.org>2024-06-27 07:54:44 +0000
commit127fa2261b730a42e6d98b7927c3888ecd08f3e0 (patch)
tree4d5e70c87614e62e7b6ff51b5d376f95fbe257c1
parent536235f07e57c9108c6c3b1eacb323164e0f4cfb (diff)
parent73016dc8a41a494ddacf1b7e5b3b6a7852b3a74a (diff)
downloadrust-127fa2261b730a42e6d98b7927c3888ecd08f3e0.tar.gz
rust-127fa2261b730a42e6d98b7927c3888ecd08f3e0.zip
Auto merge of #127014 - jhpratt:rollup-45ic8f5, r=jhpratt
Rollup of 6 pull requests

Successful merges:

 - #126571 (Less `maybe_whole_expr`, take 2)
 - #126721 (coverage: Make `#[coverage(..)]` apply recursively to nested functions)
 - #126928 (Some `Nonterminal` removal precursors)
 - #126929 (Remove `__rust_force_expr`.)
 - #126980 (set self.is_known_utf8 to false in extend_from_slice)
 - #126983 (Remove `f16` and `f128` ICE paths from smir)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs9
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs17
-rw-r--r--compiler/rustc_expand/src/config.rs6
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs5
-rw-r--r--compiler/rustc_middle/src/query/mod.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs33
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs73
-rw-r--r--compiler/rustc_passes/src/check_attr.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs4
-rw-r--r--compiler/stable_mir/src/ty.rs2
-rw-r--r--library/alloc/src/macros.rs18
-rw-r--r--library/std/src/sys_common/wtf8.rs2
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs24
-rw-r--r--tests/coverage/attr/impl.cov-map24
-rw-r--r--tests/coverage/attr/impl.coverage42
-rw-r--r--tests/coverage/attr/impl.rs41
-rw-r--r--tests/coverage/attr/module.cov-map24
-rw-r--r--tests/coverage/attr/module.coverage38
-rw-r--r--tests/coverage/attr/module.rs37
-rw-r--r--tests/coverage/attr/nested.cov-map82
-rw-r--r--tests/coverage/attr/nested.coverage74
-rw-r--r--tests/coverage/attr/off-on-sandwich.cov-map8
-rw-r--r--tests/coverage/attr/off-on-sandwich.coverage10
-rw-r--r--tests/coverage/no_cov_crate.cov-map13
-rw-r--r--tests/coverage/no_cov_crate.coverage14
-rw-r--r--tests/ui/coverage-attr/name-value.rs4
-rw-r--r--tests/ui/coverage-attr/name-value.stderr87
-rw-r--r--tests/ui/coverage-attr/no-coverage.rs4
-rw-r--r--tests/ui/coverage-attr/no-coverage.stderr22
-rw-r--r--tests/ui/coverage-attr/word-only.rs4
-rw-r--r--tests/ui/coverage-attr/word-only.stderr87
-rw-r--r--tests/ui/macros/nonterminal-matching.rs30
-rw-r--r--tests/ui/macros/nonterminal-matching.stderr90
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.rs2
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.stderr7
37 files changed, 560 insertions, 399 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 676a2377c3b..593c78df3cd 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -327,7 +327,8 @@ impl MetaItem {
         I: Iterator<Item = &'a TokenTree>,
     {
         // FIXME: Share code with `parse_path`.
-        let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() {
+        let tt = tokens.next().map(|tt| TokenTree::uninterpolate(tt));
+        let path = match tt.as_deref() {
             Some(&TokenTree::Token(
                 Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
                 _,
@@ -368,6 +369,12 @@ impl MetaItem {
                 token::Nonterminal::NtPath(path) => (**path).clone(),
                 _ => return None,
             },
+            Some(TokenTree::Token(
+                Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. },
+                _,
+            )) => {
+                panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
+            }
             _ => return None,
         };
         let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 3d46415507d..b4ddbe20689 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -224,7 +224,7 @@ impl AttrTokenStream {
                                 // Inner attributes are only supported on extern blocks, functions,
                                 // impls, and modules. All of these have their inner attributes
                                 // placed at the beginning of the rightmost outermost braced group:
-                                // e.g. fn foo() { #![my_attr} }
+                                // e.g. fn foo() { #![my_attr] }
                                 //
                                 // Therefore, we can insert them back into the right location
                                 // without needing to do any extra position tracking.
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index fb71cdaa8ff..d224695d1f2 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -124,22 +124,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         .emit();
                 }
             }
-            sym::coverage => {
-                let inner = attr.meta_item_list();
-                match inner.as_deref() {
-                    Some([item]) if item.has_name(sym::off) => {
-                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
-                    }
-                    Some([item]) if item.has_name(sym::on) => {
-                        // Allow #[coverage(on)] for being explicit, maybe also in future to enable
-                        // coverage on a smaller scope within an excluded larger scope.
-                    }
-                    Some(_) | None => {
-                        tcx.dcx()
-                            .span_delayed_bug(attr.span, "unexpected value of coverage attribute");
-                    }
-                }
-            }
             sym::rustc_std_internal_symbol => {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
             }
@@ -584,7 +568,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     }
 
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
-        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
         codegen_fn_attrs.inline = InlineAttr::Never;
     }
 
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index badfa6d3aa3..56cbb54fcec 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -214,6 +214,12 @@ impl<'a> StripUnconfigured<'a> {
                 ) => {
                     panic!("Nonterminal should have been flattened: {:?}", tree);
                 }
+                AttrTokenTree::Token(
+                    Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. },
+                    _,
+                ) => {
+                    panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree);
+                }
                 AttrTokenTree::Token(token, spacing) => {
                     Some(AttrTokenTree::Token(token, spacing)).into_iter()
                 }
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 3fa5054baed..c8f0d0795a3 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -87,10 +87,7 @@ bitflags::bitflags! {
         /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
         /// function as an entry function from Non-Secure code.
         const CMSE_NONSECURE_ENTRY      = 1 << 13;
-        /// `#[coverage(off)]`: indicates that the function should be ignored by
-        /// the MIR `InstrumentCoverage` pass and not added to the coverage map
-        /// during codegen.
-        const NO_COVERAGE               = 1 << 14;
+        // (Bit 14 was used for `#[coverage(off)]`, but is now unused.)
         /// `#[used(linker)]`:
         /// indicates that neither LLVM nor the linker will eliminate this function.
         const USED_LINKER               = 1 << 15;
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c5afecffb07..230a44bcf24 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -572,6 +572,15 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    /// Checks for the nearest `#[coverage(off)]` or `#[coverage(on)]` on
+    /// this def and any enclosing defs, up to the crate root.
+    ///
+    /// Returns `false` if `#[coverage(off)]` was found, or `true` if
+    /// either `#[coverage(on)]` or no coverage attribute was found.
+    query coverage_attr_on(key: LocalDefId) -> bool {
+        desc { |tcx| "checking for `#[coverage(..)]` on `{}`", tcx.def_path_str(key) }
+    }
+
     /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
     /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
     /// have had a chance to potentially remove some of them.
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 25744009be8..1fce2abbbbf 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -6,11 +6,13 @@ use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::sym;
 
 /// Registers query/hook implementations related to coverage.
 pub(crate) fn provide(providers: &mut Providers) {
     providers.hooks.is_eligible_for_coverage =
         |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id);
+    providers.queries.coverage_attr_on = coverage_attr_on;
     providers.queries.coverage_ids_info = coverage_ids_info;
 }
 
@@ -38,7 +40,12 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         return false;
     }
 
-    if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+    if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NAKED) {
+        trace!("InstrumentCoverage skipped for {def_id:?} (`#[naked]`)");
+        return false;
+    }
+
+    if !tcx.coverage_attr_on(def_id) {
         trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
         return false;
     }
@@ -46,6 +53,30 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     true
 }
 
+/// Query implementation for `coverage_attr_on`.
+fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    // Check for annotations directly on this def.
+    if let Some(attr) = tcx.get_attr(def_id, sym::coverage) {
+        match attr.meta_item_list().as_deref() {
+            Some([item]) if item.has_name(sym::off) => return false,
+            Some([item]) if item.has_name(sym::on) => return true,
+            Some(_) | None => {
+                // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
+                tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute");
+            }
+        }
+    }
+
+    match tcx.opt_local_parent(def_id) {
+        // Check the parent def (and so on recursively) until we find an
+        // enclosing attribute or reach the crate root.
+        Some(parent) => tcx.coverage_attr_on(parent),
+        // We reached the crate root without seeing a coverage attribute, so
+        // allow coverage instrumentation by default.
+        None => true,
+    }
+}
+
 /// Query implementation for `coverage_ids_info`.
 fn coverage_ids_info<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9fad954adda..e0c70884fee 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -39,36 +39,6 @@ use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span};
 use thin_vec::{thin_vec, ThinVec};
 use tracing::instrument;
 
-/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
-/// dropped into the token stream, which happens while parsing the result of
-/// macro expansion). Placement of these is not as complex as I feared it would
-/// be. The important thing is to make sure that lookahead doesn't balk at
-/// `token::Interpolated` tokens.
-macro_rules! maybe_whole_expr {
-    ($p:expr) => {
-        if let token::Interpolated(nt) = &$p.token.kind {
-            match &**nt {
-                token::NtExpr(e) | token::NtLiteral(e) => {
-                    let e = e.clone();
-                    $p.bump();
-                    return Ok(e);
-                }
-                token::NtPath(path) => {
-                    let path = (**path).clone();
-                    $p.bump();
-                    return Ok($p.mk_expr($p.prev_token.span, ExprKind::Path(None, path)));
-                }
-                token::NtBlock(block) => {
-                    let block = block.clone();
-                    $p.bump();
-                    return Ok($p.mk_expr($p.prev_token.span, ExprKind::Block(block, None)));
-                }
-                _ => {}
-            };
-        }
-    };
-}
-
 #[derive(Debug)]
 pub(super) enum LhsExpr {
     // Already parsed just the outer attributes.
@@ -1421,7 +1391,27 @@ impl<'a> Parser<'a> {
     /// correctly if called from `parse_dot_or_call_expr()`.
     fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
-        maybe_whole_expr!(self);
+
+        if let token::Interpolated(nt) = &self.token.kind {
+            match &**nt {
+                token::NtExpr(e) | token::NtLiteral(e) => {
+                    let e = e.clone();
+                    self.bump();
+                    return Ok(e);
+                }
+                token::NtPath(path) => {
+                    let path = (**path).clone();
+                    self.bump();
+                    return Ok(self.mk_expr(self.prev_token.span, ExprKind::Path(None, path)));
+                }
+                token::NtBlock(block) => {
+                    let block = block.clone();
+                    self.bump();
+                    return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None)));
+                }
+                _ => {}
+            };
+        }
 
         // Outer attributes are already parsed and will be
         // added to the return value after the fact.
@@ -2190,7 +2180,26 @@ impl<'a> Parser<'a> {
     /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
     /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
     pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
-        maybe_whole_expr!(self);
+        if let token::Interpolated(nt) = &self.token.kind {
+            match &**nt {
+                // FIXME(nnethercote) The `NtExpr` case should only match if
+                // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing
+                // an `UnOp::Neg` and an `ExprKind::Lit`, like how
+                // `can_begin_literal_maybe_minus` works. But this method has
+                // been over-accepting for a long time, and to make that change
+                // here requires also changing some `parse_literal_maybe_minus`
+                // call sites to accept additional expression kinds. E.g.
+                // `ExprKind::Path` must be accepted when parsing range
+                // patterns. That requires some care. So for now, we continue
+                // being less strict here than we should be.
+                token::NtExpr(e) | token::NtLiteral(e) => {
+                    let e = e.clone();
+                    self.bump();
+                    return Ok(e);
+                }
+                _ => {}
+            };
+        }
 
         let lo = self.token.span;
         let minus_present = self.eat(&token::BinOp(token::Minus));
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d33f12a973f..5f8e4a8b7a7 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -369,13 +369,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    /// Checks that `#[coverage(..)]` is applied to a function or closure.
+    /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
+    /// or to an impl block or module.
     fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) -> bool {
         match target {
-            // #[coverage(..)] on function is fine
             Target::Fn
             | Target::Closure
-            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
+            | Target::Impl
+            | Target::Mod => true,
+
             _ => {
                 self.dcx().emit_err(errors::CoverageNotFnOrClosure {
                     attr_span: attr.span,
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index c9c1570a29a..7b5abcf4513 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -188,8 +188,10 @@ impl RustcInternal for FloatTy {
 
     fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
         match self {
+            FloatTy::F16 => rustc_ty::FloatTy::F16,
             FloatTy::F32 => rustc_ty::FloatTy::F32,
             FloatTy::F64 => rustc_ty::FloatTy::F64,
+            FloatTy::F128 => rustc_ty::FloatTy::F128,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 9cd841bba10..74c3fcc9b9e 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -304,10 +304,10 @@ impl<'tcx> Stable<'tcx> for ty::FloatTy {
 
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
         match self {
-            ty::FloatTy::F16 => unimplemented!("f16_f128"),
+            ty::FloatTy::F16 => FloatTy::F16,
             ty::FloatTy::F32 => FloatTy::F32,
             ty::FloatTy::F64 => FloatTy::F64,
-            ty::FloatTy::F128 => unimplemented!("f16_f128"),
+            ty::FloatTy::F128 => FloatTy::F128,
         }
     }
 }
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 8c120a96e75..01e4f1d1f33 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -608,8 +608,10 @@ impl UintTy {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum FloatTy {
+    F16,
     F32,
     F64,
+    F128,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 0f767df6063..d5ca5c4ed27 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -41,18 +41,18 @@
 #[allow_internal_unstable(rustc_attrs, liballoc_internals)]
 macro_rules! vec {
     () => (
-        $crate::__rust_force_expr!($crate::vec::Vec::new())
+        $crate::vec::Vec::new()
     );
     ($elem:expr; $n:expr) => (
-        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
+        $crate::vec::from_elem($elem, $n)
     );
     ($($x:expr),+ $(,)?) => (
-        $crate::__rust_force_expr!(<[_]>::into_vec(
+        <[_]>::into_vec(
             // This rustc_box is not required, but it produces a dramatic improvement in compile
             // time when constructing arrays with many elements.
             #[rustc_box]
             $crate::boxed::Box::new([$($x),+])
-        ))
+        )
     );
 }
 
@@ -126,13 +126,3 @@ macro_rules! format {
         res
     }}
 }
-
-/// Force AST node to an expression to improve diagnostics in pattern position.
-#[doc(hidden)]
-#[macro_export]
-#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
-macro_rules! __rust_force_expr {
-    ($e:expr) => {
-        $e
-    };
-}
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 708f62f476e..117a3e23044 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -480,7 +480,7 @@ impl Wtf8Buf {
     #[inline]
     pub(crate) fn extend_from_slice(&mut self, other: &[u8]) {
         self.bytes.extend_from_slice(other);
-        self.is_known_utf8 = self.is_known_utf8 || self.next_surrogate(0).is_none();
+        self.is_known_utf8 = false;
     }
 }
 
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index 6a1cc41a8fb..b57c99a8452 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -725,3 +725,27 @@ fn wtf8_utf8_boundary_between_surrogates() {
     string.push(CodePoint::from_u32(0xD800).unwrap());
     check_utf8_boundary(&string, 3);
 }
+
+#[test]
+fn wobbled_wtf8_plus_bytes_isnt_utf8() {
+    let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() };
+    assert!(!string.is_known_utf8);
+    string.extend_from_slice(b"some utf-8");
+    assert!(!string.is_known_utf8);
+}
+
+#[test]
+fn wobbled_wtf8_plus_str_isnt_utf8() {
+    let mut string: Wtf8Buf = unsafe { Wtf8::from_bytes_unchecked(b"\xED\xA0\x80").to_owned() };
+    assert!(!string.is_known_utf8);
+    string.push_str("some utf-8");
+    assert!(!string.is_known_utf8);
+}
+
+#[test]
+fn unwobbly_wtf8_plus_utf8_is_utf8() {
+    let mut string: Wtf8Buf = Wtf8Buf::from_str("hello world");
+    assert!(string.is_known_utf8);
+    string.push_str("some utf-8");
+    assert!(string.is_known_utf8);
+}
diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map
new file mode 100644
index 00000000000..9b0deed8b64
--- /dev/null
+++ b/tests/coverage/attr/impl.cov-map
@@ -0,0 +1,24 @@
+Function name: <impl::MyStruct>::off_on (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 05, 00, 13]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 14, 5) to (start + 0, 19)
+
+Function name: <impl::MyStruct>::on_inherit (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 05, 00, 17]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 22, 5) to (start + 0, 23)
+
+Function name: <impl::MyStruct>::on_on (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 12]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 25, 5) to (start + 0, 18)
+
diff --git a/tests/coverage/attr/impl.coverage b/tests/coverage/attr/impl.coverage
new file mode 100644
index 00000000000..560429fb5fe
--- /dev/null
+++ b/tests/coverage/attr/impl.coverage
@@ -0,0 +1,42 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks,
+   LL|       |// and is inherited by any enclosed functions.
+   LL|       |
+   LL|       |struct MyStruct;
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |impl MyStruct {
+   LL|       |    fn off_inherit() {}
+   LL|       |
+   LL|       |    #[coverage(on)]
+   LL|      0|    fn off_on() {}
+   LL|       |
+   LL|       |    #[coverage(off)]
+   LL|       |    fn off_off() {}
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(on)]
+   LL|       |impl MyStruct {
+   LL|      0|    fn on_inherit() {}
+   LL|       |
+   LL|       |    #[coverage(on)]
+   LL|      0|    fn on_on() {}
+   LL|       |
+   LL|       |    #[coverage(off)]
+   LL|       |    fn on_off() {}
+   LL|       |}
+   LL|       |
+   LL|       |trait MyTrait {
+   LL|       |    fn method();
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |impl MyTrait for MyStruct {
+   LL|       |    fn method() {}
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {}
+
diff --git a/tests/coverage/attr/impl.rs b/tests/coverage/attr/impl.rs
new file mode 100644
index 00000000000..d4d784a3502
--- /dev/null
+++ b/tests/coverage/attr/impl.rs
@@ -0,0 +1,41 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+
+// Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks,
+// and is inherited by any enclosed functions.
+
+struct MyStruct;
+
+#[coverage(off)]
+impl MyStruct {
+    fn off_inherit() {}
+
+    #[coverage(on)]
+    fn off_on() {}
+
+    #[coverage(off)]
+    fn off_off() {}
+}
+
+#[coverage(on)]
+impl MyStruct {
+    fn on_inherit() {}
+
+    #[coverage(on)]
+    fn on_on() {}
+
+    #[coverage(off)]
+    fn on_off() {}
+}
+
+trait MyTrait {
+    fn method();
+}
+
+#[coverage(off)]
+impl MyTrait for MyStruct {
+    fn method() {}
+}
+
+#[coverage(off)]
+fn main() {}
diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map
new file mode 100644
index 00000000000..34898eb4ca8
--- /dev/null
+++ b/tests/coverage/attr/module.cov-map
@@ -0,0 +1,24 @@
+Function name: module::off::on (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0c, 05, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 12, 5) to (start + 0, 15)
+
+Function name: module::on::inherit (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 14, 05, 00, 14]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 20, 5) to (start + 0, 20)
+
+Function name: module::on::on (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 0f]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 23, 5) to (start + 0, 15)
+
diff --git a/tests/coverage/attr/module.coverage b/tests/coverage/attr/module.coverage
new file mode 100644
index 00000000000..c1b9f0e35c0
--- /dev/null
+++ b/tests/coverage/attr/module.coverage
@@ -0,0 +1,38 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Checks that `#[coverage(..)]` can be applied to modules, and is inherited
+   LL|       |// by any enclosed functions.
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |mod off {
+   LL|       |    fn inherit() {}
+   LL|       |
+   LL|       |    #[coverage(on)]
+   LL|      0|    fn on() {}
+   LL|       |
+   LL|       |    #[coverage(off)]
+   LL|       |    fn off() {}
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(on)]
+   LL|       |mod on {
+   LL|      0|    fn inherit() {}
+   LL|       |
+   LL|       |    #[coverage(on)]
+   LL|      0|    fn on() {}
+   LL|       |
+   LL|       |    #[coverage(off)]
+   LL|       |    fn off() {}
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |mod nested_a {
+   LL|       |    mod nested_b {
+   LL|       |        fn inner() {}
+   LL|       |    }
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {}
+
diff --git a/tests/coverage/attr/module.rs b/tests/coverage/attr/module.rs
new file mode 100644
index 00000000000..4bfb1e7729b
--- /dev/null
+++ b/tests/coverage/attr/module.rs
@@ -0,0 +1,37 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+
+// Checks that `#[coverage(..)]` can be applied to modules, and is inherited
+// by any enclosed functions.
+
+#[coverage(off)]
+mod off {
+    fn inherit() {}
+
+    #[coverage(on)]
+    fn on() {}
+
+    #[coverage(off)]
+    fn off() {}
+}
+
+#[coverage(on)]
+mod on {
+    fn inherit() {}
+
+    #[coverage(on)]
+    fn on() {}
+
+    #[coverage(off)]
+    fn off() {}
+}
+
+#[coverage(off)]
+mod nested_a {
+    mod nested_b {
+        fn inner() {}
+    }
+}
+
+#[coverage(off)]
+fn main() {}
diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map
index a613bb7f8cd..0f2d5542f75 100644
--- a/tests/coverage/attr/nested.cov-map
+++ b/tests/coverage/attr/nested.cov-map
@@ -1,35 +1,3 @@
-Function name: <<<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method::MyInner as nested::MyTrait>::trait_method (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 39, 15, 02, 16]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 57, 21) to (start + 2, 22)
-
-Function name: <<<nested::MyOuter>::outer_method::MyMiddle>::middle_method::MyInner>::inner_method (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 15, 02, 16]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 35, 21) to (start + 2, 22)
-
-Function name: <<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 36, 0d, 08, 0e]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 54, 13) to (start + 8, 14)
-
-Function name: <<nested::MyOuter>::outer_method::MyMiddle>::middle_method (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 20, 0d, 08, 0e]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 32, 13) to (start + 8, 14)
-
 Function name: nested::closure_expr
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02]
 Number of files: 1
@@ -39,23 +7,6 @@ Number of file 0 mappings: 2
 - Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2)
 
-Function name: nested::closure_expr::{closure#0}::{closure#0} (unused)
-Raw bytes (14): 0x[01, 01, 00, 02, 00, 47, 1a, 01, 17, 00, 04, 0d, 01, 0a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Zero) at (prev + 71, 26) to (start + 1, 23)
-- Code(Zero) at (prev + 4, 13) to (start + 1, 10)
-
-Function name: nested::closure_expr::{closure#0}::{closure#0}::{closure#0} (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 48, 1d, 02, 0e]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 72, 29) to (start + 2, 14)
-
 Function name: nested::closure_tail
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02]
 Number of files: 1
@@ -65,36 +16,3 @@ Number of file 0 mappings: 2
 - Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2)
 
-Function name: nested::closure_tail::{closure#0}::{closure#0} (unused)
-Raw bytes (14): 0x[01, 01, 00, 02, 00, 58, 14, 01, 1f, 00, 06, 15, 01, 12]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Zero) at (prev + 88, 20) to (start + 1, 31)
-- Code(Zero) at (prev + 6, 21) to (start + 1, 18)
-
-Function name: nested::closure_tail::{closure#0}::{closure#0}::{closure#0} (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 1c, 02, 1a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 90, 28) to (start + 2, 26)
-
-Function name: nested::outer_fn::middle_fn (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 05, 05, 06]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 17, 5) to (start + 5, 6)
-
-Function name: nested::outer_fn::middle_fn::inner_fn (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 18, 9) to (start + 2, 10)
-
diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage
index 13129572aec..bdd117b7dfa 100644
--- a/tests/coverage/attr/nested.coverage
+++ b/tests/coverage/attr/nested.coverage
@@ -14,12 +14,12 @@
    LL|       |
    LL|       |#[coverage(off)]
    LL|       |fn outer_fn() {
-   LL|      0|    fn middle_fn() {
-   LL|      0|        fn inner_fn() {
-   LL|      0|            do_stuff();
-   LL|      0|        }
-   LL|      0|        do_stuff();
-   LL|      0|    }
+   LL|       |    fn middle_fn() {
+   LL|       |        fn inner_fn() {
+   LL|       |            do_stuff();
+   LL|       |        }
+   LL|       |        do_stuff();
+   LL|       |    }
    LL|       |    do_stuff();
    LL|       |}
    LL|       |
@@ -29,15 +29,15 @@
    LL|       |    fn outer_method(&self) {
    LL|       |        struct MyMiddle;
    LL|       |        impl MyMiddle {
-   LL|      0|            fn middle_method(&self) {
-   LL|      0|                struct MyInner;
-   LL|      0|                impl MyInner {
-   LL|      0|                    fn inner_method(&self) {
-   LL|      0|                        do_stuff();
-   LL|      0|                    }
-   LL|      0|                }
-   LL|      0|                do_stuff();
-   LL|      0|            }
+   LL|       |            fn middle_method(&self) {
+   LL|       |                struct MyInner;
+   LL|       |                impl MyInner {
+   LL|       |                    fn inner_method(&self) {
+   LL|       |                        do_stuff();
+   LL|       |                    }
+   LL|       |                }
+   LL|       |                do_stuff();
+   LL|       |            }
    LL|       |        }
    LL|       |        do_stuff();
    LL|       |    }
@@ -51,15 +51,15 @@
    LL|       |    fn trait_method(&self) {
    LL|       |        struct MyMiddle;
    LL|       |        impl MyTrait for MyMiddle {
-   LL|      0|            fn trait_method(&self) {
-   LL|      0|                struct MyInner;
-   LL|      0|                impl MyTrait for MyInner {
-   LL|      0|                    fn trait_method(&self) {
-   LL|      0|                        do_stuff();
-   LL|      0|                    }
-   LL|      0|                }
-   LL|      0|                do_stuff();
-   LL|      0|            }
+   LL|       |            fn trait_method(&self) {
+   LL|       |                struct MyInner;
+   LL|       |                impl MyTrait for MyInner {
+   LL|       |                    fn trait_method(&self) {
+   LL|       |                        do_stuff();
+   LL|       |                    }
+   LL|       |                }
+   LL|       |                do_stuff();
+   LL|       |            }
    LL|       |        }
    LL|       |        do_stuff();
    LL|       |    }
@@ -68,12 +68,12 @@
    LL|      1|fn closure_expr() {
    LL|      1|    let _outer = #[coverage(off)]
    LL|       |    || {
-   LL|      0|        let _middle = || {
-   LL|      0|            let _inner = || {
-   LL|      0|                do_stuff();
-   LL|      0|            };
-   LL|      0|            do_stuff();
-   LL|      0|        };
+   LL|       |        let _middle = || {
+   LL|       |            let _inner = || {
+   LL|       |                do_stuff();
+   LL|       |            };
+   LL|       |            do_stuff();
+   LL|       |        };
    LL|       |        do_stuff();
    LL|       |    };
    LL|      1|    do_stuff();
@@ -85,14 +85,14 @@
    LL|       |        #[coverage(off)]
    LL|       |        || {
    LL|       |            let _middle = {
-   LL|      0|                || {
-   LL|      0|                    let _inner = {
-   LL|      0|                        || {
-   LL|      0|                            do_stuff();
-   LL|      0|                        }
+   LL|       |                || {
+   LL|       |                    let _inner = {
+   LL|       |                        || {
+   LL|       |                            do_stuff();
+   LL|       |                        }
    LL|       |                    };
-   LL|      0|                    do_stuff();
-   LL|      0|                }
+   LL|       |                    do_stuff();
+   LL|       |                }
    LL|       |            };
    LL|       |            do_stuff();
    LL|       |        }
diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map
index 72b96420cb5..ed77d7d17e6 100644
--- a/tests/coverage/attr/off-on-sandwich.cov-map
+++ b/tests/coverage/attr/off-on-sandwich.cov-map
@@ -6,14 +6,6 @@ Number of expressions: 0
 Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6)
 
-Function name: off_on_sandwich::sparse_a::sparse_b
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 05, 10, 06]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 34, 5) to (start + 16, 6)
-
 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a]
 Number of files: 1
diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage
index e831b0e926e..58c128b8342 100644
--- a/tests/coverage/attr/off-on-sandwich.coverage
+++ b/tests/coverage/attr/off-on-sandwich.coverage
@@ -31,10 +31,10 @@
    LL|       |fn sparse_a() {
    LL|       |    sparse_b();
    LL|       |    sparse_b();
-   LL|      2|    fn sparse_b() {
-   LL|      2|        sparse_c();
-   LL|      2|        sparse_c();
-   LL|      2|        #[coverage(on)]
+   LL|       |    fn sparse_b() {
+   LL|       |        sparse_c();
+   LL|       |        sparse_c();
+   LL|       |        #[coverage(on)]
    LL|      4|        fn sparse_c() {
    LL|      4|            sparse_d();
    LL|      4|            sparse_d();
@@ -47,7 +47,7 @@
    LL|      8|                }
    LL|      8|            }
    LL|      4|        }
-   LL|      2|    }
+   LL|       |    }
    LL|       |}
    LL|       |
    LL|       |#[coverage(off)]
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
index e623f6480b9..281efb6d00d 100644
--- a/tests/coverage/no_cov_crate.cov-map
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -59,16 +59,3 @@ Number of file 0 mappings: 4
     = (c0 - c1)
 - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
-Function name: no_cov_crate::nested_fns::outer_not_covered::inner
-Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-Number of file 0 mappings: 4
-- Code(Counter(0)) at (prev + 38, 9) to (start + 1, 23)
-- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
-- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
-    = (c0 - c1)
-- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
-
diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage
index f5a0322bf3e..29ad1f979cf 100644
--- a/tests/coverage/no_cov_crate.coverage
+++ b/tests/coverage/no_cov_crate.coverage
@@ -35,13 +35,13 @@
    LL|       |mod nested_fns {
    LL|       |    #[coverage(off)]
    LL|       |    pub fn outer_not_covered(is_true: bool) {
-   LL|      1|        fn inner(is_true: bool) {
-   LL|      1|            if is_true {
-   LL|      1|                println!("called and covered");
-   LL|      1|            } else {
-   LL|      0|                println!("absolutely not covered");
-   LL|      0|            }
-   LL|      1|        }
+   LL|       |        fn inner(is_true: bool) {
+   LL|       |            if is_true {
+   LL|       |                println!("called and covered");
+   LL|       |            } else {
+   LL|       |                println!("absolutely not covered");
+   LL|       |            }
+   LL|       |        }
    LL|       |        println!("called but not covered");
    LL|       |        inner(is_true);
    LL|       |    }
diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs
index cfd78a03e43..24a0feb0710 100644
--- a/tests/ui/coverage-attr/name-value.rs
+++ b/tests/ui/coverage-attr/name-value.rs
@@ -10,13 +10,11 @@
 
 #[coverage = "off"]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 mod my_mod {}
 
 mod my_mod_inner {
     #![coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR attribute should be applied to a function definition or closure
 }
 
 #[coverage = "off"]
@@ -26,7 +24,6 @@ struct MyStruct;
 
 #[coverage = "off"]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 impl MyStruct {
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
@@ -51,7 +48,6 @@ trait MyTrait {
 
 #[coverage = "off"]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 impl MyTrait for MyStruct {
     #[coverage = "off"]
     //~^ ERROR malformed `coverage` attribute input
diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr
index caac687c94d..986467dda69 100644
--- a/tests/ui/coverage-attr/name-value.stderr
+++ b/tests/ui/coverage-attr/name-value.stderr
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:17:5
+  --> $DIR/name-value.rs:16:5
    |
 LL |     #![coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     #![coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:22:1
+  --> $DIR/name-value.rs:20:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:31:5
+  --> $DIR/name-value.rs:28:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:27:1
+  --> $DIR/name-value.rs:25:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:41:5
+  --> $DIR/name-value.rs:38:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:46:5
+  --> $DIR/name-value.rs:43:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:37:1
+  --> $DIR/name-value.rs:34:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:56:5
+  --> $DIR/name-value.rs:52:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -116,7 +116,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:61:5
+  --> $DIR/name-value.rs:57:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:52:1
+  --> $DIR/name-value.rs:49:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -142,7 +142,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:67:1
+  --> $DIR/name-value.rs:63:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -155,27 +155,7 @@ LL | #[coverage(on)]
    |
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:11:1
-   |
-LL | #[coverage = "off"]
-   | ^^^^^^^^^^^^^^^^^^^
-...
-LL | mod my_mod {}
-   | ------------- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:17:5
-   |
-LL | / mod my_mod_inner {
-LL | |     #![coverage = "off"]
-   | |     ^^^^^^^^^^^^^^^^^^^^
-LL | |
-LL | |
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:22:1
+  --> $DIR/name-value.rs:20:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -184,21 +164,7 @@ LL | struct MyStruct;
    | ---------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:27:1
-   |
-LL |   #[coverage = "off"]
-   |   ^^^^^^^^^^^^^^^^^^^
-...
-LL | / impl MyStruct {
-LL | |     #[coverage = "off"]
-LL | |
-LL | |
-LL | |     const X: u32 = 7;
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:37:1
+  --> $DIR/name-value.rs:34:1
    |
 LL |   #[coverage = "off"]
    |   ^^^^^^^^^^^^^^^^^^^
@@ -213,22 +179,7 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:52:1
-   |
-LL |   #[coverage = "off"]
-   |   ^^^^^^^^^^^^^^^^^^^
-...
-LL | / impl MyTrait for MyStruct {
-LL | |     #[coverage = "off"]
-LL | |
-LL | |
-...  |
-LL | |     type T = ();
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:41:5
+  --> $DIR/name-value.rs:38:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -237,7 +188,7 @@ LL |     const X: u32;
    |     ------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:46:5
+  --> $DIR/name-value.rs:43:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -246,7 +197,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:31:5
+  --> $DIR/name-value.rs:28:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -255,7 +206,7 @@ LL |     const X: u32 = 7;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:56:5
+  --> $DIR/name-value.rs:52:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -264,7 +215,7 @@ LL |     const X: u32 = 8;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:61:5
+  --> $DIR/name-value.rs:57:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -272,6 +223,6 @@ LL |     #[coverage = "off"]
 LL |     type T = ();
    |     ------------ not a function or closure
 
-error: aborting due to 23 previous errors
+error: aborting due to 19 previous errors
 
 For more information about this error, try `rustc --explain E0788`.
diff --git a/tests/ui/coverage-attr/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs
index 5290fccca61..9545b0b55cf 100644
--- a/tests/ui/coverage-attr/no-coverage.rs
+++ b/tests/ui/coverage-attr/no-coverage.rs
@@ -2,7 +2,7 @@
 #![feature(coverage_attribute)]
 #![feature(impl_trait_in_assoc_type)]
 #![warn(unused_attributes)]
-#![coverage(off)] //~ ERROR attribute should be applied to a function definition or closure
+#![coverage(off)]
 
 #[coverage(off)] //~ ERROR attribute should be applied to a function definition or closure
 trait Trait {
@@ -15,7 +15,7 @@ trait Trait {
     type U;
 }
 
-#[coverage(off)] //~ ERROR attribute should be applied to a function definition or closure
+#[coverage(off)]
 impl Trait for () {
     const X: u32 = 0;
 
diff --git a/tests/ui/coverage-attr/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr
index c5e3b0922cb..3897d295940 100644
--- a/tests/ui/coverage-attr/no-coverage.stderr
+++ b/tests/ui/coverage-attr/no-coverage.stderr
@@ -12,20 +12,6 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:18:1
-   |
-LL |   #[coverage(off)]
-   |   ^^^^^^^^^^^^^^^^
-LL | / impl Trait for () {
-LL | |     const X: u32 = 0;
-LL | |
-LL | |     #[coverage(off)]
-...  |
-LL | |     type U = impl Trait;
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
   --> $DIR/no-coverage.rs:39:5
    |
 LL |     #[coverage(off)]
@@ -97,12 +83,6 @@ LL |     #[coverage(off)]
 LL |     type T;
    |     ------- not a function or closure
 
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:5:1
-   |
-LL | #![coverage(off)]
-   | ^^^^^^^^^^^^^^^^^ not a function or closure
-
 error: unconstrained opaque type
   --> $DIR/no-coverage.rs:26:14
    |
@@ -111,6 +91,6 @@ LL |     type U = impl Trait;
    |
    = note: `U` must be used in combination with a concrete type within the same impl
 
-error: aborting due to 13 previous errors
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0788`.
diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs
index 0a61d1e709f..ea12e7b19ee 100644
--- a/tests/ui/coverage-attr/word-only.rs
+++ b/tests/ui/coverage-attr/word-only.rs
@@ -10,13 +10,11 @@
 
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 mod my_mod {}
 
 mod my_mod_inner {
     #![coverage]
     //~^ ERROR malformed `coverage` attribute input
-    //~| ERROR attribute should be applied to a function definition or closure
 }
 
 #[coverage]
@@ -26,7 +24,6 @@ struct MyStruct;
 
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 impl MyStruct {
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
@@ -51,7 +48,6 @@ trait MyTrait {
 
 #[coverage]
 //~^ ERROR malformed `coverage` attribute input
-//~| ERROR attribute should be applied to a function definition or closure
 impl MyTrait for MyStruct {
     #[coverage]
     //~^ ERROR malformed `coverage` attribute input
diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr
index 18b5fed7484..1ce149724c6 100644
--- a/tests/ui/coverage-attr/word-only.stderr
+++ b/tests/ui/coverage-attr/word-only.stderr
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:17:5
+  --> $DIR/word-only.rs:16:5
    |
 LL |     #![coverage]
    |     ^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     #![coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:22:1
+  --> $DIR/word-only.rs:20:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:31:5
+  --> $DIR/word-only.rs:28:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:27:1
+  --> $DIR/word-only.rs:25:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:41:5
+  --> $DIR/word-only.rs:38:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:46:5
+  --> $DIR/word-only.rs:43:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:37:1
+  --> $DIR/word-only.rs:34:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:56:5
+  --> $DIR/word-only.rs:52:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -116,7 +116,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:61:5
+  --> $DIR/word-only.rs:57:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:52:1
+  --> $DIR/word-only.rs:49:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -142,7 +142,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:67:1
+  --> $DIR/word-only.rs:63:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -155,27 +155,7 @@ LL | #[coverage(on)]
    |
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:11:1
-   |
-LL | #[coverage]
-   | ^^^^^^^^^^^
-...
-LL | mod my_mod {}
-   | ------------- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:17:5
-   |
-LL | / mod my_mod_inner {
-LL | |     #![coverage]
-   | |     ^^^^^^^^^^^^
-LL | |
-LL | |
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:22:1
+  --> $DIR/word-only.rs:20:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -184,21 +164,7 @@ LL | struct MyStruct;
    | ---------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:27:1
-   |
-LL |   #[coverage]
-   |   ^^^^^^^^^^^
-...
-LL | / impl MyStruct {
-LL | |     #[coverage]
-LL | |
-LL | |
-LL | |     const X: u32 = 7;
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:37:1
+  --> $DIR/word-only.rs:34:1
    |
 LL |   #[coverage]
    |   ^^^^^^^^^^^
@@ -213,22 +179,7 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:52:1
-   |
-LL |   #[coverage]
-   |   ^^^^^^^^^^^
-...
-LL | / impl MyTrait for MyStruct {
-LL | |     #[coverage]
-LL | |
-LL | |
-...  |
-LL | |     type T = ();
-LL | | }
-   | |_- not a function or closure
-
-error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:41:5
+  --> $DIR/word-only.rs:38:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -237,7 +188,7 @@ LL |     const X: u32;
    |     ------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:46:5
+  --> $DIR/word-only.rs:43:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -246,7 +197,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:31:5
+  --> $DIR/word-only.rs:28:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -255,7 +206,7 @@ LL |     const X: u32 = 7;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:56:5
+  --> $DIR/word-only.rs:52:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -264,7 +215,7 @@ LL |     const X: u32 = 8;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:61:5
+  --> $DIR/word-only.rs:57:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -272,6 +223,6 @@ LL |     #[coverage]
 LL |     type T = ();
    |     ------------ not a function or closure
 
-error: aborting due to 23 previous errors
+error: aborting due to 19 previous errors
 
 For more information about this error, try `rustc --explain E0788`.
diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs
index 84fffe44d6a..5f0d6b2f90e 100644
--- a/tests/ui/macros/nonterminal-matching.rs
+++ b/tests/ui/macros/nonterminal-matching.rs
@@ -23,4 +23,34 @@ simple_nonterminal!(a, 'a, (x, y, z)); // OK
 
 complex_nonterminal!(enum E {});
 
+// `ident`, `lifetime`, and `tt` all work. Other fragments do not. See
+// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
+macro_rules! foo {
+    (ident $x:ident) => { bar!(ident $x); };
+    (lifetime $x:lifetime) => { bar!(lifetime $x); };
+    (tt $x:tt) => { bar!(tt $x); };
+    (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3`
+    (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4`
+    (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c`
+    (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0`
+}
+
+macro_rules! bar {
+    (ident abc) => {};
+    (lifetime 'abc) => {};
+    (tt 2) => {};
+    (expr 3) => {};
+    (literal 4) => {};
+    (path a::b::c) => {};
+    (stmt let abc = 0) => {};
+}
+
+foo!(ident abc);
+foo!(lifetime 'abc);
+foo!(tt 2);
+foo!(expr 3);
+foo!(literal 4);
+foo!(path a::b::c);
+foo!(stmt let abc = 0);
+
 fn main() {}
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
index d19141145fa..3ee88b5f52e 100644
--- a/tests/ui/macros/nonterminal-matching.stderr
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -23,5 +23,93 @@ LL | complex_nonterminal!(enum E {});
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 1 previous error
+error: no rules expected the token `3`
+  --> $DIR/nonterminal-matching.rs:32:35
+   |
+LL |     (expr $x:expr) => { bar!(expr $x); };
+   |                                   ^^ no rules expected this token in macro call
+...
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL | foo!(expr 3);
+   | ------------ in this macro invocation
+   |
+note: while trying to match `3`
+  --> $DIR/nonterminal-matching.rs:42:11
+   |
+LL |     (expr 3) => {};
+   |           ^
+   = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
+   = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
+   = help: try using `:tt` instead in the macro definition
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: no rules expected the token `4`
+  --> $DIR/nonterminal-matching.rs:33:44
+   |
+LL |     (literal $x:literal) => { bar!(literal $x); };
+   |                                            ^^ no rules expected this token in macro call
+...
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL | foo!(literal 4);
+   | --------------- in this macro invocation
+   |
+note: while trying to match `4`
+  --> $DIR/nonterminal-matching.rs:43:14
+   |
+LL |     (literal 4) => {};
+   |              ^
+   = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
+   = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
+   = help: try using `:tt` instead in the macro definition
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: no rules expected the token `a::b::c`
+  --> $DIR/nonterminal-matching.rs:34:35
+   |
+LL |     (path $x:path) => { bar!(path $x); };
+   |                                   ^^ no rules expected this token in macro call
+...
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL | foo!(path a::b::c);
+   | ------------------ in this macro invocation
+   |
+note: while trying to match `a`
+  --> $DIR/nonterminal-matching.rs:44:11
+   |
+LL |     (path a::b::c) => {};
+   |           ^
+   = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
+   = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
+   = help: try using `:tt` instead in the macro definition
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: no rules expected the token `let abc = 0`
+  --> $DIR/nonterminal-matching.rs:35:35
+   |
+LL |     (stmt $x:stmt) => { bar!(stmt $x); };
+   |                                   ^^ no rules expected this token in macro call
+...
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL | foo!(stmt let abc = 0);
+   | ---------------------- in this macro invocation
+   |
+note: while trying to match `let`
+  --> $DIR/nonterminal-matching.rs:45:11
+   |
+LL |     (stmt let abc = 0) => {};
+   |           ^^^
+   = note: captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens
+   = note: see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information
+   = help: try using `:tt` instead in the macro definition
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs
index ce4298b8bb3..26d7d4280fa 100644
--- a/tests/ui/macros/vec-macro-in-pattern.rs
+++ b/tests/ui/macros/vec-macro-in-pattern.rs
@@ -4,7 +4,7 @@
 
 fn main() {
     match Some(vec![42]) {
-        Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns
+        Some(vec![43]) => {} //~ ERROR expected pattern, found `#`
         _ => {}
     }
 }
diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr
index 1a446b8c3ed..f32a2cf8e43 100644
--- a/tests/ui/macros/vec-macro-in-pattern.stderr
+++ b/tests/ui/macros/vec-macro-in-pattern.stderr
@@ -1,10 +1,13 @@
-error: arbitrary expressions aren't allowed in patterns
+error: expected pattern, found `#`
   --> $DIR/vec-macro-in-pattern.rs:7:14
    |
 LL |         Some(vec![43]) => {}
    |              ^^^^^^^^
+   |              |
+   |              expected pattern
+   |              in this macro invocation
+   |              this macro call doesn't expand to a pattern
    |
-   = note: the `expr` fragment specifier forces the metavariable's content to be an expression
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error