Skip to content
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

Add core and alloc over std Lints #15281

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

bushrat011899
Copy link
Contributor

@bushrat011899 bushrat011899 commented Sep 18, 2024

Objective

Solution

  • Added the following lints to the workspace:
    • std_instead_of_core
    • std_instead_of_alloc
    • alloc_instead_of_core
  • Used cargo +nightly fmt with item level use formatting to split all use statements into single items.
  • Used cargo clippy --workspace --all-targets --all-features --fix --allow-dirty to attempt to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an extern crate alloc; statement in a crate root).
  • Manually removed certain uses of std where negative feature gating prevented --all-features from finding the offending uses.
  • Used cargo +nightly fmt with crate level use formatting to re-merge all use statements matching Bevy's previous styling.
  • Manually fixed cases where the fmt tool could not re-merge use statements due to conditional compilation attributes.

Testing

  • Ran CI locally

Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

Notes

  • This is a massive change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future.
  • Making this change has no impact on user code, but does mean Bevy contributors will be warned to use core and alloc instead of std where possible.
  • This lint is a critical first step towards investigating no_std options for Bevy.

@bushrat011899 bushrat011899 added C-Code-Quality A section of code that is hard to understand or change X-Controversial There is active debate or serious implications around merging this PR A-Cross-Cutting Impacts the entire engine D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 18, 2024
@bushrat011899 bushrat011899 marked this pull request as draft September 18, 2024 06:31
Copy link
Contributor

Your PR increases Bevy Minimum Supported Rust Version. Please update the rust-version field in the root Cargo.toml file.

@bushrat011899 bushrat011899 marked this pull request as ready for review September 18, 2024 09:17
@alice-i-cecile
Copy link
Member

I think we should do this. This is easy to enforce and for contributors to adapt to, and the auto-fix is particularly nice. Import consistency is a nice side benefit too.

I'm not convinced that Bevy will ever be able to be fully no-std, but doing this now will make supporting weird platforms (notably consoles) in the future much easier and give us a better sense of how far away we are, what changes we need upstream and what parts of the standard library the teams will need to reimplement for their platform.

@janhohenheim janhohenheim added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 18, 2024
@alice-i-cecile alice-i-cecile added S-Needs-SME Decision or review from an SME is required and removed S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it labels Sep 18, 2024
We wish to use different lints for the examples, and `cargo` currently doesn't support overriding workspace lints within a crate. As a workaround, all workspace lints are duplicated for the root crate to allow it to specifically allow the standard library.
@bushrat011899
Copy link
Contributor Author

bushrat011899 commented Sep 18, 2024

To avoid changes to the examples, I've had to duplicate the workspace lints in the root Cargo.toml, as there is currently no way to override workspace lints within a particular member (see rust-lang/cargo#13157 for details). Examples are now unchanged beyond their use statements being re-merged by cargo +nightly fmt as described in this PR description.

Copy link
Contributor Author

@bushrat011899 bushrat011899 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below are some comments for reviewers which may help with parsing such a large set of changes. I believe this highlights all the noteworthy classes of changes that are made in this PR.

Cargo.toml Outdated
rust-version = "1.79.0"
rust-version = "1.81.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required for core::error::Error

Comment on lines +48 to +50
std_instead_of_core = "warn"
std_instead_of_alloc = "warn"
alloc_instead_of_core = "warn"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lints direct Bevy contributors to use core where possible, then alloc, and then finally std. The status quo is to just import everything from std. Enabling these lints makes investigation into a no_std Bevy feasible. Additionally, items in alloc and std but not in core can indicate blocking or allocating types, which could impact performance.

Comment on lines -55 to -56
[lints]
workspace = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We explicitly don't want examples to be subject to the same linting requirements as the rest of Bevy, since it is encouraged that users rely on the Rust std library when possible. Unfortunately, there is no way to override just those lints, so a copy of the workspace lints is needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to this effect here and in the workspace lints to reduce the risk of desync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

format!("{}_entities_{}", entity_count, std::any::type_name::<T>()),
format!("{}_entities_{}", entity_count, core::any::type_name::<T>()),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most changes look like this, where some inline call to a std item needs to be replaced with the core/alloc alternative. As std re-exports alloc and core, this is a non-breaking change even in public facing signatures.

Comment on lines -10 to +13
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
extern crate alloc;

use alloc::sync::Arc;
use core::sync::atomic::{AtomicBool, Ordering};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cases where the alloc crate is required, an extern crate alloc; must be placed in the lib.rs/main.rs file at the crate root. It may be possible to remove these if we instead created a bevy_alloc crate, and depend on it for the alloc types. This may be desirable anyway, as it would be a more appropriate home for things like HashMap and EntityHashSet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather us just follow convention instead of establishing our own patterns. This seems like a rather non-intrusive requirement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, and there's definitely a benefit to keeping it explicit and simple, especially considering this feature is aimed at the more low-level side of Rust programming.

crates/bevy_asset/src/io/file/file_watcher.rs Outdated Show resolved Hide resolved
impl #impl_generics ::std::ops::Deref for #ident #ty_generics #where_clause {
impl #impl_generics ::core::ops::Deref for #ident #ty_generics #where_clause {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Care needs to be taken with these macros, as we can rely on the existence of core, but we can't rely on the existence of alloc, as the callsite needs to already have extern crate alloc; added. Again, this would be addressed by providing a bevy_alloc crate, giving a concrete FQN that we can always rely on.

@@ -6,6 +6,8 @@
//! To demonstrate change detection, there are some console outputs based on changes in
//! the `EntityCounter` resource and updated Age components

#![expect(clippy::std_instead_of_core)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These examples require this expect attribute because they are inside the bevy_ecs crate and thus subject to the workspace lints. It's not ideal, but there are only a couple of cases where this is required.

Comment on lines +8 to +10
// Re-exported for use within `define_label!`
#[doc(hidden)]
pub use alloc::boxed::Box;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required for the define_label! macro. It's definitely not ideal, and I'd like to move it to a dedicated bevy_alloc crate instead, but it's a minimal issue IMO.

use bevy::math::ops;
use bevy::prelude::*;
use bevy::{math::ops, prelude::*};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples have just had minor formatting changes made to their use statements based on cargo +nightly fmt. They are exempt from the lint requiring core and alloc where possible.

Explains the requirement for duplicating the lints as a form of workspace overrides
examples/ui/text_debug.rs Outdated Show resolved Hide resolved
Copy link
Member

@james7132 james7132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only have looked through half the the files so far, but so far LGTM.

Comment on lines -10 to +13
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
extern crate alloc;

use alloc::sync::Arc;
use core::sync::atomic::{AtomicBool, Ordering};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather us just follow convention instead of establishing our own patterns. This seems like a rather non-intrusive requirement.

However, `bevy_ptr` and `bevy_utils` must still link to `core` and `alloc` due to the possibility of being `no_std` based on feature gating.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Cross-Cutting Impacts the entire engine C-Code-Quality A section of code that is hard to understand or change D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-SME Decision or review from an SME is required X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prefer core and alloc over std where possible
6 participants