-
Notifications
You must be signed in to change notification settings - Fork 85
define cfg_if! and cfg_if_expr! internal macros #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
⏳ Code review in progress. Analyzing for code quality issues and best practices. Detailed findings will be posted upon completion. Using Amazon Q Developer for GitHubAmazon Q Developer1 is an AI-powered assistant that integrates directly into your GitHub workflow, enhancing your development process with intelligent features for code development, review, and transformation. Slash Commands
FeaturesAgentic Chat Code Review CustomizationYou can create project-specific rules for Amazon Q Developer to follow:
Example rule:
FeedbackTo provide feedback on Amazon Q Developer, create an issue in the Amazon Q Developer public repository. For more detailed information, visit the Amazon Q for GitHub documentation. Footnotes
|
Summary of ChangesHello @cosmicexplorer, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request integrates custom Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
This PR introduces internal cfg_if!
and cfg_if_expr!
macros to improve platform-specific conditional compilation logic. The implementation is well-structured and addresses a real need for cleaner conditional compilation patterns.
Key Findings
Critical Issues:
- Crash Risk: The
todo!()
macro insrc/read.rs
will panic on non-Unix/Windows platforms when processing symlinks, creating a potential denial-of-service vulnerability - Behavioral Change: Using
std::process::exit(1)
in examples changes program flow compared to the originalreturn 1
statements
Suggestions:
- The macros need proper re-exports at the crate root for external accessibility
- Remove unnecessary clippy suppressions where possible
- Consider separating unrelated changes (like the
fuzzing
→arbitrary
feature change) into separate commits
Recommendation
The core macro implementation is solid and improves code maintainability. However, the critical crash risk with todo!()
must be addressed before merging. The behavioral changes in examples should also be reviewed to ensure they maintain the intended program flow.
The PR title correctly follows Conventional Commits format with the feat:
prefix, which is appropriate for this new internal functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces cfg_if!
and cfg_if_expr!
macros to simplify platform-specific conditional logic, removing verbose #[cfg]
attributes throughout the codebase. This is a great improvement for code readability and maintainability. The implementation of the macros is solid, vendoring cfg_if
and adding a new cfg_if_expr
for expression-based conditionals.
My review focuses on ensuring the refactoring doesn't introduce regressions. I've found one high-severity issue where symlink handling on non-Unix/Windows platforms was changed to panic, which is a regression from the previous behavior of treating them as regular files. I've also noted a minor clippy-related style issue. Overall, this is a valuable change once the identified issues are addressed.
744947c
to
98de40b
Compare
let mut file = self.by_index(i)?; | ||
|
||
let mut outpath = directory.clone(); | ||
/* TODO: the control flow of this method call and subsequent expectations about the |
Check notice
Code scanning / devskim
A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note
drop(file); | ||
make_symlink(&outpath, &target, &self.shared.files)?; | ||
continue; | ||
} | ||
let mut file = self.by_index(i)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method body in general is the only place that has any non-trivial conditional logic changed. I believe the if
within the #[cfg(any(...))]
block is easier to follow. I've also changed all #[cfg(...)]
conditionals to rest directly on the if
block they adorn, instead of the prior convention which created a larger enclosing scope for each #[cfg(...)]
clause.
But I particularly want to point out the one non-trivial logic change in the region I've highlighted here. The reason we needed to drop(file)
was because of lifetime requirements for self
on the call to make_symlink()
. However, the previous code was unconditionally dropping the current entry handle on every single iteration.
This is very unlikely to have any noticeable effect on performance now, but it seems more correct and could be necessary for performance of future strategies. Since it's a very subtle semantic change, I wanted to call it out.
08cef35
to
3764d59
Compare
8deaa94
to
33ab21b
Compare
- allow unreachable code in a branch of a cfg_if_expr! - make main() alone handle process exit status - refactor files_by_unix_mode - allow specifying output type for cfg_if_expr! - use cfg_if! and cfg_if_expr! to rewrite a complex conditional for calculating default compression - add explicit compile_error!() cases to catch subtle fallback scenarios
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good; just a few nitpicks.
/// | ||
/// Note that any `return` operation within the expressions provided to this macro will apply to the | ||
/// generated closure, not the enclosing scope--it cannot be used to interfere with external | ||
/// control flow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this gotcha be checked at build-time, by raising an error when a branch expression starts with return
, break
or continue
and a warning when those keywords occur later in the expression?
CryptoReader::Aes { | ||
vendor_version: AesVendorVersion::Ae2, | ||
.. | ||
cfg_if! { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the needless_return
can probably be eliminated here by using cfg_if_expr!
instead.
/// Store all entries which specify a numeric "mode" which is familiar to POSIX operating systems. | ||
#[cfg(unix)] | ||
#[derive(Default, Debug)] | ||
struct FilesByUnixMode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this UnixModesByPath
instead. "By" usually refers to a map's keys, not values.
impl FilesByUnixMode { | ||
pub fn add_mode(&mut self, path: PathBuf, mode: u32) { | ||
// We don't print a warning or consider it remotely out of the ordinary to receive two | ||
// separate modes for the same path: just take the later one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this happen? It's not clear to me that this is the correct behavior, especially in debug builds.
Problem
The
zip
crate occasionally encounters some very tricky platform-specific conditional logic. Because Rust's#[cfg(...)]
markers are only parsed and not typechecked, it's very easy to introduce subtle breakage that only shows up in a specific scenario.Performing some action if
#[cfg(...)]
condition is true and another is not is a common desire, but#[cfg(not(...))]
clauses to achieve this tend to be difficult to read and audit.Solution
There is an existing crate
cfg-if
which provides a very simplemacro_rules!
macro to perform these if/else conditional checks safely, but we would like to avoid introducing an external dependency that controls the very fine-grained distinctions between platforms. So upon seeing that the stdlib also just vendors in thecfg_if!
macro, this PR does the same for our crate:However, the Rust syntax has a subtle and very annoying failure mode that disallows annotating certain expressions with
#[cfg(...)]
except on nightly compilers. In particular, this makescfg_if!
unusable for expression-based platform conditionals. So a secondmacro_rules!
macro was also devised namedcfg_if_expr!
, which wraps the result ofcfg_if!
within an immediately-invoked closure. Using this macro looks like:Result
Like most macros, the result is aesthetic and somewhat subjective. I think that these macros serve the security goals of this crate by incorporating an explicit
else
or_ =>
branch. I think the negative logic of#[cfg(not(...))]
clauses is extremely difficult to model for readers of the code, and since the two#[cfg(...)]
and#[cfg(not(...))]
branches aren't linked syntactically, they may eventually drift away from each other over time.Using these macros makes it clear that the code will match exactly one case, evaluated in linear order. By standardizing that single-branch scenario, we make it easier to focus our analysis on the unusual cases that don't or can't conform to this simpler model.