From aa30dd444b00248065d9c286527bf9168c9cfb4b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 May 2024 15:23:49 +1000 Subject: [PATCH 01/11] Fix a typo in a comment. --- compiler/rustc_ast/src/tokenstream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From bca5cd3a9dccc166e936b21eb86e6a58d3f4b84e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Jun 2024 14:14:58 +1000 Subject: [PATCH 02/11] Extend `tests/ui/macros/nonterminal-matching.rs`. To involve `macro_rules!` macros, and also a mix of fragment specifiers, some of which feature the forwaring limitation and some of which don't. --- tests/ui/macros/nonterminal-matching.rs | 30 +++++++ tests/ui/macros/nonterminal-matching.stderr | 90 ++++++++++++++++++++- 2 files changed, 119 insertions(+), 1 deletion(-) 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 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 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 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 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 From 2e4d547d4a862aafd9b9b8382a1bbcde1a4c0d32 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 15 May 2024 09:29:11 +1000 Subject: [PATCH 03/11] Extra panic cases. Just some extra sanity checking, making explicit some values not possible in code working with token trees -- we shouldn't be seeing explicit delimiter tokens, because they should be represented as `TokenTree::Delimited`. --- compiler/rustc_ast/src/attr/mod.rs | 9 ++++++++- compiler/rustc_expand/src/config.rs | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) 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, { // 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_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() } From 9828e960ab4cccc9526fd6cc61df430588bd0487 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 23 Jun 2024 16:12:39 +1000 Subject: [PATCH 04/11] Remove `__rust_force_expr`. This was added (with a different name) to improve an error message. It is no longer needed -- removing it changes the error message, but overall I think the new message is no worse: - the mention of `#` in the first line is a little worse, - but the extra context makes it very clear what the problem is, perhaps even clearer than the old message, - and the removal of the note about the `expr` fragment (an internal detail of `__rust_force_expr`) is an improvement. Overall I think the error is quite clear and still far better than the old message that prompted #61933, which didn't even mention patterns. The motivation for this is #124141, which will cause pasted metavariables to be tokenized and reparsed instead of the AST node being cached. This change in behaviour occasionally has a non-zero perf cost, and `__rust_force_expr` causes the tokenize/reparse step to occur twice. Removing `__rust_force_expr` greatly reduces the extra overhead for the `deep-vector` benchmark. --- library/alloc/src/macros.rs | 18 ++++-------------- tests/ui/macros/vec-macro-in-pattern.rs | 2 +- tests/ui/macros/vec-macro-in-pattern.stderr | 7 +++++-- 3 files changed, 10 insertions(+), 17 deletions(-) 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/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 From 379b7614627b3a917a5f459388f95c4fb55c39ad Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Jun 2024 14:44:55 +1000 Subject: [PATCH 05/11] Inline and remove `maybe_whole_expr!`. And remove the `NtPath` and `NtBlock` cases in `parse_literal_maybe_minus`, because they are unnecessary. --- compiler/rustc_parse/src/parser/expr.rs | 73 ++++++++++++++----------- 1 file changed, 41 insertions(+), 32 deletions(-) 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> { 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> { - 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)); From 457fda1701e191d9ff439d9d01ee650e6bbefee6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 20 Jun 2024 10:49:40 +1000 Subject: [PATCH 06/11] coverage: Detach `#[coverage(..)]` from codegen attribute handling --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 17 ------------ .../src/middle/codegen_fn_attrs.rs | 5 +--- compiler/rustc_middle/src/query/mod.rs | 8 ++++++ .../rustc_mir_transform/src/coverage/query.rs | 27 ++++++++++++++++++- 4 files changed, 35 insertions(+), 22 deletions(-) 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_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..320e21e85da 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -572,6 +572,14 @@ rustc_queries! { separate_provide_extern } + /// Checks for `#[coverage(off)]` or `#[coverage(on)]`. + /// + /// 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..14dcb7ef424 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,24 @@ 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 { + 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"); + } + } + } + + // We didn't see an explicit coverage attribute, so + // allow coverage instrumentation by default. + true +} + /// Query implementation for `coverage_ids_info`. fn coverage_ids_info<'tcx>( tcx: TyCtxt<'tcx>, From 3262611cc5db7ce83dee4268fb1901311b24e5fc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 22 Jun 2024 16:34:24 +1000 Subject: [PATCH 07/11] coverage: Apply `#[coverage(..)]` recursively to nested functions --- compiler/rustc_middle/src/query/mod.rs | 3 +- .../rustc_mir_transform/src/coverage/query.rs | 12 ++- tests/coverage/attr/nested.cov-map | 82 ------------------- tests/coverage/attr/nested.coverage | 74 ++++++++--------- tests/coverage/attr/off-on-sandwich.cov-map | 8 -- tests/coverage/attr/off-on-sandwich.coverage | 10 +-- tests/coverage/no_cov_crate.cov-map | 13 --- tests/coverage/no_cov_crate.coverage | 14 ++-- 8 files changed, 60 insertions(+), 156 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 320e21e85da..230a44bcf24 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -572,7 +572,8 @@ rustc_queries! { separate_provide_extern } - /// Checks for `#[coverage(off)]` or `#[coverage(on)]`. + /// 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. diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 14dcb7ef424..1fce2abbbbf 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -55,6 +55,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// 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, @@ -66,9 +67,14 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { } } - // We didn't see an explicit coverage attribute, so - // allow coverage instrumentation by default. - true + 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`. 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: <<::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: <<::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: <::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: <::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| | } From 7f37f8af5f067e0f4f8d14adb7d76f013e3c4118 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 21 Jun 2024 21:59:02 +1000 Subject: [PATCH 08/11] coverage: Allow `#[coverage(..)]` on `impl` and `mod` These attributes apply to all enclosed functions/methods/closures, unless explicitly overridden by another coverage attribute. --- compiler/rustc_passes/src/check_attr.rs | 9 ++- tests/coverage/attr/impl.cov-map | 24 +++++++ tests/coverage/attr/impl.coverage | 42 +++++++++++ tests/coverage/attr/impl.rs | 41 +++++++++++ tests/coverage/attr/module.cov-map | 24 +++++++ tests/coverage/attr/module.coverage | 38 ++++++++++ tests/coverage/attr/module.rs | 37 ++++++++++ tests/ui/coverage-attr/name-value.rs | 4 -- tests/ui/coverage-attr/name-value.stderr | 87 +++++------------------ tests/ui/coverage-attr/no-coverage.rs | 4 +- tests/ui/coverage-attr/no-coverage.stderr | 22 +----- tests/ui/coverage-attr/word-only.rs | 4 -- tests/ui/coverage-attr/word-only.stderr | 87 +++++------------------ 13 files changed, 253 insertions(+), 170 deletions(-) create mode 100644 tests/coverage/attr/impl.cov-map create mode 100644 tests/coverage/attr/impl.coverage create mode 100644 tests/coverage/attr/impl.rs create mode 100644 tests/coverage/attr/module.cov-map create mode 100644 tests/coverage/attr/module.coverage create mode 100644 tests/coverage/attr/module.rs 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/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: ::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: ::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: ::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/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 @@ -11,20 +11,6 @@ LL | | type U; 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 | @@ -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`. From e5167fe7bd52a8eaebbf01d0b1469785306f4a96 Mon Sep 17 00:00:00 2001 From: ash <97464181+Borgerr@users.noreply.github.com> Date: Tue, 25 Jun 2024 23:58:43 -0600 Subject: [PATCH 09/11] set self.is_known_utf8 to false in extend_from_slice --- library/std/src/sys_common/wtf8.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } } From 5aac24909c321dd4bb8d90380f9b2dd9f0162c68 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 25 Jun 2024 22:29:37 -0700 Subject: [PATCH 10/11] std: test a variety of ways to extend a Wtf8Buf --- library/std/src/sys_common/wtf8/tests.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) 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); +} From 518b74ec5d97317af70d3fdbc41eac903622a6b9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 04:09:38 -0400 Subject: [PATCH 11/11] Remove `f16` and `f128` ICE paths from smir --- compiler/rustc_smir/src/rustc_internal/internal.rs | 2 ++ compiler/rustc_smir/src/rustc_smir/convert/ty.rs | 4 ++-- compiler/stable_mir/src/ty.rs | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) 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)]