Rollup merge of #143891 - scrabsha:push-xxtttopqoprr, r=jdonszelmann
Port `#[coverage]` to the new attribute system r? ``````@jdonszelmann``````
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr, UsedBy};
|
||||
use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
@@ -52,6 +52,45 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
|
||||
}
|
||||
|
||||
pub(crate) struct CoverageParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
||||
const PATH: &[Symbol] = &[sym::coverage];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(args) = args.list() else {
|
||||
cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(arg) = args.single() else {
|
||||
cx.expected_single_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
|
||||
|
||||
let Some(arg) = arg.meta_item() else {
|
||||
fail_incorrect_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let status = match arg.path().word_sym() {
|
||||
Some(sym::off) => CoverageStatus::Off,
|
||||
Some(sym::on) => CoverageStatus::On,
|
||||
None | Some(_) => {
|
||||
fail_incorrect_argument(arg.span());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::Coverage(cx.attr_span, status))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ExportNameParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
|
||||
|
||||
@@ -17,8 +17,9 @@ use crate::attributes::allow_unstable::{
|
||||
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||
};
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
|
||||
OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
|
||||
OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
|
||||
UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
@@ -139,6 +140,7 @@ attribute_parsers!(
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Single<CoverageParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<DummyParser>,
|
||||
Single<ExportNameParser>,
|
||||
@@ -452,6 +454,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: false,
|
||||
list: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn expected_specific_argument_and_list(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: false,
|
||||
list: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -469,6 +490,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: true,
|
||||
list: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -533,7 +533,9 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
||||
|
||||
pub(crate) enum AttributeParseErrorReason {
|
||||
ExpectedNoArgs,
|
||||
ExpectedStringLiteral { byte_string: Option<Span> },
|
||||
ExpectedStringLiteral {
|
||||
byte_string: Option<Span>,
|
||||
},
|
||||
ExpectedIntegerLiteral,
|
||||
ExpectedAtLeastOneArgument,
|
||||
ExpectedSingleArgument,
|
||||
@@ -541,7 +543,12 @@ pub(crate) enum AttributeParseErrorReason {
|
||||
UnexpectedLiteral,
|
||||
ExpectedNameValue(Option<Symbol>),
|
||||
DuplicateKey(Symbol),
|
||||
ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
|
||||
ExpectedSpecificArgument {
|
||||
possibilities: Vec<&'static str>,
|
||||
strings: bool,
|
||||
/// Should we tell the user to write a list when they didn't?
|
||||
list: bool,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct AttributeParseError {
|
||||
@@ -615,7 +622,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
||||
format!("expected this to be of the form `{name} = \"...\"`"),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings,
|
||||
list: false,
|
||||
} => {
|
||||
let quote = if strings { '"' } else { '`' };
|
||||
match possibilities.as_slice() {
|
||||
&[] => {}
|
||||
@@ -641,6 +652,38 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
||||
}
|
||||
}
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings,
|
||||
list: true,
|
||||
} => {
|
||||
let quote = if strings { '"' } else { '`' };
|
||||
match possibilities.as_slice() {
|
||||
&[] => {}
|
||||
&[x] => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!(
|
||||
"this attribute is only valid with {quote}{x}{quote} as an argument"
|
||||
),
|
||||
);
|
||||
}
|
||||
[first, second] => {
|
||||
diag.span_label(self.span, format!("this attribute is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
|
||||
}
|
||||
[first @ .., second_to_last, last] => {
|
||||
let mut res = String::new();
|
||||
for i in first {
|
||||
res.push_str(&format!("{quote}{i}{quote}, "));
|
||||
}
|
||||
res.push_str(&format!(
|
||||
"{quote}{second_to_last}{quote} or {quote}{last}{quote}"
|
||||
));
|
||||
|
||||
diag.span_label(self.span, format!("this attribute is only valid with one of the following arguments: {res}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let suggestions = self.template.suggestions(false, &name);
|
||||
|
||||
Reference in New Issue
Block a user