Skip to content

Commit 6682d90

Browse files
authored
Rollup merge of rust-lang#143891 - scrabsha:push-xxtttopqoprr, r=jdonszelmann
Port `#[coverage]` to the new attribute system r? ````@jdonszelmann````
2 parents b8518e7 + 4e054fc commit 6682d90

File tree

17 files changed

+377
-405
lines changed

17 files changed

+377
-405
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,22 @@ pub enum DeprecatedSince {
110110
Err,
111111
}
112112

113+
#[derive(
114+
Copy,
115+
Debug,
116+
Eq,
117+
PartialEq,
118+
Encodable,
119+
Decodable,
120+
Clone,
121+
HashStable_Generic,
122+
PrintAttribute
123+
)]
124+
pub enum CoverageStatus {
125+
On,
126+
Off,
127+
}
128+
113129
impl Deprecation {
114130
/// Whether an item marked with #[deprecated(since = "X")] is currently
115131
/// deprecated (i.e., whether X is not greater than the current rustc
@@ -274,6 +290,9 @@ pub enum AttributeKind {
274290
/// Represents `#[const_trait]`.
275291
ConstTrait(Span),
276292

293+
/// Represents `#[coverage]`.
294+
Coverage(Span, CoverageStatus),
295+
277296
///Represents `#[rustc_deny_explicit_impl]`.
278297
DenyExplicitImpl(Span),
279298

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ impl AttributeKind {
2828
ConstStability { .. } => Yes,
2929
ConstStabilityIndirect => No,
3030
ConstTrait(..) => No,
31+
Coverage(..) => No,
3132
DenyExplicitImpl(..) => No,
3233
Deprecation { .. } => Yes,
3334
DoNotImplementViaObject(..) => No,

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
1+
use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
22
use rustc_feature::{AttributeTemplate, template};
33
use rustc_session::parse::feature_err;
44
use rustc_span::{Span, Symbol, sym};
@@ -52,6 +52,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
5252
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
5353
}
5454

55+
pub(crate) struct CoverageParser;
56+
57+
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
58+
const PATH: &[Symbol] = &[sym::coverage];
59+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
60+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
61+
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
62+
63+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
64+
let Some(args) = args.list() else {
65+
cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
66+
return None;
67+
};
68+
69+
let Some(arg) = args.single() else {
70+
cx.expected_single_argument(args.span);
71+
return None;
72+
};
73+
74+
let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
75+
76+
let Some(arg) = arg.meta_item() else {
77+
fail_incorrect_argument(args.span);
78+
return None;
79+
};
80+
81+
let status = match arg.path().word_sym() {
82+
Some(sym::off) => CoverageStatus::Off,
83+
Some(sym::on) => CoverageStatus::On,
84+
None | Some(_) => {
85+
fail_incorrect_argument(arg.span());
86+
return None;
87+
}
88+
};
89+
90+
Some(AttributeKind::Coverage(cx.attr_span, status))
91+
}
92+
}
93+
5594
pub(crate) struct ExportNameParser;
5695

5796
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use crate::attributes::allow_unstable::{
1717
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
1818
};
1919
use crate::attributes::codegen_attrs::{
20-
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
21-
OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
20+
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
21+
OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
22+
UsedParser,
2223
};
2324
use crate::attributes::confusables::ConfusablesParser;
2425
use crate::attributes::deprecation::DeprecationParser;
@@ -139,6 +140,7 @@ attribute_parsers!(
139140
// tidy-alphabetical-end
140141

141142
// tidy-alphabetical-start
143+
Single<CoverageParser>,
142144
Single<DeprecationParser>,
143145
Single<DummyParser>,
144146
Single<ExportNameParser>,
@@ -452,6 +454,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
452454
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
453455
possibilities,
454456
strings: false,
457+
list: false,
458+
},
459+
})
460+
}
461+
462+
pub(crate) fn expected_specific_argument_and_list(
463+
&self,
464+
span: Span,
465+
possibilities: Vec<&'static str>,
466+
) -> ErrorGuaranteed {
467+
self.emit_err(AttributeParseError {
468+
span,
469+
attr_span: self.attr_span,
470+
template: self.template.clone(),
471+
attribute: self.attr_path.clone(),
472+
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
473+
possibilities,
474+
strings: false,
475+
list: true,
455476
},
456477
})
457478
}
@@ -469,6 +490,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
469490
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
470491
possibilities,
471492
strings: true,
493+
list: false,
472494
},
473495
})
474496
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -533,15 +533,22 @@ pub(crate) struct LinkOrdinalOutOfRange {
533533

534534
pub(crate) enum AttributeParseErrorReason {
535535
ExpectedNoArgs,
536-
ExpectedStringLiteral { byte_string: Option<Span> },
536+
ExpectedStringLiteral {
537+
byte_string: Option<Span>,
538+
},
537539
ExpectedIntegerLiteral,
538540
ExpectedAtLeastOneArgument,
539541
ExpectedSingleArgument,
540542
ExpectedList,
541543
UnexpectedLiteral,
542544
ExpectedNameValue(Option<Symbol>),
543545
DuplicateKey(Symbol),
544-
ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
546+
ExpectedSpecificArgument {
547+
possibilities: Vec<&'static str>,
548+
strings: bool,
549+
/// Should we tell the user to write a list when they didn't?
550+
list: bool,
551+
},
545552
}
546553

547554
pub(crate) struct AttributeParseError {
@@ -615,7 +622,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
615622
format!("expected this to be of the form `{name} = \"...\"`"),
616623
);
617624
}
618-
AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
625+
AttributeParseErrorReason::ExpectedSpecificArgument {
626+
possibilities,
627+
strings,
628+
list: false,
629+
} => {
619630
let quote = if strings { '"' } else { '`' };
620631
match possibilities.as_slice() {
621632
&[] => {}
@@ -641,6 +652,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
641652
}
642653
}
643654
}
655+
AttributeParseErrorReason::ExpectedSpecificArgument {
656+
possibilities,
657+
strings,
658+
list: true,
659+
} => {
660+
let quote = if strings { '"' } else { '`' };
661+
match possibilities.as_slice() {
662+
&[] => {}
663+
&[x] => {
664+
diag.span_label(
665+
self.span,
666+
format!(
667+
"this attribute is only valid with {quote}{x}{quote} as an argument"
668+
),
669+
);
670+
}
671+
[first, second] => {
672+
diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
673+
}
674+
[first @ .., second_to_last, last] => {
675+
let mut res = String::new();
676+
for i in first {
677+
res.push_str(&format!("{quote}{i}{quote}, "));
678+
}
679+
res.push_str(&format!(
680+
"{quote}{second_to_last}{quote} or {quote}{last}{quote}"
681+
));
682+
683+
diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}"));
684+
}
685+
}
686+
}
644687
}
645688

646689
let suggestions = self.template.suggestions(false, &name);

compiler/rustc_mir_transform/src/coverage/query.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
use rustc_attr_data_structures::{AttributeKind, CoverageStatus, find_attr};
12
use rustc_index::bit_set::DenseBitSet;
23
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
34
use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind};
45
use rustc_middle::mir::{Body, Statement, StatementKind};
56
use rustc_middle::ty::{self, TyCtxt};
67
use rustc_middle::util::Providers;
78
use rustc_span::def_id::LocalDefId;
8-
use rustc_span::sym;
99
use tracing::trace;
1010

1111
use crate::coverage::counters::node_flow::make_node_counters;
@@ -58,26 +58,20 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
5858
/// Query implementation for `coverage_attr_on`.
5959
fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
6060
// Check for annotations directly on this def.
61-
if let Some(attr) = tcx.get_attr(def_id, sym::coverage) {
62-
match attr.meta_item_list().as_deref() {
63-
Some([item]) if item.has_name(sym::off) => return false,
64-
Some([item]) if item.has_name(sym::on) => return true,
65-
Some(_) | None => {
66-
// Other possibilities should have been rejected by `rustc_parse::validate_attr`.
67-
// Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
68-
tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute");
69-
}
61+
if let Some(coverage_status) =
62+
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Coverage(_, status) => status)
63+
{
64+
*coverage_status == CoverageStatus::On
65+
} else {
66+
match tcx.opt_local_parent(def_id) {
67+
// Check the parent def (and so on recursively) until we find an
68+
// enclosing attribute or reach the crate root.
69+
Some(parent) => tcx.coverage_attr_on(parent),
70+
// We reached the crate root without seeing a coverage attribute, so
71+
// allow coverage instrumentation by default.
72+
None => true,
7073
}
7174
}
72-
73-
match tcx.opt_local_parent(def_id) {
74-
// Check the parent def (and so on recursively) until we find an
75-
// enclosing attribute or reach the crate root.
76-
Some(parent) => tcx.coverage_attr_on(parent),
77-
// We reached the crate root without seeing a coverage attribute, so
78-
// allow coverage instrumentation by default.
79-
None => true,
80-
}
8175
}
8276

8377
/// Query implementation for `coverage_ids_info`.

compiler/rustc_parse/src/validate_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ pub fn check_builtin_meta_item(
318318
| sym::rustc_layout_scalar_valid_range_end
319319
| sym::no_implicit_prelude
320320
| sym::automatically_derived
321+
| sym::coverage
321322
) {
322323
return;
323324
}

compiler/rustc_passes/src/check_attr.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
288288
&Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => {
289289
self.check_rustc_std_internal_symbol(attr_span, span, target)
290290
}
291+
&Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => {
292+
self.check_coverage(attr_span, span, target)
293+
}
291294
Attribute::Unparsed(attr_item) => {
292295
style = Some(attr_item.style);
293296
match attr.path().as_slice() {
@@ -297,7 +300,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
297300
[sym::diagnostic, sym::on_unimplemented, ..] => {
298301
self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
299302
}
300-
[sym::coverage, ..] => self.check_coverage(attr, span, target),
301303
[sym::no_sanitize, ..] => {
302304
self.check_no_sanitize(attr, span, target)
303305
}
@@ -588,7 +590,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
588590

589591
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,
590592
/// or to an impl block or module.
591-
fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
593+
fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) {
592594
let mut not_fn_impl_mod = None;
593595
let mut no_body = None;
594596

@@ -611,7 +613,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
611613
}
612614

613615
self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
614-
attr_span: attr.span(),
616+
attr_span,
615617
not_fn_impl_mod,
616618
no_body,
617619
help: (),

tests/ui/attributes/malformed-attrs.stderr

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ error: malformed `crate_name` attribute input
3737
LL | #[crate_name]
3838
| ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
3939

40-
error: malformed `coverage` attribute input
41-
--> $DIR/malformed-attrs.rs:90:1
42-
|
43-
LL | #[coverage]
44-
| ^^^^^^^^^^^
45-
|
46-
help: the following are the possible correct uses
47-
|
48-
LL | #[coverage(off)]
49-
| +++++
50-
LL | #[coverage(on)]
51-
| ++++
52-
5340
error: malformed `no_sanitize` attribute input
5441
--> $DIR/malformed-attrs.rs:92:1
5542
|
@@ -460,6 +447,19 @@ error[E0539]: malformed `link_section` attribute input
460447
LL | #[link_section]
461448
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
462449

450+
error[E0539]: malformed `coverage` attribute input
451+
--> $DIR/malformed-attrs.rs:90:1
452+
|
453+
LL | #[coverage]
454+
| ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
455+
|
456+
help: try changing it to one of the following valid forms of the attribute
457+
|
458+
LL | #[coverage(off)]
459+
| +++++
460+
LL | #[coverage(on)]
461+
| ++++
462+
463463
error[E0565]: malformed `no_implicit_prelude` attribute input
464464
--> $DIR/malformed-attrs.rs:97:1
465465
|
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: malformed `coverage` attribute input
1+
error[E0539]: malformed `coverage` attribute input
22
--> $DIR/bad-attr-ice.rs:11:1
33
|
44
LL | #[coverage]
5-
| ^^^^^^^^^^^
5+
| ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
66
|
7-
help: the following are the possible correct uses
7+
help: try changing it to one of the following valid forms of the attribute
88
|
99
LL | #[coverage(off)]
1010
| +++++
@@ -13,3 +13,4 @@ LL | #[coverage(on)]
1313

1414
error: aborting due to 1 previous error
1515

16+
For more information about this error, try `rustc --explain E0539`.

0 commit comments

Comments
 (0)