Skip to content

New lint: Suggests using Cell<T: Copy> instead of RefCell<T: Copy> - #17522

Draft
qdot3 wants to merge 11 commits into
rust-lang:masterfrom
qdot3:refcell_cell
Draft

New lint: Suggests using Cell<T: Copy> instead of RefCell<T: Copy>#17522
qdot3 wants to merge 11 commits into
rust-lang:masterfrom
qdot3:refcell_cell

Conversation

@qdot3

@qdot3 qdot3 commented Aug 8, 2026

Copy link
Copy Markdown

Implementation of #17380

This lint suggests using Cell instead of RefCell for Copy types. RefCell avoids cloning, but it introduces additional memory overhead and runtime checks, which are not worthwhile for Copy types.

Scope

  • Field definitions
  • Type aliases
  • Input/output types of functions, methods, and trait methods (definition site)
  • Associated types
  • Simple let statements (e.g., let _ = RefCell::new(1))
  • All of the above when appearing inside tuples or arrays

Out of scope

  • Any expressions other than simple constructors in let statements
  • Input/output types of trait methods (implementation site)
changelog: new lint: [`refcell_cell`]

@rustbot rustbot added the S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned. label Aug 8, 2026
@rustbot

rustbot commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome!

You should hear from one of our reviewers after this PR gets at least 2 reviews from the community.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Aug 8, 2026
@qdot3
qdot3 marked this pull request as draft August 8, 2026 01:06
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Aug 8, 2026
@qdot3
qdot3 marked this pull request as ready for review August 8, 2026 01:51
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Aug 8, 2026
@rustbot

This comment has been minimized.

@CommanderStorm CommanderStorm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Community review:
Seems like a good start, but I think it needs another round in the oven given that both the perf caveats and the other lints are not fully 100% aligned.

View changes since this review

Comment thread clippy_lints/src/refcell_cell.rs Outdated
Comment on lines +135 to +136
// Because this may be required to be `RefCell`
let mut app = Applicability::MaybeIncorrect;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like a bit of an unclear comment. Can you clarify this comment?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed:

// This can be a false positive, for example, when passed to a function
// that requires `RefCell`.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It should ideally be handled, but I'm not sure whether it is feasible. I need some time to investigate.

Comment thread clippy_lints/src/refcell_cell.rs Outdated
let mut app = Applicability::MaybeIncorrect;
let sugg = {
let (init, _) = snippet_with_context(cx, span, stmt.span.ctxt(), "..", &mut app);
init.into_owned().replace("RefCell", "Cell")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this .replace("RefCell", "Cell") seems suspicious.

How about RefCell<InnerRefCell> where InnerRefCell is a struct with Copy?

@qdot3 qdot3 Aug 11, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed. I now address HIR directly.

Comment thread clippy_lints/src/refcell_cell.rs Outdated
Comment on lines +124 to +127
snippet(cx, init.span, "").contains("RefCell"),
let_stmt
.ty
.is_some_and(|ty| snippet(cx, ty.span, "").contains("RefCell")),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the blanket String .contains here safe, as in does this have false-positives? Can't we do this via matching instead as in the outer if-let?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed. I now handle both the type annotation and the initialization expression directly.

@@ -1,3 +1,4 @@
#![allow(clippy::refcell_cell)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can this be expect? (also applies to the other instances)

The reason behind this is that this way we "GC" these lints when they don't apply.

Comment thread tests/ui/clone_on_copy.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

instead of an lint, should this be a change to that lint to not lint in this case?

@qdot3 qdot3 Aug 12, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Since refcell_cell is a perf lint, I think it should be fired in this case. Using RefCell over Cell here can be a matter of style, and I think the choice between perf and style should be left to users.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should we not instead add an exeption to those lints to not lint?

They seem a bit conflicting...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

/// ### Why is this bad?
/// `RefCell` avoids cloning at the cost of additional memory usage and
/// instructions, which isn't worth it for `Copy` types.
///

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

there are some Known problems regarding trait bounds as noted in the tests, can we document them here?

Also, we need to note that while on avarage this is a good idea, there might be better options..

There is no runtime cost to using Cell<T>, however if one is using it to wrap larger (Copy) structs, it might be worthwhile to instead wrap individual fields in Cell<T> since each write is a full copy of the struct

https://manishearth.github.io/blog/2015/05/27/wrapper-types-in-rust-choosing-your-guarantees/

@qdot3 qdot3 Aug 14, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I documented it and introduced new configuration named max_cheap_copy_size to suppress the lint for large Copy types. The default value is 16, witch is the size of u/i128.

@CommanderStorm CommanderStorm Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How did you come up/reason that this should be 16? (It might be right, but I'd like to know how you came up with it) 🤔

Can you add that either as a comment or into the PR description since otherwise it is not very clear.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

To be honest, I chose it simply because it's the minimum size required to represent all primitive integer types. But the word size is better, since it usually fits in a cache line. And since this is a perf lint, performance should take priority over avoiding extra configuration.

@qdot3
qdot3 marked this pull request as draft August 11, 2026 14:55
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Aug 11, 2026
@rustbot

This comment has been minimized.

@qdot3
qdot3 force-pushed the refcell_cell branch 2 times, most recently from 0246405 to 8cef563 Compare August 14, 2026 06:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-community-reviews Status: This is awaiting for positive reviews from the community before a maintainer is assigned.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants