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

Open
wants to merge 2 commits into
base: master
from

Conversation

Projects
None yet
8 participants
@Susurrus
Copy link
Contributor

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 was marked as outdated.

Copy link
Collaborator

rust-highfive commented Feb 2, 2019

r? @matthewjasper

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

Show resolved Hide resolved src/librustc_lint/builtin.rs Outdated
@Centril

This comment has been minimized.

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

This comment has been minimized.

Copy link
Contributor

Centril commented Feb 2, 2019

@rust-highfive

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Feb 2, 2019

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 Susurrus force-pushed the Susurrus:missing_trait_impls branch from b622b58 to 66c226c Feb 2, 2019

@Susurrus

This comment has been minimized.

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() {

This comment has been minimized.

@scottmcm

scottmcm Feb 3, 2019

Member

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.)

This comment has been minimized.

@Susurrus

Susurrus Feb 4, 2019

Author Contributor

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.

This comment has been minimized.

@scottmcm

scottmcm Feb 11, 2019

Member

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 Susurrus force-pushed the Susurrus:missing_trait_impls branch from 66c226c to 1e94b95 Feb 4, 2019

@Susurrus

This comment has been minimized.

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

This comment has been minimized.

Copy link
Collaborator

rust-highfive commented Feb 4, 2019

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

This comment has been minimized.

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

This comment has been minimized.

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.

Deprecate lints checking for Debug or Copy impls
These lints are now implemented in Clippy and those should be used
instead.
@bors

This comment has been minimized.

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 Susurrus referenced this pull request Feb 9, 2019

Open

WIP: Add missing trait implementation lints #3752

0 of 10 tasks complete

@Susurrus Susurrus force-pushed the Susurrus:missing_trait_impls branch from 1e94b95 to f10126c Feb 9, 2019

@Susurrus

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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...)

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 12, 2019

This PR does not add any new lints anymore. They are going to be implemented in clippy and the two rustc lints are going to get deprecated

@Centril

This comment has been minimized.

Copy link
Contributor

Centril commented Feb 16, 2019

OK... hmm... why are we deprecating the lints tho? I was happy for this to be done in rustc personally.

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Feb 16, 2019

It's not a correctness thing, and they have to be enabled explicitly anyway. So users have to discover them. I think the discoverability of clippy lints is much higher than of allow-by-default rustc lints.

@Centril

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

Manishearth commented Feb 17, 2019

@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

This comment has been minimized.

Copy link
Member

Manishearth commented Feb 17, 2019

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

Manishearth commented Feb 17, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment