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

Warn on repr without hints #51401

Merged
merged 9 commits into from Jun 9, 2018
Merged

Warn on repr without hints #51401

merged 9 commits into from Jun 9, 2018

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Jun 6, 2018

Fix #51376.

@rust-highfive
Copy link
Collaborator

r? @cramertj

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 6, 2018
@cramertj
Copy link
Member

cramertj commented Jun 6, 2018

r=me with travis passing.

@rust-highfive

This comment has been minimized.

has_hints = !list.is_empty();
}
if !has_hints {
span_warn!(
Copy link
Contributor

Choose a reason for hiding this comment

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

This will be an unsilencable warning instead of a lint, is that intended? So far we reserved that for future incompatibility warnings.

A test for this would be good, too

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'll be adding a test. I feel that an empty repr (or it's cousin, #[repr = "C"]) should be hard failures in the future. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think all the overhead of carefully managing the transition to a hard error, and the eventual breakage of (hypothetical) old crates, is worth it for this. This is just supposed to catch a silly programmer mistake, it's not a soundness issue or anything. IMO this should be a lint, warn-by-default for now and maybe later upgraded to deny-by-default.

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 feel strongly that having an incorrect repl (specially #[repr = "C"]) is hiding a pretty severe bug. Having said that, I can see how it should be a lint instead. I'll push my latest changes and rework this into a lint at a later time.

Copy link
Contributor

Choose a reason for hiding this comment

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

It does indicate a severe bug, and it should report an error, but making it a hard error rather than a deny-by-default-lint error just unnecessarily breaks stability promises and unmaintained crates without helping users any more.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will turn into a lint once I free myself to work on this a bit more. Please verify that the current output is reasonable.

if let Some(ref list) = list {
has_hints = !list.is_empty();
}
if !has_hints {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I think this is better written as let is_empty = list.map(|list| list.is_empty()).unwrap_or(true); and then if empty { ... }.

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 caught that while reworking this. Changed it.

@estebank

This comment has been minimized.

@estebank estebank changed the title Warn on repr without hints [wip] Warn on repr without hints Jun 6, 2018
@oli-obk

This comment has been minimized.

@estebank

This comment has been minimized.

let mut warn = if let Some(ref lit) = attr.value_str() {
// avoid warning about empty `repr` on `#[repr = "foo"]`
let sp = match format!("{}", lit).as_ref() {
"C" | "packed" | "rust" | "u*" | "i*" | "transparent" => {
Copy link
Contributor

Choose a reason for hiding this comment

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

You still need to expand these int placeholders

Copy link
Contributor Author

@estebank estebank Jun 6, 2018

Choose a reason for hiding this comment

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

Oh, by repr(u*) it means repr(u8), for example, is allowed? We should update the rustonomicon's description, it wasn't clear to me :-/

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea. This could be better documented

|
= note: #[warn(bad_repr)] on by default
= help: valid hints include `#[repr(C)]`, `#[repr(packed)]`, `#[repr(rust)]`, and `#[repr(transparent)]`
= note: for more information, visit <https://doc.rust-lang.org/nomicon/other-reprs.html>
Copy link
Contributor

Choose a reason for hiding this comment

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

I recommend https://doc.rust-lang.org/reference/type-layout.html instead, it's more authorative and up to date

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.

let sp = match format!("{}", lit).as_ref() {
"C" | "packed" | "rust" | "u*" | "i*" | "transparent" => {
let lo = attr.span.lo() + BytePos(2);
let hi = attr.span.hi() - BytePos(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

So, this skips the leading #[ and trailing ], but only for some cases (e.g., repr = "C" but not repr = "B"). What's the rationale for that extra work and inconsistency? Why not always use attr.span?

Copy link
Contributor

Choose a reason for hiding this comment

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

Note that such span operations break down in the presence of macros. We've had some pain with those in clippy. It's usually better to have less prettier ^^^^^^^^^ in the non-macro case than to throw up a bunch of macro internals at the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's to be 100% confident that the suggested code will be correct like in the following case:

warning: `repr` attribute isn't configurable with a literal
 --> file.rs:1:3
  |
1 | #[   repr   =    "C"   ]
  |   ^^^^^^^^^^^^^^^^^^^^^ help: give `repr` a hint: `repr(C)`

In the cases where we're not suggesting anything attr.span is good enough. If we use attr.span for the case above, the output would be:

warning: `repr` attribute isn't configurable with a literal
 --> file.rs:1:3
  |
1 | #[   repr   =    "C"   ]
  |   ^^-------------------^
  |     |
  |     help: give `repr` a hint: `repr(C)`

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really follow. I guess it might explain why these calculations are only done in one branch, but why are they done at all? Why try to exclude the #[ and ] from the labels in the first place? It doesn't significantly change how the diagnostic looks and I haven't seen other attribute-related diagnostics do it.

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 though that repr attrs could be applied to the enclosing element, like other attributes #![repr(C)], but I just tried it and it was rejected. Is this the case everywhere? In that case I don't have to worry about the possible difference between #![repr] and #[repr] and wouldn't have to do this span wrangling.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think #![repr] is valid, but I also don't get why that would make any difference for the span. The span points at the attribute either way, doesn't it? (Actually, I am now even more confused: if #![repr] was valid, lo + 2 would be off by one for it)

@@ -696,7 +696,9 @@ impl EarlyLintPass for BadRepr {
let mut warn = if let Some(ref lit) = attr.value_str() {
// avoid warning about empty `repr` on `#[repr = "foo"]`
let sp = match format!("{}", lit).as_ref() {
"C" | "packed" | "rust" | "u*" | "i*" | "transparent" => {
| "C" | "packed" | "rust" | "transparent"
| "u8" | "u16" | "u32" | "u64" | "u128"
Copy link
Contributor

Choose a reason for hiding this comment

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

usize, isize, too

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

warn.span_suggestion(
sp,
"give `repr` a hint",
format!("repr({})", lit),
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I guess as written this suggestion needs the smalelr span to avoid IDEs dropping the #[ and ]?

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 believe that the last changes would be agreeable to you (IDEs should not be mucking around with escaping of suggestion text).

@rust-highfive

This comment has been minimized.

@@ -687,6 +687,18 @@ impl EarlyLintPass for BadRepr {
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
if attr.name() == "repr" {
let list = attr.meta_item_list();
let outer = match attr.style {
ast::AttrStyle::Outer => true,
ast::AttrStyle::Inner => false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we all seem to be in agreement this isn't actually allowed, I suggest an assert_eq! and simplifying the code accordingly.

@rust-highfive

This comment has been minimized.

@estebank
Copy link
Contributor Author

estebank commented Jun 7, 2018

@bors r=cramertj

@bors
Copy link
Contributor

bors commented Jun 7, 2018

📌 Commit 0e3f19d has been approved by cramertj

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 7, 2018
Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this pull request Jun 8, 2018
bors added a commit that referenced this pull request Jun 8, 2018
Rollup of 13 pull requests

Successful merges:

 - #50143 (Add deprecation lint for duplicated `macro_export`s)
 - #51099 (Fix Issue 38777)
 - #51276 (Dedup auto traits in trait objects.)
 - #51298 (Stabilize unit tests with non-`()` return type)
 - #51360 (Suggest parentheses when a struct literal needs them)
 - #51391 (Use spans pointing at the inside of a rustdoc attribute)
 - #51394 (Use scope tree depths to speed up `nearest_common_ancestor`.)
 - #51396 (Make the size of Option<NonZero*> a documented guarantee.)
 - #51401 (Warn on `repr` without hints)
 - #51412 (Avoid useless Vec clones in pending_obligations().)
 - #51427 (compiletest: autoremove duplicate .nll.* files (#51204))
 - #51436 (Do not require stage 2 compiler for rustdoc)
 - #51437 (rustbuild: generate full list of dependencies for metadata)

Failed merges:
@bors bors merged commit 0e3f19d into rust-lang:master Jun 9, 2018
@estebank estebank deleted the warn-repr branch November 9, 2023 05:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants