mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
adds feature gating of no_coverage
at either crate- or function-level
This commit is contained in:
parent
888d0b4c96
commit
3a5df48021
@ -16,10 +16,19 @@ pub fn expand_deriving_eq(
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
) {
|
||||
let inline = cx.meta_word(span, sym::inline);
|
||||
let no_coverage_ident =
|
||||
rustc_ast::attr::mk_nested_word_item(Ident::new(sym::no_coverage, span));
|
||||
let no_coverage_feature =
|
||||
rustc_ast::attr::mk_list_item(Ident::new(sym::feature, span), vec![no_coverage_ident]);
|
||||
let no_coverage = cx.meta_word(span, sym::no_coverage);
|
||||
let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
|
||||
let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
|
||||
let attrs = vec![cx.attribute(inline), cx.attribute(no_coverage), cx.attribute(doc)];
|
||||
let attrs = vec![
|
||||
cx.attribute(inline),
|
||||
cx.attribute(no_coverage_feature),
|
||||
cx.attribute(no_coverage),
|
||||
cx.attribute(doc),
|
||||
];
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
attributes: Vec::new(),
|
||||
|
@ -649,6 +649,10 @@ declare_features! (
|
||||
/// Allows `extern "wasm" fn`
|
||||
(active, wasm_abi, "1.53.0", Some(83788), None),
|
||||
|
||||
/// Allows function attribute `#[no_coverage]`, to bypass coverage
|
||||
/// instrumentation of that function.
|
||||
(active, no_coverage, "1.53.0", Some(84605), None),
|
||||
|
||||
/// Allows trait bounds in `const fn`.
|
||||
(active, const_fn_trait_bound, "1.53.0", Some(57563), None),
|
||||
|
||||
|
@ -264,7 +264,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
|
||||
// Code generation:
|
||||
ungated!(inline, AssumedUsed, template!(Word, List: "always|never")),
|
||||
ungated!(no_coverage, AssumedUsed, template!(Word)),
|
||||
ungated!(cold, AssumedUsed, template!(Word)),
|
||||
ungated!(no_builtins, AssumedUsed, template!(Word)),
|
||||
ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)),
|
||||
@ -274,6 +273,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
template!(List: "address, memory, thread"),
|
||||
experimental!(no_sanitize)
|
||||
),
|
||||
ungated!(
|
||||
// Not exclusively gated at the crate level (though crate-level is
|
||||
// supported). The feature can alternatively be enabled on individual
|
||||
// functions.
|
||||
no_coverage, AssumedUsed,
|
||||
template!(Word),
|
||||
),
|
||||
|
||||
// FIXME: #14408 assume docs are used since rustdoc looks at them.
|
||||
ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
|
||||
|
@ -2661,6 +2661,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
let mut inline_span = None;
|
||||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
let mut no_coverage_feature_enabled = false;
|
||||
let mut no_coverage_attr = None;
|
||||
for attr in attrs.iter() {
|
||||
if tcx.sess.check_name(attr, sym::cold) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
||||
@ -2724,8 +2726,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
|
||||
} else if tcx.sess.check_name(attr, sym::no_mangle) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
} else if attr.has_name(sym::feature) {
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
if list.iter().any(|nested_meta_item| nested_meta_item.has_name(sym::no_coverage)) {
|
||||
tcx.sess.mark_attr_used(attr);
|
||||
no_coverage_feature_enabled = true;
|
||||
}
|
||||
}
|
||||
} else if tcx.sess.check_name(attr, sym::no_coverage) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
|
||||
no_coverage_attr = Some(attr);
|
||||
} else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
} else if tcx.sess.check_name(attr, sym::used) {
|
||||
@ -2936,6 +2945,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(no_coverage_attr) = no_coverage_attr {
|
||||
if tcx.sess.features_untracked().no_coverage || no_coverage_feature_enabled {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE
|
||||
} else {
|
||||
let mut err = feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::no_coverage,
|
||||
no_coverage_attr.span,
|
||||
"the `#[no_coverage]` attribute is an experimental feature",
|
||||
);
|
||||
if tcx.sess.parse_sess.unstable_features.is_nightly_build() {
|
||||
err.help("or, alternatively, add `#[feature(no_coverage)]` to the function");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
|
||||
if !attr.has_name(sym::inline) {
|
||||
return ia;
|
||||
|
@ -274,6 +274,7 @@ pub trait Eq: PartialEq<Self> {
|
||||
//
|
||||
// This should never be implemented by hand.
|
||||
#[doc(hidden)]
|
||||
#[cfg_attr(not(bootstrap), feature(no_coverage))]
|
||||
#[cfg_attr(not(bootstrap), no_coverage)]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -1,34 +0,0 @@
|
||||
1| |// FIXME(#84561): function-like macros produce unintuitive coverage results.
|
||||
2| |// This test demonstrates some of the problems.
|
||||
3| |
|
||||
4| 9|#[derive(Debug, PartialEq, Eq)]
|
||||
^5
|
||||
------------------
|
||||
| <issue_84561::Foo as core::cmp::PartialEq>::eq:
|
||||
| 4| 9|#[derive(Debug, PartialEq, Eq)]
|
||||
------------------
|
||||
| Unexecuted instantiation: <issue_84561::Foo as core::cmp::PartialEq>::ne
|
||||
------------------
|
||||
5| |struct Foo(u32);
|
||||
6| |
|
||||
7| 1|fn main() {
|
||||
8| 1| let bar = Foo(1);
|
||||
9| 0| assert_eq!(bar, Foo(1));
|
||||
10| 1| let baz = Foo(0);
|
||||
11| 0| assert_ne!(baz, Foo(1));
|
||||
12| 1| println!("{:?}", Foo(1));
|
||||
13| 1| println!("{:?}", bar);
|
||||
14| 1| println!("{:?}", baz);
|
||||
15| |
|
||||
16| 1| assert_eq!(Foo(1), Foo(1));
|
||||
17| 1| assert_ne!(Foo(0), Foo(1));
|
||||
18| 0| assert_eq!(Foo(2), Foo(2));
|
||||
19| 1| let bar = Foo(1);
|
||||
20| 1| assert_ne!(Foo(0), Foo(3));
|
||||
21| 1| assert_ne!(Foo(0), Foo(4));
|
||||
22| 1| assert_eq!(Foo(3), Foo(3));
|
||||
23| 0| assert_ne!(Foo(0), Foo(5));
|
||||
24| 1| println!("{:?}", bar);
|
||||
25| 1| println!("{:?}", Foo(1));
|
||||
26| 1|}
|
||||
|
@ -0,0 +1,18 @@
|
||||
1| |// Enables `no_coverage` on the entire crate
|
||||
2| |#![feature(no_coverage)]
|
||||
3| |
|
||||
4| |#[no_coverage]
|
||||
5| |fn do_not_add_coverage_1() {
|
||||
6| | println!("called but not covered");
|
||||
7| |}
|
||||
8| |
|
||||
9| |#[no_coverage]
|
||||
10| |fn do_not_add_coverage_2() {
|
||||
11| | println!("called but not covered");
|
||||
12| |}
|
||||
13| |
|
||||
14| 1|fn main() {
|
||||
15| 1| do_not_add_coverage_1();
|
||||
16| 1| do_not_add_coverage_2();
|
||||
17| 1|}
|
||||
|
@ -0,0 +1,19 @@
|
||||
1| |// Enables `no_coverage` on individual functions
|
||||
2| |
|
||||
3| |#[feature(no_coverage)]
|
||||
4| |#[no_coverage]
|
||||
5| |fn do_not_add_coverage_1() {
|
||||
6| | println!("called but not covered");
|
||||
7| |}
|
||||
8| |
|
||||
9| |#[no_coverage]
|
||||
10| |#[feature(no_coverage)]
|
||||
11| |fn do_not_add_coverage_2() {
|
||||
12| | println!("called but not covered");
|
||||
13| |}
|
||||
14| |
|
||||
15| 1|fn main() {
|
||||
16| 1| do_not_add_coverage_1();
|
||||
17| 1| do_not_add_coverage_2();
|
||||
18| 1|}
|
||||
|
@ -1,26 +0,0 @@
|
||||
// FIXME(#84561): function-like macros produce unintuitive coverage results.
|
||||
// This test demonstrates some of the problems.
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Foo(u32);
|
||||
|
||||
fn main() {
|
||||
let bar = Foo(1);
|
||||
assert_eq!(bar, Foo(1));
|
||||
let baz = Foo(0);
|
||||
assert_ne!(baz, Foo(1));
|
||||
println!("{:?}", Foo(1));
|
||||
println!("{:?}", bar);
|
||||
println!("{:?}", baz);
|
||||
|
||||
assert_eq!(Foo(1), Foo(1));
|
||||
assert_ne!(Foo(0), Foo(1));
|
||||
assert_eq!(Foo(2), Foo(2));
|
||||
let bar = Foo(1);
|
||||
assert_ne!(Foo(0), Foo(3));
|
||||
assert_ne!(Foo(0), Foo(4));
|
||||
assert_eq!(Foo(3), Foo(3));
|
||||
assert_ne!(Foo(0), Foo(5));
|
||||
println!("{:?}", bar);
|
||||
println!("{:?}", Foo(1));
|
||||
}
|
17
src/test/run-make-fulldeps/coverage/no_cov_crate.rs
Normal file
17
src/test/run-make-fulldeps/coverage/no_cov_crate.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Enables `no_coverage` on the entire crate
|
||||
#![feature(no_coverage)]
|
||||
|
||||
#[no_coverage]
|
||||
fn do_not_add_coverage_1() {
|
||||
println!("called but not covered");
|
||||
}
|
||||
|
||||
#[no_coverage]
|
||||
fn do_not_add_coverage_2() {
|
||||
println!("called but not covered");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
do_not_add_coverage_1();
|
||||
do_not_add_coverage_2();
|
||||
}
|
18
src/test/run-make-fulldeps/coverage/no_cov_func.rs
Normal file
18
src/test/run-make-fulldeps/coverage/no_cov_func.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Enables `no_coverage` on individual functions
|
||||
|
||||
#[feature(no_coverage)]
|
||||
#[no_coverage]
|
||||
fn do_not_add_coverage_1() {
|
||||
println!("called but not covered");
|
||||
}
|
||||
|
||||
#[no_coverage]
|
||||
#[feature(no_coverage)]
|
||||
fn do_not_add_coverage_2() {
|
||||
println!("called but not covered");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
do_not_add_coverage_1();
|
||||
do_not_add_coverage_2();
|
||||
}
|
8
src/test/ui/feature-gates/feature-gate-no_coverage.rs
Normal file
8
src/test/ui/feature-gates/feature-gate-no_coverage.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[no_coverage]
|
||||
#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]`
|
||||
fn no_coverage_is_enabled_on_this_function() {}
|
||||
|
||||
#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
|
||||
fn requires_feature_no_coverage() {}
|
13
src/test/ui/feature-gates/feature-gate-no_coverage.stderr
Normal file
13
src/test/ui/feature-gates/feature-gate-no_coverage.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0658]: the `#[no_coverage]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-no_coverage.rs:7:1
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
|
||||
= help: add `#![feature(no_coverage)]` to the crate attributes to enable
|
||||
= help: or, alternatively, add `#[feature(no_coverage)]` to the function
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
Loading…
Reference in New Issue
Block a user