From c3ab01080aa82dadc95b61fda0ee1b102836d927 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Thu, 12 May 2022 22:29:01 -0400 Subject: [PATCH 1/4] Improve `cfg_if!` parsing during module resolution Fixes 4442 * Prevent Infinite loop when reaching tokens that can't be parsed as items. For example, nested `if #[..]` checks. * Handle arbitrarily nested `if #[..]`, `else if #[..]`, `else` checks. --- src/parse/macros/cfg_if.rs | 82 +++++++++++++++++++++------------- tests/source/issue-4442/a.rs | 2 + tests/source/issue-4442/b.rs | 2 + tests/source/issue-4442/c.rs | 2 + tests/source/issue-4442/d.rs | 2 + tests/source/issue-4442/e.rs | 2 + tests/source/issue-4442/lib.rs | 26 +++++++++++ tests/target/issue-4442/a.rs | 3 ++ tests/target/issue-4442/b.rs | 3 ++ tests/target/issue-4442/c.rs | 3 ++ tests/target/issue-4442/d.rs | 3 ++ tests/target/issue-4442/e.rs | 3 ++ tests/target/issue-4442/lib.rs | 26 +++++++++++ 13 files changed, 127 insertions(+), 32 deletions(-) create mode 100644 tests/source/issue-4442/a.rs create mode 100644 tests/source/issue-4442/b.rs create mode 100644 tests/source/issue-4442/c.rs create mode 100644 tests/source/issue-4442/d.rs create mode 100644 tests/source/issue-4442/e.rs create mode 100644 tests/source/issue-4442/lib.rs create mode 100644 tests/target/issue-4442/a.rs create mode 100644 tests/target/issue-4442/b.rs create mode 100644 tests/target/issue-4442/c.rs create mode 100644 tests/target/issue-4442/d.rs create mode 100644 tests/target/issue-4442/e.rs create mode 100644 tests/target/issue-4442/lib.rs diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index 5fc988e4319..638c3c1267b 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -2,7 +2,7 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use rustc_ast::ast; use rustc_ast::token::{Delimiter, TokenKind}; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_span::symbol::kw; use crate::parse::macros::build_stream_parser; @@ -31,32 +31,7 @@ fn parse_cfg_if_inner<'a>( while parser.token.kind != TokenKind::Eof { if process_if_cfg { - if !parser.eat_keyword(kw::If) { - return Err("Expected `if`"); - } - - if !matches!(parser.token.kind, TokenKind::Pound) { - return Err("Failed to parse attributes"); - } - - // Inner attributes are not actually syntactically permitted here, but we don't - // care about inner vs outer attributes in this position. Our purpose with this - // special case parsing of cfg_if macros is to ensure we can correctly resolve - // imported modules that may have a custom `path` defined. - // - // As such, we just need to advance the parser past the attribute and up to - // to the opening brace. - // See also https://github.com/rust-lang/rust/pull/79433 - parser - .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) - .map_err(|e| { - e.cancel(); - "Failed to parse attributes" - })?; - } - - if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) { - return Err("Expected an opening brace"); + eat_if(&mut parser)?; } while parser.token != TokenKind::CloseDelim(Delimiter::Brace) @@ -64,7 +39,17 @@ fn parse_cfg_if_inner<'a>( { let item = match parser.parse_item(ForceCollect::No) { Ok(Some(item_ptr)) => item_ptr.into_inner(), - Ok(None) => continue, + Ok(None) => { + if matches!(parser.token.kind, TokenKind::Ident(symbol, ..) if symbol == kw::If) + { + // eat a nested if + eat_if(&mut parser)?; + } else { + // Not sure what token we're on. To prevent infinite loops bump the parser + parser.bump(); + } + continue; + } Err(err) => { err.cancel(); parser.psess.dcx.reset_err_count(); @@ -82,12 +67,15 @@ fn parse_cfg_if_inner<'a>( return Err("Expected a closing brace"); } - if parser.eat(&TokenKind::Eof) { - break; + if matches!(parser.token.kind, TokenKind::Ident(symbol, ..) if symbol == kw::Else) { + // there might be an `else` after the `if` + parser.eat_keyword(kw::Else); + // there might be an opening brace after the `else`, but it might also be an `else if` + parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)); } - if !parser.eat_keyword(kw::Else) { - return Err("Expected `else`"); + if parser.eat(&TokenKind::Eof) { + break; } process_if_cfg = parser.token.is_keyword(kw::If); @@ -95,3 +83,33 @@ fn parse_cfg_if_inner<'a>( Ok(items) } + +fn eat_if(parser: &mut Parser<'_>) -> Result<(), &'static str> { + if !parser.eat_keyword(kw::If) { + return Err("Expected `if`"); + } + + if !matches!(parser.token.kind, TokenKind::Pound) { + return Err("Failed to parse attributes"); + } + + // Inner attributes are not actually syntactically permitted here, but we don't + // care about inner vs outer attributes in this position. Our purpose with this + // special case parsing of cfg_if macros is to ensure we can correctly resolve + // imported modules that may have a custom `path` defined. + // + // As such, we just need to advance the parser past the attribute and up to + // to the opening brace. + // See also https://github.com/rust-lang/rust/pull/79433 + parser + .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted) + .map_err(|e| { + e.cancel(); + "Failed to parse attributes" + })?; + + if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) { + return Err("Expected an opening brace"); + } + Ok(()) +} diff --git a/tests/source/issue-4442/a.rs b/tests/source/issue-4442/a.rs new file mode 100644 index 00000000000..4278f0f85b8 --- /dev/null +++ b/tests/source/issue-4442/a.rs @@ -0,0 +1,2 @@ +fn a () +{println!("mod a")} diff --git a/tests/source/issue-4442/b.rs b/tests/source/issue-4442/b.rs new file mode 100644 index 00000000000..da69971945b --- /dev/null +++ b/tests/source/issue-4442/b.rs @@ -0,0 +1,2 @@ +fn b () +{println!("mod b")} diff --git a/tests/source/issue-4442/c.rs b/tests/source/issue-4442/c.rs new file mode 100644 index 00000000000..43fadb4146d --- /dev/null +++ b/tests/source/issue-4442/c.rs @@ -0,0 +1,2 @@ +fn c () +{println!("mod c")} diff --git a/tests/source/issue-4442/d.rs b/tests/source/issue-4442/d.rs new file mode 100644 index 00000000000..99a9598f325 --- /dev/null +++ b/tests/source/issue-4442/d.rs @@ -0,0 +1,2 @@ +fn d () +{println!("mod d")} diff --git a/tests/source/issue-4442/e.rs b/tests/source/issue-4442/e.rs new file mode 100644 index 00000000000..dc28c824946 --- /dev/null +++ b/tests/source/issue-4442/e.rs @@ -0,0 +1,2 @@ +fn e () +{println!("mod e")} diff --git a/tests/source/issue-4442/lib.rs b/tests/source/issue-4442/lib.rs new file mode 100644 index 00000000000..4eddbfa28fa --- /dev/null +++ b/tests/source/issue-4442/lib.rs @@ -0,0 +1,26 @@ +// main.rs +cfg_if::cfg_if! { + if #[cfg(not(feature = "client"))] { + mod a; + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + mod b; + } else { + mod c; + } + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + if #[cfg(feature = "server")] { + mod d; + } else { + mod e; + } + } + } + } + } + } + } +} diff --git a/tests/target/issue-4442/a.rs b/tests/target/issue-4442/a.rs new file mode 100644 index 00000000000..6ee01582a2c --- /dev/null +++ b/tests/target/issue-4442/a.rs @@ -0,0 +1,3 @@ +fn a() { + println!("mod a") +} diff --git a/tests/target/issue-4442/b.rs b/tests/target/issue-4442/b.rs new file mode 100644 index 00000000000..c1a0a54d143 --- /dev/null +++ b/tests/target/issue-4442/b.rs @@ -0,0 +1,3 @@ +fn b() { + println!("mod b") +} diff --git a/tests/target/issue-4442/c.rs b/tests/target/issue-4442/c.rs new file mode 100644 index 00000000000..1e4661c5033 --- /dev/null +++ b/tests/target/issue-4442/c.rs @@ -0,0 +1,3 @@ +fn c() { + println!("mod c") +} diff --git a/tests/target/issue-4442/d.rs b/tests/target/issue-4442/d.rs new file mode 100644 index 00000000000..3679b181da8 --- /dev/null +++ b/tests/target/issue-4442/d.rs @@ -0,0 +1,3 @@ +fn d() { + println!("mod d") +} diff --git a/tests/target/issue-4442/e.rs b/tests/target/issue-4442/e.rs new file mode 100644 index 00000000000..5a21024b9ac --- /dev/null +++ b/tests/target/issue-4442/e.rs @@ -0,0 +1,3 @@ +fn e() { + println!("mod e") +} diff --git a/tests/target/issue-4442/lib.rs b/tests/target/issue-4442/lib.rs new file mode 100644 index 00000000000..4eddbfa28fa --- /dev/null +++ b/tests/target/issue-4442/lib.rs @@ -0,0 +1,26 @@ +// main.rs +cfg_if::cfg_if! { + if #[cfg(not(feature = "client"))] { + mod a; + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + mod b; + } else { + mod c; + } + if #[cfg(feature = "server")] { + if #[cfg(not(feature = "client"))] { + if #[cfg(feature = "server")] { + mod d; + } else { + mod e; + } + } + } + } + } + } + } +} From df9a3a0017465ef3869c68296179aa0cdec900d1 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 6 Jul 2022 09:11:03 -0400 Subject: [PATCH 2/4] Add cfg_if! test case for issue 5428 --- tests/target/issue_5428.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/target/issue_5428.rs diff --git a/tests/target/issue_5428.rs b/tests/target/issue_5428.rs new file mode 100644 index 00000000000..727d8e4c20f --- /dev/null +++ b/tests/target/issue_5428.rs @@ -0,0 +1,6 @@ +// cfg-if: version 1.0.0 +cfg_if::cfg_if! { + if #[cfg(windows)] { + compile_error!{"..."}; + } +} From 3c1160df86c5e5f9b6c8dbd921e095ef4e7b803e Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 6 Jul 2022 15:03:05 -0400 Subject: [PATCH 3/4] Add cfg_if! test case for issue 5413 --- tests/source/issue_5413.rs | 16 ++++++++++++++++ tests/target/issue_5413.rs | 15 +++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/source/issue_5413.rs create mode 100644 tests/target/issue_5413.rs diff --git a/tests/source/issue_5413.rs b/tests/source/issue_5413.rs new file mode 100644 index 00000000000..c4952f69cba --- /dev/null +++ b/tests/source/issue_5413.rs @@ -0,0 +1,16 @@ +cfg_if! { + if +} + +cfg_if! { + if #[a] { } else if +} + +cfg_if! { + if #[a] { if } +} + +fn main( + ) { +println!("hello world!"); + } diff --git a/tests/target/issue_5413.rs b/tests/target/issue_5413.rs new file mode 100644 index 00000000000..67f7e06d6a4 --- /dev/null +++ b/tests/target/issue_5413.rs @@ -0,0 +1,15 @@ +cfg_if! { + if +} + +cfg_if! { + if #[a] { } else if +} + +cfg_if! { + if #[a] { if } +} + +fn main() { + println!("hello world!"); +} From 853e9d17315b817e39038b7aa8be769a608a869f Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Mon, 24 Jun 2024 15:15:41 -0400 Subject: [PATCH 4/4] Add test case for issue 6215 --- tests/target/issue_6215.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/target/issue_6215.rs diff --git a/tests/target/issue_6215.rs b/tests/target/issue_6215.rs new file mode 100644 index 00000000000..abfce77b4f4 --- /dev/null +++ b/tests/target/issue_6215.rs @@ -0,0 +1,9 @@ +cfg_if!( + if #[cfg(feature = "xxxx")] { + if #[cfg(feature = "yyyy")] { + pub const C1: u8 = 1; + } else { + pub const C2: u8 = 2; + } + } +);