Skip to content

Commit b79a99d

Browse files
committed
coverage: Overhaul validation of #[coverage(..)]
1 parent 6d24063 commit b79a99d

File tree

8 files changed

+41
-81
lines changed

8 files changed

+41
-81
lines changed

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
2727
2828
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
2929
30-
codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
31-
3230
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
3331
3432
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ use rustc_span::{sym, Span};
1515
use rustc_target::spec::{abi, SanitizerSet};
1616

1717
use crate::errors;
18-
use crate::target_features::from_target_feature;
19-
use crate::{
20-
errors::{ExpectedCoverageSymbol, ExpectedUsedSymbol},
21-
target_features::check_target_feature_trait_unsafe,
22-
};
18+
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
2319

2420
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
2521
use rustc_middle::mir::mono::Linkage::*;
@@ -139,7 +135,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
139135
// coverage on a smaller scope within an excluded larger scope.
140136
}
141137
Some(_) | None => {
142-
tcx.dcx().emit_err(ExpectedCoverageSymbol { span: attr.span });
138+
tcx.dcx()
139+
.span_delayed_bug(attr.span, "unexpected value of coverage attribute");
143140
}
144141
}
145142
}
@@ -174,7 +171,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
174171
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
175172
}
176173
Some(_) => {
177-
tcx.dcx().emit_err(ExpectedUsedSymbol { span: attr.span });
174+
tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span });
178175
}
179176
None => {
180177
// Unfortunately, unconditionally using `llvm.used` causes

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -564,13 +564,6 @@ pub struct UnknownArchiveKind<'a> {
564564
pub kind: &'a str,
565565
}
566566

567-
#[derive(Diagnostic)]
568-
#[diag(codegen_ssa_expected_coverage_symbol)]
569-
pub struct ExpectedCoverageSymbol {
570-
#[primary_span]
571-
pub span: Span,
572-
}
573-
574567
#[derive(Diagnostic)]
575568
#[diag(codegen_ssa_expected_used_symbol)]
576569
pub struct ExpectedUsedSymbol {

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
478478
EncodeCrossCrate::No, experimental!(no_sanitize)
479479
),
480480
gated!(
481-
coverage, Normal, template!(Word, List: "on|off"),
481+
coverage, Normal, template!(List: "off|on"),
482482
ErrorPreceding, EncodeCrossCrate::No,
483483
coverage_attribute, experimental!(coverage)
484484
),

compiler/rustc_parse/src/validate_attr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ pub fn check_builtin_meta_item(
149149
) {
150150
// Some special attributes like `cfg` must be checked
151151
// before the generic check, so we skip them here.
152-
let should_skip = |name| name == sym::cfg;
152+
// Coverage attributes are checked by the `check_attr` pass, which gives
153+
// better error messages.
154+
let should_skip = |name| name == sym::cfg || name == sym::coverage;
153155

154156
if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
155157
emit_malformed_attribute(psess, style, meta.span, name, template);

compiler/rustc_passes/messages.ftl

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,12 @@ passes_continue_labeled_block =
103103
.label = labeled blocks cannot be `continue`'d
104104
.block_label = labeled block the `continue` points to
105105
106-
passes_coverage_fn_defn =
107-
`#[coverage]` may only be applied to function definitions
106+
passes_coverage_expected_off_or_on =
107+
expected `coverage(off)` or `coverage(on)`
108108
109-
passes_coverage_ignored_function_prototype =
110-
`#[coverage]` is ignored on function prototypes
111-
112-
passes_coverage_not_coverable =
113-
`#[coverage]` must be applied to coverable code
114-
.label = not coverable code
115-
116-
passes_coverage_propagate =
117-
`#[coverage]` does not propagate into items and must be applied to the contained functions directly
109+
passes_coverage_not_fn_or_closure =
110+
attribute should be applied to a function definition or closure
111+
.label = not a function or closure
118112
119113
passes_dead_codes =
120114
{ $multiple ->

compiler/rustc_passes/src/check_attr.rs

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
126126
self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
127127
}
128128
[sym::inline] => self.check_inline(hir_id, attr, span, target),
129-
[sym::coverage] => self.check_coverage(hir_id, attr, span, target),
129+
[sym::coverage] => self.check_coverage(attr, span, target),
130130
[sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
131131
[sym::marker] => self.check_marker(hir_id, attr, span, target),
132132
[sym::target_feature] => {
@@ -388,53 +388,34 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
388388
}
389389
}
390390

391-
/// Checks if a `#[coverage]` is applied directly to a function
392-
fn check_coverage(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
393-
match target {
394-
// #[coverage] on function is fine
395-
Target::Fn
396-
| Target::Closure
397-
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
398-
399-
// function prototypes can't be covered
400-
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
401-
self.tcx.emit_node_span_lint(
402-
UNUSED_ATTRIBUTES,
403-
hir_id,
404-
attr.span,
405-
errors::IgnoredCoverageFnProto,
406-
);
407-
true
408-
}
391+
/// Checks that `#[coverage(..)]` is applied to a function or closure, and
392+
/// that it has the form `#[coverage(off)]` or `#[coverage(on)]`.
393+
fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) -> bool {
394+
let mut ok = true;
409395

410-
Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
411-
self.tcx.emit_node_span_lint(
412-
UNUSED_ATTRIBUTES,
413-
hir_id,
414-
attr.span,
415-
errors::IgnoredCoveragePropagate,
416-
);
417-
true
418-
}
419-
420-
Target::Expression | Target::Statement | Target::Arm => {
421-
self.tcx.emit_node_span_lint(
422-
UNUSED_ATTRIBUTES,
423-
hir_id,
424-
attr.span,
425-
errors::IgnoredCoverageFnDefn,
426-
);
427-
true
396+
ok &= match attr.meta_item_list().as_deref() {
397+
Some([arg]) if arg.has_name(sym::on) || arg.has_name(sym::off) => true,
398+
Some(_) | None => {
399+
self.dcx().emit_err(errors::CoverageExpectedOffOrOn { attr_span: attr.span });
400+
false
428401
}
402+
};
429403

404+
ok &= match target {
405+
// #[coverage(..)] on function is fine
406+
Target::Fn
407+
| Target::Closure
408+
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
430409
_ => {
431-
self.dcx().emit_err(errors::IgnoredCoverageNotCoverable {
410+
self.dcx().emit_err(errors::CoverageNotFnOrClosure {
432411
attr_span: attr.span,
433412
defn_span: span,
434413
});
435414
false
436415
}
437-
}
416+
};
417+
418+
ok
438419
}
439420

440421
fn check_generic_attr(

compiler/rustc_passes/src/errors.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,16 @@ pub struct InlineNotFnOrClosure {
6060
pub defn_span: Span,
6161
}
6262

63-
#[derive(LintDiagnostic)]
64-
#[diag(passes_coverage_ignored_function_prototype)]
65-
pub struct IgnoredCoverageFnProto;
66-
67-
#[derive(LintDiagnostic)]
68-
#[diag(passes_coverage_propagate)]
69-
pub struct IgnoredCoveragePropagate;
70-
71-
#[derive(LintDiagnostic)]
72-
#[diag(passes_coverage_fn_defn)]
73-
pub struct IgnoredCoverageFnDefn;
63+
#[derive(Diagnostic)]
64+
#[diag(passes_coverage_expected_off_or_on)]
65+
pub struct CoverageExpectedOffOrOn {
66+
#[primary_span]
67+
pub attr_span: Span,
68+
}
7469

7570
#[derive(Diagnostic)]
76-
#[diag(passes_coverage_not_coverable, code = E0788)]
77-
pub struct IgnoredCoverageNotCoverable {
71+
#[diag(passes_coverage_not_fn_or_closure, code = E0788)]
72+
pub struct CoverageNotFnOrClosure {
7873
#[primary_span]
7974
pub attr_span: Span,
8075
#[label]

0 commit comments

Comments
 (0)