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

WIP: Add lint for missing Clone impls #58070

Closed
wants to merge 2 commits into from

Conversation

Susurrus
Copy link
Contributor

@Susurrus Susurrus commented Feb 2, 2019

This is a WIP implementation for #58066. I've just implemented a lint for missing Clone implementations. For the other traits listed in #58066, I'll add separate commits for the missing ones once I've gotten some feedback here and am sure I'm on the right track.

Closes #58066.

@rust-highfive

This comment has been minimized.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 2, 2019
@Centril
Copy link
Contributor

Centril commented Feb 2, 2019

If we are going to add all the lints we should also add them into a lint-group missing_implementations so that they can be activated all at once.

@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. relnotes Marks issues that should be documented in the release notes of the next release. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. labels Feb 2, 2019
@Centril
Copy link
Contributor

Centril commented Feb 2, 2019

r? @oli-obk

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-6.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:2811f027:start=1549083338745918743,finish=1549083339719494070,duration=973575327
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-6.0
---
[00:57:28]     Checking core v0.0.0 (/checkout/src/libcore)
[00:57:57]     Checking rustc-std-workspace-core v1.0.0 (/checkout/src/tools/rustc-std-workspace-core)
[00:57:57]     Checking compiler_builtins v0.1.5
[00:57:59]  Documenting alloc v0.0.0 (/checkout/src/liballoc)
[00:57:59] error[E0602]: unknown lint: `missing_clone_implementations`
[00:57:59]   |
[00:57:59]   = help: did you mean: `missing_copy_implementations`
[00:57:59]   = note: requested on the command line with `-A missing_clone_implementations`
[00:58:00] error: Compilation failed, aborting rustdoc
[00:58:00] 
[00:58:00] error: Could not document `alloc`.
[00:58:00] 
[00:58:00] 
[00:58:00] Caused by:
[00:58:00]   process didn't exit successfully: `/checkout/obj/build/bootstrap/debug/rustdoc --crate-name alloc src/liballoc/lib.rs --color always --target x86_64-unknown-linux-gnu -o /checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/doc --markdown-css rust.css --markdown-no-toc --index-page /checkout/src/doc/index.md -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps -L dependency=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/release/deps --extern compiler_builtins=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps/libcompiler_builtins-d54fe968dea87029.rmeta --extern core=/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps/libcore-84e5b9599b1b7754.rmeta` (exit code: 1)
[00:58:00] 
[00:58:00] 
[00:58:00] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "rustdoc" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-Z" "unstable-options" "-p" "alloc" "--" "--markdown-css" "rust.css" "--markdown-no-toc" "--index-page" "/checkout/src/doc/index.md"
[00:58:00] 
[00:58:00] 
[00:58:00] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap doc
[00:58:00] Build completed unsuccessfully in 0:05:31
[00:58:00] Build completed unsuccessfully in 0:05:31
[00:58:00] make: *** [all] Error 1
[00:58:00] Makefile:18: recipe for target 'all' failed
The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:35d50f2e
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
Sat Feb  2 05:53:52 UTC 2019
---
travis_time:end:0ecaee20:start=1549086833090839038,finish=1549086833096859706,duration=6020668
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:09467123
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb --batch -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:117e1c24
travis_time:start:117e1c24
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:2ba1ef0e
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@Susurrus
Copy link
Contributor Author

Susurrus commented Feb 2, 2019

Tests succeeded locally, so pushed the latest version here. I've only refactored the code and added both a lint for missing Clone implementations and a missing_impls lint group. Once I get a little feedback that this is the right path forward, I'll add the remaining trait lints (and add them to the group as well):

  • Eq
  • PartialEq
  • Ord
  • PartialOrd
  • Hash
  • Display
  • Default

if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
return;
}
if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
Copy link
Member

Choose a reason for hiding this comment

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

Did the new version of this lose the "and we're not going to warn you if the type cannot be Copy" part?

If we're doing these for essentially everything that can be derived, maybe there's a way to approximately check whether the derive would work? (Maybe even have a structured suggestion to make it easy to add the derive? One could just turn on the lint and click the buttons in your IDE to add the derives.)

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 don't think this warned you if the type couldn't be Copy, it just didn't trigger the lint. I'm wondering if this is really a problem in practice. I'd think that if you set this lint globally, you'd want it to trigger on all types and not exclude types that it can't be implemented for, so you'd have to whitelist them explicitly.

Copy link
Member

Choose a reason for hiding this comment

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

I think this is super important. I would never use a lint suggesting Copy if I had to suppress it any time I put a Vec or a HashSet inside my struct.

@Susurrus
Copy link
Contributor Author

Susurrus commented Feb 4, 2019

I started implementing Hash and found that my macro fails because there isn't a method to check if the given trait is implemented called hash_trait. This applies to: PartialEq, Hash, Display, Default. I'm looking at the language_item_table! macro call in src/librustc/middle/lang_items.rs and I'm wonder if it's a trivial fix to add these these in there, or if that actually breaks things by making new language items.

I also ran into problems implementing Eq (which I just updated this PR with), where if PartialEq is derived, the error doesn't show for Eq not being implemented. I'm uncertain why that is right now.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-6.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:0910872c:start=1549257012648784783,finish=1549257089502524442,duration=76853739659
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-6.0
---
[01:02:31] .................................................................................................... 2700/5367
[01:02:35] .................................................................................................... 2800/5367
[01:02:39] .................................................................................................... 2900/5367
[01:02:43] .................................................................................................... 3000/5367
[01:02:46] .............................................................F...................................... 3100/5367
[01:02:50] ...............................................F.................................................... 3200/5367
[01:02:57] ..........................................................................................ii...i..ii 3400/5367
[01:03:01] .................................................................................................... 3500/5367
[01:03:05] .................................................................................................... 3600/5367
[01:03:08] .......................................................................................ii........... 3700/5367
---
[01:04:09] .................................................................................................... 5300/5367
[01:04:11] ......i............................................................
[01:04:11] failures:
[01:04:11] 
[01:04:11] ---- [ui] ui/lint/group-missing-impls.rs stdout ----
[01:04:11] 
[01:04:11] 11    |         ^^^^^^^^^^^^^
[01:04:11] 11    |         ^^^^^^^^^^^^^
[01:04:11] 12    = note: #[deny(missing_debug_implementations)] implied by #[deny(missing_impls)]
[01:04:11] 13 
[01:04:11] + error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] +   --> $DIR/group-missing-impls.rs:6:1
[01:04:11] +    |
[01:04:11] + LL | pub struct A; //~ ERROR type does not implement `fmt::Debug`
[01:04:11] +    |
[01:04:11] + note: lint level defined here
[01:04:11] +   --> $DIR/group-missing-impls.rs:2:9
[01:04:11] +    |
[01:04:11] +    |
[01:04:11] + LL | #![deny(missing_impls)]
[01:04:11] +    |         ^^^^^^^^^^^^^
[01:04:11] +    = note: #[deny(missing_eq_implementations)] implied by #[deny(missing_impls)]
[01:04:11] + 
[01:04:11] 14 error: type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation
[01:04:11] 15   --> $DIR/group-missing-impls.rs:9:1
[01:04:11] 
[01:04:11] 37    |         ^^^^^^^^^^^^^
[01:04:11] 37    |         ^^^^^^^^^^^^^
[01:04:11] 38    = note: #[deny(missing_clone_implementations)] implied by #[deny(missing_impls)]
[01:04:11] 39 
[01:04:11] + error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] +   --> $DIR/group-missing-impls.rs:9:1
[01:04:11] + LL | pub struct B;
[01:04:11] +    | ^^^^^^^^^^^^^
[01:04:11] + 
[01:04:11] + 
[01:04:11] 40 error: type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation
[01:04:11] 41   --> $DIR/group-missing-impls.rs:14:1
[01:04:11] 
[01:04:11] 
[01:04:11] 43 LL | pub struct C; //~ ERROR type does not implement `Copy`
[01:04:11] 45 
[01:04:11] - error: aborting due to 4 previous errors
[01:04:11] - error: aborting due to 4 previous errors
[01:04:11] + error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] +   --> $DIR/group-missing-impls.rs:14:1
[01:04:11] +    |
[01:04:11] + LL | pub struct C; //~ ERROR type does not implement `Copy`
[01:04:11] + 
[01:04:11] + 
[01:04:11] + error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] +   --> $DIR/group-missing-impls.rs:17:1
[01:04:11] + LL | pub struct D;
[01:04:11] +    | ^^^^^^^^^^^^^
[01:04:11] + 
[01:04:11] + error: aborting due to 8 previous errors
[01:04:11] + error: aborting due to 8 previous errors
[01:04:11] 47 
[01:04:11] 48 
[01:04:11] 
[01:04:11] 
[01:04:11] The actual stderr differed from the expected stderr.
[01:04:11] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/group-missing-impls/group-missing-impls.stderr
[01:04:11] To update references, rerun the tests and pass the `--bless` flag
[01:04:11] To only update this specific test, also pass `--test-args lint/group-missing-impls.rs`
[01:04:11] error: 1 errors occurred comparing output.
[01:04:11] status: exit code: 1
[01:04:11] status: exit code: 1
[01:04:11] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/lint/group-missing-impls.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/group-missing-impls/a" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--crate-type" "lib" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/group-missing-impls/auxiliary" "-A" "unused"
[01:04:11] ------------------------------------------
[01:04:11] 
[01:04:11] ------------------------------------------
[01:04:11] stderr:
[01:04:11] stderr:
[01:04:11] ------------------------------------------
[01:04:11] {"message":"type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation","code":{"code":"missing_debug_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":104,"byte_end":117,"line_start":6,"line_end":6,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct A; //~ ERROR type does not implement `fmt::Debug`","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":43,"byte_end":56,"line_start":2,"line_end":2,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(missing_impls)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"#[deny(missing_debug_implementations)] implied by #[deny(missing_impls)]","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error: type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:6:1\n   |\nLL | pub struct A; //~ ERROR type does not implement `fmt::Debug`\n   | ^^^^^^^^^^^^^\n   |\nnote: lint level defined here\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:2:9\n   |\nLL | #![deny(missing_impls)]\n   |         ^^^^^^^^^^^^^\n   = note: #[deny(missing_debug_implementations)] implied by #[deny(missing_impls)]\n\n"}
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":104,"byte_end":117,"line_start":6,"line_end":6,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct A; //~ ERROR type does not implement `fmt::Debug`","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":43,"byte_end":56,"line_start":2,"line_end":2,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(missing_impls)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"#[deny(missing_eq_implementations)] implied by #[deny(missing_impls)]","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:6:1\n   |\nLL | pub struct A; //~ ERROR type does not implement `fmt::Debug`\n   | ^^^^^^^^^^^^^\n   |\nnote: lint level defined here\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:2:9\n   |\nLL | #![deny(missing_impls)]\n   |         ^^^^^^^^^^^^^\n   = note: #[deny(missing_eq_implementations)] implied by #[deny(missing_impls)]\n\n"}
[01:04:11] {"message":"type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation","code":{"code":"missing_copy_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":183,"byte_end":196,"line_start":9,"line_end":9,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct B;","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":43,"byte_end":56,"line_start":2,"line_end":2,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(missing_impls)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"#[deny(missing_copy_implementations)] implied by #[deny(missing_impls)]","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error: type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:9:1\n   |\nLL | pub struct B;\n   | ^^^^^^^^^^^^^\n   |\nnote: lint level defined here\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:2:9\n   |\nLL | #![deny(missing_impls)]\n   |         ^^^^^^^^^^^^^\n   = note: #[deny(missing_copy_implementations)] implied by #[deny(missing_impls)]\n\n"}
[01:04:11] {"message":"type does not implement `Clone`; consider adding #[derive(Clone)] or a manual implementation","code":{"code":"missing_clone_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":183,"byte_end":196,"line_start":9,"line_end":9,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct B;","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":43,"byte_end":56,"line_start":2,"line_end":2,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![deny(missing_impls)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"#[deny(missing_clone_implementations)] implied by #[deny(missing_impls)]","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error: type does not implement `Clone`; consider adding #[derive(Clone)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:9:1\n   |\nLL | pub struct B;\n   | ^^^^^^^^^^^^^\n   |\nnote: lint level defined here\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:2:9\n   |\nLL | #![deny(missing_impls)]\n   |         ^^^^^^^^^^^^^\n   = note: #[deny(missing_clone_implementations)] implied by #[deny(missing_impls)]\n\n"}
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":183,"byte_end":196,"line_start":9,"line_end":9,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct B;","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:9:1\n   |\nLL | pub struct B;\n   | ^^^^^^^^^^^^^\n\n"}
[01:04:11] {"message":"type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation","code":{"code":"missing_copy_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":307,"byte_end":320,"line_start":14,"line_end":14,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct C; //~ ERROR type does not implement `Copy`","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: type does not implement `Copy`; consider adding #[derive(Copy)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:14:1\n   |\nLL | pub struct C; //~ ERROR type does not implement `Copy`\n   | ^^^^^^^^^^^^^\n\n"}
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":307,"byte_end":320,"line_start":14,"line_end":14,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct C; //~ ERROR type does not implement `Copy`","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:14:1\n   |\nLL | pub struct C; //~ ERROR type does not implement `Copy`\n   | ^^^^^^^^^^^^^\n\n"}
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/group-missing-impls.rs","byte_start":393,"byte_end":406,"line_start":17,"line_end":17,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub struct D;","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/group-missing-impls.rs:17:1\n   |\nLL | pub struct D;\n   | ^^^^^^^^^^^^^\n\n"}
[01:04:11] 
[01:04:11] ------------------------------------------
[01:04:11] 
[01:04:11] 
[01:04:11] thread '[ui] ui/lint/group-missing-impls.rs' panicked at 'explicit panic', src/tools/compiletest/src/runtest.rs:3295:9
[01:04:11] 
[01:04:11] ---- [ui] ui/lint/missing-eq-implementations.rs stdout ----
[01:04:11] diff of stderr:
[01:04:11] 
[01:04:11] 
[01:04:11] 11    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
[01:04:11] 12 
[01:04:11] 13 error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] -   --> $DIR/missing-eq-implementations.rs:16:1
[01:04:11] -    |
[01:04:11] - LL | pub enum D {} //~ ERROR type does not implement `Eq`
[01:04:11] - 
[01:04:11] - 
[01:04:11] - error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] 20   --> $DIR/missing-eq-implementations.rs:18:1
[01:04:11] 21    |
[01:04:11] 22 LL | pub struct Foo; //~ ERROR type does not implement `Eq`
[01:04:11] 23    | ^^^^^^^^^^^^^^^
[01:04:11] 24 
[01:04:11] 24 
[01:04:11] - error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation
[01:04:11] -   --> $DIR/missing-eq-implementations.rs:29:1
[01:04:11] -    |
[01:04:11] - LL | pub struct Qux; //~ ERROR type does not implement `Eq`
[01:04:11] - 
[01:04:11] - error: aborting due to 4 previous errors
[01:04:11] + error: aborting due to 2 previous errors
[01:04:11] 32 
[01:04:11] 32 
[01:04:11] 33 
[01:04:11] 
[01:04:11] 
[01:04:11] The actual stderr differed from the expected stderr.
[01:04:11] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/missing-eq-implementations/missing-eq-implementations.stderr
[01:04:11] To update references, rerun the tests and pass the `--bless` flag
[01:04:11] To only update this specific test, also pass `--test-args lint/missing-eq-implementations.rs`
[01:04:11] error: 1 errors occurred comparing output.
[01:04:11] status: exit code: 1
[01:04:11] status: exit code: 1
[01:04:11] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/lint/missing-eq-implementations.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/missing-eq-implementations/a" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--crate-type" "lib" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/lint/missing-eq-implementations/auxiliary" "-A" "unused"
[01:04:11] ------------------------------------------
[01:04:11] 
[01:04:11] ------------------------------------------
[01:04:11] stderr:
[01:04:11] stderr:
[01:04:11] ------------------------------------------
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/missing-eq-implementations.rs","byte_start":91,"byte_end":104,"line_start":5,"line_end":5,"column_start":1,"column_end":14,"is_primary":true,"text":[{"text":"pub enum A {} //~ ERROR type does not implement `Eq`","highlight_start":1,"highlight_end":14}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"/checkout/src/test/ui/lint/missing-eq-implementations.rs","byte_start":43,"byte_end":69,"line_start":2,"line_end":2,"column_start":9,"column_end":35,"is_primary":true,"text":[{"text":"#![deny(missing_eq_implementations)]","highlight_start":9,"highlight_end":35}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null}],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/missing-eq-implementations.rs:5:1\n   |\nLL | pub enum A {} //~ ERROR type does not implement `Eq`\n   | ^^^^^^^^^^^^^\n   |\nnote: lint level defined here\n  --> /checkout/src/test/ui/lint/missing-eq-implementations.rs:2:9\n   |\nLL | #![deny(missing_eq_implementations)]\n   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n"}
[01:04:11] {"message":"type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation","code":{"code":"missing_eq_implementations","explanation":null},"level":"error","spans":[{"file_name":"/checkout/src/test/ui/lint/missing-eq-implementations.rs","byte_start":314,"byte_end":329,"line_start":18,"line_end":18,"column_start":1,"column_end":16,"is_primary":true,"text":[{"text":"pub struct Foo; //~ ERROR type does not implement `Eq`","highlight_start":1,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error: type does not implement `Eq`; consider adding #[derive(Eq)] or a manual implementation\n  --> /checkout/src/test/ui/lint/missing-eq-implementations.rs:18:1\n   |\nLL | pub struct Foo; //~ ERROR type does not implement `Eq`\n   | ^^^^^^^^^^^^^^^\n\n"}
[01:04:11] 
[01:04:11] ------------------------------------------
[01:04:11] 
[01:04:11] thread '[ui] ui/lint/missing-eq-implementations.rs' panicked at 'explicit panic', src/tools/compiletest/src/runtest.rs:3295:9
[01:04:11] thread '[ui] ui/lint/missing-eq-implementations.rs' panicked at 'explicit panic', src/tools/compiletest/src/runtest.rs:3295:9
[01:04:11] 
[01:04:11] 
[01:04:11] failures:
[01:04:11]     [ui] ui/lint/group-missing-impls.rs
[01:04:11]     [ui] ui/lint/missing-eq-implementations.rs
[01:04:11] test result: FAILED. 5342 passed; 2 failed; 23 ignored; 0 measured; 0 filtered out
[01:04:11] 
[01:04:11] thread 'main' panicked at 'Some tests failed', src/tools/compiletest/src/main.rs:502:22
[01:04:11] 
[01:04:11] 
[01:04:11] 
[01:04:11] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-6.0/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--target-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "6.0.0\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always"
[01:04:11] 
[01:04:11] 
[01:04:11] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:04:11] Build completed unsuccessfully in 0:04:15
[01:04:11] Build completed unsuccessfully in 0:04:15
[01:04:11] make: *** [check] Error 1
[01:04:11] Makefile:48: recipe for target 'check' failed
The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:0b647dc7
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
Mon Feb  4 06:15:50 UTC 2019
---
travis_time:end:30796788:start=1549260952034832792,finish=1549260952039911318,duration=5078526
travis_fold:end:after_failure.3
travis_fold:start:after_failure.4
travis_time:start:038549a6
$ ln -s . checkout && for CORE in obj/cores/core.*; do EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); if [ -f "$EXE" ]; then printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; gdb --batch -q -c "$CORE" "$EXE" -iex 'set auto-load off' -iex 'dir src/' -iex 'set sysroot .' -ex bt -ex q; echo travis_fold":"end:crashlog; fi; done || true
travis_fold:end:after_failure.4
travis_fold:start:after_failure.5
travis_time:start:086338e4
travis_time:start:086338e4
$ cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
cat: ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers: No such file or directory
travis_fold:end:after_failure.5
travis_fold:start:after_failure.6
travis_time:start:0272f5ef
$ dmesg | grep -i kill

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@Susurrus
Copy link
Contributor Author

Susurrus commented Feb 5, 2019

So looking at the lang_items docs I'm not seeing much clarity on what a lang_item actually is. As in, whether it'd be inappropriate here to define more. Only 3 traits need this treatment: Default, Display, and Hash. What're the rules around defining new lang items here? Does it break anything anywhere else? I'd think since they're in the stdlib, that this wouldn't be a big deal, but I probably don't have enough context.

@Susurrus
Copy link
Contributor Author

Susurrus commented Feb 5, 2019

I'm coming back to this because I actually went and ported this change to rust-clippy. But this implementation currently relies on these lang items being defined, so it fails there just as it fails here. So I need to rewrite if I can't add these 3 traits as lang items no matter where I put it. Any guidance here is appreciated.

These lints are now implemented in Clippy and those should be used
instead.
@bors
Copy link
Contributor

bors commented Feb 9, 2019

☔ The latest upstream changes (presumably #58316) made this pull request unmergeable. Please resolve the merge conflicts.

@Susurrus
Copy link
Contributor Author

Susurrus commented Feb 9, 2019

Okay, I whipped up rust-lang/rust-clippy#3752, which has just Debug and Copy, which should be enough for us to finalize the work necessary here in rust.

I've changed this PR to mark those lints as deprecated and also added Debug, Display, and Hash as lang items so they can be easily checked the same way as all the other traits. This enables Clippy to easily implement all of these lints.

@oli-obk
Copy link
Contributor

oli-obk commented Feb 10, 2019

Ok, this is totally awesome. I talked with @Manishearth at the all hands about this and we have a way to be able to not affect the lang theam here: We add a new attribute to the compiler: #[diagnostic = "debug_trait"] and similar so we can stop checking for lang items and instead just check for diagnostic-specific items.

This will be a bit more involved. Essentially we need to

  1. duplicate the get_lang_items query. Though I don't think there's any point in having a method per diagnostic item.
  2. So I suggest we just make the query return a FxHashMap<Symbol, NodeId>.
  3. We can then build a wrapper method on the TyCtxt that maps a &str to an Option<NodeId> for user convenience
  4. Throw the new attribute on a bunch of types (basically go through https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/paths.rs and just flag all the things in that list)
  5. see if there are any rustc diagnostics that could benefit from this
  6. replace all uses of util/path.rs with a use of the &str -> Option<NodeId> method
  7. complain to @oli-obk that they didn't think this through and there's uses of util/path.rs that do something different
  8. figure out if we need any of this in EarlyLintPasses and make them LateLintPasses
  9. see 7.

@Centril
Copy link
Contributor

Centril commented Feb 11, 2019

(The lang team is involved here not because of lang items, but because new lints are being added... once @oli-obk feels the implementation here is up to snuff ping me and I'll FCP-merge...)

@Centril
Copy link
Contributor

Centril commented Feb 16, 2019

I think the discoverability of clippy lints is much higher than of allow-by-default rustc lints.

This might be an issue of not having a page such as https://rust-lang.github.io/rust-clippy/master/index.html for the rustc lints; if we had that then rustc lints would become more discoverable?

@oli-obk
Copy link
Contributor

oli-obk commented Feb 16, 2019

Even so, if we don't consider them important enough to be enabled by default, why do we have them in the compiler? People looking for more static analysis usually go to clippy I presume?

@Centril
Copy link
Contributor

Centril commented Feb 16, 2019

Presumably we have them in the compiler because clippy wasn't a well known thing at that point in time? What other allow-by-default lints do we have? If we're going for deprecation on the basis of "allow by default should be in clippy" then a more holistic approach seems preferable?

@oli-obk
Copy link
Contributor

oli-obk commented Feb 16, 2019

They might be older than clippy XD

Here's a list of all allow-by-default lints in rustc that are not edition related to best of my knowledge

@Centril
Copy link
Contributor

Centril commented Feb 16, 2019

  • UNUSED_EXTERN_CRATES is an idiom lint used when migrating to Rust 2018 (and activated by #![deny(rust_2018_idioms)].
  • ELIDED_LIFETIMES_IN_PATHS is an idiom lint, e.g. on fmt: Formatter. Should become warn-by-default soon-ish?
  • EXPLICIT_OUTLIVES_REQUIREMENTS is an idiom lint, e.g. struct Foo<T: 'a>(&'a T); -- I'm not sure we want to promote this to a warning ever.
  • MISSING_DOC_CODE_EXAMPLES seems useful to keep as a way of enforcing documentation quality.
  • UNSAFE_CODE we should keep; this one is quite useful to #![forbid(..)] to ensure that you only have safe code in a crate. This could be done in clippy, but I think it's less common to run clippy as part of CI so having it in rustc is useful.
  • MISSING_DOCS is pretty useful to maintain docs quality; plenty of people use it.
  • VARIANT_SIZE_DIFFERENCES would fit in the perf category of clippy.

...other listed lints I'm less familiar with.

@Manishearth
Copy link
Member

@Centril the webpage isn't what makes clippy lints discoverable, clippy allow-by-default lints are a power user tool too, and we don't expect people to find them normally. The difference is that lint levels in clippy are typically one level higher than the level the lint would have in rustc; they're discovered because they trigger warnings.

I do think unsafe_code and the doc lints (also the idiom ones) should stay in rust, they are independently well-known. The rest could be moved around, probably.

@Manishearth
Copy link
Member

Oh, also, the 1.0 RFC defined what goes in rustc and what doesn't: rust-lang/rfcs#2476

It doesn't impose hard restrictions, but the rough idea was that anything that fits as a clippy correctness lint should probably be uplifted to rustc as a warn lint, and anything that doesn't (like most allow by default lints in rustc) probably should be in clippy.

@Centril
Copy link
Contributor

Centril commented Feb 17, 2019

@Manishearth

@Centril the webpage isn't what makes clippy lints discoverable, clippy allow-by-default lints are a power user tool too, and we don't expect people to find them normally. The difference is that lint levels in clippy are typically one level higher than the level the lint would have in rustc; they're discovered because they trigger warnings.

Let me rephrase... I think we can make rustc lints more discoverable and so more useful by having a webpage like that linked in a prominent place.

Oh, also, the 1.0 RFC defined what goes in rustc and what doesn't: rust-lang/rfcs#2476

(cc #53224)

Sure; the RFC talks about future lints, not removing existing ones (because they already exist, and there's some churn for existing code-bases using them). I think if we want to downlift lints from rustc to clippy, let's go through them one by one and see which candidates there are and then the lang + compiler teams can confirm the deprecation.

@Manishearth
Copy link
Member

I don't think that lint discoverability is that easy. The clippy lint list gets linked to from everything clippy outputs and people still don't know about it.

And yeah, the RFC talks about future lints, it also doesn't specify hard rules: I only brought it up because it specifies a standard that the community agreed upon, one that will be a useful default for making this judgement for existing lints if we are going down that path. It still should be case by case, I didn't say otherwise.

@Dylan-DPC-zz
Copy link

ping from triage @Susurrus @oli-obk @Centril @Manishearth what's the update on this?

@Centril
Copy link
Contributor

Centril commented Mar 5, 2019

So to remove the existing lints, I'd like to see this first converted into deny + crater of that to see how widely this is in use. If the lints have some users, I think the churn of removing them isn't worth it.

@Susurrus
Copy link
Contributor Author

Susurrus commented Mar 7, 2019

I think there is a positive reception to adding missing trait lints for all the traits suggested by the API guidelines in Clippy based on feedback I've gotten to my PR there (rust-lang/rust-clippy#3752). That's where I've been spending my effort. However, that PR relies on the changes I propose here in src/librustc/middle/lang_items.rs. And there's the open question of what to do about the existing two lints here. As these aren't correctness lints, it's likely the right home for these are in Clippy long-term. One thing we could do now is add the lang item stuff that I need here and let Clippy add the lints as they see fit. Once they're in Clippy, we can reopen an issue about whether they belong in rustc too. Or do people think we need a consensus on our strategy now, as it doesn't make sense to add them to Clippy if they'd also be kept in the compiler.

@Centril
Copy link
Contributor

Centril commented Mar 7, 2019

I do think the existing missing_implementations lints are correctness lints in the sense that if they are used, the author considers it a bug if Debug isn't implemented. The standard library uses this to that effect iirc. I don't mind duplication in clippy for them tho; but if we are to remove them from here, there shouldn't be any notable amount of users.

@oli-obk
Copy link
Contributor

oli-obk commented Mar 7, 2019

I do think the existing missing_implementations lints are correctness lints in the sense that if they are used, the author considers it a bug if Debug isn't implemented.

According to clippy's lint grouping rules, that's a restriction lint, not a correctness lint.

@Centril
Copy link
Contributor

Centril commented Mar 7, 2019

@oli-obk Yes fair enough.

@Dylan-DPC-zz
Copy link

ping from triage @Sussurus @oli-obk any updates on this? are we blocked on anything?

@oli-obk
Copy link
Contributor

oli-obk commented Mar 19, 2019

@Susurrus I think as a first step we should do the refactorings suggested above for just the lints that are in rustc, and then implement the other lints in clippy. This way we can punt the decision on deprecating the rustc lints into the future without being blocked or implementing all the lints in rustc

@Centril Centril removed T-lang Relevant to the language team, which will review and decide on the PR/issue. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. relnotes Marks issues that should be documented in the release notes of the next release. labels Mar 19, 2019
@Centril
Copy link
Contributor

Centril commented Mar 19, 2019

Removing the labels with that understanding :)

@Centril Centril added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 30, 2019
@Centril
Copy link
Contributor

Centril commented Mar 30, 2019

Ping from triage @Susurrus :)

@Dylan-DPC-zz
Copy link

ping from triage @Susurrus Unfortunately we haven't heard from you on this in a while, so I'm closing the PR to keep things tidy. Don't worry though, if you'll have time again in the future please reopen this PR, we'll be happy to review it again! Thanks

@Dylan-DPC-zz Dylan-DPC-zz added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add lints for all common traits
9 participants