Skip to content

Commit 2ceeeb1

Browse files
authoredOct 4, 2024
Rollup merge of #131034 - Urgau:cfg-true-false, r=nnethercote
Implement RFC3695 Allow boolean literals as cfg predicates This PR implements rust-lang/rfcs#3695: allow boolean literals as cfg predicates, i.e. `cfg(true)` and `cfg(false)`. r? `@nnethercote` *(or anyone with parser knowledge)* cc `@clubby789`
2 parents 3002af6 + a3ffa1e commit 2ceeeb1

File tree

26 files changed

+284
-58
lines changed

26 files changed

+284
-58
lines changed
 

‎compiler/rustc_ast/src/attr/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,16 @@ impl NestedMetaItem {
527527
}
528528
}
529529

530+
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
531+
/// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
532+
pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
533+
match self {
534+
NestedMetaItem::MetaItem(_item) => Some(self),
535+
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
536+
_ => None,
537+
}
538+
}
539+
530540
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
531541
pub fn meta_item(&self) -> Option<&MetaItem> {
532542
match self {

‎compiler/rustc_attr/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ attr_unknown_version_literal =
107107
attr_unstable_cfg_target_compact =
108108
compact `cfg(target(..))` is experimental and subject to change
109109
110+
attr_unsupported_literal_cfg_boolean =
111+
literal in `cfg` predicate value must be a boolean
110112
attr_unsupported_literal_cfg_string =
111113
literal in `cfg` predicate value must be a string
112114
attr_unsupported_literal_deprecated_kv_pair =

‎compiler/rustc_attr/src/builtin.rs

+45-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
1818
use rustc_session::{RustcVersion, Session};
1919
use rustc_span::Span;
2020
use rustc_span::hygiene::Transparency;
21-
use rustc_span::symbol::{Symbol, sym};
21+
use rustc_span::symbol::{Symbol, kw, sym};
2222

2323
use crate::fluent_generated;
2424
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
3636
pub(crate) enum UnsupportedLiteralReason {
3737
Generic,
3838
CfgString,
39+
CfgBoolean,
3940
DeprecatedString,
4041
DeprecatedKvPair,
4142
}
@@ -533,7 +534,7 @@ pub struct Condition {
533534

534535
/// Tests if a cfg-pattern matches the cfg set
535536
pub fn cfg_matches(
536-
cfg: &ast::MetaItem,
537+
cfg: &ast::NestedMetaItem,
537538
sess: &Session,
538539
lint_node_id: NodeId,
539540
features: Option<&Features>,
@@ -604,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
604605
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
605606
/// evaluate individual items.
606607
pub fn eval_condition(
607-
cfg: &ast::MetaItem,
608+
cfg: &ast::NestedMetaItem,
608609
sess: &Session,
609610
features: Option<&Features>,
610611
eval: &mut impl FnMut(Condition) -> bool,
611612
) -> bool {
612613
let dcx = sess.dcx();
614+
615+
let cfg = match cfg {
616+
ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
617+
ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
618+
if let Some(features) = features {
619+
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
620+
// and `true`, and we want to keep the former working without feature gate
621+
gate_cfg(
622+
&((
623+
if *b { kw::True } else { kw::False },
624+
sym::cfg_boolean_literals,
625+
|features: &Features| features.cfg_boolean_literals,
626+
)),
627+
cfg.span(),
628+
sess,
629+
features,
630+
);
631+
}
632+
return *b;
633+
}
634+
_ => {
635+
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
636+
span: cfg.span(),
637+
reason: UnsupportedLiteralReason::CfgBoolean,
638+
is_bytestr: false,
639+
start_point_span: sess.source_map().start_point(cfg.span()),
640+
});
641+
return false;
642+
}
643+
};
644+
613645
match &cfg.kind {
614646
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
615647
try_gate_cfg(sym::version, cfg.span, sess, features);
@@ -645,7 +677,7 @@ pub fn eval_condition(
645677
}
646678
ast::MetaItemKind::List(mis) => {
647679
for mi in mis.iter() {
648-
if !mi.is_meta_item() {
680+
if mi.meta_item_or_bool().is_none() {
649681
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
650682
span: mi.span(),
651683
reason: UnsupportedLiteralReason::Generic,
@@ -663,23 +695,19 @@ pub fn eval_condition(
663695
.iter()
664696
// We don't use any() here, because we want to evaluate all cfg condition
665697
// as eval_condition can (and does) extra checks
666-
.fold(false, |res, mi| {
667-
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
668-
}),
698+
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
669699
sym::all => mis
670700
.iter()
671701
// We don't use all() here, because we want to evaluate all cfg condition
672702
// as eval_condition can (and does) extra checks
673-
.fold(true, |res, mi| {
674-
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
675-
}),
703+
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
676704
sym::not => {
677705
let [mi] = mis.as_slice() else {
678706
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
679707
return false;
680708
};
681709

682-
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
710+
!eval_condition(mi, sess, features, eval)
683711
}
684712
sym::target => {
685713
if let Some(features) = features
@@ -700,7 +728,12 @@ pub fn eval_condition(
700728
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
701729
}
702730

703-
res & eval_condition(&mi, sess, features, eval)
731+
res & eval_condition(
732+
&ast::NestedMetaItem::MetaItem(mi),
733+
sess,
734+
features,
735+
eval,
736+
)
704737
})
705738
}
706739
_ => {

‎compiler/rustc_attr/src/session_diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
206206
let mut diag = Diag::new(dcx, level, match self.reason {
207207
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
208208
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
209+
UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
209210
UnsupportedLiteralReason::DeprecatedString => {
210211
fluent::attr_unsupported_literal_deprecated_string
211212
}

‎compiler/rustc_builtin_macros/src/cfg.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_ast::token;
66
use rustc_ast::tokenstream::TokenStream;
77
use rustc_errors::PResult;
88
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
9-
use rustc_parse::parser::attr::AllowLeadingUnsafe;
109
use rustc_span::Span;
1110
use {rustc_ast as ast, rustc_attr as attr};
1211

@@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
3635
})
3736
}
3837

39-
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
38+
fn parse_cfg<'a>(
39+
cx: &ExtCtxt<'a>,
40+
span: Span,
41+
tts: TokenStream,
42+
) -> PResult<'a, ast::NestedMetaItem> {
4043
let mut p = cx.new_parser_from_tts(tts);
4144

4245
if p.token == token::Eof {
4346
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
4447
}
4548

46-
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
49+
let cfg = p.parse_meta_item_inner()?;
4750

4851
let _ = p.eat(&token::Comma);
4952

‎compiler/rustc_codegen_ssa/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub struct NativeLib {
156156
pub kind: NativeLibKind,
157157
pub name: Symbol,
158158
pub filename: Option<Symbol>,
159-
pub cfg: Option<ast::MetaItem>,
159+
pub cfg: Option<ast::NestedMetaItem>,
160160
pub verbatim: bool,
161161
pub dll_imports: Vec<cstore::DllImport>,
162162
}

‎compiler/rustc_expand/src/config.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
55
use rustc_ast::tokenstream::{
66
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
77
};
8-
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
8+
use rustc_ast::{
9+
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
10+
};
911
use rustc_attr as attr;
1012
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1113
use rustc_feature::{
@@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
449451
}
450452
}
451453

452-
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
454+
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
453455
let span = meta_item.span;
454456
match meta_item.meta_item_list() {
455457
None => {
@@ -464,7 +466,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
464466
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
465467
None
466468
}
467-
Some([single]) => match single.meta_item() {
469+
Some([single]) => match single.meta_item_or_bool() {
468470
Some(meta_item) => Some(meta_item),
469471
None => {
470472
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });

‎compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ declare_features! (
371371
(unstable, async_for_loop, "1.77.0", Some(118898)),
372372
/// Allows using C-variadics.
373373
(unstable, c_variadic, "1.34.0", Some(44930)),
374+
/// Allows the use of `#[cfg(<true/false>)]`.
375+
(unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
374376
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
375377
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
376378
/// Provides the relocation model information as cfg entry

‎compiler/rustc_metadata/src/native_libs.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ops::ControlFlow;
22
use std::path::{Path, PathBuf};
33

4-
use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
4+
use rustc_ast::CRATE_NODE_ID;
55
use rustc_attr as attr;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_middle::query::LocalCrate;
@@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
304304
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
305305
continue;
306306
};
307-
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
307+
let [link_cfg] = link_cfg else {
308+
sess.dcx()
309+
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
310+
continue;
311+
};
312+
let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
308313
sess.dcx()
309314
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
310315
continue;

‎compiler/rustc_parse/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::path::Path;
1818

1919
use rustc_ast as ast;
2020
use rustc_ast::tokenstream::TokenStream;
21-
use rustc_ast::{AttrItem, Attribute, MetaItem, token};
21+
use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
2222
use rustc_ast_pretty::pprust;
2323
use rustc_data_structures::sync::Lrc;
2424
use rustc_errors::{Diag, FatalError, PResult};
@@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
160160
pub fn parse_cfg_attr(
161161
cfg_attr: &Attribute,
162162
psess: &ParseSess,
163-
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
163+
) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
164164
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
165165
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
166166
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";

‎compiler/rustc_parse/src/parser/attr.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
356356
}
357357

358358
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
359-
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
360-
let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
359+
pub fn parse_cfg_attr(
360+
&mut self,
361+
) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
362+
let cfg_predicate = self.parse_meta_item_inner()?;
361363
self.expect(&token::Comma)?;
362364

363365
// Presumably, the majority of the time there will only be one attr.
@@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
452454
/// ```ebnf
453455
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
454456
/// ```
455-
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
457+
pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
456458
match self.parse_unsuffixed_meta_item_lit() {
457459
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
458460
Err(err) => err.cancel(), // we provide a better error below

‎compiler/rustc_session/src/cstore.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub struct NativeLib {
7272
pub name: Symbol,
7373
/// If packed_bundled_libs enabled, actual filename of library is stored.
7474
pub filename: Option<Symbol>,
75-
pub cfg: Option<ast::MetaItem>,
75+
pub cfg: Option<ast::NestedMetaItem>,
7676
pub foreign_module: Option<DefId>,
7777
pub verbatim: Option<bool>,
7878
pub dll_imports: Vec<DllImport>,

‎compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ symbols! {
544544
cfg_accessible,
545545
cfg_attr,
546546
cfg_attr_multi,
547+
cfg_boolean_literals,
547548
cfg_doctest,
548549
cfg_eval,
549550
cfg_fmt_debug,

‎compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::iter;
22
use std::path::PathBuf;
33

4-
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
4+
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::codes::*;
77
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
282282

283283
#[derive(Debug)]
284284
pub struct OnUnimplementedDirective {
285-
pub condition: Option<MetaItem>,
285+
pub condition: Option<NestedMetaItem>,
286286
pub subcommands: Vec<OnUnimplementedDirective>,
287287
pub message: Option<OnUnimplementedFormatString>,
288288
pub label: Option<OnUnimplementedFormatString>,
@@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
414414
let cond = item_iter
415415
.next()
416416
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
417-
.meta_item()
417+
.meta_item_or_bool()
418418
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
419419
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
420420
if let Some(value) = cfg.value
@@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
558558
IgnoredDiagnosticOption::maybe_emit_warning(
559559
tcx,
560560
item_def_id,
561-
directive.condition.as_ref().map(|i| i.span),
562-
aggr.condition.as_ref().map(|i| i.span),
561+
directive.condition.as_ref().map(|i| i.span()),
562+
aggr.condition.as_ref().map(|i| i.span()),
563563
"condition",
564564
);
565565
IgnoredDiagnosticOption::maybe_emit_warning(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# `cfg_boolean_literals`
2+
3+
The tracking issue for this feature is: [#131204]
4+
5+
[#131204]: https://github.com/rust-lang/rust/issues/131204
6+
7+
------------------------
8+
9+
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
10+
literal as cfg predicate. They always evaluate to true/false respectively.
11+
12+
## Examples
13+
14+
```rust
15+
#![feature(cfg_boolean_literals)]
16+
17+
#[cfg(true)]
18+
const A: i32 = 5;
19+
20+
#[cfg(all(false))]
21+
const A: i32 = 58 * 89;
22+
```

‎src/librustdoc/clean/cfg.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use std::fmt::{self, Write};
77
use std::{mem, ops};
88

9-
use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
9+
use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem};
1010
use rustc_data_structures::fx::FxHashSet;
1111
use rustc_feature::Features;
1212
use rustc_session::parse::ParseSess;
@@ -48,6 +48,10 @@ impl Cfg {
4848
) -> Result<Option<Cfg>, InvalidCfgError> {
4949
match nested_cfg {
5050
NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
51+
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b {
52+
true => Ok(Some(Cfg::True)),
53+
false => Ok(Some(Cfg::False)),
54+
},
5155
NestedMetaItem::Lit(ref lit) => {
5256
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
5357
}
@@ -120,8 +124,8 @@ impl Cfg {
120124
///
121125
/// If the content is not properly formatted, it will return an error indicating what and where
122126
/// the error is.
123-
pub(crate) fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
124-
Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
127+
pub(crate) fn parse(cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
128+
Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
125129
}
126130

127131
/// Checks whether the given configuration can be matched in the current session.

‎src/librustdoc/clean/cfg/tests.rs

+34-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
1+
use rustc_ast::ast::LitIntType;
2+
use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle};
23
use rustc_span::symbol::{Ident, kw};
34
use rustc_span::{DUMMY_SP, create_default_session_globals_then};
45
use thin_vec::thin_vec;
@@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
1314
Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
1415
}
1516

16-
fn dummy_meta_item_word(name: &str) -> MetaItem {
17-
MetaItem {
17+
fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem {
18+
NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP })
19+
}
20+
21+
fn dummy_meta_item_word(name: &str) -> NestedMetaItem {
22+
NestedMetaItem::MetaItem(MetaItem {
1823
unsafety: Safety::Default,
1924
path: Path::from_ident(Ident::from_str(name)),
2025
kind: MetaItemKind::Word,
2126
span: DUMMY_SP,
22-
}
27+
})
2328
}
2429

25-
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
30+
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem {
2631
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
27-
MetaItem {
32+
NestedMetaItem::MetaItem(MetaItem {
2833
unsafety: Safety::Default,
2934
path: Path::from_ident(Ident::from_str(name)),
3035
kind: MetaItemKind::NameValue(lit),
3136
span: DUMMY_SP,
32-
}
37+
})
3338
}
3439

3540
macro_rules! dummy_meta_item_list {
3641
($name:ident, [$($list:ident),* $(,)?]) => {
37-
MetaItem {
42+
NestedMetaItem::MetaItem(MetaItem {
3843
unsafety: Safety::Default,
3944
path: Path::from_ident(Ident::from_str(stringify!($name))),
4045
kind: MetaItemKind::List(thin_vec![
4146
$(
42-
NestedMetaItem::MetaItem(
43-
dummy_meta_item_word(stringify!($list)),
44-
),
47+
dummy_meta_item_word(stringify!($list)),
4548
)*
4649
]),
4750
span: DUMMY_SP,
48-
}
51+
})
4952
};
5053

5154
($name:ident, [$($list:expr),* $(,)?]) => {
52-
MetaItem {
55+
NestedMetaItem::MetaItem(MetaItem {
5356
unsafety: Safety::Default,
5457
path: Path::from_ident(Ident::from_str(stringify!($name))),
5558
kind: MetaItemKind::List(thin_vec![
56-
$(
57-
NestedMetaItem::MetaItem($list),
58-
)*
59+
$($list,)*
5960
]),
6061
span: DUMMY_SP,
61-
}
62+
})
6263
};
6364
}
6465

@@ -251,6 +252,14 @@ fn test_cfg_or() {
251252
#[test]
252253
fn test_parse_ok() {
253254
create_default_session_globals_then(|| {
255+
let r#true = Symbol::intern("true");
256+
let mi = dummy_lit(r#true, LitKind::Bool(true));
257+
assert_eq!(Cfg::parse(&mi), Ok(Cfg::True));
258+
259+
let r#false = Symbol::intern("false");
260+
let mi = dummy_lit(r#false, LitKind::Bool(false));
261+
assert_eq!(Cfg::parse(&mi), Ok(Cfg::False));
262+
254263
let mi = dummy_meta_item_word("all");
255264
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
256265

@@ -309,6 +318,14 @@ fn test_parse_err() {
309318

310319
let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
311320
assert!(Cfg::parse(&mi).is_err());
321+
322+
let c = Symbol::intern("e");
323+
let mi = dummy_lit(c, LitKind::Char('e'));
324+
assert!(Cfg::parse(&mi).is_err());
325+
326+
let five = Symbol::intern("5");
327+
let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed));
328+
assert!(Cfg::parse(&mi).is_err());
312329
})
313330
}
314331

‎src/librustdoc/clean/types.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::{Arc, OnceLock as OnceCell};
55
use std::{fmt, iter};
66

77
use arrayvec::ArrayVec;
8+
use rustc_ast::NestedMetaItem;
89
use rustc_ast_pretty::pprust;
910
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
1011
use rustc_const_eval::const_eval::is_unstable_const_fn;
@@ -986,7 +987,7 @@ pub(crate) trait AttributesExt {
986987
.peekable();
987988
if doc_cfg.peek().is_some() && doc_cfg_active {
988989
doc_cfg
989-
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
990+
.filter_map(|attr| Cfg::parse(&attr).ok())
990991
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
991992
} else if doc_auto_cfg_active {
992993
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
@@ -1042,7 +1043,7 @@ pub(crate) trait AttributesExt {
10421043
let mut meta = attr.meta_item().unwrap().clone();
10431044
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
10441045

1045-
if let Ok(feat_cfg) = Cfg::parse(&meta) {
1046+
if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) {
10461047
cfg &= feat_cfg;
10471048
}
10481049
}

‎src/librustdoc/visit_ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
164164
.unwrap_or(&[])
165165
.iter()
166166
.filter_map(|attr| {
167-
Cfg::parse(attr.meta_item()?)
167+
Cfg::parse(attr)
168168
.map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
169169
.ok()
170170
})
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
3+
#![feature(cfg_boolean_literals)]
4+
#![feature(doc_cfg)]
5+
6+
#[doc(cfg(false))]
7+
pub fn foo() {}
8+
9+
#[doc(cfg(true))]
10+
pub fn bar() {}
11+
12+
#[doc(cfg(any(true)))]
13+
pub fn zoo() {}
14+
15+
#[doc(cfg(all(true)))]
16+
pub fn toy() {}
17+
18+
#[doc(cfg(not(true)))]
19+
pub fn nay() {}

‎tests/ui/cfg/raw-true-false.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
//@ compile-flags: --cfg false --check-cfg=cfg(r#false)
3+
4+
#![deny(warnings)]
5+
6+
#[expect(unexpected_cfgs)]
7+
mod a {
8+
#[cfg(r#true)]
9+
pub fn foo() {}
10+
}
11+
12+
mod b {
13+
#[cfg(r#false)]
14+
pub fn bar() {}
15+
}
16+
17+
fn main() {
18+
b::bar()
19+
}

‎tests/ui/cfg/true-false.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ run-pass
2+
3+
#![feature(link_cfg)]
4+
#![feature(cfg_boolean_literals)]
5+
6+
#[cfg(true)]
7+
fn foo() -> bool {
8+
cfg!(true)
9+
}
10+
11+
#[cfg(false)]
12+
fn foo() -> bool {
13+
cfg!(false)
14+
}
15+
16+
#[cfg_attr(true, cfg(false))]
17+
fn foo() {}
18+
19+
#[link(name = "foo", cfg(false))]
20+
extern "C" {}
21+
22+
fn main() {
23+
assert!(foo());
24+
assert!(cfg!(true));
25+
assert!(!cfg!(false));
26+
assert!(cfg!(not(false)));
27+
assert!(cfg!(all(true)));
28+
assert!(cfg!(any(true)));
29+
assert!(!cfg!(not(true)));
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#[cfg(true)] //~ ERROR `cfg(true)` is experimental
2+
fn foo() {}
3+
4+
#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental
5+
//~^ ERROR `cfg(false)` is experimental
6+
fn foo() {}
7+
8+
fn main() {
9+
cfg!(false); //~ ERROR `cfg(false)` is experimental
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0658]: `cfg(true)` is experimental and subject to change
2+
--> $DIR/feature-gate-cfg-boolean-literals.rs:1:7
3+
|
4+
LL | #[cfg(true)]
5+
| ^^^^
6+
|
7+
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
8+
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error[E0658]: `cfg(true)` is experimental and subject to change
12+
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:12
13+
|
14+
LL | #[cfg_attr(true, cfg(false))]
15+
| ^^^^
16+
|
17+
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
18+
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
19+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20+
21+
error[E0658]: `cfg(false)` is experimental and subject to change
22+
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:22
23+
|
24+
LL | #[cfg_attr(true, cfg(false))]
25+
| ^^^^^
26+
|
27+
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
28+
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
29+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
30+
31+
error[E0658]: `cfg(false)` is experimental and subject to change
32+
--> $DIR/feature-gate-cfg-boolean-literals.rs:9:10
33+
|
34+
LL | cfg!(false);
35+
| ^^^^^
36+
|
37+
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
38+
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
39+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
40+
41+
error: aborting due to 4 previous errors
42+
43+
For more information about this error, try `rustc --explain E0658`.

‎tests/ui/macros/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn main() {
22
cfg!(); //~ ERROR macro requires a cfg-pattern
3-
cfg!(123); //~ ERROR expected identifier
3+
cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean
44
cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
55
cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
66
}

‎tests/ui/macros/cfg.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ LL | cfg!();
66
|
77
= note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
88

9-
error: expected identifier, found `123`
9+
error[E0565]: literal in `cfg` predicate value must be a boolean
1010
--> $DIR/cfg.rs:3:10
1111
|
1212
LL | cfg!(123);
13-
| ^^^ expected identifier
13+
| ^^^
1414

1515
error[E0565]: literal in `cfg` predicate value must be a string
1616
--> $DIR/cfg.rs:4:16

0 commit comments

Comments
 (0)
Please sign in to comment.