Rollup merge of #131034 - Urgau:cfg-true-false, r=nnethercote
Implement RFC3695 Allow boolean literals as cfg predicates This PR implements https://github.com/rust-lang/rfcs/pull/3695: allow boolean literals as cfg predicates, i.e. `cfg(true)` and `cfg(false)`. r? `@nnethercote` *(or anyone with parser knowledge)* cc `@clubby789`
This commit is contained in:
commit
2ceeeb159d
@ -527,6 +527,16 @@ impl NestedMetaItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
|
||||||
|
/// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
|
||||||
|
pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
|
||||||
|
match self {
|
||||||
|
NestedMetaItem::MetaItem(_item) => Some(self),
|
||||||
|
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
|
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
|
||||||
pub fn meta_item(&self) -> Option<&MetaItem> {
|
pub fn meta_item(&self) -> Option<&MetaItem> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -107,6 +107,8 @@ attr_unknown_version_literal =
|
|||||||
attr_unstable_cfg_target_compact =
|
attr_unstable_cfg_target_compact =
|
||||||
compact `cfg(target(..))` is experimental and subject to change
|
compact `cfg(target(..))` is experimental and subject to change
|
||||||
|
|
||||||
|
attr_unsupported_literal_cfg_boolean =
|
||||||
|
literal in `cfg` predicate value must be a boolean
|
||||||
attr_unsupported_literal_cfg_string =
|
attr_unsupported_literal_cfg_string =
|
||||||
literal in `cfg` predicate value must be a string
|
literal in `cfg` predicate value must be a string
|
||||||
attr_unsupported_literal_deprecated_kv_pair =
|
attr_unsupported_literal_deprecated_kv_pair =
|
||||||
|
@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
|
|||||||
use rustc_session::{RustcVersion, Session};
|
use rustc_session::{RustcVersion, Session};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::hygiene::Transparency;
|
use rustc_span::hygiene::Transparency;
|
||||||
use rustc_span::symbol::{Symbol, sym};
|
use rustc_span::symbol::{Symbol, kw, sym};
|
||||||
|
|
||||||
use crate::fluent_generated;
|
use crate::fluent_generated;
|
||||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||||
@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
|||||||
pub(crate) enum UnsupportedLiteralReason {
|
pub(crate) enum UnsupportedLiteralReason {
|
||||||
Generic,
|
Generic,
|
||||||
CfgString,
|
CfgString,
|
||||||
|
CfgBoolean,
|
||||||
DeprecatedString,
|
DeprecatedString,
|
||||||
DeprecatedKvPair,
|
DeprecatedKvPair,
|
||||||
}
|
}
|
||||||
@ -533,7 +534,7 @@ pub struct Condition {
|
|||||||
|
|
||||||
/// Tests if a cfg-pattern matches the cfg set
|
/// Tests if a cfg-pattern matches the cfg set
|
||||||
pub fn cfg_matches(
|
pub fn cfg_matches(
|
||||||
cfg: &ast::MetaItem,
|
cfg: &ast::NestedMetaItem,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
lint_node_id: NodeId,
|
lint_node_id: NodeId,
|
||||||
features: Option<&Features>,
|
features: Option<&Features>,
|
||||||
@ -604,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
|||||||
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||||
/// evaluate individual items.
|
/// evaluate individual items.
|
||||||
pub fn eval_condition(
|
pub fn eval_condition(
|
||||||
cfg: &ast::MetaItem,
|
cfg: &ast::NestedMetaItem,
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
features: Option<&Features>,
|
features: Option<&Features>,
|
||||||
eval: &mut impl FnMut(Condition) -> bool,
|
eval: &mut impl FnMut(Condition) -> bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let dcx = sess.dcx();
|
let dcx = sess.dcx();
|
||||||
|
|
||||||
|
let cfg = match cfg {
|
||||||
|
ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
|
||||||
|
ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||||
|
if let Some(features) = features {
|
||||||
|
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
|
||||||
|
// and `true`, and we want to keep the former working without feature gate
|
||||||
|
gate_cfg(
|
||||||
|
&((
|
||||||
|
if *b { kw::True } else { kw::False },
|
||||||
|
sym::cfg_boolean_literals,
|
||||||
|
|features: &Features| features.cfg_boolean_literals,
|
||||||
|
)),
|
||||||
|
cfg.span(),
|
||||||
|
sess,
|
||||||
|
features,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return *b;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
|
span: cfg.span(),
|
||||||
|
reason: UnsupportedLiteralReason::CfgBoolean,
|
||||||
|
is_bytestr: false,
|
||||||
|
start_point_span: sess.source_map().start_point(cfg.span()),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match &cfg.kind {
|
match &cfg.kind {
|
||||||
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||||
@ -645,7 +677,7 @@ pub fn eval_condition(
|
|||||||
}
|
}
|
||||||
ast::MetaItemKind::List(mis) => {
|
ast::MetaItemKind::List(mis) => {
|
||||||
for mi in mis.iter() {
|
for mi in mis.iter() {
|
||||||
if !mi.is_meta_item() {
|
if mi.meta_item_or_bool().is_none() {
|
||||||
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||||
span: mi.span(),
|
span: mi.span(),
|
||||||
reason: UnsupportedLiteralReason::Generic,
|
reason: UnsupportedLiteralReason::Generic,
|
||||||
@ -663,23 +695,19 @@ pub fn eval_condition(
|
|||||||
.iter()
|
.iter()
|
||||||
// We don't use any() here, because we want to evaluate all cfg condition
|
// We don't use any() here, because we want to evaluate all cfg condition
|
||||||
// as eval_condition can (and does) extra checks
|
// as eval_condition can (and does) extra checks
|
||||||
.fold(false, |res, mi| {
|
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
|
||||||
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
|
||||||
}),
|
|
||||||
sym::all => mis
|
sym::all => mis
|
||||||
.iter()
|
.iter()
|
||||||
// We don't use all() here, because we want to evaluate all cfg condition
|
// We don't use all() here, because we want to evaluate all cfg condition
|
||||||
// as eval_condition can (and does) extra checks
|
// as eval_condition can (and does) extra checks
|
||||||
.fold(true, |res, mi| {
|
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
|
||||||
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
|
||||||
}),
|
|
||||||
sym::not => {
|
sym::not => {
|
||||||
let [mi] = mis.as_slice() else {
|
let [mi] = mis.as_slice() else {
|
||||||
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
!eval_condition(mi, sess, features, eval)
|
||||||
}
|
}
|
||||||
sym::target => {
|
sym::target => {
|
||||||
if let Some(features) = features
|
if let Some(features) = features
|
||||||
@ -700,7 +728,12 @@ pub fn eval_condition(
|
|||||||
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
|
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
res & eval_condition(&mi, sess, features, eval)
|
res & eval_condition(
|
||||||
|
&ast::NestedMetaItem::MetaItem(mi),
|
||||||
|
sess,
|
||||||
|
features,
|
||||||
|
eval,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
|
|||||||
let mut diag = Diag::new(dcx, level, match self.reason {
|
let mut diag = Diag::new(dcx, level, match self.reason {
|
||||||
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
|
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
|
||||||
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
|
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
|
||||||
|
UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
|
||||||
UnsupportedLiteralReason::DeprecatedString => {
|
UnsupportedLiteralReason::DeprecatedString => {
|
||||||
fluent::attr_unsupported_literal_deprecated_string
|
fluent::attr_unsupported_literal_deprecated_string
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use rustc_ast::token;
|
|||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||||
use rustc_parse::parser::attr::AllowLeadingUnsafe;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use {rustc_ast as ast, rustc_attr as attr};
|
use {rustc_ast as ast, rustc_attr as attr};
|
||||||
|
|
||||||
@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
|
fn parse_cfg<'a>(
|
||||||
|
cx: &ExtCtxt<'a>,
|
||||||
|
span: Span,
|
||||||
|
tts: TokenStream,
|
||||||
|
) -> PResult<'a, ast::NestedMetaItem> {
|
||||||
let mut p = cx.new_parser_from_tts(tts);
|
let mut p = cx.new_parser_from_tts(tts);
|
||||||
|
|
||||||
if p.token == token::Eof {
|
if p.token == token::Eof {
|
||||||
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
|
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
|
let cfg = p.parse_meta_item_inner()?;
|
||||||
|
|
||||||
let _ = p.eat(&token::Comma);
|
let _ = p.eat(&token::Comma);
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ pub struct NativeLib {
|
|||||||
pub kind: NativeLibKind,
|
pub kind: NativeLibKind,
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
pub filename: Option<Symbol>,
|
pub filename: Option<Symbol>,
|
||||||
pub cfg: Option<ast::MetaItem>,
|
pub cfg: Option<ast::NestedMetaItem>,
|
||||||
pub verbatim: bool,
|
pub verbatim: bool,
|
||||||
pub dll_imports: Vec<cstore::DllImport>,
|
pub dll_imports: Vec<cstore::DllImport>,
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
|
|||||||
use rustc_ast::tokenstream::{
|
use rustc_ast::tokenstream::{
|
||||||
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
|
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
|
||||||
};
|
};
|
||||||
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
|
use rustc_ast::{
|
||||||
|
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
|
||||||
|
};
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||||
use rustc_feature::{
|
use rustc_feature::{
|
||||||
@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
|
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
|
||||||
let span = meta_item.span;
|
let span = meta_item.span;
|
||||||
match meta_item.meta_item_list() {
|
match meta_item.meta_item_list() {
|
||||||
None => {
|
None => {
|
||||||
@ -464,7 +466,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
|
|||||||
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
|
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Some([single]) => match single.meta_item() {
|
Some([single]) => match single.meta_item_or_bool() {
|
||||||
Some(meta_item) => Some(meta_item),
|
Some(meta_item) => Some(meta_item),
|
||||||
None => {
|
None => {
|
||||||
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
|
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
|
||||||
|
@ -371,6 +371,8 @@ declare_features! (
|
|||||||
(unstable, async_for_loop, "1.77.0", Some(118898)),
|
(unstable, async_for_loop, "1.77.0", Some(118898)),
|
||||||
/// Allows using C-variadics.
|
/// Allows using C-variadics.
|
||||||
(unstable, c_variadic, "1.34.0", Some(44930)),
|
(unstable, c_variadic, "1.34.0", Some(44930)),
|
||||||
|
/// Allows the use of `#[cfg(<true/false>)]`.
|
||||||
|
(unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
|
||||||
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
||||||
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
|
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
|
||||||
/// Provides the relocation model information as cfg entry
|
/// Provides the relocation model information as cfg entry
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
|
use rustc_ast::CRATE_NODE_ID;
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_middle::query::LocalCrate;
|
use rustc_middle::query::LocalCrate;
|
||||||
@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
|
|||||||
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
|
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
|
let [link_cfg] = link_cfg else {
|
||||||
|
sess.dcx()
|
||||||
|
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
|
||||||
sess.dcx()
|
sess.dcx()
|
||||||
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
|
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
|
||||||
continue;
|
continue;
|
||||||
|
@ -18,7 +18,7 @@ use std::path::Path;
|
|||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::{AttrItem, Attribute, MetaItem, token};
|
use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Diag, FatalError, PResult};
|
use rustc_errors::{Diag, FatalError, PResult};
|
||||||
@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
|
|||||||
pub fn parse_cfg_attr(
|
pub fn parse_cfg_attr(
|
||||||
cfg_attr: &Attribute,
|
cfg_attr: &Attribute,
|
||||||
psess: &ParseSess,
|
psess: &ParseSess,
|
||||||
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
|
) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
|
||||||
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
|
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
|
||||||
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
|
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
|
||||||
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
|
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
|
||||||
|
@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
|
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
|
||||||
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
|
pub fn parse_cfg_attr(
|
||||||
let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
|
&mut self,
|
||||||
|
) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
|
||||||
|
let cfg_predicate = self.parse_meta_item_inner()?;
|
||||||
self.expect(&token::Comma)?;
|
self.expect(&token::Comma)?;
|
||||||
|
|
||||||
// Presumably, the majority of the time there will only be one attr.
|
// Presumably, the majority of the time there will only be one attr.
|
||||||
@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
|
|||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
|
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
||||||
match self.parse_unsuffixed_meta_item_lit() {
|
match self.parse_unsuffixed_meta_item_lit() {
|
||||||
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
|
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
|
||||||
Err(err) => err.cancel(), // we provide a better error below
|
Err(err) => err.cancel(), // we provide a better error below
|
||||||
|
@ -72,7 +72,7 @@ pub struct NativeLib {
|
|||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
/// If packed_bundled_libs enabled, actual filename of library is stored.
|
/// If packed_bundled_libs enabled, actual filename of library is stored.
|
||||||
pub filename: Option<Symbol>,
|
pub filename: Option<Symbol>,
|
||||||
pub cfg: Option<ast::MetaItem>,
|
pub cfg: Option<ast::NestedMetaItem>,
|
||||||
pub foreign_module: Option<DefId>,
|
pub foreign_module: Option<DefId>,
|
||||||
pub verbatim: Option<bool>,
|
pub verbatim: Option<bool>,
|
||||||
pub dll_imports: Vec<DllImport>,
|
pub dll_imports: Vec<DllImport>,
|
||||||
|
@ -544,6 +544,7 @@ symbols! {
|
|||||||
cfg_accessible,
|
cfg_accessible,
|
||||||
cfg_attr,
|
cfg_attr,
|
||||||
cfg_attr_multi,
|
cfg_attr_multi,
|
||||||
|
cfg_boolean_literals,
|
||||||
cfg_doctest,
|
cfg_doctest,
|
||||||
cfg_eval,
|
cfg_eval,
|
||||||
cfg_fmt_debug,
|
cfg_fmt_debug,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
|
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
|
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
|
||||||
@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OnUnimplementedDirective {
|
pub struct OnUnimplementedDirective {
|
||||||
pub condition: Option<MetaItem>,
|
pub condition: Option<NestedMetaItem>,
|
||||||
pub subcommands: Vec<OnUnimplementedDirective>,
|
pub subcommands: Vec<OnUnimplementedDirective>,
|
||||||
pub message: Option<OnUnimplementedFormatString>,
|
pub message: Option<OnUnimplementedFormatString>,
|
||||||
pub label: Option<OnUnimplementedFormatString>,
|
pub label: Option<OnUnimplementedFormatString>,
|
||||||
@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||||||
let cond = item_iter
|
let cond = item_iter
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
|
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
|
||||||
.meta_item()
|
.meta_item_or_bool()
|
||||||
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
|
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
|
||||||
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
|
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
|
||||||
if let Some(value) = cfg.value
|
if let Some(value) = cfg.value
|
||||||
@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
|
|||||||
IgnoredDiagnosticOption::maybe_emit_warning(
|
IgnoredDiagnosticOption::maybe_emit_warning(
|
||||||
tcx,
|
tcx,
|
||||||
item_def_id,
|
item_def_id,
|
||||||
directive.condition.as_ref().map(|i| i.span),
|
directive.condition.as_ref().map(|i| i.span()),
|
||||||
aggr.condition.as_ref().map(|i| i.span),
|
aggr.condition.as_ref().map(|i| i.span()),
|
||||||
"condition",
|
"condition",
|
||||||
);
|
);
|
||||||
IgnoredDiagnosticOption::maybe_emit_warning(
|
IgnoredDiagnosticOption::maybe_emit_warning(
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
# `cfg_boolean_literals`
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#131204]
|
||||||
|
|
||||||
|
[#131204]: https://github.com/rust-lang/rust/issues/131204
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
|
||||||
|
literal as cfg predicate. They always evaluate to true/false respectively.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#![feature(cfg_boolean_literals)]
|
||||||
|
|
||||||
|
#[cfg(true)]
|
||||||
|
const A: i32 = 5;
|
||||||
|
|
||||||
|
#[cfg(all(false))]
|
||||||
|
const A: i32 = 58 * 89;
|
||||||
|
```
|
@ -6,7 +6,7 @@
|
|||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::{mem, ops};
|
use std::{mem, ops};
|
||||||
|
|
||||||
use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
|
use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
@ -48,6 +48,10 @@ impl Cfg {
|
|||||||
) -> Result<Option<Cfg>, InvalidCfgError> {
|
) -> Result<Option<Cfg>, InvalidCfgError> {
|
||||||
match nested_cfg {
|
match nested_cfg {
|
||||||
NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
|
NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
|
||||||
|
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b {
|
||||||
|
true => Ok(Some(Cfg::True)),
|
||||||
|
false => Ok(Some(Cfg::False)),
|
||||||
|
},
|
||||||
NestedMetaItem::Lit(ref lit) => {
|
NestedMetaItem::Lit(ref lit) => {
|
||||||
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
|
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
|
||||||
}
|
}
|
||||||
@ -120,8 +124,8 @@ impl Cfg {
|
|||||||
///
|
///
|
||||||
/// If the content is not properly formatted, it will return an error indicating what and where
|
/// If the content is not properly formatted, it will return an error indicating what and where
|
||||||
/// the error is.
|
/// the error is.
|
||||||
pub(crate) fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
|
pub(crate) fn parse(cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
|
||||||
Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
|
Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether the given configuration can be matched in the current session.
|
/// Checks whether the given configuration can be matched in the current session.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
|
use rustc_ast::ast::LitIntType;
|
||||||
|
use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle};
|
||||||
use rustc_span::symbol::{Ident, kw};
|
use rustc_span::symbol::{Ident, kw};
|
||||||
use rustc_span::{DUMMY_SP, create_default_session_globals_then};
|
use rustc_span::{DUMMY_SP, create_default_session_globals_then};
|
||||||
use thin_vec::thin_vec;
|
use thin_vec::thin_vec;
|
||||||
@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
|
|||||||
Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
|
Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy_meta_item_word(name: &str) -> MetaItem {
|
fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem {
|
||||||
MetaItem {
|
NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dummy_meta_item_word(name: &str) -> NestedMetaItem {
|
||||||
|
NestedMetaItem::MetaItem(MetaItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
path: Path::from_ident(Ident::from_str(name)),
|
path: Path::from_ident(Ident::from_str(name)),
|
||||||
kind: MetaItemKind::Word,
|
kind: MetaItemKind::Word,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
|
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem {
|
||||||
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
|
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
|
||||||
MetaItem {
|
NestedMetaItem::MetaItem(MetaItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
path: Path::from_ident(Ident::from_str(name)),
|
path: Path::from_ident(Ident::from_str(name)),
|
||||||
kind: MetaItemKind::NameValue(lit),
|
kind: MetaItemKind::NameValue(lit),
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! dummy_meta_item_list {
|
macro_rules! dummy_meta_item_list {
|
||||||
($name:ident, [$($list:ident),* $(,)?]) => {
|
($name:ident, [$($list:ident),* $(,)?]) => {
|
||||||
MetaItem {
|
NestedMetaItem::MetaItem(MetaItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||||
kind: MetaItemKind::List(thin_vec![
|
kind: MetaItemKind::List(thin_vec![
|
||||||
$(
|
$(
|
||||||
NestedMetaItem::MetaItem(
|
dummy_meta_item_word(stringify!($list)),
|
||||||
dummy_meta_item_word(stringify!($list)),
|
|
||||||
),
|
|
||||||
)*
|
)*
|
||||||
]),
|
]),
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
($name:ident, [$($list:expr),* $(,)?]) => {
|
($name:ident, [$($list:expr),* $(,)?]) => {
|
||||||
MetaItem {
|
NestedMetaItem::MetaItem(MetaItem {
|
||||||
unsafety: Safety::Default,
|
unsafety: Safety::Default,
|
||||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||||
kind: MetaItemKind::List(thin_vec![
|
kind: MetaItemKind::List(thin_vec![
|
||||||
$(
|
$($list,)*
|
||||||
NestedMetaItem::MetaItem($list),
|
|
||||||
)*
|
|
||||||
]),
|
]),
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +252,14 @@ fn test_cfg_or() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_parse_ok() {
|
fn test_parse_ok() {
|
||||||
create_default_session_globals_then(|| {
|
create_default_session_globals_then(|| {
|
||||||
|
let r#true = Symbol::intern("true");
|
||||||
|
let mi = dummy_lit(r#true, LitKind::Bool(true));
|
||||||
|
assert_eq!(Cfg::parse(&mi), Ok(Cfg::True));
|
||||||
|
|
||||||
|
let r#false = Symbol::intern("false");
|
||||||
|
let mi = dummy_lit(r#false, LitKind::Bool(false));
|
||||||
|
assert_eq!(Cfg::parse(&mi), Ok(Cfg::False));
|
||||||
|
|
||||||
let mi = dummy_meta_item_word("all");
|
let mi = dummy_meta_item_word("all");
|
||||||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
|
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
|
||||||
|
|
||||||
@ -309,6 +318,14 @@ fn test_parse_err() {
|
|||||||
|
|
||||||
let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
|
let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
|
||||||
assert!(Cfg::parse(&mi).is_err());
|
assert!(Cfg::parse(&mi).is_err());
|
||||||
|
|
||||||
|
let c = Symbol::intern("e");
|
||||||
|
let mi = dummy_lit(c, LitKind::Char('e'));
|
||||||
|
assert!(Cfg::parse(&mi).is_err());
|
||||||
|
|
||||||
|
let five = Symbol::intern("5");
|
||||||
|
let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed));
|
||||||
|
assert!(Cfg::parse(&mi).is_err());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use std::sync::{Arc, OnceLock as OnceCell};
|
|||||||
use std::{fmt, iter};
|
use std::{fmt, iter};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
use rustc_ast::NestedMetaItem;
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
|
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
|
||||||
use rustc_const_eval::const_eval::is_unstable_const_fn;
|
use rustc_const_eval::const_eval::is_unstable_const_fn;
|
||||||
@ -986,7 +987,7 @@ pub(crate) trait AttributesExt {
|
|||||||
.peekable();
|
.peekable();
|
||||||
if doc_cfg.peek().is_some() && doc_cfg_active {
|
if doc_cfg.peek().is_some() && doc_cfg_active {
|
||||||
doc_cfg
|
doc_cfg
|
||||||
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
|
.filter_map(|attr| Cfg::parse(&attr).ok())
|
||||||
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
|
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
|
||||||
} else if doc_auto_cfg_active {
|
} else if doc_auto_cfg_active {
|
||||||
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
|
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
|
||||||
@ -1042,7 +1043,7 @@ pub(crate) trait AttributesExt {
|
|||||||
let mut meta = attr.meta_item().unwrap().clone();
|
let mut meta = attr.meta_item().unwrap().clone();
|
||||||
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
|
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
|
||||||
|
|
||||||
if let Ok(feat_cfg) = Cfg::parse(&meta) {
|
if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) {
|
||||||
cfg &= feat_cfg;
|
cfg &= feat_cfg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||||||
.unwrap_or(&[])
|
.unwrap_or(&[])
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|attr| {
|
.filter_map(|attr| {
|
||||||
Cfg::parse(attr.meta_item()?)
|
Cfg::parse(attr)
|
||||||
.map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
|
.map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
|
||||||
.ok()
|
.ok()
|
||||||
})
|
})
|
||||||
|
19
tests/rustdoc-ui/cfg-boolean-literal.rs
Normal file
19
tests/rustdoc-ui/cfg-boolean-literal.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(cfg_boolean_literals)]
|
||||||
|
#![feature(doc_cfg)]
|
||||||
|
|
||||||
|
#[doc(cfg(false))]
|
||||||
|
pub fn foo() {}
|
||||||
|
|
||||||
|
#[doc(cfg(true))]
|
||||||
|
pub fn bar() {}
|
||||||
|
|
||||||
|
#[doc(cfg(any(true)))]
|
||||||
|
pub fn zoo() {}
|
||||||
|
|
||||||
|
#[doc(cfg(all(true)))]
|
||||||
|
pub fn toy() {}
|
||||||
|
|
||||||
|
#[doc(cfg(not(true)))]
|
||||||
|
pub fn nay() {}
|
19
tests/ui/cfg/raw-true-false.rs
Normal file
19
tests/ui/cfg/raw-true-false.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ compile-flags: --cfg false --check-cfg=cfg(r#false)
|
||||||
|
|
||||||
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
#[expect(unexpected_cfgs)]
|
||||||
|
mod a {
|
||||||
|
#[cfg(r#true)]
|
||||||
|
pub fn foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod b {
|
||||||
|
#[cfg(r#false)]
|
||||||
|
pub fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
b::bar()
|
||||||
|
}
|
30
tests/ui/cfg/true-false.rs
Normal file
30
tests/ui/cfg/true-false.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
#![feature(link_cfg)]
|
||||||
|
#![feature(cfg_boolean_literals)]
|
||||||
|
|
||||||
|
#[cfg(true)]
|
||||||
|
fn foo() -> bool {
|
||||||
|
cfg!(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(false)]
|
||||||
|
fn foo() -> bool {
|
||||||
|
cfg!(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(true, cfg(false))]
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
#[link(name = "foo", cfg(false))]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert!(foo());
|
||||||
|
assert!(cfg!(true));
|
||||||
|
assert!(!cfg!(false));
|
||||||
|
assert!(cfg!(not(false)));
|
||||||
|
assert!(cfg!(all(true)));
|
||||||
|
assert!(cfg!(any(true)));
|
||||||
|
assert!(!cfg!(not(true)));
|
||||||
|
}
|
10
tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
Normal file
10
tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[cfg(true)] //~ ERROR `cfg(true)` is experimental
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental
|
||||||
|
//~^ ERROR `cfg(false)` is experimental
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
cfg!(false); //~ ERROR `cfg(false)` is experimental
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
error[E0658]: `cfg(true)` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-boolean-literals.rs:1:7
|
||||||
|
|
|
||||||
|
LL | #[cfg(true)]
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
|
||||||
|
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: `cfg(true)` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:12
|
||||||
|
|
|
||||||
|
LL | #[cfg_attr(true, cfg(false))]
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
|
||||||
|
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: `cfg(false)` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:22
|
||||||
|
|
|
||||||
|
LL | #[cfg_attr(true, cfg(false))]
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
|
||||||
|
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: `cfg(false)` is experimental and subject to change
|
||||||
|
--> $DIR/feature-gate-cfg-boolean-literals.rs:9:10
|
||||||
|
|
|
||||||
|
LL | cfg!(false);
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
|
||||||
|
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -1,6 +1,6 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
cfg!(); //~ ERROR macro requires a cfg-pattern
|
cfg!(); //~ ERROR macro requires a cfg-pattern
|
||||||
cfg!(123); //~ ERROR expected identifier
|
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!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
|
||||||
cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
|
cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ LL | cfg!();
|
|||||||
|
|
|
|
||||||
= note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: expected identifier, found `123`
|
error[E0565]: literal in `cfg` predicate value must be a boolean
|
||||||
--> $DIR/cfg.rs:3:10
|
--> $DIR/cfg.rs:3:10
|
||||||
|
|
|
|
||||||
LL | cfg!(123);
|
LL | cfg!(123);
|
||||||
| ^^^ expected identifier
|
| ^^^
|
||||||
|
|
||||||
error[E0565]: literal in `cfg` predicate value must be a string
|
error[E0565]: literal in `cfg` predicate value must be a string
|
||||||
--> $DIR/cfg.rs:4:16
|
--> $DIR/cfg.rs:4:16
|
||||||
|
Loading…
x
Reference in New Issue
Block a user