diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index af94e8acaf68e..7f5d12aef82bc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -12,7 +12,7 @@ use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::{ParseSess, feature_err}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::context::{AcceptContext, ShouldEmit, Stage}; @@ -47,20 +47,19 @@ pub fn parse_cfg<'c, S: Stage>( cx.expected_single_argument(list.span); return None; }; - parse_cfg_entry(cx, single) + parse_cfg_entry(cx, single).ok() } -pub(crate) fn parse_cfg_entry( +pub fn parse_cfg_entry( cx: &mut AcceptContext<'_, '_, S>, item: &MetaItemOrLitParser<'_>, -) -> Option { - Some(match item { +) -> Result { + Ok(match item { MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { ArgParser::List(list) => match meta.path().word_sym() { Some(sym::not) => { let Some(single) = list.single() else { - cx.expected_single_argument(list.span); - return None; + return Err(cx.expected_single_argument(list.span)); }; CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) } @@ -75,29 +74,24 @@ pub(crate) fn parse_cfg_entry( Some(sym::target) => parse_cfg_entry_target(cx, list, meta.span())?, Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?, _ => { - cx.emit_err(session_diagnostics::InvalidPredicate { + return Err(cx.emit_err(session_diagnostics::InvalidPredicate { span: meta.span(), predicate: meta.path().to_string(), - }); - return None; + })); } }, a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => { let Some(name) = meta.path().word_sym() else { - cx.expected_identifier(meta.path().span()); - return None; + return Err(cx.expected_identifier(meta.path().span())); }; parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)? } }, MetaItemOrLitParser::Lit(lit) => match lit.kind { LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), - _ => { - cx.expected_identifier(lit.span); - return None; - } + _ => return Err(cx.expected_identifier(lit.span)), }, - MetaItemOrLitParser::Err(_, _) => return None, + MetaItemOrLitParser::Err(_, err) => return Err(*err), }) } @@ -105,19 +99,22 @@ fn parse_cfg_entry_version( cx: &mut AcceptContext<'_, '_, S>, list: &MetaItemListParser<'_>, meta_span: Span, -) -> Option { +) -> Result { try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); let Some(version) = list.single() else { - cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }); - return None; + return Err( + cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }) + ); }; let Some(version_lit) = version.lit() else { - cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() }); - return None; + return Err( + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() }) + ); }; let Some(version_str) = version_lit.value_str() else { - cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span }); - return None; + return Err( + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span }) + ); }; let min_version = parse_version(version_str).or_else(|| { @@ -127,14 +124,14 @@ fn parse_cfg_entry_version( None }); - Some(CfgEntry::Version(min_version, list.span)) + Ok(CfgEntry::Version(min_version, list.span)) } fn parse_cfg_entry_target( cx: &mut AcceptContext<'_, '_, S>, list: &MetaItemListParser<'_>, meta_span: Span, -) -> Option { +) -> Result { if let Some(features) = cx.features_option() && !features.cfg_target_compact() { @@ -161,17 +158,16 @@ fn parse_cfg_entry_target( // Then, parse it as a name-value item let Some(name) = sub_item.path().word_sym() else { - cx.expected_identifier(sub_item.path().span()); - return None; + return Err(cx.expected_identifier(sub_item.path().span())); }; let name = Symbol::intern(&format!("target_{name}")); - if let Some(cfg) = + if let Ok(cfg) = parse_name_value(name, sub_item.path().span(), Some(nv), sub_item.span(), cx) { result.push(cfg); } } - Some(CfgEntry::All(result, list.span)) + Ok(CfgEntry::All(result, list.span)) } fn parse_name_value( @@ -180,21 +176,22 @@ fn parse_name_value( value: Option<&NameValueParser>, span: Span, cx: &mut AcceptContext<'_, '_, S>, -) -> Option { +) -> Result { try_gate_cfg(name, span, cx.sess(), cx.features_option()); let value = match value { None => None, Some(value) => { let Some(value_str) = value.value_as_str() else { - cx.expected_string_literal(value.value_span, Some(value.value_as_lit())); - return None; + return Err( + cx.expected_string_literal(value.value_span, Some(value.value_as_lit())) + ); }; Some((value_str, value.value_span)) } }; - Some(CfgEntry::NameValue { name, name_span, value, span }) + Ok(CfgEntry::NameValue { name, name_span, value, span }) } pub fn eval_config_entry( @@ -404,7 +401,7 @@ fn parse_cfg_attr_internal<'a>( parse_cfg_entry, &CFG_ATTR_TEMPLATE, ) - .ok_or_else(|| { + .map_err(|_err: ErrorGuaranteed| { let mut diag = sess.dcx().struct_err( "cfg_entry parsing failing with `ShouldEmit::ErrorsAndLints` should emit a error.", ); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 40ecd91e5cfc1..a8c0ea6c18b7f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -397,7 +397,7 @@ impl LinkParser { ) .emit(); } - *cfg = parse_cfg_entry(cx, link_cfg); + *cfg = parse_cfg_entry(cx, link_cfg).ok(); true } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b8ef11c26d80e..9d6532d498f9f 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -166,9 +166,9 @@ impl<'sess> AttributeParser<'sess, Early> { features: Option<&'sess Features>, emit_errors: ShouldEmit, args: &I, - parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> Option, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> T, template: &AttributeTemplate, - ) -> Option { + ) -> T { let mut parser = Self { features, tools: Vec::new(), diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index bcd0d674c75f1..9579b0eae804a 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -106,7 +106,7 @@ mod target_checking; pub mod validate_attr; pub use attributes::cfg::{ - CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, + CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; pub use attributes::cfg_old::*; pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 85b8ef79c0504..ba077ebff34c0 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -2,13 +2,16 @@ //! a literal `true` or `false` based on whether the given cfg matches the //! current compilation environment. -use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_errors::PResult; +use rustc_ast::{AttrStyle, CRATE_NODE_ID, token}; +use rustc_attr_parsing as attr; +use rustc_attr_parsing::parser::MetaItemOrLitParser; +use rustc_attr_parsing::{AttributeParser, CFG_TEMPLATE, ShouldEmit, parse_cfg_entry}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; +use rustc_hir::AttrPath; +use rustc_hir::attrs::CfgEntry; use rustc_parse::exp; -use rustc_span::Span; -use {rustc_ast as ast, rustc_attr_parsing as attr}; +use rustc_span::{ErrorGuaranteed, Ident, Span}; use crate::errors; @@ -21,38 +24,47 @@ pub(crate) fn expand_cfg( ExpandResult::Ready(match parse_cfg(cx, sp, tts) { Ok(cfg) => { - let matches_cfg = attr::cfg_matches( + let matches_cfg = attr::eval_config_entry( + cx.sess, &cfg, - &cx.sess, cx.current_expansion.lint_node_id, Some(cx.ecfg.features), - ); + ShouldEmit::ErrorsAndLints, + ) + .as_bool(); + MacEager::expr(cx.expr_bool(sp, matches_cfg)) } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } + Err(guar) => DummyResult::any(sp, guar), }) } -fn parse_cfg<'a>( - cx: &ExtCtxt<'a>, - span: Span, - tts: TokenStream, -) -> PResult<'a, ast::MetaItemInner> { - let mut p = cx.new_parser_from_tts(tts); - - if p.token == token::Eof { - return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); +fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result { + let mut parser = cx.new_parser_from_tts(tts); + if parser.token == token::Eof { + return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item_inner()?; + let meta = MetaItemOrLitParser::parse_single(&mut parser, ShouldEmit::ErrorsAndLints) + .map_err(|diag| diag.emit())?; + let cfg = AttributeParser::parse_single_args( + cx.sess, + span, + AttrStyle::Inner, + AttrPath { segments: vec![Ident::from_str("cfg")].into_boxed_slice(), span }, + span, + CRATE_NODE_ID, + Some(cx.ecfg.features), + ShouldEmit::ErrorsAndLints, + &meta, + parse_cfg_entry, + &CFG_TEMPLATE, + )?; - let _ = p.eat(exp!(Comma)); + let _ = parser.eat(exp!(Comma)); - if !p.eat(exp!(Eof)) { - return Err(cx.dcx().create_err(errors::OneCfgPattern { span })); + if !parser.eat(exp!(Eof)) { + return Err(cx.dcx().emit_err(errors::OneCfgPattern { span })); } Ok(cfg) diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index f00d177394489..acd5ce345859f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The `not` cfg-predicate was malformed. Erroneous code example: -```compile_fail,E0536 +```compile_fail,E0805 pub fn main() { if cfg!(not()) { } } diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index 50998572274ec..4b817f682a297 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -1,6 +1,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern - cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean - cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string + cfg!(123); //~ ERROR malformed `cfg` attribute input + cfg!(foo = 123); //~ ERROR malformed `cfg` attribute input cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index ad3f9b188ddb9..6b283c0cb9d39 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -4,17 +4,27 @@ error: macro requires a cfg-pattern as an argument LL | cfg!(); | ^^^^^^ cfg-pattern required -error[E0565]: literal in `cfg` predicate value must be a boolean - --> $DIR/cfg.rs:3:10 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg.rs:3:5 | LL | cfg!(123); - | ^^^ + | ^^^^^---^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#![cfg(predicate)]` + | + = note: for more information, visit -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg.rs:4:16 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg.rs:4:5 | LL | cfg!(foo = 123); - | ^^^ + | ^^^^^^^^^^^---^ + | | | + | | expected a string literal here + | help: must be of the form: `#![cfg(predicate)]` + | + = note: for more information, visit error: expected 1 cfg-pattern --> $DIR/cfg.rs:5:5 @@ -24,4 +34,4 @@ LL | cfg!(foo, bar); error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0565`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/span/E0536.rs b/tests/ui/span/E0536.rs deleted file mode 100644 index ae07336335419..0000000000000 --- a/tests/ui/span/E0536.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn main() { - if cfg!(not()) { } //~ ERROR E0536 -} diff --git a/tests/ui/span/E0536.stderr b/tests/ui/span/E0536.stderr deleted file mode 100644 index 6c25f9140a1ab..0000000000000 --- a/tests/ui/span/E0536.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0536]: expected 1 cfg-pattern - --> $DIR/E0536.rs:2:13 - | -LL | if cfg!(not()) { } - | ^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0536`. diff --git a/tests/ui/span/E0805.rs b/tests/ui/span/E0805.rs new file mode 100644 index 0000000000000..097f5cd8e586e --- /dev/null +++ b/tests/ui/span/E0805.rs @@ -0,0 +1,3 @@ +pub fn main() { + if cfg!(not()) { } //~ ERROR E0805 +} diff --git a/tests/ui/span/E0805.stderr b/tests/ui/span/E0805.stderr new file mode 100644 index 0000000000000..369f82049429f --- /dev/null +++ b/tests/ui/span/E0805.stderr @@ -0,0 +1,14 @@ +error[E0805]: malformed `cfg` attribute input + --> $DIR/E0805.rs:2:8 + | +LL | if cfg!(not()) { } + | ^^^^^^^^--^ + | | | + | | expected a single argument here + | help: must be of the form: `#![cfg(predicate)]` + | + = note: for more information, visit + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0805`.