Port cfg_select! to the new attribute parsing system
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
This commit is contained in:
parent
c111ccc45d
commit
90f36afc1b
5 changed files with 114 additions and 82 deletions
|
|
@ -1,20 +1,26 @@
|
|||
use rustc_ast::token::Token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{MetaItemInner, token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::Span;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
pub enum CfgSelectPredicate {
|
||||
Cfg(MetaItemInner),
|
||||
Cfg(CfgEntry),
|
||||
Wildcard(Token),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CfgSelectBranches {
|
||||
/// All the conditional branches.
|
||||
pub reachable: Vec<(MetaItemInner, TokenStream, Span)>,
|
||||
pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
|
||||
/// The first wildcard `_ => { ... }` branch.
|
||||
pub wildcard: Option<(Token, TokenStream, Span)>,
|
||||
/// All branches after the first wildcard, including further wildcards.
|
||||
|
|
@ -22,15 +28,20 @@ pub struct CfgSelectBranches {
|
|||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||
}
|
||||
|
||||
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {
|
||||
pub fn parse_cfg_select(
|
||||
p: &mut Parser<'_>,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
lint_node_id: NodeId,
|
||||
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
|
||||
let mut branches = CfgSelectBranches::default();
|
||||
|
||||
while p.token != token::Eof {
|
||||
if p.eat_keyword(exp!(Underscore)) {
|
||||
let underscore = p.prev_token;
|
||||
p.expect(exp!(FatArrow))?;
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree()?;
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = underscore.span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
|
|
@ -40,17 +51,36 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let meta_item = p.parse_meta_item_inner()?;
|
||||
p.expect(exp!(FatArrow))?;
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
cfg_span,
|
||||
cfg_span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath {
|
||||
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||
span: cfg_span,
|
||||
},
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
lint_node_id,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
)?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree()?;
|
||||
let span = meta_item.span().to(p.token.span);
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = cfg_span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
None => branches.reachable.push((meta_item, tts, span)),
|
||||
Some(_) => {
|
||||
branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span))
|
||||
}
|
||||
None => branches.reachable.push((cfg, tts, span)),
|
||||
Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
||||
|
|
@ -9,11 +11,11 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
|||
/// Selects the first arm whose predicate evaluates to true.
|
||||
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
|
||||
for (cfg, tt, arm_span) in branches.reachable {
|
||||
if attr::cfg_matches(
|
||||
&cfg,
|
||||
if let EvalConfigResult::True = attr::eval_config_entry(
|
||||
&ecx.sess,
|
||||
&cfg,
|
||||
ecx.current_expansion.lint_node_id,
|
||||
Some(ecx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
) {
|
||||
return Some((tt, arm_span));
|
||||
}
|
||||
|
|
@ -27,37 +29,41 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
ExpandResult::Ready(
|
||||
match parse_cfg_select(
|
||||
&mut ecx.new_parser_from_tts(tts),
|
||||
ecx.sess,
|
||||
Some(ecx.ecfg.features),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
})
|
||||
Err(guar) => DummyResult::any(sp, guar),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,6 +194,18 @@ pub enum CfgEntry {
|
|||
Version(Option<RustcVersion>, Span),
|
||||
}
|
||||
|
||||
impl CfgEntry {
|
||||
pub fn span(&self) -> Span {
|
||||
let (CfgEntry::All(_, span)
|
||||
| CfgEntry::Any(_, span)
|
||||
| CfgEntry::Not(_, span)
|
||||
| CfgEntry::Bool(_, span)
|
||||
| CfgEntry::NameValue { span, .. }
|
||||
| CfgEntry::Version(_, span)) = self;
|
||||
*span
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible values for the `#[linkage]` attribute, allowing to specify the
|
||||
/// linkage type for a `MonoItem`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -63,25 +63,25 @@ cfg_select! {}
|
|||
|
||||
cfg_select! {
|
||||
=> {}
|
||||
//~^ ERROR expected unsuffixed literal, found `=>`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
() => {}
|
||||
//~^ ERROR expected unsuffixed literal, found `(`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(`
|
||||
}
|
||||
|
||||
cfg_select! { //~ ERROR none of the predicates in this `cfg_select` evaluated to true
|
||||
cfg_select! {
|
||||
"str" => {}
|
||||
//~^ ERROR literal in `cfg` predicate value must be a boolean
|
||||
//~^ ERROR malformed `cfg_select` macro input [E0539]
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
a::b => {}
|
||||
//~^ ERROR `cfg` predicate key must be an identifier
|
||||
//~^ ERROR malformed `cfg_select` macro input [E0539]
|
||||
}
|
||||
|
||||
cfg_select! { //~ ERROR none of the predicates in this `cfg_select` evaluated to true
|
||||
cfg_select! {
|
||||
a() => {}
|
||||
//~^ ERROR invalid predicate `a` [E0537]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,38 +21,31 @@ error: none of the predicates in this `cfg_select` evaluated to true
|
|||
LL | cfg_select! {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: expected unsuffixed literal, found `=>`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
|
||||
--> $DIR/cfg_select.rs:65:5
|
||||
|
|
||||
LL | => {}
|
||||
| ^^
|
||||
|
||||
error: expected unsuffixed literal, found `(`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(`
|
||||
--> $DIR/cfg_select.rs:70:5
|
||||
|
|
||||
LL | () => {}
|
||||
| ^
|
||||
|
||||
error[E0565]: literal in `cfg` predicate value must be a boolean
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:75:5
|
||||
|
|
||||
LL | "str" => {}
|
||||
| ^^^^^
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:74:1
|
||||
| ^^^^^ expected a valid identifier here
|
||||
|
|
||||
LL | / cfg_select! {
|
||||
LL | | "str" => {}
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: `cfg` predicate key must be an identifier
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:80:5
|
||||
|
|
||||
LL | a::b => {}
|
||||
| ^^^^
|
||||
| ^^^^ expected a valid identifier here
|
||||
|
|
||||
|
||||
error[E0537]: invalid predicate `a`
|
||||
--> $DIR/cfg_select.rs:85:5
|
||||
|
|
@ -60,15 +53,6 @@ error[E0537]: invalid predicate `a`
|
|||
LL | a() => {}
|
||||
| ^^^
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:84:1
|
||||
|
|
||||
LL | / cfg_select! {
|
||||
LL | | a() => {}
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
|
||||
--> $DIR/cfg_select.rs:90:7
|
||||
|
|
||||
|
|
@ -81,7 +65,7 @@ error: expected one of `(`, `::`, `=>`, or `=`, found `!`
|
|||
LL | cfg!() => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
error: aborting due to 11 previous errors; 1 warning emitted
|
||||
error: aborting due to 9 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0537, E0565.
|
||||
Some errors have detailed explanations: E0537, E0539.
|
||||
For more information about an error, try `rustc --explain E0537`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue