]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #87759 - m-ou-se:linux-process-sealed, r=jyn514
authorYuki Okushi <jtitor@2k36.org>
Fri, 6 Aug 2021 02:21:33 +0000 (11:21 +0900)
committerGitHub <noreply@github.com>
Fri, 6 Aug 2021 02:21:33 +0000 (11:21 +0900)
Re-use std::sealed::Sealed in os/linux/process.

This uses `std::sealed::Sealed` in `std::os::linux::process` instead of defining new `Sealed` traits there.

418 files changed:
Cargo.lock
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_codegen_cranelift/src/unsize.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/va_arg.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/meth.rs
compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
compiler/rustc_codegen_ssa/src/mir/operand.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_codegen_ssa/src/target_features.rs
compiler/rustc_codegen_ssa/src/traits/builder.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0625.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0633.md
compiler/rustc_errors/src/emitter.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/removed.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/locator.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/pointer.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
compiler/rustc_mir/src/interpret/cast.rs
compiler/rustc_mir/src/interpret/memory.rs
compiler/rustc_mir/src/interpret/operand.rs
compiler/rustc_mir/src/interpret/terminator.rs
compiler/rustc_mir/src/interpret/traits.rs
compiler/rustc_mir/src/shim.rs
compiler/rustc_mir/src/transform/abort_unwinding_calls.rs [new file with mode: 0644]
compiler/rustc_mir/src/transform/generator.rs
compiler/rustc_mir/src/transform/mod.rs
compiler/rustc_mir/src/transform/no_landing_pads.rs [deleted file]
compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/naked_functions.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/collect.rs
library/core/src/internal_macros.rs
library/core/src/lib.rs
library/core/src/num/int_macros.rs
library/core/src/num/mod.rs
library/core/src/num/uint_macros.rs
library/core/src/option.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/result.rs
library/core/src/slice/iter/macros.rs
library/core/src/stream/from_iter.rs [new file with mode: 0644]
library/core/src/stream/mod.rs
library/panic_unwind/src/lib.rs
library/panic_unwind/src/seh.rs
library/proc_macro/src/bridge/mod.rs
library/proc_macro/src/lib.rs
library/std/src/lazy.rs
library/std/src/lib.rs
library/std/src/net/ip.rs
library/std/src/panicking.rs
library/std/src/sys/unix/thread.rs
library/std/tests/run-time-detect.rs
library/stdarch
library/unwind/src/lib.rs
library/unwind/src/libunwind.rs
src/bootstrap/bootstrap.py
src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/trait-upcasting.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/asm.md
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/fixtures/highlight.html [new file with mode: 0644]
src/librustdoc/html/highlight/fixtures/sample.html
src/librustdoc/html/highlight/tests.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/span_map.rs [new file with mode: 0644]
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/images/toggle-minus.svg [new file with mode: 0644]
src/librustdoc/html/static/images/toggle-plus.svg [new file with mode: 0644]
src/librustdoc/html/static_files.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/visit_ast.rs
src/test/codegen/c-variadic.rs
src/test/codegen/catch-unwind.rs
src/test/codegen/no-plt.rs
src/test/codegen/try-panic-abort.rs [deleted file]
src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/nounwind.rs [new file with mode: 0644]
src/test/codegen/unwind-and-panic-abort.rs [new file with mode: 0644]
src/test/codegen/unwind-extern-exports.rs
src/test/codegen/unwind-extern-imports.rs
src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
src/test/mir-opt/simplify_cfg.rs
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
src/test/run-make-fulldeps/coverage/abort.rs
src/test/run-make-fulldeps/foreign-exceptions/foo.rs
src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs [new file with mode: 0644]
src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr [new file with mode: 0644]
src/test/rustdoc-ui/generate-link-to-definition-opt.rs [new file with mode: 0644]
src/test/rustdoc-ui/generate-link-to-definition-opt.stderr [new file with mode: 0644]
src/test/rustdoc-ui/generate-link-to-definition-opt2.rs [new file with mode: 0644]
src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr [new file with mode: 0644]
src/test/rustdoc/auxiliary/source-code-bar.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/source_code.rs [new file with mode: 0644]
src/test/rustdoc/check-source-code-urls-to-def.rs [new file with mode: 0644]
src/test/ui/asm/naked-functions-ffi.rs [new file with mode: 0644]
src/test/ui/asm/naked-functions-ffi.stderr [new file with mode: 0644]
src/test/ui/asm/naked-functions-unused.rs [new file with mode: 0644]
src/test/ui/asm/naked-functions-unused.stderr [new file with mode: 0644]
src/test/ui/asm/naked-functions.rs
src/test/ui/asm/naked-functions.stderr
src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr
src/test/ui/associated-types/defaults-wf.stderr
src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
src/test/ui/async-await/dont-suggest-missing-await.stderr
src/test/ui/async-await/generator-desc.stderr
src/test/ui/async-await/issue-61076.rs
src/test/ui/async-await/issue-61076.stderr
src/test/ui/async-await/issue-72442.stderr
src/test/ui/async-await/issues/issue-67893.stderr
src/test/ui/async-await/pin-needed-to-poll.stderr
src/test/ui/async-await/suggest-missing-await-closure.stderr
src/test/ui/async-await/suggest-missing-await.stderr
src/test/ui/attributes/key-value-non-ascii.stderr
src/test/ui/borrowck/move-error-snippets.stderr
src/test/ui/bound-suggestions.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
src/test/ui/c-variadic/issue-86053-1.stderr
src/test/ui/closures/closure-move-sync.stderr
src/test/ui/const-generics/const-argument-if-length.full.stderr
src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
src/test/ui/const-ptr/out_of_bounds_read.stderr
src/test/ui/consts/const-eval/partial_ptr_overwrite.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/unwind-abort.rs
src/test/ui/consts/const-eval/unwind-abort.stderr
src/test/ui/consts/const_unsafe_unreachable_ub.stderr
src/test/ui/consts/miri_unleashed/drop.stderr
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/offset_ub.stderr
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/consts/unwind-abort.rs
src/test/ui/cross/cross-file-errors/main.stderr
src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr
src/test/ui/derives/derives-span-Eq-enum.stderr
src/test/ui/derives/derives-span-Eq-struct.stderr
src/test/ui/derives/derives-span-Eq-tuple-struct.stderr
src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr
src/test/ui/derives/derives-span-Hash-enum.stderr
src/test/ui/derives/derives-span-Hash-struct.stderr
src/test/ui/derives/derives-span-Hash-tuple-struct.stderr
src/test/ui/derives/deriving-meta-unknown-trait.stderr
src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr
src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr
src/test/ui/empty/empty-struct-braces-expr.stderr
src/test/ui/empty/empty-struct-braces-pat-1.stderr
src/test/ui/empty/empty-struct-braces-pat-2.stderr
src/test/ui/empty/empty-struct-braces-pat-3.stderr
src/test/ui/empty/empty-struct-tuple-pat.stderr
src/test/ui/empty/empty-struct-unit-pat.stderr
src/test/ui/error-codes/E0004-2.stderr
src/test/ui/error-codes/E0005.stderr
src/test/ui/error-codes/E0297.stderr
src/test/ui/explore-issue-38412.stderr
src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
src/test/ui/feature-gates/feature-gate-unwind-attributes.rs [deleted file]
src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr [deleted file]
src/test/ui/generator/sized-yield.stderr
src/test/ui/generic-associated-types/cross-crate-bounds.stderr
src/test/ui/generic-associated-types/issue-86483.stderr
src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs [new file with mode: 0644]
src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr [new file with mode: 0644]
src/test/ui/impl-trait/impl-generic-mismatch.stderr
src/test/ui/impl-trait/issues/issue-78722.stderr
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
src/test/ui/inference/issue-86162-1.rs [new file with mode: 0644]
src/test/ui/inference/issue-86162-1.stderr [new file with mode: 0644]
src/test/ui/inference/issue-86162-2.rs [new file with mode: 0644]
src/test/ui/inference/issue-86162-2.stderr [new file with mode: 0644]
src/test/ui/interior-mutability/interior-mutability.stderr
src/test/ui/issues/issue-17546.stderr
src/test/ui/issues/issue-20433.stderr
src/test/ui/issues/issue-21160.stderr
src/test/ui/issues/issue-21202.stderr
src/test/ui/issues/issue-27033.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-43189.stderr
src/test/ui/issues/issue-54943.stderr
src/test/ui/issues/issue-56175.stderr
src/test/ui/issues/issue-60283.stderr
src/test/ui/issues/issue-69725.stderr
src/test/ui/issues/issue-7607-1.stderr
src/test/ui/issues/issue-78720.stderr
src/test/ui/kindck/kindck-send-object1.stderr
src/test/ui/limits/issue-55878.stderr
src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr
src/test/ui/macros/macro-name-typo.stderr
src/test/ui/macros/macro-path-prelude-fail-3.stderr
src/test/ui/macros/macro-use-wrong-name.stderr
src/test/ui/malformed/malformed-derive-entry.stderr
src/test/ui/malformed/malformed-unwind-1.rs [deleted file]
src/test/ui/malformed/malformed-unwind-1.stderr [deleted file]
src/test/ui/malformed/malformed-unwind-2.rs [deleted file]
src/test/ui/malformed/malformed-unwind-2.stderr [deleted file]
src/test/ui/mir/issue-80742.stderr
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr
src/test/ui/no-send-res-ports.stderr
src/test/ui/panics/abort-on-panic.rs
src/test/ui/parser/byte-literals.stderr
src/test/ui/parser/byte-string-literals.stderr
src/test/ui/parser/issue-62894.stderr
src/test/ui/parser/issue-87635.rs [new file with mode: 0644]
src/test/ui/parser/issue-87635.stderr [new file with mode: 0644]
src/test/ui/parser/lifetime_starts_expressions.rs
src/test/ui/parser/lifetime_starts_expressions.stderr
src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
src/test/ui/pattern/usefulness/match-privately-empty.stderr
src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
src/test/ui/privacy/privacy5.stderr
src/test/ui/privacy/private-method-cross-crate.stderr
src/test/ui/privacy/restricted/test.stderr
src/test/ui/proc-macro/auxiliary/api/parse.rs
src/test/ui/proc-macro/auxiliary/assert-span-pos.rs [new file with mode: 0644]
src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr
src/test/ui/proc-macro/parent-source-spans.stderr
src/test/ui/proc-macro/resolve-error.stderr
src/test/ui/proc-macro/span-absolute-posititions.rs [new file with mode: 0644]
src/test/ui/proc-macro/span-absolute-posititions.stderr [new file with mode: 0644]
src/test/ui/proc-macro/span-from-proc-macro.stderr
src/test/ui/range/range-1.stderr
src/test/ui/recursion/recursive-types-are-not-uninhabited.stderr
src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr
src/test/ui/regions/regions-close-object-into-object-5.stderr
src/test/ui/regions/regions-infer-bound-from-trait-self.stderr
src/test/ui/regions/regions-infer-bound-from-trait.stderr
src/test/ui/resolve/issue-19452.stderr
src/test/ui/resolve/levenshtein.stderr
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
src/test/ui/rfc-2008-non-exhaustive/struct.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
src/test/ui/rust-2021/future-prelude-collision-shadow.stderr
src/test/ui/simd/simd-generics.rs
src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs [new file with mode: 0644]
src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr [new file with mode: 0644]
src/test/ui/span/transitive-dep-span.stderr
src/test/ui/suggestions/attribute-typos.stderr
src/test/ui/suggestions/do-not-attempt-to-add-suggestions-with-no-changes.stderr
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
src/test/ui/suggestions/imm-ref-trait-object.stderr
src/test/ui/suggestions/import-trait-for-method-call.stderr
src/test/ui/suggestions/issue-81839.stderr
src/test/ui/suggestions/match-ergonomics.stderr
src/test/ui/suggestions/match-prev-arm-needing-semi.rs
src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
src/test/ui/suggestions/multibyte-escapes.rs [new file with mode: 0644]
src/test/ui/suggestions/multibyte-escapes.stderr [new file with mode: 0644]
src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
src/test/ui/suggestions/pattern-slice-vec.fixed [new file with mode: 0644]
src/test/ui/suggestions/pattern-slice-vec.rs [new file with mode: 0644]
src/test/ui/suggestions/pattern-slice-vec.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-change-mut.stderr
src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed
src/test/ui/suggestions/suggest-impl-trait-lifetime.rs
src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
src/test/ui/thread-local-in-ctfe.stderr
src/test/ui/thread-local-static.stderr
src/test/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr
src/test/ui/traits/bad-sized.stderr
src/test/ui/traits/bound/on-structs-and-enums-xc.stderr
src/test/ui/traits/bound/on-structs-and-enums-xc1.stderr
src/test/ui/traits/bound/same-crate-name.stderr
src/test/ui/traits/issue-85735.rs [new file with mode: 0644]
src/test/ui/traits/issue-85735.stderr [new file with mode: 0644]
src/test/ui/traits/mutual-recursion-issue-75860.stderr
src/test/ui/traits/suggest-deferences/issue-39029.stderr
src/test/ui/traits/suggest-where-clause.stderr
src/test/ui/traits/trait-upcasting/basic.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/diamond.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/invalid-upcast.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/invalid-upcast.stderr [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/lifetime.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/replace-vptr.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/struct.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/subtrait-method.rs [new file with mode: 0644]
src/test/ui/traits/trait-upcasting/subtrait-method.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-83693.stderr
src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
src/test/ui/union/union-derive-clone.mirunsafeck.stderr
src/test/ui/union/union-derive-clone.thirunsafeck.stderr
src/test/ui/union/union-derive-eq.mirunsafeck.stderr
src/test/ui/union/union-derive-eq.thirunsafeck.stderr
src/test/ui/union/union-drop.rs
src/test/ui/union/union-drop.thirunsafeck.stderr [deleted file]
src/test/ui/unique-object-noncopyable.stderr
src/test/ui/unique-pinned-nocopy.stderr
src/test/ui/unsafe/issue-87414-query-cycle.rs [new file with mode: 0644]
src/test/ui/unsafe/union-assignop.mirunsafeck.stderr [new file with mode: 0644]
src/test/ui/unsafe/union-assignop.rs [new file with mode: 0644]
src/test/ui/unsafe/union-assignop.thirunsafeck.stderr [new file with mode: 0644]
src/test/ui/wf/wf-impl-self-type.stderr
src/test/ui/xc-private-method.stderr
src/test/ui/xc-private-method2.stderr
src/test/ui/xcrate/xcrate-unit-struct.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
src/tools/clippy/clippy_lints/src/implicit_hasher.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
src/tools/miri
src/tools/rustbook/Cargo.toml

index ee4e09334a5d933e8c756cdb8559e6ce44ea8dc0..76a71d8994dfa9c3fcac936c6986a368e1ce87ce 100644 (file)
@@ -255,7 +255,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
 [[package]]
 name = "cargo"
-version = "0.56.0"
+version = "0.57.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -388,7 +388,7 @@ dependencies = [
 
 [[package]]
 name = "cargo-util"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "anyhow",
  "core-foundation",
@@ -2100,9 +2100,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ee73932975c44c485e541416d7c30abb31a053af7e49682f6e856f1e4d6ab2a"
+checksum = "0651782b4cc514c3f98c0acf9b5af1101a735bbe1ac6852bb1a90cb91bdf0ed4"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -3649,6 +3649,7 @@ dependencies = [
  "libc",
  "object 0.25.2",
  "pathdiff",
+ "regex",
  "rustc_apfloat",
  "rustc_ast",
  "rustc_attr",
index 7fecf537cfbd3fc077008e6a2bc5ff4c38fde740..bacf5662bc0058d4e98afbf064553bfc630aec94 100644 (file)
@@ -442,18 +442,10 @@ fn lower_expr_if(
         then: &Block,
         else_opt: Option<&Expr>,
     ) -> hir::ExprKind<'hir> {
-        macro_rules! make_if {
-            ($opt:expr) => {{
-                let cond = self.lower_expr(cond);
-                let then_expr = self.lower_block_expr(then);
-                hir::ExprKind::If(cond, self.arena.alloc(then_expr), $opt)
-            }};
-        }
-        if let Some(rslt) = else_opt {
-            make_if!(Some(self.lower_expr(rslt)))
-        } else {
-            make_if!(None)
-        }
+        let cond = self.lower_expr(cond);
+        let then = self.arena.alloc(self.lower_block_expr(then));
+        let els = else_opt.map(|els| self.lower_expr(els));
+        hir::ExprKind::If(cond, then, els)
     }
 
     fn lower_expr_if_let(
index b7b053cd5ddb7a910f24f795abb0ddac2ecb1044..a50fc698850c688eb53df7c1561c676662f153af 100644 (file)
@@ -87,50 +87,6 @@ pub enum OptimizeAttr {
     Size,
 }
 
-#[derive(Copy, Clone, PartialEq)]
-pub enum UnwindAttr {
-    Allowed,
-    Aborts,
-}
-
-/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
-pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option<UnwindAttr> {
-    attrs.iter().fold(None, |ia, attr| {
-        if sess.check_name(attr, sym::unwind) {
-            if let Some(meta) = attr.meta() {
-                if let MetaItemKind::List(items) = meta.kind {
-                    if items.len() == 1 {
-                        if items[0].has_name(sym::allowed) {
-                            return Some(UnwindAttr::Allowed);
-                        } else if items[0].has_name(sym::aborts) {
-                            return Some(UnwindAttr::Aborts);
-                        }
-                    }
-
-                    struct_span_err!(
-                        sess.diagnostic(),
-                        attr.span,
-                        E0633,
-                        "malformed `unwind` attribute input"
-                    )
-                    .span_label(attr.span, "invalid argument")
-                    .span_suggestions(
-                        attr.span,
-                        "the allowed arguments are `allowed` and `aborts`",
-                        (vec!["allowed", "aborts"])
-                            .into_iter()
-                            .map(|s| format!("#[unwind({})]", s)),
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
-                }
-            }
-        }
-
-        ia
-    })
-}
-
 /// Represents the following attributes:
 ///
 /// - `#[stable]`
index b9d379c6117c91d846e3620649c2e40f951daf9f..d594731b4dfce5870bc9358d0a5edf466f64fe60 100644 (file)
@@ -25,39 +25,73 @@ pub(crate) fn unsized_info<'tcx>(
             .bcx
             .ins()
             .iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
-        (&ty::Dynamic(..), &ty::Dynamic(..)) => {
-            // For now, upcasts are limited to changes in marker
-            // traits, and hence never actually require an actual
-            // change to the vtable.
-            old_info.expect("unsized_info: missing old info for trait upcast")
+        (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+            let old_info =
+                old_info.expect("unsized_info: missing old info for trait upcasting coercion");
+            if data_a.principal_def_id() == data_b.principal_def_id() {
+                return old_info;
+            }
+            // trait upcasting coercion
+
+            // if both of the two `principal`s are `None`, this function would have returned early above.
+            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
+            let principal_a = data_a
+                .principal()
+                .expect("unsized_info: missing principal trait for trait upcasting coercion");
+            let principal_b = data_b
+                .principal()
+                .expect("unsized_info: missing principal trait for trait upcasting coercion");
+
+            let vptr_entry_idx = fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
+                principal_a.with_self_ty(fx.tcx, source),
+                principal_b.with_self_ty(fx.tcx, source),
+            ));
+
+            if let Some(entry_idx) = vptr_entry_idx {
+                let entry_idx = u32::try_from(entry_idx).unwrap();
+                let entry_offset = entry_idx * fx.pointer_type.bytes();
+                let vptr_ptr = Pointer::new(old_info).offset_i64(fx, entry_offset.into()).load(
+                    fx,
+                    fx.pointer_type,
+                    crate::vtable::vtable_memflags(),
+                );
+                vptr_ptr
+            } else {
+                old_info
+            }
         }
         (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
 
-/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
-fn unsize_thin_ptr<'tcx>(
+/// Coerce `src` to `dst_ty`.
+fn unsize_ptr<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     src: Value,
     src_layout: TyAndLayout<'tcx>,
     dst_layout: TyAndLayout<'tcx>,
+    old_info: Option<Value>,
 ) -> (Value, Value) {
     match (&src_layout.ty.kind(), &dst_layout.ty.kind()) {
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _))
         | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
         | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
             assert!(!fx.layout_of(a).is_unsized());
-            (src, unsized_info(fx, a, b, None))
+            (src, unsized_info(fx, a, b, old_info))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
             let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty());
             assert!(!fx.layout_of(a).is_unsized());
-            (src, unsized_info(fx, a, b, None))
+            (src, unsized_info(fx, a, b, old_info))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
+            if src_layout == dst_layout {
+                return (src, old_info.unwrap());
+            }
+
             let mut result = None;
             for i in 0..src_layout.fields.count() {
                 let src_f = src_layout.field(fx, i);
@@ -71,11 +105,11 @@ fn unsize_thin_ptr<'tcx>(
                 let dst_f = dst_layout.field(fx, i);
                 assert_ne!(src_f.ty, dst_f.ty);
                 assert_eq!(result, None);
-                result = Some(unsize_thin_ptr(fx, src, src_f, dst_f));
+                result = Some(unsize_ptr(fx, src, src_f, dst_f, old_info));
             }
             result.unwrap()
         }
-        _ => bug!("unsize_thin_ptr: called on bad types"),
+        _ => bug!("unsize_ptr: called on bad types"),
     }
 }
 
@@ -91,12 +125,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
     let mut coerce_ptr = || {
         let (base, info) =
             if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() {
-                // fat-ptr to fat-ptr unsize preserves the vtable
-                // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
-                src.load_scalar_pair(fx)
+                let (old_base, old_info) = src.load_scalar_pair(fx);
+                unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info))
             } else {
                 let base = src.load_scalar(fx);
-                unsize_thin_ptr(fx, base, src.layout(), dst.layout())
+                unsize_ptr(fx, base, src.layout(), dst.layout(), None)
             };
         dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
     };
index 4a5f9f133a2bbc8e2168fd4668036fb46f3d091f..1b31587430887e3931829a4c81f3c86e109e1b75 100644 (file)
@@ -5,7 +5,7 @@
 use crate::constant::data_id_for_alloc_id;
 use crate::prelude::*;
 
-fn vtable_memflags() -> MemFlags {
+pub(crate) fn vtable_memflags() -> MemFlags {
     let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
     flags.set_readonly(); // A vtable is always read-only.
     flags
index 5675a5d9812413c7caec00ce84b083ee564a1301..d8fa7786c3780d9fbab39c71ad4fda7999b1202c 100644 (file)
@@ -497,9 +497,10 @@ fn scalar_load_metadata<'a, 'll, 'tcx>(
             OperandValue::Immediate(self.to_immediate(llval, place.layout))
         } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
             let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
+            let pair_ty = place.layout.llvm_type(self);
 
             let mut load = |i, scalar: &abi::Scalar, align| {
-                let llptr = self.struct_gep(place.llval, i as u64);
+                let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
                 let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
                 let load = self.load(llty, llptr, align);
                 scalar_load_metadata(self, load, scalar);
@@ -543,7 +544,11 @@ fn write_operand_repeatedly(
             .val
             .store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
 
-        let next = body_bx.inbounds_gep(current, &[self.const_usize(1)]);
+        let next = body_bx.inbounds_gep(
+            self.backend_type(cg_elem.layout),
+            current,
+            &[self.const_usize(1)],
+        );
         body_bx.br(header_bx.llbb());
         header_bx.add_incoming_to_phi(current, next, body_bx.llbb());
 
@@ -639,10 +644,11 @@ fn atomic_store(
         }
     }
 
-    fn gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
+    fn gep(&mut self, ty: &'ll Type, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
         unsafe {
-            llvm::LLVMBuildGEP(
+            llvm::LLVMBuildGEP2(
                 self.llbuilder,
+                ty,
                 ptr,
                 indices.as_ptr(),
                 indices.len() as c_uint,
@@ -651,10 +657,16 @@ fn gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
         }
     }
 
-    fn inbounds_gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
+    fn inbounds_gep(
+        &mut self,
+        ty: &'ll Type,
+        ptr: &'ll Value,
+        indices: &[&'ll Value],
+    ) -> &'ll Value {
         unsafe {
-            llvm::LLVMBuildInBoundsGEP(
+            llvm::LLVMBuildInBoundsGEP2(
                 self.llbuilder,
+                ty,
                 ptr,
                 indices.as_ptr(),
                 indices.len() as c_uint,
@@ -663,9 +675,9 @@ fn inbounds_gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Valu
         }
     }
 
-    fn struct_gep(&mut self, ptr: &'ll Value, idx: u64) -> &'ll Value {
+    fn struct_gep(&mut self, ty: &'ll Type, ptr: &'ll Value, idx: u64) -> &'ll Value {
         assert_eq!(idx as c_uint as u64, idx);
-        unsafe { llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, UNNAMED) }
+        unsafe { llvm::LLVMBuildStructGEP2(self.llbuilder, ty, ptr, idx as c_uint, UNNAMED) }
     }
 
     /* Casts */
index 35e72621c565d6473423b398758fb201f925c8e5..5532f53e40823fc0ede2a3e56ed85206001637e7 100644 (file)
@@ -268,7 +268,8 @@ fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -
                     }
                 };
                 let llval = unsafe {
-                    llvm::LLVMConstInBoundsGEP(
+                    llvm::LLVMRustConstInBoundsGEP2(
+                        self.type_i8(),
                         self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
                         &self.const_usize(offset.bytes()),
                         1,
@@ -303,7 +304,8 @@ fn from_const_alloc(
             let base_addr = self.static_addr_of(init, alloc.align, None);
 
             let llval = unsafe {
-                llvm::LLVMConstInBoundsGEP(
+                llvm::LLVMRustConstInBoundsGEP2(
+                    self.type_i8(),
                     self.const_bitcast(base_addr, self.type_i8p()),
                     &self.const_usize(offset.bytes()),
                     1,
index de3f719b8163c7ab0486ead4761cd579a06c078d..c33d35cc285d358e969904d6a3ccc246b5f078dd 100644 (file)
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
 pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
     if needs_gdb_debug_scripts_section(bx) {
-        let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
+        let gdb_debug_scripts_section =
+            bx.const_bitcast(get_or_insert_gdb_debug_scripts_section_global(bx), bx.type_i8p());
         // Load just the first byte as that's all that's necessary to force
         // LLVM to keep around the reference to the global.
-        let indices = [bx.const_i32(0), bx.const_i32(0)];
-        let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices);
-        let volative_load_instruction = bx.volatile_load(bx.type_i8(), element);
+        let volative_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
         unsafe {
             llvm::LLVMSetAlignment(volative_load_instruction, 1);
         }
index a48a694b630f001cd5c17b34d82de0234a3a0d5d..56563668de6b07898e6a2195fa4c3a507566a058 100644 (file)
@@ -686,11 +686,19 @@ fn codegen_emcc_try(
         // create an alloca and pass a pointer to that.
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
         let i8_align = bx.tcx().data_layout.i8_align.abi;
-        let catch_data =
-            catch.alloca(bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false), ptr_align);
-        let catch_data_0 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
+        let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
+        let catch_data = catch.alloca(catch_data_type, ptr_align);
+        let catch_data_0 = catch.inbounds_gep(
+            catch_data_type,
+            catch_data,
+            &[bx.const_usize(0), bx.const_usize(0)],
+        );
         catch.store(ptr, catch_data_0, ptr_align);
-        let catch_data_1 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
+        let catch_data_1 = catch.inbounds_gep(
+            catch_data_type,
+            catch_data,
+            &[bx.const_usize(0), bx.const_usize(1)],
+        );
         catch.store(is_rust_panic, catch_data_1, i8_align);
         let catch_data = catch.bitcast(catch_data, bx.type_i8p());
 
index 68d566cca095c3ea9faff2561310b88711eeede7..e803ad6d88e3c05a5b0cf93275778766aeaeda32 100644 (file)
@@ -1011,7 +1011,8 @@ pub fn LLVMConstArray(
     pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
 
     // Constant expressions
-    pub fn LLVMConstInBoundsGEP(
+    pub fn LLVMRustConstInBoundsGEP2(
+        ty: &'a Type,
         ConstantVal: &'a Value,
         ConstantIndices: *const &'a Value,
         NumIndices: c_uint,
@@ -1394,22 +1395,25 @@ pub fn LLVMBuildLoad2(
 
     pub fn LLVMBuildStore(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value;
 
-    pub fn LLVMBuildGEP(
+    pub fn LLVMBuildGEP2(
         B: &Builder<'a>,
+        Ty: &'a Type,
         Pointer: &'a Value,
         Indices: *const &'a Value,
         NumIndices: c_uint,
         Name: *const c_char,
     ) -> &'a Value;
-    pub fn LLVMBuildInBoundsGEP(
+    pub fn LLVMBuildInBoundsGEP2(
         B: &Builder<'a>,
+        Ty: &'a Type,
         Pointer: &'a Value,
         Indices: *const &'a Value,
         NumIndices: c_uint,
         Name: *const c_char,
     ) -> &'a Value;
-    pub fn LLVMBuildStructGEP(
+    pub fn LLVMBuildStructGEP2(
         B: &Builder<'a>,
+        Ty: &'a Type,
         Pointer: &'a Value,
         Idx: c_uint,
         Name: *const c_char,
index 9df1bd7d1d9bb20897aa3022a92bfd6aab9d629f..c9fb09570c35ad52b4462857adff174b322c4227 100644 (file)
@@ -50,12 +50,12 @@ fn emit_direct_ptr_va_arg(
 
     let aligned_size = size.align_to(slot_size).bytes() as i32;
     let full_direct_size = bx.cx().const_i32(aligned_size);
-    let next = bx.inbounds_gep(addr, &[full_direct_size]);
+    let next = bx.inbounds_gep(bx.type_i8(), addr, &[full_direct_size]);
     bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
 
     if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big {
         let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
-        let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
+        let adjusted = bx.inbounds_gep(bx.type_i8(), addr, &[adjusted_size]);
         (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
     } else {
         (bx.bitcast(addr, bx.cx().type_ptr_to(llty)), addr_align)
@@ -98,6 +98,7 @@ fn emit_aapcs_va_arg(
     // Implementation of the AAPCS64 calling convention for va_args see
     // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
     let va_list_addr = list.immediate();
+    let va_list_ty = list.deref(bx.cx).layout.llvm_type(bx);
     let layout = bx.cx.layout_of(target_ty);
 
     let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
@@ -109,11 +110,11 @@ fn emit_aapcs_va_arg(
 
     let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
     let (reg_off, reg_top_index, slot_size) = if gr_type {
-        let gr_offs = bx.struct_gep(va_list_addr, 7);
+        let gr_offs = bx.struct_gep(va_list_ty, va_list_addr, 7);
         let nreg = (layout.size.bytes() + 7) / 8;
         (gr_offs, 3, nreg * 8)
     } else {
-        let vr_off = bx.struct_gep(va_list_addr, 9);
+        let vr_off = bx.struct_gep(va_list_ty, va_list_addr, 9);
         let nreg = (layout.size.bytes() + 15) / 16;
         (vr_off, 5, nreg * 16)
     };
@@ -141,15 +142,15 @@ fn emit_aapcs_va_arg(
     maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
 
     let top_type = bx.type_i8p();
-    let top = in_reg.struct_gep(va_list_addr, reg_top_index);
+    let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index);
     let top = in_reg.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
 
     // reg_value = *(@top + reg_off_v);
-    let mut reg_addr = in_reg.gep(top, &[reg_off_v]);
+    let mut reg_addr = in_reg.gep(bx.type_i8(), top, &[reg_off_v]);
     if bx.tcx().sess.target.endian == Endian::Big && layout.size.bytes() != slot_size {
         // On big-endian systems the value is right-aligned in its slot.
         let offset = bx.const_i32((slot_size - layout.size.bytes()) as i32);
-        reg_addr = in_reg.gep(reg_addr, &[offset]);
+        reg_addr = in_reg.gep(bx.type_i8(), reg_addr, &[offset]);
     }
     let reg_type = layout.llvm_type(bx);
     let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
index 554fabaaf6e28e05226b57b01c128fa471c4f352..0e036a432ad399d99401926d74369ff840536d62 100644 (file)
@@ -16,6 +16,7 @@ jobserver = "0.1.22"
 tempfile = "3.2"
 pathdiff = "0.2.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+regex = "1.4"
 
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
index ab211e9daff3e3dd8eda34b9bbec277793f45a22..f3eb1e04d07dcb0d594c681bc9f25ccdc0252aca 100644 (file)
@@ -32,6 +32,7 @@
 use object::elf;
 use object::write::Object;
 use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
+use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
 use std::ffi::OsString;
@@ -672,6 +673,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     // Invoke the system linker
     info!("{:?}", &cmd);
     let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
+    let unknown_arg_regex =
+        Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
     let mut prog;
     let mut i = 0;
     loop {
@@ -688,16 +691,15 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         out.extend(&output.stdout);
         let out = String::from_utf8_lossy(&out);
 
-        // Check to see if the link failed with "unrecognized command line option:
-        // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
-        // reperform the link step without the -no-pie option. This is safe because
-        // if the linker doesn't support -no-pie then it should not default to
-        // linking executables as pie. Different versions of gcc seem to use
-        // different quotes in the error message so don't check for them.
+        // Check to see if the link failed with an error message that indicates it
+        // doesn't recognize the -no-pie option. If so, reperform the link step
+        // without it. This is safe because if the linker doesn't support -no-pie
+        // then it should not default to linking executables as pie. Different
+        // versions of gcc seem to use different quotes in the error message so
+        // don't check for them.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && out.contains("-no-pie")
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
         {
@@ -716,8 +718,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         // Fallback from '-static-pie' to '-static' in that case.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
         {
index be2bf8b199724ab59a00a6c054d38034b783e914..b60677267849ac0bb10658537f07c4acef7ebfbc 100644 (file)
@@ -23,7 +23,6 @@
 use rustc_middle::middle::lang_items;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
-use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::cgu_reuse_tracker::CguReuse;
@@ -32,6 +31,7 @@
 use rustc_span::symbol::sym;
 use rustc_target::abi::{Align, LayoutOf, VariantIdx};
 
+use std::convert::TryFrom;
 use std::ops::{Deref, DerefMut};
 use std::time::{Duration, Instant};
 
@@ -128,55 +128,95 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ///
 /// The `old_info` argument is a bit odd. It is intended for use in an upcast,
 /// where the new vtable for an object will be derived from the old one.
-pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
-    cx: &Cx,
+pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
     source: Ty<'tcx>,
     target: Ty<'tcx>,
-    old_info: Option<Cx::Value>,
-) -> Cx::Value {
+    old_info: Option<Bx::Value>,
+) -> Bx::Value {
+    let cx = bx.cx();
     let (source, target) =
-        cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env());
+        cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
     match (source.kind(), target.kind()) {
         (&ty::Array(_, len), &ty::Slice(_)) => {
             cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
         }
-        (&ty::Dynamic(..), &ty::Dynamic(..)) => {
-            // For now, upcasts are limited to changes in marker
-            // traits, and hence never actually require an actual
-            // change to the vtable.
-            old_info.expect("unsized_info: missing old info for trait upcast")
+        (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+            let old_info =
+                old_info.expect("unsized_info: missing old info for trait upcasting coercion");
+            if data_a.principal_def_id() == data_b.principal_def_id() {
+                return old_info;
+            }
+
+            // trait upcasting coercion
+
+            // if both of the two `principal`s are `None`, this function would have returned early above.
+            // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
+            let principal_a = data_a
+                .principal()
+                .expect("unsized_info: missing principal trait for trait upcasting coercion");
+            let principal_b = data_b
+                .principal()
+                .expect("unsized_info: missing principal trait for trait upcasting coercion");
+
+            let vptr_entry_idx = cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((
+                principal_a.with_self_ty(cx.tcx(), source),
+                principal_b.with_self_ty(cx.tcx(), source),
+            ));
+
+            if let Some(entry_idx) = vptr_entry_idx {
+                let ptr_ty = cx.type_i8p();
+                let ptr_align = cx.tcx().data_layout.pointer_align.abi;
+                let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
+                let gep = bx.inbounds_gep(
+                    ptr_ty,
+                    llvtable,
+                    &[bx.const_usize(u64::try_from(entry_idx).unwrap())],
+                );
+                let new_vptr = bx.load(ptr_ty, gep, ptr_align);
+                bx.nonnull_metadata(new_vptr);
+                // Vtable loads are invariant.
+                bx.set_invariant_load(new_vptr);
+                new_vptr
+            } else {
+                old_info
+            }
         }
         (_, &ty::Dynamic(ref data, ..)) => {
-            let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target)).field(cx, FAT_PTR_EXTRA);
-            cx.const_ptrcast(
-                meth::get_vtable(cx, source, data.principal()),
-                cx.backend_type(vtable_ptr),
-            )
+            let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
+                cx.layout_of(cx.tcx().mk_mut_ptr(target)),
+                1,
+                true,
+            );
+            cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
 
-/// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer.
-pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
+pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     src: Bx::Value,
     src_ty: Ty<'tcx>,
     dst_ty: Ty<'tcx>,
+    old_info: Option<Bx::Value>,
 ) -> (Bx::Value, Bx::Value) {
-    debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
+    debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
     match (src_ty.kind(), dst_ty.kind()) {
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
         | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            assert!(bx.cx().type_is_sized(a));
+            assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
             let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
-            (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
+            (bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, old_info))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
-
             let src_layout = bx.cx().layout_of(src_ty);
             let dst_layout = bx.cx().layout_of(dst_ty);
+            if src_ty == dst_ty {
+                return (src, old_info.unwrap());
+            }
             let mut result = None;
             for i in 0..src_layout.fields.count() {
                 let src_f = src_layout.field(bx.cx(), i);
@@ -190,18 +230,15 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 let dst_f = dst_layout.field(bx.cx(), i);
                 assert_ne!(src_f.ty, dst_f.ty);
                 assert_eq!(result, None);
-                result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty));
+                result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
             }
             let (lldata, llextra) = result.unwrap();
+            let lldata_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true);
+            let llextra_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true);
             // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-            // FIXME(eddyb) move these out of this `match` arm, so they're always
-            // applied, uniformly, no matter the source/destination types.
-            (
-                bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)),
-                bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)),
-            )
+            (bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty))
         }
-        _ => bug!("unsize_thin_ptr: called on bad types"),
+        _ => bug!("unsize_ptr: called on bad types"),
     }
 }
 
@@ -217,17 +254,8 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     match (src_ty.kind(), dst_ty.kind()) {
         (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
             let (base, info) = match bx.load_operand(src).val {
-                OperandValue::Pair(base, info) => {
-                    // fat-ptr to fat-ptr unsize preserves the vtable
-                    // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
-                    // So we need to pointercast the base to ensure
-                    // the types match up.
-                    // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
-                    // like `unsize_thin_ptr` does.
-                    let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR);
-                    (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
-                }
-                OperandValue::Immediate(base) => unsize_thin_ptr(bx, base, src_ty, dst_ty),
+                OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
+                OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None),
                 OperandValue::Ref(..) => bug!(),
             };
             OperandValue::Pair(base, info).store(bx, dst);
index b392b2c4ab8acfc70aa129b04767cb9efb8d9338..efeec5b728413b88b54fe472890f9aab9239c30a 100644 (file)
@@ -23,7 +23,7 @@ pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
         let llty = bx.fn_ptr_backend_type(fn_abi);
         let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
+        let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
         let ptr = bx.load(llty, gep, ptr_align);
         bx.nonnull_metadata(ptr);
         // Vtable loads are invariant.
@@ -42,7 +42,7 @@ pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
         let llty = bx.type_isize();
         let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
         let usize_align = bx.tcx().data_layout.pointer_align.abi;
-        let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
+        let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
         let ptr = bx.load(llty, gep, usize_align);
         // Vtable loads are invariant.
         bx.set_invariant_load(ptr);
index 56ff1b3934c13e1b070bf56d2becc9e3af7b18d7..75999225c031d2a071b7416a6c79d90f26e1f632 100644 (file)
@@ -116,14 +116,18 @@ pub fn codegen_intrinsic_call(
                 OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
             }
             sym::offset => {
+                let ty = substs.type_at(0);
+                let layout = bx.layout_of(ty);
                 let ptr = args[0].immediate();
                 let offset = args[1].immediate();
-                bx.inbounds_gep(ptr, &[offset])
+                bx.inbounds_gep(bx.backend_type(layout), ptr, &[offset])
             }
             sym::arith_offset => {
+                let ty = substs.type_at(0);
+                let layout = bx.layout_of(ty);
                 let ptr = args[0].immediate();
                 let offset = args[1].immediate();
-                bx.gep(ptr, &[offset])
+                bx.gep(bx.backend_type(layout), ptr, &[offset])
             }
             sym::copy => {
                 copy_intrinsic(
index 3e8386bc88feda1facf37b2d13ed2765d2147f53..cfb2befdf913752ffe89b4acd0faf8538badf4e0 100644 (file)
@@ -311,14 +311,15 @@ fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     Abi::ScalarPair(ref a, ref b) => (a, b),
                     _ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout),
                 };
+                let ty = bx.backend_type(dest.layout);
                 let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
 
-                let llptr = bx.struct_gep(dest.llval, 0);
+                let llptr = bx.struct_gep(ty, dest.llval, 0);
                 let val = bx.from_immediate(a);
                 let align = dest.align;
                 bx.store_with_flags(val, llptr, align, flags);
 
-                let llptr = bx.struct_gep(dest.llval, 1);
+                let llptr = bx.struct_gep(ty, dest.llval, 1);
                 let val = bx.from_immediate(b);
                 let align = dest.align.restrict_for_offset(b_offset);
                 bx.store_with_flags(val, llptr, align, flags);
index 66d9d1a1e0c490ef2237a25e1602c92f8ceda921..20be46606a0aad771c585580ccfeaa0f881843a6 100644 (file)
@@ -103,12 +103,13 @@ pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) =>
                 {
                     // Offset matches second field.
-                    bx.struct_gep(self.llval, 1)
+                    let ty = bx.backend_type(self.layout);
+                    bx.struct_gep(ty, self.llval, 1)
                 }
                 Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
                     // ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer.
                     let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
-                    bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())])
+                    bx.gep(bx.cx().type_i8(), byte_ptr, &[bx.const_usize(offset.bytes())])
                 }
                 Abi::Scalar(_) | Abi::ScalarPair(..) => {
                     // All fields of Scalar and ScalarPair layouts must have been handled by this point.
@@ -119,7 +120,10 @@ pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                         self.layout
                     );
                 }
-                _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)),
+                _ => {
+                    let ty = bx.backend_type(self.layout);
+                    bx.struct_gep(ty, self.llval, bx.cx().backend_field_index(self.layout, ix))
+                }
             };
             PlaceRef {
                 // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types.
@@ -185,7 +189,7 @@ pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
 
         // Cast and adjust pointer.
         let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
-        let byte_ptr = bx.gep(byte_ptr, &[offset]);
+        let byte_ptr = bx.gep(bx.cx().type_i8(), byte_ptr, &[offset]);
 
         // Finally, cast back to the type expected.
         let ll_fty = bx.cx().backend_type(field);
@@ -380,7 +384,11 @@ pub fn project_index<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         };
 
         PlaceRef {
-            llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]),
+            llval: bx.inbounds_gep(
+                bx.cx().backend_type(self.layout),
+                self.llval,
+                &[bx.cx().const_usize(0), llindex],
+            ),
             llextra: None,
             layout,
             align: self.align.restrict_for_offset(offset),
index 530de3de9e870e9604afe0526ea6e4f59dc0a346..cbb401c63d152246e33fef5f12e40ab4281a6fc9 100644 (file)
@@ -220,34 +220,23 @@ pub fn codegen_rvalue_operand(
                     }
                     mir::CastKind::Pointer(PointerCast::Unsize) => {
                         assert!(bx.cx().is_backend_scalar_pair(cast));
-                        match operand.val {
+                        let (lldata, llextra) = match operand.val {
                             OperandValue::Pair(lldata, llextra) => {
                                 // unsize from a fat pointer -- this is a
-                                // "trait-object-to-supertrait" coercion, for
-                                // example, `&'a fmt::Debug + Send => &'a fmt::Debug`.
-
-                                // HACK(eddyb) have to bitcast pointers
-                                // until LLVM removes pointee types.
-                                let lldata = bx.pointercast(
-                                    lldata,
-                                    bx.cx().scalar_pair_element_backend_type(cast, 0, true),
-                                );
-                                OperandValue::Pair(lldata, llextra)
+                                // "trait-object-to-supertrait" coercion.
+                                (lldata, Some(llextra))
                             }
                             OperandValue::Immediate(lldata) => {
                                 // "standard" unsize
-                                let (lldata, llextra) = base::unsize_thin_ptr(
-                                    &mut bx,
-                                    lldata,
-                                    operand.layout.ty,
-                                    cast.ty,
-                                );
-                                OperandValue::Pair(lldata, llextra)
+                                (lldata, None)
                             }
                             OperandValue::Ref(..) => {
                                 bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
                             }
-                        }
+                        };
+                        let (lldata, llextra) =
+                            base::unsize_ptr(&mut bx, lldata, operand.layout.ty, cast.ty, llextra);
+                        OperandValue::Pair(lldata, llextra)
                     }
                     mir::CastKind::Pointer(PointerCast::MutToConstPointer)
                     | mir::CastKind::Misc
@@ -647,7 +636,14 @@ pub fn codegen_scalar_binop(
             mir::BinOp::BitOr => bx.or(lhs, rhs),
             mir::BinOp::BitAnd => bx.and(lhs, rhs),
             mir::BinOp::BitXor => bx.xor(lhs, rhs),
-            mir::BinOp::Offset => bx.inbounds_gep(lhs, &[rhs]),
+            mir::BinOp::Offset => {
+                let pointee_type = input_ty
+                    .builtin_deref(true)
+                    .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
+                    .ty;
+                let llty = bx.cx().backend_type(bx.cx().layout_of(pointee_type));
+                bx.inbounds_gep(llty, lhs, &[rhs])
+            }
             mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
             mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
             mir::BinOp::Ne
index c89d42ecc58ac10797ee245103e281db752ebd6c..8d7e9612f4749d63c0fbb9e6388520627ac85374 100644 (file)
@@ -47,8 +47,6 @@
     ("sve", Some(sym::aarch64_target_feature)),
     // FEAT_CRC
     ("crc", Some(sym::aarch64_target_feature)),
-    // Cryptographic extension
-    ("crypto", Some(sym::aarch64_target_feature)),
     // FEAT_RAS
     ("ras", Some(sym::aarch64_target_feature)),
     // FEAT_LSE
index f0c232a97bc946bd395957a3ecea12640b054b6d..f2c523148530f63cb5de677db401cbc15490bc11 100644 (file)
@@ -176,9 +176,14 @@ fn atomic_store(
         size: Size,
     );
 
-    fn gep(&mut self, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
-    fn inbounds_gep(&mut self, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
-    fn struct_gep(&mut self, ptr: Self::Value, idx: u64) -> Self::Value;
+    fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
+    fn inbounds_gep(
+        &mut self,
+        ty: Self::Type,
+        ptr: Self::Value,
+        indices: &[Self::Value],
+    ) -> Self::Value;
+    fn struct_gep(&mut self, ty: Self::Type, ptr: Self::Value, idx: u64) -> Self::Value;
 
     fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
index 65999ba707c857a21650ea482719fc992afebe5e..719c2c6768bc8f07198ef213825e8a8215a815ef 100644 (file)
 E0622: include_str!("./error_codes/E0622.md"),
 E0623: include_str!("./error_codes/E0623.md"),
 E0624: include_str!("./error_codes/E0624.md"),
+E0625: include_str!("./error_codes/E0625.md"),
 E0626: include_str!("./error_codes/E0626.md"),
 E0627: include_str!("./error_codes/E0627.md"),
 E0628: include_str!("./error_codes/E0628.md"),
 //  E0611, // merged into E0616
 //  E0612, // merged into E0609
 //  E0613, // Removed (merged with E0609)
-    E0625, // thread-local statics cannot be accessed at compile-time
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
            // attribute
diff --git a/compiler/rustc_error_codes/src/error_codes/E0625.md b/compiler/rustc_error_codes/src/error_codes/E0625.md
new file mode 100644 (file)
index 0000000..7db8577
--- /dev/null
@@ -0,0 +1,28 @@
+A compile-time const variable is referring to a thread-local static variable.
+
+Erroneous code example:
+
+```compile_fail,E0625
+#![feature(thread_local)]
+
+#[thread_local]
+static X: usize = 12;
+
+const Y: usize = 2 * X;
+```
+
+Static and const variables can refer to other const variables but a const
+variable cannot refer to a thread-local static variable. In this example,
+`Y` cannot refer to `X`. To fix this, the value can be extracted as a const
+and then used:
+
+```
+#![feature(thread_local)]
+
+const C: usize = 12;
+
+#[thread_local]
+static X: usize = C;
+
+const Y: usize = 2 * C;
+```
index 4d1f0c47829c9b9662143f7036374465d995fdf4..5b6c15c82eb637f51843205430d3256ae6034202 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The `unwind` attribute was malformed.
 
 Erroneous code example:
 
-```compile_fail,E0633
+```compile_fail
 #![feature(unwind_attributes)]
 
 #[unwind()] // error: expected one argument
index 87272b1605b798ce9bf5678e2b20a815e23ab2ae..050f3ae583371d722fc8101f7c7723af44d2e4ab 100644 (file)
@@ -954,7 +954,6 @@ fn render_source_line(
         //   |
         for pos in 0..=line_len {
             draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2);
-            buffer.putc(line_offset + pos + 1, width_offset - 2, '|', Style::LineNumber);
         }
 
         // Write the horizontal lines for multiline annotations
@@ -1344,7 +1343,11 @@ fn emit_message_default(
                 let buffer_msg_line_offset = buffer.num_lines();
 
                 // Add spacing line
-                draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
+                draw_col_separator_no_space(
+                    &mut buffer,
+                    buffer_msg_line_offset,
+                    max_line_num_len + 1,
+                );
 
                 // Then, the secondary file indicator
                 buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
index 993a7c2c162c6b7936f5496c1e295e50cc050160..fc0924ac5f920540e5e596e619362d347530f058 100644 (file)
@@ -342,6 +342,9 @@ struct HandlerInner {
     deduplicated_warn_count: usize,
 
     future_breakage_diagnostics: Vec<Diagnostic>,
+
+    /// If set to `true`, no warning or error will be emitted.
+    quiet: bool,
 }
 
 /// A key denoting where from a diagnostic was stashed.
@@ -456,10 +459,19 @@ pub fn with_emitter_and_flags(
                 emitted_diagnostics: Default::default(),
                 stashed_diagnostics: Default::default(),
                 future_breakage_diagnostics: Vec::new(),
+                quiet: false,
             }),
         }
     }
 
+    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+        let prev = self.inner.borrow_mut().quiet;
+        self.inner.borrow_mut().quiet = true;
+        let ret = f();
+        self.inner.borrow_mut().quiet = prev;
+        ret
+    }
+
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc_middle.
     pub fn can_emit_warnings(&self) -> bool {
@@ -818,7 +830,7 @@ fn emit_stashed_diagnostics(&mut self) {
     }
 
     fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
-        if diagnostic.cancelled() {
+        if diagnostic.cancelled() || self.quiet {
             return;
         }
 
@@ -1035,6 +1047,9 @@ fn bug(&mut self, msg: &str) -> ! {
     }
 
     fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
+        if self.quiet {
+            return;
+        }
         if self.flags.report_delayed_bugs {
             self.emit_diagnostic(&diagnostic);
         }
index b949d885900d954e20c147f4147d1976d3b482fc..42ae8e972c274ee8c61a703842d53fae2731a7b3 100644 (file)
@@ -1,7 +1,7 @@
 use crate::base::{ExtCtxt, ResolverExpand};
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
+use rustc_ast::token::{self, Nonterminal, NtIdent};
 use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
 use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
 use rustc_ast_pretty::pprust;
@@ -537,32 +537,54 @@ fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
 
 impl server::Literal for Rustc<'_> {
     fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
-        let override_span = None;
-        let stream = parse_stream_from_source_str(
-            FileName::proc_macro_source_code(s),
-            s.to_owned(),
-            self.sess,
-            override_span,
-        );
-        if stream.len() != 1 {
-            return Err(());
-        }
-        let tree = stream.into_trees().next().unwrap();
-        let token = match tree {
-            tokenstream::TokenTree::Token(token) => token,
-            tokenstream::TokenTree::Delimited { .. } => return Err(()),
+        let name = FileName::proc_macro_source_code(s);
+        let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned());
+
+        let first_span = parser.token.span.data();
+        let minus_present = parser.eat(&token::BinOp(token::Minus));
+
+        let lit_span = parser.token.span.data();
+        let mut lit = match parser.token.kind {
+            token::Literal(lit) => lit,
+            _ => return Err(()),
         };
-        let span_data = token.span.data();
-        if (span_data.hi.0 - span_data.lo.0) as usize != s.len() {
-            // There is a comment or whitespace adjacent to the literal.
+
+        // Check no comment or whitespace surrounding the (possibly negative)
+        // literal, or more tokens after it.
+        if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
             return Err(());
         }
-        let lit = match token.kind {
-            TokenKind::Literal(lit) => lit,
-            _ => return Err(()),
-        };
+
+        if minus_present {
+            // If minus is present, check no comment or whitespace in between it
+            // and the literal token.
+            if first_span.hi.0 != lit_span.lo.0 {
+                return Err(());
+            }
+
+            // Check literal is a kind we allow to be negated in a proc macro token.
+            match lit.kind {
+                token::LitKind::Bool
+                | token::LitKind::Byte
+                | token::LitKind::Char
+                | token::LitKind::Str
+                | token::LitKind::StrRaw(_)
+                | token::LitKind::ByteStr
+                | token::LitKind::ByteStrRaw(_)
+                | token::LitKind::Err => return Err(()),
+                token::LitKind::Integer | token::LitKind::Float => {}
+            }
+
+            // Synthesize a new symbol that includes the minus sign.
+            let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]);
+            lit = token::Lit::new(lit.kind, symbol, lit.suffix);
+        }
+
         Ok(Literal { lit, span: self.call_site })
     }
+    fn to_string(&mut self, literal: &Self::Literal) -> String {
+        literal.lit.to_string()
+    }
     fn debug_kind(&mut self, literal: &Self::Literal) -> String {
         format!("{:?}", literal.lit.kind)
     }
index 638330c904d756712da48ad1bb3f98969791c4c1..128b51c206162d5fe0fcc5b6fb1be3b25ab564af 100644 (file)
@@ -311,11 +311,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `extern "platform-intrinsic" { ... }`.
     (active, platform_intrinsics, "1.4.0", Some(27731), None),
 
-    /// Allows `#[unwind(..)]`.
-    ///
-    /// Permits specifying whether a function should permit unwinding or abort on unwind.
-    (active, unwind_attributes, "1.4.0", Some(58760), None),
-
     /// Allows attributes on expressions and non-item statements.
     (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
 
@@ -687,6 +682,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
     (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
 
+    /// Allows explicit generic arguments specification with `impl Trait` present.
+    (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
index 36d035cdfd3ae34bd53566d79b0ccad199852d04..49cca3fbc3985211ed7526ec9340342615170dae 100644 (file)
@@ -419,10 +419,6 @@ macro_rules! experimental {
     ),
     gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)),
     gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)),
-    gated!(
-        unwind, AssumedUsed, template!(List: "allowed|aborts"), unwind_attributes,
-        experimental!(unwind),
-    ),
     gated!(
         compiler_builtins, AssumedUsed, template!(Word),
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
index f63c207a540c2ff72c32320733d572b59d40295f..46b36f2b7040f6f28163dbd6ef81f72c44aaa076 100644 (file)
@@ -156,6 +156,11 @@ macro_rules! declare_features {
     (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
      Some("removed in favor of full type_alias_impl_trait")),
 
+    /// Allows `#[unwind(..)]`.
+    ///
+    /// Permits specifying whether a function should permit unwinding or abort on unwind.
+    (removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")),
+
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
index f885c0a4b87bd1f6c42312128203d18381cb6227..d5e1c061bf0bab92f8c1c9b8ca551a27e33d329a 100644 (file)
@@ -71,7 +71,7 @@
     subst::{GenericArgKind, Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, iter};
@@ -89,16 +89,17 @@ pub(super) fn note_and_explain_region(
     prefix: &str,
     region: ty::Region<'tcx>,
     suffix: &str,
+    alt_span: Option<Span>,
 ) {
     let (description, span) = match *region {
         ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
-            msg_span_from_free_region(tcx, region)
+            msg_span_from_free_region(tcx, region, alt_span)
         }
 
-        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),
+        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span),
 
         // uh oh, hope no user ever sees THIS
-        ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
+        ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span),
 
         ty::RePlaceholder(_) => return,
 
@@ -108,7 +109,7 @@ pub(super) fn note_and_explain_region(
         // We shouldn't really be having unification failures with ReVar
         // and ReLateBound though.
         ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
-            (format!("lifetime {:?}", region), None)
+            (format!("lifetime {:?}", region), alt_span)
         }
     };
 
@@ -122,7 +123,7 @@ pub(super) fn note_and_explain_free_region(
     region: ty::Region<'tcx>,
     suffix: &str,
 ) {
-    let (description, span) = msg_span_from_free_region(tcx, region);
+    let (description, span) = msg_span_from_free_region(tcx, region, None);
 
     emit_msg_span(err, prefix, description, span, suffix);
 }
@@ -130,14 +131,15 @@ pub(super) fn note_and_explain_free_region(
 fn msg_span_from_free_region(
     tcx: TyCtxt<'tcx>,
     region: ty::Region<'tcx>,
+    alt_span: Option<Span>,
 ) -> (String, Option<Span>) {
     match *region {
         ty::ReEarlyBound(_) | ty::ReFree(_) => {
             msg_span_from_early_bound_and_free_regions(tcx, region)
         }
-        ty::ReStatic => ("the static lifetime".to_owned(), None),
-        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
-        ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
+        ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
+        ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span),
         _ => bug!("{:?}", region),
     }
 }
@@ -319,6 +321,7 @@ pub fn unexpected_hidden_region_diagnostic(
                 &format!("hidden type `{}` captures ", hidden_ty),
                 hidden_region,
                 "",
+                None,
             );
         }
     }
@@ -1485,31 +1488,49 @@ fn add_labels_for_types(
                     let count = values.len();
                     let kind = key.descr();
                     let mut returned_async_output_error = false;
-                    for sp in values {
-                        err.span_label(
-                            *sp,
-                            format!(
-                                "{}{}{} {}{}",
-                                if sp.is_desugaring(DesugaringKind::Async)
-                                    && !returned_async_output_error
-                                {
-                                    "checked the `Output` of this `async fn`, "
-                                } else if count == 1 {
-                                    "the "
-                                } else {
-                                    ""
-                                },
-                                if count > 1 { "one of the " } else { "" },
-                                target,
-                                kind,
-                                pluralize!(count),
-                            ),
-                        );
-                        if sp.is_desugaring(DesugaringKind::Async)
-                            && returned_async_output_error == false
-                        {
-                            err.note("while checking the return type of the `async fn`");
+                    for &sp in values {
+                        if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
+                            if &[sp] != err.span.primary_spans() {
+                                let mut span: MultiSpan = sp.into();
+                                span.push_span_label(
+                                    sp,
+                                    format!(
+                                        "checked the `Output` of this `async fn`, {}{} {}{}",
+                                        if count > 1 { "one of the " } else { "" },
+                                        target,
+                                        kind,
+                                        pluralize!(count),
+                                    ),
+                                );
+                                err.span_note(
+                                    span,
+                                    "while checking the return type of the `async fn`",
+                                );
+                            } else {
+                                err.span_label(
+                                    sp,
+                                    format!(
+                                        "checked the `Output` of this `async fn`, {}{} {}{}",
+                                        if count > 1 { "one of the " } else { "" },
+                                        target,
+                                        kind,
+                                        pluralize!(count),
+                                    ),
+                                );
+                                err.note("while checking the return type of the `async fn`");
+                            }
                             returned_async_output_error = true;
+                        } else {
+                            err.span_label(
+                                sp,
+                                format!(
+                                    "{}{} {}{}",
+                                    if count == 1 { "the " } else { "one of the " },
+                                    target,
+                                    kind,
+                                    pluralize!(count),
+                                ),
+                            );
                         }
                     }
                 }
@@ -2285,8 +2306,9 @@ fn binding_suggestion<'tcx, S: fmt::Display>(
                     &format!("{} must be valid for ", labeled_user_string),
                     sub,
                     "...",
+                    None,
                 );
-                if let Some(infer::RelateParamBound(_, t)) = origin {
+                if let Some(infer::RelateParamBound(_, t, _)) = origin {
                     let return_impl_trait = self
                         .in_progress_typeck_results
                         .map(|typeck_results| typeck_results.borrow().hir_owner)
@@ -2332,6 +2354,7 @@ fn report_sub_sup_conflict(
             "first, the lifetime cannot outlive ",
             sup_region,
             "...",
+            None,
         );
 
         debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
@@ -2358,6 +2381,7 @@ fn report_sub_sup_conflict(
                         "...but the lifetime must also be valid for ",
                         sub_region,
                         "...",
+                        None,
                     );
                     err.span_note(
                         sup_trace.cause.span,
@@ -2379,6 +2403,7 @@ fn report_sub_sup_conflict(
             "but, the lifetime must be valid for ",
             sub_region,
             "...",
+            None,
         );
 
         self.note_region_origin(&mut err, &sub_origin);
index 9a718102cf11d8d225cab04a461eadd1ac2bebae..c2025f3fe4da27498f64b7bef5c8fbf12b7a2f1b 100644 (file)
@@ -753,23 +753,11 @@ pub fn emit_inference_failure_err(
             if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
                 (&arg_data.kind, &arg_data.parent)
             {
-                let has_impl_trait =
-                    self.tcx.generics_of(parent_data.def_id).params.iter().any(|param| {
-                        matches!(
-                            param.kind,
-                            ty::GenericParamDefKind::Type {
-                                synthetic: Some(
-                                    hir::SyntheticTyParamKind::ImplTrait
-                                        | hir::SyntheticTyParamKind::FromAttr,
-                                ),
-                                ..
-                            }
-                        )
-                    });
-
                 // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
                 // as an argument otherwise it will cause the E0282 error.
-                if !has_impl_trait {
+                if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
+                    || self.tcx.features().explicit_generic_args_with_impl_trait
+                {
                     err.span_suggestion_verbose(
                         span,
                         "consider specifying the const argument",
@@ -814,7 +802,7 @@ fn annotate_method_call(
             let borrow = typeck_results.borrow();
             if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
                 let generics = self.tcx.generics_of(did);
-                if !generics.params.is_empty() {
+                if !generics.params.is_empty() && !generics.has_impl_trait() {
                     err.span_suggestion_verbose(
                         segment.ident.span.shrink_to_hi(),
                         &format!(
index cca195417270bd5289d45d8e82f921ec06572094..c60a7149e40eb30bb85f019df45857eff2b0f3ca 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorReport
         multi_span
             .push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
         err.span_note(multi_span, "because this has an unmet lifetime requirement");
-        note_and_explain_region(self.tcx(), &mut err, "", sup, "...");
+        note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
index c88869abc29e4d0b797752466059b61e45f6104c..4bc59a4baf5cae5c1bddb5c0a1ffbf05d711c41f 100644 (file)
@@ -74,14 +74,18 @@ pub(super) fn note_region_origin(
                     ),
                 );
             }
-            infer::RelateParamBound(span, t) => {
+            infer::RelateParamBound(span, t, opt_span) => {
                 label_or_note(
                     span,
                     &format!(
-                        "...so that the type `{}` will meet its required lifetime bounds",
-                        self.ty_to_string(t)
+                        "...so that the type `{}` will meet its required lifetime bounds{}",
+                        self.ty_to_string(t),
+                        if opt_span.is_some() { "..." } else { "" },
                     ),
                 );
+                if let Some(span) = opt_span {
+                    err.span_note(span, "...that is required by this bound");
+                }
             }
             infer::RelateRegionParamBound(span) => {
                 label_or_note(
@@ -117,6 +121,7 @@ pub(super) fn report_concrete_failure(
                             "",
                             sup,
                             " doesn't meet the lifetime requirements",
+                            None,
                         );
                     }
                     (_, ty::RePlaceholder(_)) => {
@@ -126,16 +131,18 @@ pub(super) fn report_concrete_failure(
                             "the required lifetime does not necessarily outlive ",
                             sub,
                             "",
+                            None,
                         );
                     }
                     _ => {
-                        note_and_explain_region(self.tcx, &mut err, "", sup, "...");
+                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
                         note_and_explain_region(
                             self.tcx,
                             &mut err,
                             "...does not necessarily outlive ",
                             sub,
                             "",
+                            None,
                         );
                     }
                 }
@@ -154,6 +161,7 @@ pub(super) fn report_concrete_failure(
                     "...the reference is valid for ",
                     sub,
                     "...",
+                    None,
                 );
                 note_and_explain_region(
                     self.tcx,
@@ -161,6 +169,7 @@ pub(super) fn report_concrete_failure(
                     "...but the borrowed content is only valid for ",
                     sup,
                     "",
+                    None,
                 );
                 err
             }
@@ -179,6 +188,7 @@ pub(super) fn report_concrete_failure(
                     "...the borrowed pointer is valid for ",
                     sub,
                     "...",
+                    None,
                 );
                 note_and_explain_region(
                     self.tcx,
@@ -186,6 +196,7 @@ pub(super) fn report_concrete_failure(
                     &format!("...but `{}` is only valid for ", var_name),
                     sup,
                     "",
+                    None,
                 );
                 err
             }
@@ -197,17 +208,25 @@ pub(super) fn report_concrete_failure(
                     "lifetime of the source pointer does not outlive lifetime bound of the \
                      object type"
                 );
-                note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, "");
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "object type is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
                 note_and_explain_region(
                     self.tcx,
                     &mut err,
                     "source pointer is only valid for ",
                     sup,
                     "",
+                    None,
                 );
                 err
             }
-            infer::RelateParamBound(span, ty) => {
+            infer::RelateParamBound(span, ty, opt_span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
                     span,
@@ -216,10 +235,22 @@ pub(super) fn report_concrete_failure(
                     self.ty_to_string(ty)
                 );
                 match *sub {
-                    ty::ReStatic => {
-                        note_and_explain_region(self.tcx, &mut err, "type must satisfy ", sub, "")
-                    }
-                    _ => note_and_explain_region(self.tcx, &mut err, "type must outlive ", sub, ""),
+                    ty::ReStatic => note_and_explain_region(
+                        self.tcx,
+                        &mut err,
+                        "type must satisfy ",
+                        sub,
+                        if opt_span.is_some() { " as required by this binding" } else { "" },
+                        opt_span,
+                    ),
+                    _ => note_and_explain_region(
+                        self.tcx,
+                        &mut err,
+                        "type must outlive ",
+                        sub,
+                        if opt_span.is_some() { " as required by this binding" } else { "" },
+                        opt_span,
+                    ),
                 }
                 err
             }
@@ -232,6 +263,7 @@ pub(super) fn report_concrete_failure(
                     "lifetime parameter instantiated with ",
                     sup,
                     "",
+                    None,
                 );
                 note_and_explain_region(
                     self.tcx,
@@ -239,6 +271,7 @@ pub(super) fn report_concrete_failure(
                     "but lifetime parameter must outlive ",
                     sub,
                     "",
+                    None,
                 );
                 err
             }
@@ -255,6 +288,7 @@ pub(super) fn report_concrete_failure(
                     "the return value is only valid for ",
                     sup,
                     "",
+                    None,
                 );
                 err
             }
@@ -266,8 +300,22 @@ pub(super) fn report_concrete_failure(
                     "a value of type `{}` is borrowed for too long",
                     self.ty_to_string(ty)
                 );
-                note_and_explain_region(self.tcx, &mut err, "the type is valid for ", sub, "");
-                note_and_explain_region(self.tcx, &mut err, "but the borrow lasts for ", sup, "");
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "the type is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "but the borrow lasts for ",
+                    sup,
+                    "",
+                    None,
+                );
                 err
             }
             infer::ReferenceOutlivesReferent(ty, span) => {
@@ -278,13 +326,21 @@ pub(super) fn report_concrete_failure(
                     "in type `{}`, reference has a longer lifetime than the data it references",
                     self.ty_to_string(ty)
                 );
-                note_and_explain_region(self.tcx, &mut err, "the pointer is valid for ", sub, "");
+                note_and_explain_region(
+                    self.tcx,
+                    &mut err,
+                    "the pointer is valid for ",
+                    sub,
+                    "",
+                    None,
+                );
                 note_and_explain_region(
                     self.tcx,
                     &mut err,
                     "but the referenced data is only valid for ",
                     sup,
                     "",
+                    None,
                 );
                 err
             }
index d3bfb2b2e4428090a07ea433f4f8de16598929ba..f0d63f512fcbc2e4341b94e9ffabd3db7e94931c 100644 (file)
@@ -375,7 +375,7 @@ pub enum SubregionOrigin<'tcx> {
 
     /// Some type parameter was instantiated with the given type,
     /// and that type must outlive some region.
-    RelateParamBound(Span, Ty<'tcx>),
+    RelateParamBound(Span, Ty<'tcx>, Option<Span>),
 
     /// The given region parameter was instantiated with a region
     /// that must outlive some other region.
@@ -1705,7 +1705,7 @@ pub fn span(&self) -> Span {
         match *self {
             Subtype(ref a) => a.span(),
             RelateObjectBound(a) => a,
-            RelateParamBound(a, _) => a,
+            RelateParamBound(a, ..) => a,
             RelateRegionParamBound(a) => a,
             Reborrow(a) => a,
             ReborrowUpvar(a, _) => a,
index 3e2978fd170aea36526f911f1faa6486dc38a1cf..437083c68dceca7c7d6243ab08883a6cc91f0803 100644 (file)
@@ -64,7 +64,7 @@
 use crate::infer::{
     self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
 };
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
@@ -99,7 +99,14 @@ pub fn register_region_obligation_with_cause(
         cause: &ObligationCause<'tcx>,
     ) {
         let origin = SubregionOrigin::from_obligation_cause(cause, || {
-            infer::RelateParamBound(cause.span, sup_type)
+            infer::RelateParamBound(
+                cause.span,
+                sup_type,
+                match cause.code.peel_derives() {
+                    ObligationCauseCode::BindingObligation(_, span) => Some(*span),
+                    _ => None,
+                },
+            )
         });
 
         self.register_region_obligation(
index de0d5fb0097f91bfed87d54016651b9382661145..b896143400698745985faaabf8bda2b2109ebeb9 100644 (file)
@@ -740,6 +740,7 @@ macro_rules! tracked {
     tracked!(new_llvm_pass_manager, Some(true));
     tracked!(no_generate_arange_section, true);
     tracked!(no_link, true);
+    tracked!(no_profiler_runtime, true);
     tracked!(osx_rpath_install_name, true);
     tracked!(panic_abort_tests, true);
     tracked!(plt, Some(true));
@@ -748,7 +749,7 @@ macro_rules! tracked {
     tracked!(print_fuel, Some("abc".to_string()));
     tracked!(profile, true);
     tracked!(profile_emit, Some(PathBuf::from("abc")));
-    tracked!(profiler_runtime, None);
+    tracked!(profiler_runtime, "abc".to_string());
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
index b3c64b76820f11e3b55aa4da2437d1c8d3444a0d..c590cd00bd54568f3222adc6c846ebd0f35804b6 100644 (file)
@@ -38,7 +38,7 @@
 use rustc_feature::{GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
 use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
 use rustc_hir::{HirId, Node};
 use rustc_index::vec::Idx;
@@ -511,7 +511,7 @@ fn doc_hidden(&self) -> bool {
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
-        id: hir::HirId,
+        def_id: LocalDefId,
         sp: Span,
         article: &'static str,
         desc: &'static str,
@@ -530,13 +530,13 @@ fn check_missing_docs_attrs(
         // Only check publicly-visible items, using the result from the privacy pass.
         // It's an option so the crate root can also use this function (it doesn't
         // have a `NodeId`).
-        if id != hir::CRATE_HIR_ID {
-            if !cx.access_levels.is_exported(id) {
+        if def_id != CRATE_DEF_ID {
+            if !cx.access_levels.is_exported(def_id) {
                 return;
             }
         }
 
-        let attrs = cx.tcx.hir().attrs(id);
+        let attrs = cx.tcx.get_attrs(def_id.to_def_id());
         let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
         if !has_doc {
             cx.struct_span_lint(
@@ -568,12 +568,12 @@ fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
     }
 
     fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) {
-        self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.module().inner, "the", "crate");
+        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate");
 
         for macro_def in krate.exported_macros() {
             // Non exported macros should be skipped, since `missing_docs` only
             // applies to externally visible items.
-            if !cx.access_levels.is_exported(macro_def.hir_id()) {
+            if !cx.access_levels.is_exported(macro_def.def_id) {
                 continue;
             }
 
@@ -632,7 +632,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
 
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, it.hir_id(), it.span, article, desc);
+        self.check_missing_docs_attrs(cx, it.def_id, it.span, article, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
@@ -642,7 +642,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem
 
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, trait_item.hir_id(), trait_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -652,22 +652,23 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, impl_item.hir_id(), impl_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, foreign_item.hir_id(), foreign_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, foreign_item.def_id, foreign_item.span, article, desc);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
         if !sf.is_positional() {
-            self.check_missing_docs_attrs(cx, sf.hir_id, sf.span, "a", "struct field")
+            let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
+            self.check_missing_docs_attrs(cx, def_id, sf.span, "a", "struct field")
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
-        self.check_missing_docs_attrs(cx, v.id, v.span, "a", "variant");
+        self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), v.span, "a", "variant");
     }
 }
 
@@ -709,7 +710,7 @@ fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.hir_id()) {
+        if !cx.access_levels.is_reachable(item.def_id) {
             return;
         }
         let (def, ty) = match item.kind {
@@ -796,7 +797,7 @@ pub struct MissingDebugImplementations {
 
 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.hir_id()) {
+        if !cx.access_levels.is_reachable(item.def_id) {
             return;
         }
 
@@ -1314,14 +1315,14 @@ fn perform_lint(
         &self,
         cx: &LateContext<'_>,
         what: &str,
-        id: hir::HirId,
+        def_id: LocalDefId,
         vis: &hir::Visibility<'_>,
         span: Span,
         exportable: bool,
     ) {
         let mut applicability = Applicability::MachineApplicable;
         match vis.node {
-            hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => {
+            hir::VisibilityKind::Public if !cx.access_levels.is_reachable(def_id) => {
                 if span.from_expansion() {
                     applicability = Applicability::MaybeIncorrect;
                 }
@@ -1354,14 +1355,14 @@ fn perform_lint(
 
 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        self.perform_lint(cx, "item", item.hir_id(), &item.vis, item.span, true);
+        self.perform_lint(cx, "item", item.def_id, &item.vis, item.span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
         self.perform_lint(
             cx,
             "item",
-            foreign_item.hir_id(),
+            foreign_item.def_id,
             &foreign_item.vis,
             foreign_item.span,
             true,
@@ -1369,11 +1370,12 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::Forei
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        self.perform_lint(cx, "field", field.hir_id, &field.vis, field.span, false);
+        let def_id = cx.tcx.hir().local_def_id(field.hir_id);
+        self.perform_lint(cx, "field", def_id, &field.vis, field.span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
-        self.perform_lint(cx, "item", impl_item.hir_id(), &impl_item.vis, impl_item.span, false);
+        self.perform_lint(cx, "item", impl_item.def_id, &impl_item.vis, impl_item.span, false);
     }
 }
 
index ad8a41a56cc16287799824e5ea34ed0bb6dad769..4a646013ff89166a51d5f2fff2a4e4704fc274ef 100644 (file)
@@ -750,6 +750,14 @@ fn lookup_with_diagnostics(
                         db.note(&format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
                     }
                 }
+                BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => {
+                    db.multipart_suggestion(
+                        "wrap this expression in parentheses",
+                        vec![(span.shrink_to_lo(), "(".to_string()),
+                             (span.shrink_to_hi(), ")".to_string())],
+                        Applicability::MachineApplicable
+                    );
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
index 7195c41eae92e7aacb32d08ad578f93c977f1dfb..9b1ee53df23bd1c99386d415499b52c66c88f870 100644 (file)
     /// The asm block must not contain any operands other than `const` and
     /// `sym`. Additionally, naked function should specify a non-Rust ABI.
     ///
+    /// Naked functions cannot be inlined. All forms of the `inline` attribute
+    /// are prohibited.
+    ///
     /// While other definitions of naked functions were previously accepted,
     /// they are unsupported and might not work reliably. This is a
     /// [future-incompatible] lint that will transition into hard error in
         RUST_2021_PRELUDE_COLLISIONS,
         RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
         UNSUPPORTED_CALLING_CONVENTIONS,
+        BREAK_WITH_LABEL_AND_LOOP,
     ]
 }
 
         reference: "issue #00000 <https://github.com/rust-lang/rust/issues/00000>",
     };
 }
+
+declare_lint! {
+    /// The `break_with_label_and_loop` lint detects labeled `break` expressions with
+    /// an unlabeled loop as their value expression.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// 'label: loop {
+    ///     break 'label loop { break 42; };
+    /// };
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In Rust, loops can have a label, and `break` expressions can refer to that label to
+    /// break out of specific loops (and not necessarily the innermost one). `break` expressions
+    /// can also carry a value expression, which can be another loop. A labeled `break` with an
+    /// unlabeled loop as its value expression is easy to confuse with an unlabeled break with
+    /// a labeled loop and is thus discouraged (but allowed for compatibility); use parentheses
+    /// around the loop expression to silence this warning. Unlabeled `break` expressions with
+    /// labeled loops yield a hard error, which can also be silenced by wrapping the expression
+    /// in parentheses.
+    pub BREAK_WITH_LABEL_AND_LOOP,
+    Warn,
+    "`break` expression with label and unlabeled loop as value expression"
+}
index 6c38b8f5bc0a14c84fd5fe14939fc5461f312b41..b8f5345ffb8849dd2640cd7da128ce0361c419c8 100644 (file)
@@ -304,6 +304,7 @@ pub enum BuiltinLintDiagnostics {
     OrPatternsBackCompat(Span, String),
     ReservedPrefix(Span),
     TrailingMacro(bool, Ident),
+    BreakWithLabelAndLoop(Span),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
index 4cdc8a4155bcc58ba6489aab09e433a750afdace..7666803911e0b6d12fc3c5e19a93aeb8c3741904 100644 (file)
@@ -1551,6 +1551,16 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
   LLVMSetLinkage(V, fromRust(RustLinkage));
 }
 
+extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty,
+                                                  LLVMValueRef ConstantVal,
+                                                  LLVMValueRef *ConstantIndices,
+                                                  unsigned NumIndices) {
+  ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
+                               NumIndices);
+  Constant *Val = unwrap<Constant>(ConstantVal);
+  return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
+}
+
 // Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
 // the common sizes (1, 8, 16, 32, 64, 128 bits)
 extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
index 5373169bda7abb36cecad68419d16bf036f93452..394cb8389357f2f02633f06c2cf2f4f58b2a9748 100644 (file)
@@ -777,19 +777,17 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
     }
 
     fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
-        let profiler_runtime = &self.sess.opts.debugging_opts.profiler_runtime;
-
-        if !(profiler_runtime.is_some()
-            && (self.sess.instrument_coverage()
+        if self.sess.opts.debugging_opts.no_profiler_runtime
+            || !(self.sess.instrument_coverage()
                 || self.sess.opts.debugging_opts.profile
-                || self.sess.opts.cg.profile_generate.enabled()))
+                || self.sess.opts.cg.profile_generate.enabled())
         {
             return;
         }
 
         info!("loading profiler");
 
-        let name = Symbol::intern(profiler_runtime.as_ref().unwrap());
+        let name = Symbol::intern(&self.sess.opts.debugging_opts.profiler_runtime);
         if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
             self.sess.err(
                 "`profiler_builtins` crate (required by compiler options) \
index 4936b22c7b983010e15e699bda1f5ed370ba793e..cf8577a26cf714fd6c31b056e753b3c51208982f 100644 (file)
@@ -1103,8 +1103,8 @@ impl CrateError {
                         if sess.is_nightly_build() {
                             err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
                         }
-                    } else if Some(crate_name)
-                        == sess.opts.debugging_opts.profiler_runtime.as_deref().map(Symbol::intern)
+                    } else if crate_name
+                        == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime)
                     {
                         err.note(&"the compiler may have been built without the profiler runtime");
                     }
index b1606ef8f636b14319f24c51230a2d5fe7d6a739..c313146b072225913328a692daab2ac6d706bd55 100644 (file)
@@ -581,14 +581,6 @@ pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
         self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some()
     }
 
-    /// Whether `hir_id` corresponds to a `mod` or a crate.
-    pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
-        matches!(
-            self.get(hir_id),
-            Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
-        )
-    }
-
     /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
     /// `while` or `loop` before reaching it, as block tail returns are not
     /// available in them.
index 93e7aeaffce3771ea62e15a0a0552b8000107fd6..b2705c7693914919901344d957cb4a92f73eeb15 100644 (file)
@@ -52,13 +52,9 @@ pub struct CodegenFnAttrFlags: u32 {
         /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
         /// function is never null.
         const ALLOCATOR                 = 1 << 1;
-        /// `#[unwind]`: an indicator that this function may unwind despite what
-        /// its ABI signature may otherwise imply.
-        const UNWIND                    = 1 << 2;
-        /// `#[rust_allocator_nounwind]`, an indicator that an imported FFI
-        /// function will never unwind. Probably obsolete by recent changes with
-        /// #[unwind], but hasn't been removed/migrated yet
-        const RUSTC_ALLOCATOR_NOUNWIND  = 1 << 3;
+        /// An indicator that function will never unwind. Will become obsolete
+        /// once C-unwind is fully stabilized.
+        const NEVER_UNWIND              = 1 << 3;
         /// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
         /// should be generated.
         const NAKED                     = 1 << 4;
index 54188985d7c5f18f56c24980d5f7ed37140d9e7a..a11ca74b25ee3473c214328b4f5f3f9e7282489e 100644 (file)
@@ -3,9 +3,8 @@
 //! which are available for use externally when compiled as a library.
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::HirId;
 use rustc_macros::HashStable;
-use std::fmt;
+use rustc_span::def_id::LocalDefId;
 use std::hash::Hash;
 
 /// Represents the levels of accessibility an item can have.
@@ -27,8 +26,8 @@ pub enum AccessLevel {
 }
 
 /// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Clone)]
-pub struct AccessLevels<Id = HirId> {
+#[derive(Debug)]
+pub struct AccessLevels<Id = LocalDefId> {
     pub map: FxHashMap<Id, AccessLevel>,
 }
 
@@ -49,14 +48,8 @@ pub fn is_public(&self, id: Id) -> bool {
     }
 }
 
-impl<Id: Hash + Eq> Default for AccessLevels<Id> {
+impl<Id> Default for AccessLevels<Id> {
     fn default() -> Self {
         AccessLevels { map: Default::default() }
     }
 }
-
-impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(&self.map, f)
-    }
-}
index 2804fe580615c2dfafea4c99c1016762a318939c..f0b4b6b5a0ca640080c3d48850a8292f50867914 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, HirId};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
@@ -36,12 +36,12 @@ pub struct DeprecationEntry {
     pub attr: Deprecation,
     /// The `DefId` where the attr was originally attached. `None` for non-local
     /// `DefId`'s.
-    origin: Option<HirId>,
+    origin: Option<LocalDefId>,
 }
 
 impl DeprecationEntry {
-    pub fn local(attr: Deprecation, id: HirId) -> DeprecationEntry {
-        DeprecationEntry { attr, origin: Some(id) }
+    pub fn local(attr: Deprecation, def_id: LocalDefId) -> DeprecationEntry {
+        DeprecationEntry { attr, origin: Some(def_id) }
     }
 
     pub fn external(attr: Deprecation) -> DeprecationEntry {
@@ -61,9 +61,9 @@ pub fn same_origin(&self, other: &DeprecationEntry) -> bool {
 pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
-    pub stab_map: FxHashMap<HirId, &'tcx Stability>,
-    pub const_stab_map: FxHashMap<HirId, &'tcx ConstStability>,
-    pub depr_map: FxHashMap<HirId, DeprecationEntry>,
+    pub stab_map: FxHashMap<LocalDefId, &'tcx Stability>,
+    pub const_stab_map: FxHashMap<LocalDefId, &'tcx ConstStability>,
+    pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
 
     /// Maps for each crate whether it is part of the staged API.
     pub staged_api: FxHashMap<CrateNum, bool>,
@@ -73,16 +73,16 @@ pub struct Index<'tcx> {
 }
 
 impl<'tcx> Index<'tcx> {
-    pub fn local_stability(&self, id: HirId) -> Option<&'tcx Stability> {
-        self.stab_map.get(&id).cloned()
+    pub fn local_stability(&self, def_id: LocalDefId) -> Option<&'tcx Stability> {
+        self.stab_map.get(&def_id).copied()
     }
 
-    pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> {
-        self.const_stab_map.get(&id).cloned()
+    pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<&'tcx ConstStability> {
+        self.const_stab_map.get(&def_id).copied()
     }
 
-    pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
-        self.depr_map.get(&id).cloned()
+    pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
+        self.depr_map.get(&def_id).cloned()
     }
 }
 
index bbf792edcded9ee27cade96ed363776996ec9cb3..a29b42b45df375f2a158c7d76756d1ebaa8b30a1 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
 use super::{
-    read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer,
+    read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance,
     ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, UndefinedBehaviorInfo, UninitBytesAccess,
     UnsupportedOpInfo,
 };
@@ -53,6 +53,8 @@ pub struct Allocation<Tag = AllocId, Extra = ()> {
 pub enum AllocError {
     /// Encountered a pointer where we needed raw bytes.
     ReadPointerAsBytes,
+    /// Partially overwriting a pointer.
+    PartialPointerOverwrite(Size),
     /// Using uninitialized data where it is not allowed.
     InvalidUninitBytes(Option<UninitBytesAccess>),
 }
@@ -60,11 +62,13 @@ pub enum AllocError {
 
 impl AllocError {
     pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
+        use AllocError::*;
         match self {
-            AllocError::ReadPointerAsBytes => {
-                InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes)
-            }
-            AllocError::InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
+            ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes),
+            PartialPointerOverwrite(offset) => InterpError::Unsupported(
+                UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
+            ),
+            InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
                 UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
             ),
         }
@@ -218,7 +222,7 @@ pub fn relocations(&self) -> &Relocations<Tag> {
 }
 
 /// Byte accessors.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
     /// The last argument controls whether we error out when there are uninitialized
     /// or pointer bytes. You should never call this, call `get_bytes` or
     /// `get_bytes_with_uninit_and_ptr` instead,
@@ -275,30 +279,35 @@ pub fn get_bytes_with_uninit_and_ptr(
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
     /// on `InterpCx` instead.
-    pub fn get_bytes_mut(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> &mut [u8] {
+    pub fn get_bytes_mut(
+        &mut self,
+        cx: &impl HasDataLayout,
+        range: AllocRange,
+    ) -> AllocResult<&mut [u8]> {
         self.mark_init(range, true);
-        self.clear_relocations(cx, range);
+        self.clear_relocations(cx, range)?;
 
-        &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
+        Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
     }
 
     /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
-    pub fn get_bytes_mut_ptr(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> *mut [u8] {
+    pub fn get_bytes_mut_ptr(
+        &mut self,
+        cx: &impl HasDataLayout,
+        range: AllocRange,
+    ) -> AllocResult<*mut [u8]> {
         self.mark_init(range, true);
-        // This also clears relocations that just overlap with the written range. So writing to some
-        // byte can de-initialize its neighbors! See
-        // <https://github.com/rust-lang/rust/issues/87184> for details.
-        self.clear_relocations(cx, range);
+        self.clear_relocations(cx, range)?;
 
         assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
         let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
         let len = range.end().bytes_usize() - range.start.bytes_usize();
-        ptr::slice_from_raw_parts_mut(begin_ptr, len)
+        Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
     }
 }
 
 /// Reading and writing.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
     /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
     /// given range contains neither relocations nor uninitialized bytes.
@@ -395,7 +404,7 @@ pub fn write_scalar(
         };
 
         let endian = cx.data_layout().endian;
-        let dst = self.get_bytes_mut(cx, range);
+        let dst = self.get_bytes_mut(cx, range)?;
         write_target_uint(endian, dst, bytes).unwrap();
 
         // See if we have to also write a relocation.
@@ -433,13 +442,16 @@ fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> Alloc
     /// uninitialized. This is a somewhat odd "spooky action at a distance",
     /// but it allows strictly more code to run than if we would just error
     /// immediately in that case.
-    fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
+    fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult
+    where
+        Tag: Provenance,
+    {
         // Find the start and end of the given range and its outermost relocations.
         let (first, last) = {
             // Find all relocations overlapping the given range.
             let relocations = self.get_relocations(cx, range);
             if relocations.is_empty() {
-                return;
+                return Ok(());
             }
 
             (
@@ -450,17 +462,27 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
         let start = range.start;
         let end = range.end();
 
-        // Mark parts of the outermost relocations as uninitialized if they partially fall outside the
-        // given range.
+        // We need to handle clearing the relocations from parts of a pointer. See
+        // <https://github.com/rust-lang/rust/issues/87184> for details.
         if first < start {
+            if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+                return Err(AllocError::PartialPointerOverwrite(first));
+            }
             self.init_mask.set_range(first, start, false);
         }
         if last > end {
+            if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+                return Err(AllocError::PartialPointerOverwrite(
+                    last - cx.data_layout().pointer_size,
+                ));
+            }
             self.init_mask.set_range(end, last, false);
         }
 
         // Forget all the relocations.
         self.relocations.0.remove_range(first..last);
+
+        Ok(())
     }
 
     /// Errors if there are relocations overlapping with the edges of the
index dad23d6255afb02bea6df68af3f8362837924634..4826c96000cc25ad2eb1cdf3850a422cd1bcf0e8 100644 (file)
@@ -404,6 +404,9 @@ pub enum UnsupportedOpInfo {
     Unsupported(String),
     /// Encountered a pointer where we needed raw bytes.
     ReadPointerAsBytes,
+    /// Overwriting parts of a pointer; the resulting state cannot be represented in our
+    /// `Allocation` data structure.
+    PartialPointerOverwrite(Pointer<AllocId>),
     //
     // The variants below are only reachable from CTFE/const prop, miri will never emit them.
     //
@@ -418,9 +421,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use UnsupportedOpInfo::*;
         match self {
             Unsupported(ref msg) => write!(f, "{}", msg),
-            ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
-            ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes",),
+            ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
+            PartialPointerOverwrite(ptr) => {
+                write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
+            }
             ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
+            ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
         }
     }
 }
index 568b3f252bf5f450efa6c5ea34d4879ed5ef17e5..3eee45a9230d1ffbd68e3d17e55f7e136dc97fbc 100644 (file)
@@ -108,6 +108,10 @@ pub trait Provenance: Copy + fmt::Debug {
     /// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
     const OFFSET_IS_ADDR: bool;
 
+    /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
+    /// (this avoids a separate trait in `allocation.rs` just for this purpose).
+    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool;
+
     /// Determines how a pointer should be printed.
     fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
     where
@@ -123,6 +127,9 @@ impl Provenance for AllocId {
     // so ptr-to-int casts are not possible (since we do not know the global physical offset).
     const OFFSET_IS_ADDR: bool = false;
 
+    // For now, do not allow this, so that we keep our options open.
+    const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = true;
+
     fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Forward `alternate` flag to `alloc_id` printing.
         if f.alternate() {
index c8db4aeb449b87e66b1a99e78572f7046a1dce98..e78b6fd092de2695b71d6ce9a762275237d55168 100644 (file)
@@ -237,7 +237,7 @@ pub enum TerminatorKind<'tcx> {
         /// consider it in borrowck. We don't want to accept programs which
         /// pass borrowck only when `panic=abort` or some assertions are disabled
         /// due to release vs. debug mode builds. This needs to be an `Option` because
-        /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
+        /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
         unwind: Option<BasicBlock>,
     },
 
index 2de836c058cf1d6c55501a998bb14311a3c08cfa..3c16852df059a9ee6b6938cd9bb7fdffaf252679 100644 (file)
         desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
     }
 
+    query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>)) -> Option<usize> {
+        desc { |tcx| "finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable",
+            tcx.def_path_str(key.1.def_id()), tcx.def_path_str(key.0.def_id()) }
+    }
+
     query codegen_fulfill_obligation(
         key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
     ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
index 4ce49032398bc7877cc2438953c63fec117cfcfc..3bdd91d2136093af3fa003d7323a96d7e1c996c0 100644 (file)
@@ -2854,18 +2854,11 @@ pub fn provide(providers: &mut ty::query::Providers) {
         tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
     };
 
-    providers.lookup_stability = |tcx, id| {
-        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
-        tcx.stability().local_stability(id)
-    };
-    providers.lookup_const_stability = |tcx, id| {
-        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
-        tcx.stability().local_const_stability(id)
-    };
-    providers.lookup_deprecation_entry = |tcx, id| {
-        let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
-        tcx.stability().local_deprecation_entry(id)
-    };
+    providers.lookup_stability = |tcx, id| tcx.stability().local_stability(id.expect_local());
+    providers.lookup_const_stability =
+        |tcx, id| tcx.stability().local_const_stability(id.expect_local());
+    providers.lookup_deprecation_entry =
+        |tcx, id| tcx.stability().local_deprecation_entry(id.expect_local());
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
     providers.output_filenames = |tcx, ()| tcx.output_filenames.clone();
index 4e3f475a915f35119c503b7eb02c2609bbf33fa1..0f89581ae669c43f031343ed0ac4b30f7ed8bf8f 100644 (file)
@@ -198,6 +198,21 @@ pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &Generi
             _ => bug!("expected const parameter, but found another generic parameter"),
         }
     }
+
+    /// Returns `true` if `params` has `impl Trait`.
+    pub fn has_impl_trait(&'tcx self) -> bool {
+        self.params.iter().any(|param| {
+            matches!(
+                param.kind,
+                ty::GenericParamDefKind::Type {
+                    synthetic: Some(
+                        hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
+                    ),
+                    ..
+                }
+            )
+        })
+    }
 }
 
 /// Bounds on generics.
index 95ea38d32b69508aeb4eeaa27046bdf096c47bbb..2e4395cfca8c15e0c246e59c9a231fb118da156c 100644 (file)
@@ -2601,65 +2601,124 @@ fn new_internal(
     fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
 }
 
+/// Calculates whether a function's ABI can unwind or not.
+///
+/// This takes two primary parameters:
+///
+/// * `codegen_fn_attr_flags` - these are flags calculated as part of the
+///   codegen attrs for a defined function. For function pointers this set of
+///   flags is the empty set. This is only applicable for Rust-defined
+///   functions, and generally isn't needed except for small optimizations where
+///   we try to say a function which otherwise might look like it could unwind
+///   doesn't actually unwind (such as for intrinsics and such).
+///
+/// * `abi` - this is the ABI that the function is defined with. This is the
+///   primary factor for determining whether a function can unwind or not.
+///
+/// Note that in this case unwinding is not necessarily panicking in Rust. Rust
+/// panics are implemented with unwinds on most platform (when
+/// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
+/// Notably unwinding is disallowed for more non-Rust ABIs unless it's
+/// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
+/// defined for each ABI individually, but it always corresponds to some form of
+/// stack-based unwinding (the exact mechanism of which varies
+/// platform-by-platform).
+///
+/// Rust functions are classfied whether or not they can unwind based on the
+/// active "panic strategy". In other words Rust functions are considered to
+/// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
+/// Note that Rust supports intermingling panic=abort and panic=unwind code, but
+/// only if the final panic mode is panic=abort. In this scenario any code
+/// previously compiled assuming that a function can unwind is still correct, it
+/// just never happens to actually unwind at runtime.
+///
+/// This function's answer to whether or not a function can unwind is quite
+/// impactful throughout the compiler. This affects things like:
+///
+/// * Calling a function which can't unwind means codegen simply ignores any
+///   associated unwinding cleanup.
+/// * Calling a function which can unwind from a function which can't unwind
+///   causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
+///   aborts the process.
+/// * This affects whether functions have the LLVM `nounwind` attribute, which
+///   affects various optimizations and codegen.
+///
+/// FIXME: this is actually buggy with respect to Rust functions. Rust functions
+/// compiled with `-Cpanic=unwind` and referenced from another crate compiled
+/// with `-Cpanic=abort` will look like they can't unwind when in fact they
+/// might (from a foreign exception or similar).
 pub fn fn_can_unwind(
-    panic_strategy: PanicStrategy,
+    tcx: TyCtxt<'tcx>,
     codegen_fn_attr_flags: CodegenFnAttrFlags,
-    call_conv: Conv,
     abi: SpecAbi,
 ) -> bool {
-    if panic_strategy != PanicStrategy::Unwind {
-        // In panic=abort mode we assume nothing can unwind anywhere, so
-        // optimize based on this!
-        false
-    } else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::UNWIND) {
-        // If a specific #[unwind] attribute is present, use that.
-        true
-    } else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
-        // Special attribute for allocator functions, which can't unwind.
-        false
-    } else {
-        if call_conv == Conv::Rust {
-            // Any Rust method (or `extern "Rust" fn` or `extern
-            // "rust-call" fn`) is explicitly allowed to unwind
-            // (unless it has no-unwind attribute, handled above).
-            true
-        } else {
-            // Anything else is either:
-            //
-            //  1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
-            //
-            //  2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
-            //
-            // In both of these cases, we should refer to the ABI to determine whether or not we
-            // should unwind. See Rust RFC 2945 for more information on this behavior, here:
-            // https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
-            use SpecAbi::*;
-            match abi {
-                C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
-                    unwind
-                }
-                Cdecl
-                | Fastcall
-                | Vectorcall
-                | Aapcs
-                | Win64
-                | SysV64
-                | PtxKernel
-                | Msp430Interrupt
-                | X86Interrupt
-                | AmdGpuKernel
-                | EfiApi
-                | AvrInterrupt
-                | AvrNonBlockingInterrupt
-                | CCmseNonSecureCall
-                | Wasm
-                | RustIntrinsic
-                | PlatformIntrinsic
-                | Unadjusted => false,
-                // In the `if` above, we checked for functions with the Rust calling convention.
-                Rust | RustCall => unreachable!(),
-            }
+    // Special attribute for functions which can't unwind.
+    if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
+        return false;
+    }
+
+    // Otherwise if this isn't special then unwinding is generally determined by
+    // the ABI of the itself. ABIs like `C` have variants which also
+    // specifically allow unwinding (`C-unwind`), but not all platform-specific
+    // ABIs have such an option. Otherwise the only other thing here is Rust
+    // itself, and those ABIs are determined by the panic strategy configured
+    // for this compilation.
+    //
+    // Unfortunately at this time there's also another caveat. Rust [RFC
+    // 2945][rfc] has been accepted and is in the process of being implemented
+    // and stabilized. In this interim state we need to deal with historical
+    // rustc behavior as well as plan for future rustc behavior.
+    //
+    // Historically functions declared with `extern "C"` were marked at the
+    // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
+    // or not. This is UB for functions in `panic=unwind` mode that then
+    // actually panic and unwind. Note that this behavior is true for both
+    // externally declared functions as well as Rust-defined function.
+    //
+    // To fix this UB rustc would like to change in the future to catch unwinds
+    // from function calls that may unwind within a Rust-defined `extern "C"`
+    // function and forcibly abort the process, thereby respecting the
+    // `nounwind` attribut emitted for `extern "C"`. This behavior change isn't
+    // ready to roll out, so determining whether or not the `C` family of ABIs
+    // unwinds is conditional not only on their definition but also whether the
+    // `#![feature(c_unwind)]` feature gate is active.
+    //
+    // Note that this means that unlike historical compilers rustc now, by
+    // default, unconditionally thinks that the `C` ABI may unwind. This will
+    // prevent some optimization opportunities, however, so we try to scope this
+    // change and only assume that `C` unwinds with `panic=unwind` (as opposed
+    // to `panic=abort`).
+    //
+    // Eventually the check against `c_unwind` here will ideally get removed and
+    // this'll be a little cleaner as it'll be a straightforward check of the
+    // ABI.
+    //
+    // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
+    use SpecAbi::*;
+    match abi {
+        C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
+            unwind
+                || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
         }
+        Cdecl
+        | Fastcall
+        | Vectorcall
+        | Aapcs
+        | Win64
+        | SysV64
+        | PtxKernel
+        | Msp430Interrupt
+        | X86Interrupt
+        | AmdGpuKernel
+        | EfiApi
+        | AvrInterrupt
+        | AvrNonBlockingInterrupt
+        | CCmseNonSecureCall
+        | Wasm
+        | RustIntrinsic
+        | PlatformIntrinsic
+        | Unadjusted => false,
+        Rust | RustCall => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
     }
 }
 
@@ -2695,11 +2754,6 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
     }
 }
 
-pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
-    // Assume that fn pointers may always unwind
-    CodegenFnAttrFlags::UNWIND
-}
-
 impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
 where
     C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
@@ -2709,7 +2763,7 @@ impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
         + HasParamEnv<'tcx>,
 {
     fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
+        call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
     }
 
     fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2901,12 +2955,7 @@ fn new_internal(
             c_variadic: sig.c_variadic,
             fixed_count: inputs.len(),
             conv,
-            can_unwind: fn_can_unwind(
-                cx.tcx().sess.panic_strategy(),
-                codegen_fn_attr_flags,
-                conv,
-                sig.abi,
-            ),
+            can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
         };
         fn_abi.adjust_for_abi(cx, sig.abi);
         debug!("FnAbi::new_internal = {:?}", fn_abi);
index eb11b9371433d145a24cac55f8738877d39ecb25..446a0f8e72fbd9bf1c869589879e099db7c7a94d 100644 (file)
@@ -99,7 +99,7 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
             GenericArgKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
-                let origin = infer::RelateParamBound(DUMMY_SP, t1);
+                let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
 
                 TypeOutlives::new(
                     &mut *self,
index 514c1aa9646a063c28e50ac54ca11a1a8d755d01..cee4c2e30aa0973c019918601828caeed5a8f025 100644 (file)
@@ -269,12 +269,34 @@ fn unsize_into_ptr(
                     Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
                 self.write_immediate(val, dest)
             }
-            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
-                // For now, upcasts are limited to changes in marker
-                // traits, and hence never actually require an actual
-                // change to the vtable.
+            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
                 let val = self.read_immediate(src)?;
-                self.write_immediate(*val, dest)
+                if data_a.principal_def_id() == data_b.principal_def_id() {
+                    return self.write_immediate(*val, dest);
+                }
+                // trait upcasting coercion
+                let principal_a = data_a.principal().expect(
+                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
+                );
+                let principal_b = data_b.principal().expect(
+                    "unsize_into_ptr: missing principal trait for trait upcasting coercion",
+                );
+
+                let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
+                    principal_a.with_self_ty(*self.tcx, src_pointee_ty),
+                    principal_b.with_self_ty(*self.tcx, src_pointee_ty),
+                ));
+
+                if let Some(entry_idx) = vptr_entry_idx {
+                    let entry_idx = u64::try_from(entry_idx).unwrap();
+                    let (old_data, old_vptr) = val.to_scalar_pair()?;
+                    let old_vptr = self.scalar_to_ptr(old_vptr);
+                    let new_vptr = self
+                        .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
+                    self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
+                } else {
+                    self.write_immediate(*val, dest)
+                }
             }
             (_, &ty::Dynamic(ref data, _)) => {
                 // Initial cast from sized to dyn trait
index 0396806f822fbd862bb676264303f204780f4aeb..4d13274a1200d2d8cfad0c0a6df51e6dcce3f2a4 100644 (file)
@@ -907,7 +907,7 @@ fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>(
 }
 
 /// Reading and writing.
-impl<'tcx, 'a, Tag: Copy, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
     pub fn write_scalar(
         &mut self,
         range: AllocRange,
@@ -928,7 +928,7 @@ pub fn write_ptr_sized(
     }
 }
 
-impl<'tcx, 'a, Tag: Copy, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
     pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         Ok(self
             .alloc
@@ -998,7 +998,11 @@ pub fn write_bytes(
 
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
         // (We are staying inside the bounds here so all is good.)
-        let bytes = alloc_ref.alloc.get_bytes_mut(&alloc_ref.tcx, alloc_ref.range);
+        let alloc_id = alloc_ref.alloc_id;
+        let bytes = alloc_ref
+            .alloc
+            .get_bytes_mut(&alloc_ref.tcx, alloc_ref.range)
+            .map_err(move |e| e.to_interp_error(alloc_id))?;
         // `zip` would stop when the first iterator ends; we want to definitely
         // cover all of `bytes`.
         for dest in bytes {
@@ -1072,7 +1076,10 @@ pub fn copy_repeatedly(
         let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?;
         let dest_range = alloc_range(dest_offset, size * num_copies);
         M::memory_written(extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
-        let dest_bytes = dest_alloc.get_bytes_mut_ptr(&tcx, dest_range).as_mut_ptr();
+        let dest_bytes = dest_alloc
+            .get_bytes_mut_ptr(&tcx, dest_range)
+            .map_err(|e| e.to_interp_error(dest_alloc_id))?
+            .as_mut_ptr();
 
         if compressed.no_bytes_init() {
             // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
index aba7db7816843001930e9a2f1cf58478617b1e3b..baef2a5a52c78fe73d8f3340d66edad6aafbacca 100644 (file)
@@ -63,15 +63,19 @@ pub fn new_slice(val: Scalar<Tag>, len: u64, cx: &impl HasDataLayout) -> Self {
         Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into())
     }
 
-    pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
-        Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_pointer(vtable, cx))
+    pub fn new_dyn_trait(
+        val: Scalar<Tag>,
+        vtable: Pointer<Option<Tag>>,
+        cx: &impl HasDataLayout,
+    ) -> Self {
+        Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx))
     }
 
     #[inline]
     pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
         match self {
             Immediate::Scalar(val) => val,
-            Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"),
+            Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
         }
     }
 
@@ -79,6 +83,16 @@ pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
     pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
         self.to_scalar_or_uninit().check_init()
     }
+
+    #[inline]
+    pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
+        match self {
+            Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)),
+            Immediate::Scalar(..) => {
+                bug!("Got a scalar where a scalar pair was expected")
+            }
+        }
+    }
 }
 
 // ScalarPair needs a type to interpret, so we often have an immediate and a type together
@@ -585,7 +599,7 @@ pub(super) fn eval_operands(
                 let ptr = self.global_base_pointer(Pointer::new(id, offset))?;
                 Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi))
             }
-            ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x.into())?.into()),
+            ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
             ConstValue::Slice { data, start, end } => {
                 // We rely on mutability being set correctly in `data` to prevent writes
                 // where none should happen.
index f369480d959fede95e17d9e7bc4c77271f8fb1a8..d87aa4a6267ecae614978192e9c770eb0b673650 100644 (file)
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
-        layout::fn_can_unwind(
-            self.tcx.sess.panic_strategy(),
-            attrs,
-            layout::conv_from_spec_abi(*self.tcx, abi),
-            abi,
-        )
+        layout::fn_can_unwind(*self.tcx, attrs, abi)
     }
 
     pub(super) fn eval_terminator(
@@ -73,11 +68,11 @@ pub(super) fn eval_terminator(
                     ty::FnPtr(sig) => {
                         let caller_abi = sig.abi();
                         let fn_ptr = self.read_pointer(&func)?;
-                        let fn_val = self.memory.get_fn(fn_ptr.into())?;
+                        let fn_val = self.memory.get_fn(fn_ptr)?;
                         (
                             fn_val,
                             caller_abi,
-                            self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+                            self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi),
                         )
                     }
                     ty::FnDef(def_id, substs) => {
index 7a93fcee78e3389a60ff1b8ee360215ab8a03052..a6ba00ec6952ece9e30b54fa295720de1669fa97 100644 (file)
@@ -21,7 +21,7 @@ pub fn get_vtable(
         &mut self,
         ty: Ty<'tcx>,
         poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
-    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
         trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
 
         let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
@@ -34,7 +34,7 @@ pub fn get_vtable(
 
         let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?;
 
-        Ok(vtable_ptr)
+        Ok(vtable_ptr.into())
     }
 
     /// Resolves the function at the specified slot in the provided
@@ -121,4 +121,22 @@ pub fn read_size_and_align_from_vtable(
         }
         Ok((Size::from_bytes(size), align))
     }
+
+    pub fn read_new_vtable_after_trait_upcasting_from_vtable(
+        &self,
+        vtable: Pointer<Option<M::PointerTag>>,
+        idx: u64,
+    ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+        let pointer_size = self.pointer_size();
+
+        let vtable_slot = vtable.offset(pointer_size * idx, self)?;
+        let new_vtable = self
+            .memory
+            .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
+            .expect("cannot be a ZST");
+
+        let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?);
+
+        Ok(new_vtable)
+    }
 }
index 796d024771d7f4bc0de6d7eb52f0bae03c800ac6..82c5e85dcecc08835cbbac27e1e3e8ad88eec6e1 100644 (file)
@@ -16,7 +16,7 @@
 use std::iter;
 
 use crate::transform::{
-    add_call_guards, add_moves_for_packed_drops, no_landing_pads, remove_noop_landing_pads,
+    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
     run_passes, simplify,
 };
 use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -81,10 +81,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         MirPhase::Const,
         &[&[
             &add_moves_for_packed_drops::AddMovesForPackedDrops,
-            &no_landing_pads::NoLandingPads,
             &remove_noop_landing_pads::RemoveNoopLandingPads,
             &simplify::SimplifyCfg::new("make_shim"),
             &add_call_guards::CriticalCallEdges,
+            &abort_unwinding_calls::AbortUnwindingCalls,
         ]],
     );
 
diff --git a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs b/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
new file mode 100644 (file)
index 0000000..aecb237
--- /dev/null
@@ -0,0 +1,141 @@
+use crate::transform::MirPass;
+use rustc_hir::def::DefKind;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::*;
+use rustc_middle::ty::layout;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_target::spec::abi::Abi;
+
+/// A pass that runs which is targeted at ensuring that codegen guarantees about
+/// unwinding are upheld for compilations of panic=abort programs.
+///
+/// When compiling with panic=abort codegen backends generally want to assume
+/// that all Rust-defined functions do not unwind, and it's UB if they actually
+/// do unwind. Foreign functions, however, can be declared as "may unwind" via
+/// their ABI (e.g. `extern "C-unwind"`). To uphold the guarantees that
+/// Rust-defined functions never unwind a well-behaved Rust program needs to
+/// catch unwinding from foreign functions and force them to abort.
+///
+/// This pass walks over all functions calls which may possibly unwind,
+/// and if any are found sets their cleanup to a block that aborts the process.
+/// This forces all unwinds, in panic=abort mode happening in foreign code, to
+/// trigger a process abort.
+#[derive(PartialEq)]
+pub struct AbortUnwindingCalls;
+
+impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let def_id = body.source.def_id();
+        let kind = tcx.def_kind(def_id);
+
+        // We don't simplify the MIR of constants at this time because that
+        // namely results in a cyclic query when we call `tcx.type_of` below.
+        let is_function = match kind {
+            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+            _ => tcx.is_closure(def_id),
+        };
+        if !is_function {
+            return;
+        }
+
+        // This pass only runs on functions which themselves cannot unwind,
+        // forcibly changing the body of the function to structurally provide
+        // this guarantee by aborting on an unwind. If this function can unwind,
+        // then there's nothing to do because it already should work correctly.
+        //
+        // Here we test for this function itself whether its ABI allows
+        // unwinding or not.
+        let body_flags = tcx.codegen_fn_attrs(def_id).flags;
+        let body_ty = tcx.type_of(def_id);
+        let body_abi = match body_ty.kind() {
+            ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
+            ty::Closure(..) => Abi::RustCall,
+            ty::Generator(..) => Abi::Rust,
+            _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
+        };
+        let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi);
+
+        // Look in this function body for any basic blocks which are terminated
+        // with a function call, and whose function we're calling may unwind.
+        // This will filter to functions with `extern "C-unwind"` ABIs, for
+        // example.
+        let mut calls_to_terminate = Vec::new();
+        let mut cleanups_to_remove = Vec::new();
+        for (id, block) in body.basic_blocks().iter_enumerated() {
+            if block.is_cleanup {
+                continue;
+            }
+            let terminator = match &block.terminator {
+                Some(terminator) => terminator,
+                None => continue,
+            };
+            let span = terminator.source_info.span;
+
+            let call_can_unwind = match &terminator.kind {
+                TerminatorKind::Call { func, .. } => {
+                    let ty = func.ty(body, tcx);
+                    let sig = ty.fn_sig(tcx);
+                    let flags = match ty.kind() {
+                        ty::FnPtr(_) => CodegenFnAttrFlags::empty(),
+                        ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags,
+                        _ => span_bug!(span, "invalid callee of type {:?}", ty),
+                    };
+                    layout::fn_can_unwind(tcx, flags, sig.abi())
+                }
+                TerminatorKind::Drop { .. }
+                | TerminatorKind::DropAndReplace { .. }
+                | TerminatorKind::Assert { .. }
+                | TerminatorKind::FalseUnwind { .. } => {
+                    layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+                }
+                _ => continue,
+            };
+
+            // If this function call can't unwind, then there's no need for it
+            // to have a landing pad. This means that we can remove any cleanup
+            // registered for it.
+            if !call_can_unwind {
+                cleanups_to_remove.push(id);
+                continue;
+            }
+
+            // Otherwise if this function can unwind, then if the outer function
+            // can also unwind there's nothing to do. If the outer function
+            // can't unwind, however, we need to change the landing pad for this
+            // function call to one that aborts.
+            if !body_can_unwind {
+                calls_to_terminate.push(id);
+            }
+        }
+
+        // For call instructions which need to be terminated, we insert a
+        // singular basic block which simply terminates, and then configure the
+        // `cleanup` attribute for all calls we found to this basic block we
+        // insert which means that any unwinding that happens in the functions
+        // will force an abort of the process.
+        if !calls_to_terminate.is_empty() {
+            let bb = BasicBlockData {
+                statements: Vec::new(),
+                is_cleanup: true,
+                terminator: Some(Terminator {
+                    source_info: SourceInfo::outermost(body.span),
+                    kind: TerminatorKind::Abort,
+                }),
+            };
+            let abort_bb = body.basic_blocks_mut().push(bb);
+
+            for bb in calls_to_terminate {
+                let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
+                *cleanup = Some(abort_bb);
+            }
+        }
+
+        for id in cleanups_to_remove {
+            let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
+            *cleanup = None;
+        }
+
+        // We may have invalidated some `cleanup` blocks so clean those up now.
+        super::simplify::remove_dead_blocks(tcx, body);
+    }
+}
index 3560b4b1e8645e77ed17488ac8ba954b9ea4c28c..ce4540b124fc1a7324de5eda00330e8b460d0713 100644 (file)
@@ -53,7 +53,6 @@
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
 use crate::dataflow::{self, Analysis};
-use crate::transform::no_landing_pads::no_landing_pads;
 use crate::transform::simplify;
 use crate::transform::MirPass;
 use crate::util::dump_mir;
@@ -960,8 +959,6 @@ fn create_generator_drop_shim<'tcx>(
         )
     }
 
-    no_landing_pads(tcx, &mut body);
-
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
     simplify::remove_dead_blocks(tcx, &mut body);
@@ -1133,8 +1130,6 @@ fn create_generator_resume_function<'tcx>(
     make_generator_state_argument_indirect(tcx, body);
     make_generator_state_argument_pinned(tcx, body);
 
-    no_landing_pads(tcx, body);
-
     // Make sure we remove dead blocks to remove
     // unrelated code from the drop part of the function
     simplify::remove_dead_blocks(tcx, body);
index e58a7d903082ee2ee45735811890dd5ab04c3434..fa648a6dd49ff5f2d2c22d33f9ed26b137a86d16 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
+pub mod abort_unwinding_calls;
 pub mod add_call_guards;
 pub mod add_moves_for_packed_drops;
 pub mod add_retag;
@@ -39,7 +40,6 @@
 pub mod lower_slice_len;
 pub mod match_branches;
 pub mod multiple_return_terminators;
-pub mod no_landing_pads;
 pub mod nrvo;
 pub mod promote_consts;
 pub mod remove_noop_landing_pads;
@@ -451,7 +451,6 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
 
     let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
         // Remove all things only needed by analysis
-        &no_landing_pads::NoLandingPads,
         &simplify_branches::SimplifyBranches::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &cleanup_post_borrowck::CleanupNonCodegenStatements,
@@ -459,7 +458,10 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
         // These next passes must be executed together
         &add_call_guards::CriticalCallEdges,
         &elaborate_drops::ElaborateDrops,
-        &no_landing_pads::NoLandingPads,
+        // This will remove extraneous landing pads which are no longer
+        // necessary as well as well as forcing any call in a non-unwinding
+        // function calling a possibly-unwinding function to abort the process.
+        &abort_unwinding_calls::AbortUnwindingCalls,
         // AddMovesForPackedDrops needs to run after drop
         // elaboration.
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
diff --git a/compiler/rustc_mir/src/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs
deleted file mode 100644 (file)
index 5479f0c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
-//! specified.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use rustc_target::spec::PanicStrategy;
-
-pub struct NoLandingPads;
-
-impl<'tcx> MirPass<'tcx> for NoLandingPads {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        no_landing_pads(tcx, body)
-    }
-}
-
-pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    if tcx.sess.panic_strategy() != PanicStrategy::Abort {
-        return;
-    }
-
-    for block in body.basic_blocks_mut() {
-        let terminator = block.terminator_mut();
-        if let Some(unwind) = terminator.kind.unwind_mut() {
-            unwind.take();
-        }
-    }
-}
index 1ddf7c9cd0c9e096c16b2fe73d9adb5d4aa762f3..948fcd9f4550f4e6ec0a7cbdbb606240978b494b 100644 (file)
@@ -211,7 +211,7 @@ fn find_branch_value_info<'tcx>(
                 return None;
             };
             let branch_value_scalar = branch_value.literal.try_to_scalar()?;
-            Some((branch_value_scalar.into(), branch_value_ty, *to_switch_on))
+            Some((branch_value_scalar, branch_value_ty, *to_switch_on))
         }
         _ => None,
     }
index 60cfd73b19a6e8b5b04c5e64574d197aedee7cf2..0d623806eb7e1bddc209fe31ca818729bd7d04be 100644 (file)
@@ -2,7 +2,6 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
 use crate::thir::pattern::pat_from_hir;
-use rustc_attr::{self as attr, UnwindAttr};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -19,7 +18,6 @@
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
-use rustc_target::spec::PanicStrategy;
 
 use super::lints;
 
@@ -581,60 +579,6 @@ macro_rules! unpack {
     }};
 }
 
-fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool {
-    // Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
-    let attrs = &tcx.get_attrs(fn_def_id.to_def_id());
-    let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs);
-
-    // We never unwind, so it's not relevant to stop an unwind.
-    if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
-        return false;
-    }
-
-    match unwind_attr {
-        // If an `#[unwind]` attribute was found, we should adhere to it.
-        Some(UnwindAttr::Allowed) => false,
-        Some(UnwindAttr::Aborts) => true,
-        // If no attribute was found and the panic strategy is `unwind`, then we should examine
-        // the function's ABI string to determine whether it should abort upon panic.
-        None if tcx.features().c_unwind => {
-            use Abi::*;
-            match abi {
-                // In the case of ABI's that have an `-unwind` equivalent, check whether the ABI
-                // permits unwinding. If so, we should not abort. Otherwise, we should.
-                C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
-                    !unwind
-                }
-                // Rust and `rust-call` functions are allowed to unwind, and should not abort.
-                Rust | RustCall => false,
-                // Other ABI's should abort.
-                Cdecl
-                | Fastcall
-                | Vectorcall
-                | Aapcs
-                | Win64
-                | SysV64
-                | PtxKernel
-                | Msp430Interrupt
-                | X86Interrupt
-                | AmdGpuKernel
-                | EfiApi
-                | AvrInterrupt
-                | AvrNonBlockingInterrupt
-                | CCmseNonSecureCall
-                | Wasm
-                | RustIntrinsic
-                | PlatformIntrinsic
-                | Unadjusted => true,
-            }
-        }
-        // If the `c_unwind` feature gate is not active, follow the behavior that was in place
-        // prior to #76570. This is a special case: some functions have a C ABI but are meant to
-        // unwind anyway. Don't stop them.
-        None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 /// the main entry point for building MIR for a function
 
@@ -704,8 +648,7 @@ fn construct_fn<'tcx, A>(
             }));
         let source_info = builder.source_info(fn_end);
         builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
-        let should_abort = should_abort_on_panic(tcx, fn_def.did, abi);
-        builder.build_drop_trees(should_abort);
+        builder.build_drop_trees();
         return_block.unit()
     }));
 
@@ -752,7 +695,7 @@ fn construct_const<'a, 'tcx>(
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
 
-    builder.build_drop_trees(false);
+    builder.build_drop_trees();
 
     builder.finish()
 }
index 3de894bd37056e2c1f87097dd88c037171852ae2..496db58758cdcc18b33c964a98a6e93846107a79 100644 (file)
@@ -1249,21 +1249,20 @@ fn build_exit_tree(
     }
 
     /// Build the unwind and generator drop trees.
-    crate fn build_drop_trees(&mut self, should_abort: bool) {
+    crate fn build_drop_trees(&mut self) {
         if self.generator_kind.is_some() {
-            self.build_generator_drop_trees(should_abort);
+            self.build_generator_drop_trees();
         } else {
             Self::build_unwind_tree(
                 &mut self.cfg,
                 &mut self.scopes.unwind_drops,
                 self.fn_span,
-                should_abort,
                 &mut None,
             );
         }
     }
 
-    fn build_generator_drop_trees(&mut self, should_abort: bool) {
+    fn build_generator_drop_trees(&mut self) {
         // Build the drop tree for dropping the generator while it's suspended.
         let drops = &mut self.scopes.generator_drops;
         let cfg = &mut self.cfg;
@@ -1281,7 +1280,7 @@ fn build_generator_drop_trees(&mut self, should_abort: bool) {
         // Build the drop tree for unwinding in the normal control flow paths.
         let resume_block = &mut None;
         let unwind_drops = &mut self.scopes.unwind_drops;
-        Self::build_unwind_tree(cfg, unwind_drops, fn_span, should_abort, resume_block);
+        Self::build_unwind_tree(cfg, unwind_drops, fn_span, resume_block);
 
         // Build the drop tree for unwinding when dropping a suspended
         // generator.
@@ -1296,26 +1295,20 @@ fn build_generator_drop_trees(&mut self, should_abort: bool) {
                 drops.entry_points.push((drop_data.1, blocks[drop_idx].unwrap()));
             }
         }
-        Self::build_unwind_tree(cfg, drops, fn_span, should_abort, resume_block);
+        Self::build_unwind_tree(cfg, drops, fn_span, resume_block);
     }
 
     fn build_unwind_tree(
         cfg: &mut CFG<'tcx>,
         drops: &mut DropTree,
         fn_span: Span,
-        should_abort: bool,
         resume_block: &mut Option<BasicBlock>,
     ) {
         let mut blocks = IndexVec::from_elem(None, &drops.drops);
         blocks[ROOT_NODE] = *resume_block;
         drops.build_mir::<Unwind>(cfg, &mut blocks);
         if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
-            // `TerminatorKind::Abort` is used for `#[unwind(aborts)]`
-            // functions.
-            let terminator =
-                if should_abort { TerminatorKind::Abort } else { TerminatorKind::Resume };
-
-            cfg.terminate(resume, SourceInfo::outermost(fn_span), terminator);
+            cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::Resume);
 
             *resume_block = blocks[ROOT_NODE];
         }
index 21534290d129193acd58c14935790cb5a16a7d6f..42e4fc3839e09c67f0b55501ef3d8951f9778f7e 100644 (file)
@@ -456,27 +456,25 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
                     return; // we have already visited everything by now
                 }
             }
-            ExprKind::Borrow { borrow_kind, arg } => match borrow_kind {
-                BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
-                    if !self.thir[arg]
-                        .ty
-                        .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env)
-                    {
-                        let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
-                        visit::walk_expr(&mut visitor, expr);
-                        if visitor.found {
-                            self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField);
+            ExprKind::Borrow { borrow_kind, arg } => {
+                let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
+                visit::walk_expr(&mut visitor, expr);
+                if visitor.found {
+                    match borrow_kind {
+                        BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
+                            if !self.thir[arg]
+                                .ty
+                                .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+                        {
+                            self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
                         }
+                        BorrowKind::Mut { .. } => {
+                            self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
+                        }
+                        BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {}
                     }
                 }
-                BorrowKind::Mut { .. } => {
-                    let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
-                    visit::walk_expr(&mut visitor, expr);
-                    if visitor.found {
-                        self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
-                    }
-                }
-            },
+            }
             _ => {}
         }
         visit::walk_expr(self, expr);
@@ -599,13 +597,10 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
 
     // Closures are handled by their owner, if it has a body
     if tcx.is_closure(def.did.to_def_id()) {
-        let owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
-        let owner_hir_id = tcx.hir().local_def_id_to_hir_id(owner);
-
-        if tcx.hir().maybe_body_owned_by(owner_hir_id).is_some() {
-            tcx.ensure().thir_check_unsafety(owner);
-            return;
-        }
+        let hir = tcx.hir();
+        let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
+        tcx.ensure().thir_check_unsafety(hir.local_def_id(owner));
+        return;
     }
 
     let (thir, expr) = tcx.thir_body(def);
index 1c5be61130b61a65b6af07c12f22a8a1dd8a9152..4e95cdc0efa5f30c83392dc47498ca379b5d6d4d 100644 (file)
@@ -153,16 +153,37 @@ pub(crate) fn emit_unescape_error(
         EscapeError::NonAsciiCharInByte => {
             assert!(mode.is_bytes());
             let (c, span) = last_char();
-            handler
-                .struct_span_err(span, "non-ASCII character in byte constant")
-                .span_label(span, "byte constant must be ASCII")
-                .span_suggestion(
+            let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
+            err.span_label(span, "byte constant must be ASCII");
+            if (c as u32) <= 0xFF {
+                err.span_suggestion(
                     span,
-                    "use a \\xHH escape for a non-ASCII byte",
+                    &format!(
+                        "if you meant to use the unicode code point for '{}', use a \\xHH escape",
+                        c
+                    ),
                     format!("\\x{:X}", c as u32),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+                    Applicability::MaybeIncorrect,
+                );
+            } else if matches!(mode, Mode::Byte) {
+                err.span_label(span, "this multibyte character does not fit into a single byte");
+            } else if matches!(mode, Mode::ByteStr) {
+                let mut utf8 = String::new();
+                utf8.push(c);
+                err.span_suggestion(
+                    span,
+                    &format!(
+                        "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
+                        c
+                    ),
+                    utf8.as_bytes()
+                        .iter()
+                        .map(|b: &u8| format!("\\x{:X}", *b))
+                        .fold("".to_string(), |a, c| a + &c),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            err.emit();
         }
         EscapeError::NonAsciiCharInByteString => {
             assert!(mode.is_bytes());
index b774c76103fbb7b029b59f58fcc12134ce1cf151..824f2316e5850714956d3092058e6e32d0f04320 100644 (file)
@@ -15,6 +15,8 @@
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
+use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1375,14 +1377,59 @@ fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    /// Parse `"('label ":")? break expr?`.
+    /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
+    /// If the label is followed immediately by a `:` token, the label and `:` are
+    /// parsed as part of the expression (i.e. a labeled loop). The language team has
+    /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
+    /// the break expression of an unlabeled break is a labeled loop (as in
+    /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
+    /// expression only gets a warning for compatibility reasons; and a labeled break
+    /// with a labeled loop does not even get a warning because there is no ambiguity.
     fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
-        let label = self.eat_label();
-        let kind = if self.token != token::OpenDelim(token::Brace)
+        let mut label = self.eat_label();
+        let kind = if label.is_some() && self.token == token::Colon {
+            // The value expression can be a labeled loop, see issue #86948, e.g.:
+            // `loop { break 'label: loop { break 'label 42; }; }`
+            let lexpr = self.parse_labeled_expr(label.take().unwrap(), AttrVec::new(), true)?;
+            self.struct_span_err(
+                lexpr.span,
+                "parentheses are required around this expression to avoid confusion with a labeled break expression",
+            )
+            .multipart_suggestion(
+                "wrap the expression in parentheses",
+                vec![
+                    (lexpr.span.shrink_to_lo(), "(".to_string()),
+                    (lexpr.span.shrink_to_hi(), ")".to_string()),
+                ],
+                Applicability::MachineApplicable,
+            )
+            .emit();
+            Some(lexpr)
+        } else if self.token != token::OpenDelim(token::Brace)
             || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
         {
-            self.parse_expr_opt()?
+            let expr = self.parse_expr_opt()?;
+            if let Some(ref expr) = expr {
+                if label.is_some()
+                    && matches!(
+                        expr.kind,
+                        ExprKind::While(_, _, None)
+                            | ExprKind::ForLoop(_, _, _, None)
+                            | ExprKind::Loop(_, None)
+                            | ExprKind::Block(_, None)
+                    )
+                {
+                    self.sess.buffer_lint_with_diagnostic(
+                        BREAK_WITH_LABEL_AND_LOOP,
+                        lo.to(expr.span),
+                        ast::CRATE_NODE_ID,
+                        "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
+                        BuiltinLintDiagnostics::BreakWithLabelAndLoop(expr.span),
+                    );
+                }
+            }
+            expr
         } else {
             None
         };
index f77f9bc454b84ad7cb53f6b9ea7fb4635cbb5dc9..9fcf2c4d5ec1efc12d2936b00de2541602f6e16f 100644 (file)
@@ -1714,13 +1714,11 @@ fn parse_fn_body(
                     // the AST for typechecking.
                     err.span_label(ident.span, "while parsing this `fn`");
                     err.emit();
-                    (Vec::new(), None)
                 } else {
                     return Err(err);
                 }
-            } else {
-                unreachable!()
             }
+            (Vec::new(), None)
         };
         attrs.extend(inner_attrs);
         Ok(body)
index b71ec700f81c80b77c38f38e7b9037d3838e8a6b..4e157b0a574fb52b83d9b0d1de0cb464fb40a4e7 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::privacy;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
-
 use rustc_span::symbol::{sym, Symbol};
 
 // Any local node that may call something in its body block should be
 // explored. For example, if it's a live Node::Item that is a
 // function, then we should explore its block to check for codes that
 // may need to be marked as live.
-fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
+fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     matches!(
-        tcx.hir().find(hir_id),
+        tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)),
         Some(
             Node::Item(..)
                 | Node::ImplItem(..)
@@ -31,23 +30,22 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
                 | Node::TraitItem(..)
                 | Node::Variant(..)
                 | Node::AnonConst(..)
-                | Node::Pat(..),
         )
     )
 }
 
 struct MarkSymbolVisitor<'tcx> {
-    worklist: Vec<hir::HirId>,
+    worklist: Vec<LocalDefId>,
     tcx: TyCtxt<'tcx>,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
-    live_symbols: FxHashSet<hir::HirId>,
+    live_symbols: FxHashSet<LocalDefId>,
     repr_has_repr_c: bool,
     in_pat: bool,
     inherited_pub_visibility: bool,
     pub_visibility: bool,
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
-    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+    struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
 }
 
 impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -62,19 +60,17 @@ fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
 
     fn check_def_id(&mut self, def_id: DefId) {
         if let Some(def_id) = def_id.as_local() {
-            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-            if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) {
-                self.worklist.push(hir_id);
+            if should_explore(self.tcx, def_id) || self.struct_constructors.contains_key(&def_id) {
+                self.worklist.push(def_id);
             }
-            self.live_symbols.insert(hir_id);
+            self.live_symbols.insert(def_id);
         }
     }
 
     fn insert_def_id(&mut self, def_id: DefId) {
         if let Some(def_id) = def_id.as_local() {
-            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-            debug_assert!(!should_explore(self.tcx, hir_id));
-            self.live_symbols.insert(hir_id);
+            debug_assert!(!should_explore(self.tcx, def_id));
+            self.live_symbols.insert(def_id);
         }
     }
 
@@ -233,9 +229,9 @@ fn mark_live_symbols(&mut self) {
 
             // in the case of tuple struct constructors we want to check the item, not the generated
             // tuple struct constructor function
-            let id = self.struct_constructors.get(&id).cloned().unwrap_or(id);
+            let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
 
-            if let Some(node) = self.tcx.hir().find(id) {
+            if let Some(node) = self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(id)) {
                 self.live_symbols.insert(id);
                 self.visit_node(node);
             }
@@ -326,7 +322,8 @@ fn visit_variant_data(
         let live_fields = def.fields().iter().filter(|f| {
             has_repr_c || (pub_visibility && (inherited_pub_visibility || f.vis.node.is_pub()))
         });
-        self.live_symbols.extend(live_fields.map(|f| f.hir_id));
+        let hir = self.tcx.hir();
+        self.live_symbols.extend(live_fields.map(|f| hir.local_def_id(f.hir_id)));
 
         intravisit::walk_struct_def(self, def);
     }
@@ -398,7 +395,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
     }
 
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-        self.live_symbols.insert(c.hir_id);
+        self.live_symbols.insert(self.tcx.hir().local_def_id(c.hir_id));
         intravisit::walk_anon_const(self, c);
     }
 }
@@ -445,47 +442,52 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 //   2) We are not sure to be live or not
 //     * Implementations of traits and trait methods
 struct LifeSeeder<'k, 'tcx> {
-    worklist: Vec<hir::HirId>,
+    worklist: Vec<LocalDefId>,
     krate: &'k hir::Crate<'k>,
     tcx: TyCtxt<'tcx>,
     // see `MarkSymbolVisitor::struct_constructors`
-    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+    struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
 }
 
 impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
         if allow_dead_code {
-            self.worklist.push(item.hir_id());
+            self.worklist.push(item.def_id);
         }
         match item.kind {
             hir::ItemKind::Enum(ref enum_def, _) => {
+                let hir = self.tcx.hir();
                 if allow_dead_code {
-                    self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id));
+                    self.worklist.extend(
+                        enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
+                    );
                 }
 
                 for variant in enum_def.variants {
                     if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-                        self.struct_constructors.insert(ctor_hir_id, variant.id);
+                        self.struct_constructors
+                            .insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
                     }
                 }
             }
             hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
                 if of_trait.is_some() {
-                    self.worklist.push(item.hir_id());
+                    self.worklist.push(item.def_id);
                 }
                 for impl_item_ref in items {
                     let impl_item = self.krate.impl_item(impl_item_ref.id);
                     if of_trait.is_some()
                         || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
                     {
-                        self.worklist.push(impl_item_ref.id.hir_id());
+                        self.worklist.push(impl_item_ref.id.def_id);
                     }
                 }
             }
             hir::ItemKind::Struct(ref variant_data, _) => {
                 if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
-                    self.struct_constructors.insert(ctor_hir_id, item.hir_id());
+                    self.struct_constructors
+                        .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
                 }
             }
             _ => (),
@@ -497,7 +499,7 @@ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
             && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
         {
-            self.worklist.push(trait_item.hir_id());
+            self.worklist.push(trait_item.def_id);
         }
     }
 
@@ -510,7 +512,7 @@ fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
         if matches!(foreign_item.kind, Static(..) | Fn(..))
             && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
         {
-            self.worklist.push(foreign_item.hir_id());
+            self.worklist.push(foreign_item.def_id);
         }
     }
 }
@@ -519,7 +521,7 @@ fn create_and_seed_worklist<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
     krate: &hir::Crate<'_>,
-) -> (Vec<hir::HirId>, FxHashMap<hir::HirId, hir::HirId>) {
+) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
     let worklist = access_levels
         .map
         .iter()
@@ -528,12 +530,8 @@ fn create_and_seed_worklist<'tcx>(
                 if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
             },
         )
-        .chain(
-            // Seed entry point
-            tcx.entry_fn(()).and_then(|(def_id, _)| {
-                def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
-            }),
-        )
+        // Seed entry point
+        .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
         .collect::<Vec<_>>();
 
     // Seed implemented trait items
@@ -548,7 +546,7 @@ fn find_live<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
     krate: &hir::Crate<'_>,
-) -> FxHashSet<hir::HirId> {
+) -> FxHashSet<LocalDefId> {
     let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
     let mut symbol_visitor = MarkSymbolVisitor {
         worklist,
@@ -568,7 +566,7 @@ fn find_live<'tcx>(
 
 struct DeadVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    live_symbols: FxHashSet<hir::HirId>,
+    live_symbols: FxHashSet<LocalDefId>,
 }
 
 impl DeadVisitor<'tcx> {
@@ -583,42 +581,41 @@ fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
                 | hir::ItemKind::Struct(..)
                 | hir::ItemKind::Union(..)
         );
-        should_warn && !self.symbol_is_live(item.hir_id())
+        should_warn && !self.symbol_is_live(item.def_id)
     }
 
     fn should_warn_about_field(&mut self, field: &hir::FieldDef<'_>) -> bool {
-        let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
+        let def_id = self.tcx.hir().local_def_id(field.hir_id);
+        let field_type = self.tcx.type_of(def_id);
         !field.is_positional()
-            && !self.symbol_is_live(field.hir_id)
+            && !self.symbol_is_live(def_id)
             && !field_type.is_phantom_data()
             && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id)
     }
 
     fn should_warn_about_variant(&mut self, variant: &hir::Variant<'_>) -> bool {
-        !self.symbol_is_live(variant.id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id)
+        let def_id = self.tcx.hir().local_def_id(variant.id);
+        !self.symbol_is_live(def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id)
     }
 
     fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem<'_>) -> bool {
-        !self.symbol_is_live(fi.hir_id())
-            && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id())
+        !self.symbol_is_live(fi.def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id())
     }
 
     // id := HIR id of an item's definition.
-    fn symbol_is_live(&mut self, id: hir::HirId) -> bool {
-        if self.live_symbols.contains(&id) {
+    fn symbol_is_live(&mut self, def_id: LocalDefId) -> bool {
+        if self.live_symbols.contains(&def_id) {
             return true;
         }
         // If it's a type whose items are live, then it's live, too.
         // This is done to handle the case where, for example, the static
         // method of a private type is used, but the type itself is never
         // called directly.
-        let def_id = self.tcx.hir().local_def_id(id);
         let inherent_impls = self.tcx.inherent_impls(def_id);
         for &impl_did in inherent_impls.iter() {
             for item_did in self.tcx.associated_item_def_ids(impl_did) {
-                if let Some(did) = item_did.as_local() {
-                    let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(did);
-                    if self.live_symbols.contains(&item_hir_id) {
+                if let Some(def_id) = item_did.as_local() {
+                    if self.live_symbols.contains(&def_id) {
                         return true;
                     }
                 }
@@ -721,7 +718,7 @@ fn visit_field_def(&mut self, field: &'tcx hir::FieldDef<'tcx>) {
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         match impl_item.kind {
             hir::ImplItemKind::Const(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id()) {
+                if !self.symbol_is_live(impl_item.def_id) {
                     self.warn_dead_code(
                         impl_item.hir_id(),
                         impl_item.span,
@@ -732,7 +729,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                 self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Fn(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id()) {
+                if !self.symbol_is_live(impl_item.def_id) {
                     // FIXME(66095): Because impl_item.span is annotated with things
                     // like expansion data, and ident.span isn't, we use the
                     // def_span method if it's part of a macro invocation
index 4ceefa17bcf3d01ca84a39feac2fe722d330fb9d..f2c2521ab43e4690e4366ed42f7834bb697b4968 100644 (file)
@@ -332,6 +332,11 @@ fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
             }
         }
 
+        // Don't run unused pass for #[naked]
+        if self.tcx.has_attr(def_id, sym::naked) {
+            return;
+        }
+
         if let Some(captures) = maps.tcx.typeck(local_def_id).closure_min_captures.get(&def_id) {
             for &var_hir_id in captures.keys() {
                 let var_name = maps.tcx.hir().name(var_hir_id);
index 89bc2e1a9870ff168e56e2b05038f54fde81e3e6..e05ec205b65b89ed78609cc4da9ae96b9cf7495d 100644 (file)
@@ -1,6 +1,6 @@
 //! Checks validity of naked functions.
 
-use rustc_ast::InlineAsmOptions;
+use rustc_ast::{Attribute, InlineAsmOptions};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
@@ -70,10 +70,20 @@ fn visit_fn(
             check_no_patterns(self.tcx, body.params);
             check_no_parameters_use(self.tcx, body);
             check_asm(self.tcx, hir_id, body, span);
+            check_inline(self.tcx, hir_id, attrs);
         }
     }
 }
 
+/// Check that the function isn't inlined.
+fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+    for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
+        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
+            lint.build("naked functions cannot be inlined").emit();
+        });
+    }
+}
+
 /// Checks that function uses non-Rust ABI.
 fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
     if abi == Abi::Rust {
index 0b3227abb5f8b4892d213f0b02ecf8b5d5624669..ad02f4f8269ad0f40c5d123c62bb8f4b806b4eb6 100644 (file)
@@ -351,7 +351,7 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
             item.kind
         {
-            if !self.access_levels.is_reachable(item.hir_id()) {
+            if !self.access_levels.is_reachable(item.def_id) {
                 // FIXME(#53488) remove `let`
                 let tcx = self.tcx;
                 self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
@@ -404,9 +404,7 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
     //         If other crates link to us, they're going to expect to be able to
     //         use the lang items, so we need to be sure to mark them as
     //         exported.
-    reachable_context
-        .worklist
-        .extend(access_levels.map.iter().map(|(id, _)| tcx.hir().local_def_id(*id)));
+    reachable_context.worklist.extend(access_levels.map.keys());
     for item in tcx.lang_items().items().iter() {
         if let Some(def_id) = *item {
             if let Some(def_id) = def_id.as_local() {
index 3db0409d8f009c959b9a7116f5be6ca87e974d5a..484040de0fb66b7bf4f2b86285db342ada7b299c 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::map::Map;
@@ -99,7 +99,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
     // If the node is a function, `fn_sig` is its signature
     fn annotate<F>(
         &mut self,
-        hir_id: HirId,
+        def_id: LocalDefId,
         item_sp: Span,
         fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
         kind: AnnotationKind,
@@ -110,11 +110,11 @@ fn annotate<F>(
     ) where
         F: FnOnce(&mut Self),
     {
-        let attrs = self.tcx.hir().attrs(hir_id);
-        debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+        let attrs = self.tcx.get_attrs(def_id.to_def_id());
+        debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
         let mut did_error = false;
         if !self.tcx.features().staged_api {
-            did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone());
+            did_error = self.forbid_staged_api_attrs(def_id, attrs, inherit_deprecation.clone());
         }
 
         let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) };
@@ -123,6 +123,7 @@ fn annotate<F>(
             is_deprecated = true;
 
             if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited {
+                let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                 self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| {
                     lint.build("this `#[deprecated]` annotation has no effect")
                         .span_suggestion_short(
@@ -136,13 +137,13 @@ fn annotate<F>(
             }
 
             // `Deprecation` is just two pointers, no need to intern it
-            let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
-            self.index.depr_map.insert(hir_id, depr_entry);
+            let depr_entry = DeprecationEntry::local(depr.clone(), def_id);
+            self.index.depr_map.insert(def_id, depr_entry);
         } else if let Some(parent_depr) = self.parent_depr.clone() {
             if inherit_deprecation.yes() {
                 is_deprecated = true;
-                info!("tagging child {:?} as deprecated from parent", hir_id);
-                self.index.depr_map.insert(hir_id, parent_depr);
+                info!("tagging child {:?} as deprecated from parent", def_id);
+                self.index.depr_map.insert(def_id, parent_depr);
             }
         }
 
@@ -157,7 +158,7 @@ fn annotate<F>(
             }
         } else {
             self.recurse_with_stability_attrs(
-                depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
+                depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
                 None,
                 None,
                 visit_children,
@@ -170,7 +171,7 @@ fn annotate<F>(
 
         let const_stab = const_stab.map(|(const_stab, const_span_node)| {
             let const_stab = self.tcx.intern_const_stability(const_stab);
-            self.index.const_stab_map.insert(hir_id, const_stab);
+            self.index.const_stab_map.insert(def_id, const_stab);
             const_span = Some(const_span_node);
             const_stab
         });
@@ -183,7 +184,7 @@ fn annotate<F>(
                 && !fn_sig.header.is_const()
             {
                 if !self.in_trait_impl
-                    || (self.in_trait_impl && !self.tcx.is_const_fn_raw(hir_id.owner.to_def_id()))
+                    || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
                 {
                     missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
                 }
@@ -196,7 +197,7 @@ fn annotate<F>(
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
                 if parent.level.is_unstable() {
-                    self.index.const_stab_map.insert(hir_id, parent);
+                    self.index.const_stab_map.insert(def_id, parent);
                 }
             }
         }
@@ -271,7 +272,7 @@ fn annotate<F>(
                 }
             }
 
-            self.index.stab_map.insert(hir_id, stab);
+            self.index.stab_map.insert(def_id, stab);
             stab
         });
 
@@ -281,13 +282,13 @@ fn annotate<F>(
                 if inherit_deprecation.yes() && stab.level.is_unstable()
                     || inherit_from_parent.yes()
                 {
-                    self.index.stab_map.insert(hir_id, stab);
+                    self.index.stab_map.insert(def_id, stab);
                 }
             }
         }
 
         self.recurse_with_stability_attrs(
-            depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
+            depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
             stab,
             if inherit_const_stability.yes() { const_stab } else { None },
             visit_children,
@@ -333,7 +334,7 @@ fn recurse_with_stability_attrs(
     // returns true if an error occurred, used to suppress some spurious errors
     fn forbid_staged_api_attrs(
         &mut self,
-        hir_id: HirId,
+        def_id: LocalDefId,
         attrs: &[Attribute],
         inherit_deprecation: InheritDeprecation,
     ) -> bool {
@@ -365,7 +366,7 @@ fn forbid_staged_api_attrs(
         // -Zforce-unstable-if-unmarked is set.
         if let Some(stab) = self.parent_stab {
             if inherit_deprecation.yes() && stab.level.is_unstable() {
-                self.index.stab_map.insert(hir_id, stab);
+                self.index.stab_map.insert(def_id, stab);
             }
         }
 
@@ -407,7 +408,7 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
             hir::ItemKind::Struct(ref sd, _) => {
                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
                     self.annotate(
-                        ctor_hir_id,
+                        self.tcx.hir().local_def_id(ctor_hir_id),
                         i.span,
                         None,
                         AnnotationKind::Required,
@@ -425,7 +426,7 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
         }
 
         self.annotate(
-            i.hir_id(),
+            i.def_id,
             i.span,
             fn_sig,
             kind,
@@ -444,7 +445,7 @@ fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
         };
 
         self.annotate(
-            ti.hir_id(),
+            ti.def_id,
             ti.span,
             fn_sig,
             AnnotationKind::Required,
@@ -467,7 +468,7 @@ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         };
 
         self.annotate(
-            ii.hir_id(),
+            ii.def_id,
             ii.span,
             fn_sig,
             kind,
@@ -482,7 +483,7 @@ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
         self.annotate(
-            var.id,
+            self.tcx.hir().local_def_id(var.id),
             var.span,
             None,
             AnnotationKind::Required,
@@ -492,7 +493,7 @@ fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, i
             |v| {
                 if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
                     v.annotate(
-                        ctor_hir_id,
+                        v.tcx.hir().local_def_id(ctor_hir_id),
                         var.span,
                         None,
                         AnnotationKind::Required,
@@ -510,7 +511,7 @@ fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, i
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
         self.annotate(
-            s.hir_id,
+            self.tcx.hir().local_def_id(s.hir_id),
             s.span,
             None,
             AnnotationKind::Required,
@@ -525,7 +526,7 @@ fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
         self.annotate(
-            i.hir_id(),
+            i.def_id,
             i.span,
             None,
             AnnotationKind::Required,
@@ -540,7 +541,7 @@ fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
         self.annotate(
-            md.hir_id(),
+            md.def_id,
             md.span,
             None,
             AnnotationKind::Required,
@@ -560,7 +561,7 @@ fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
         };
 
         self.annotate(
-            p.hir_id,
+            self.tcx.hir().local_def_id(p.hir_id),
             p.span,
             None,
             kind,
@@ -580,22 +581,19 @@ struct MissingStabilityAnnotations<'tcx> {
 }
 
 impl<'tcx> MissingStabilityAnnotations<'tcx> {
-    fn check_missing_stability(&self, hir_id: HirId, span: Span) {
-        let stab = self.tcx.stability().local_stability(hir_id);
-        let is_error =
-            !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(hir_id);
-        if is_error {
-            let def_id = self.tcx.hir().local_def_id(hir_id);
+    fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
+        let stab = self.tcx.stability().local_stability(def_id);
+        if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
             self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
         }
     }
 
-    fn check_missing_const_stability(&self, hir_id: HirId, span: Span) {
+    fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
         let stab_map = self.tcx.stability();
-        let stab = stab_map.local_stability(hir_id);
+        let stab = stab_map.local_stability(def_id);
         if stab.map_or(false, |stab| stab.level.is_stable()) {
-            let const_stab = stab_map.local_const_stability(hir_id);
+            let const_stab = stab_map.local_const_stability(def_id);
             if const_stab.is_none() {
                 self.tcx.sess.span_err(
                     span,
@@ -624,7 +622,7 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
                 | hir::ItemKind::ForeignMod { .. }
         ) {
-            self.check_missing_stability(i.hir_id(), i.span);
+            self.check_missing_stability(i.def_id, i.span);
         }
 
         // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
@@ -632,42 +630,42 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
         if self.tcx.features().staged_api
             && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
         {
-            self.check_missing_const_stability(i.hir_id(), i.span);
+            self.check_missing_const_stability(i.def_id, i.span);
         }
 
         intravisit::walk_item(self, i)
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        self.check_missing_stability(ti.hir_id(), ti.span);
+        self.check_missing_stability(ti.def_id, ti.span);
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id()));
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
-            self.check_missing_stability(ii.hir_id(), ii.span);
+            self.check_missing_stability(ii.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
-        self.check_missing_stability(var.id, var.span);
+        self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
         intravisit::walk_variant(self, var, g, item_id);
     }
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
-        self.check_missing_stability(s.hir_id, s.span);
+        self.check_missing_stability(self.tcx.hir().local_def_id(s.hir_id), s.span);
         intravisit::walk_field_def(self, s);
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        self.check_missing_stability(i.hir_id(), i.span);
+        self.check_missing_stability(i.def_id, i.span);
         intravisit::walk_foreign_item(self, i);
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
-        self.check_missing_stability(md.hir_id(), md.span);
+        self.check_missing_stability(md.def_id, md.span);
     }
 
     // Note that we don't need to `check_missing_stability` for default generic parameters,
@@ -731,7 +729,7 @@ fn stability_index(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> {
         }
 
         annotator.annotate(
-            hir::CRATE_HIR_ID,
+            CRATE_DEF_ID,
             krate.module().inner,
             None,
             AnnotationKind::Required,
@@ -929,7 +927,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     if tcx.stability().staged_api[&LOCAL_CRATE] {
         let krate = tcx.hir().krate();
         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
-        missing.check_missing_stability(hir::CRATE_HIR_ID, krate.module().inner);
+        missing.check_missing_stability(CRATE_DEF_ID, krate.module().inner);
         intravisit::walk_crate(&mut missing, krate);
         krate.visit_all_item_likes(&mut missing.as_deep_visitor());
     }
index cd91ecdf2bad3cbce953fb8b975b9283afff481b..1a0510d23cf1366c9e9273ecd492216f1645ec21 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
@@ -385,8 +385,7 @@ impl VisibilityLike for Option<AccessLevel> {
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
         cmp::min(
             if let Some(def_id) = def_id.as_local() {
-                let hir_id = find.tcx.hir().local_def_id_to_hir_id(def_id);
-                find.access_levels.map.get(&hir_id).cloned()
+                find.access_levels.map.get(&def_id).copied()
             } else {
                 Self::MAX
             },
@@ -416,7 +415,7 @@ struct EmbargoVisitor<'tcx> {
     /// pub macro m() {
     ///     n::p::f()
     /// }
-    macro_reachable: FxHashSet<(hir::HirId, DefId)>,
+    macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
     /// Previous accessibility level; `None` means unreachable.
     prev_level: Option<AccessLevel>,
     /// Has something changed in the level map?
@@ -430,16 +429,16 @@ struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
 }
 
 impl EmbargoVisitor<'tcx> {
-    fn get(&self, id: hir::HirId) -> Option<AccessLevel> {
-        self.access_levels.map.get(&id).cloned()
+    fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
+        self.access_levels.map.get(&def_id).copied()
     }
 
     /// Updates node level and returns the updated level.
-    fn update(&mut self, id: hir::HirId, level: Option<AccessLevel>) -> Option<AccessLevel> {
-        let old_level = self.get(id);
+    fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+        let old_level = self.get(def_id);
         // Accessibility levels can only grow.
         if level > old_level {
-            self.access_levels.map.insert(id, level.unwrap());
+            self.access_levels.map.insert(def_id, level.unwrap());
             self.changed = true;
             level
         } else {
@@ -461,31 +460,33 @@ fn reach(
 
     /// Updates the item as being reachable through a macro defined in the given
     /// module. Returns `true` if the level has changed.
-    fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool {
-        if self.macro_reachable.insert((reachable_mod, defining_mod)) {
-            self.update_macro_reachable_mod(reachable_mod, defining_mod);
+    fn update_macro_reachable(
+        &mut self,
+        module_def_id: LocalDefId,
+        defining_mod: LocalDefId,
+    ) -> bool {
+        if self.macro_reachable.insert((module_def_id, defining_mod)) {
+            self.update_macro_reachable_mod(module_def_id, defining_mod);
             true
         } else {
             false
         }
     }
 
-    fn update_macro_reachable_mod(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) {
-        let module_def_id = self.tcx.hir().local_def_id(reachable_mod);
+    fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.def_id);
             let vis = self.tcx.visibility(item_id.def_id);
-            self.update_macro_reachable_def(item_id.hir_id(), def_kind, vis, defining_mod);
+            self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_exports(module_def_id) {
             for export in exports {
-                if export.vis.is_accessible_from(defining_mod, self.tcx) {
+                if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
                         if let Some(def_id) = def_id.as_local() {
-                            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                             let vis = self.tcx.visibility(def_id.to_def_id());
-                            self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
+                            self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
                         }
                     }
                 }
@@ -495,14 +496,14 @@ fn update_macro_reachable_mod(&mut self, reachable_mod: hir::HirId, defining_mod
 
     fn update_macro_reachable_def(
         &mut self,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
         def_kind: DefKind,
         vis: ty::Visibility,
-        module: DefId,
+        module: LocalDefId,
     ) {
         let level = Some(AccessLevel::Reachable);
         if let ty::Visibility::Public = vis {
-            self.update(hir_id, level);
+            self.update(def_id, level);
         }
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
@@ -511,8 +512,8 @@ fn update_macro_reachable_def(
             | DefKind::Static
             | DefKind::TraitAlias
             | DefKind::TyAlias => {
-                if vis.is_accessible_from(module, self.tcx) {
-                    self.update(hir_id, level);
+                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                    self.update(def_id, level);
                 }
             }
 
@@ -521,23 +522,23 @@ fn update_macro_reachable_def(
             // hygiene these don't need to be marked reachable. The contents of
             // the module, however may be reachable.
             DefKind::Mod => {
-                if vis.is_accessible_from(module, self.tcx) {
-                    self.update_macro_reachable(hir_id, module);
+                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                    self.update_macro_reachable(def_id, module);
                 }
             }
 
             DefKind::Struct | DefKind::Union => {
-                // While structs and unions have type privacy, their fields do
-                // not.
+                // While structs and unions have type privacy, their fields do not.
                 if let ty::Visibility::Public = vis {
-                    let item = self.tcx.hir().expect_item(hir_id);
+                    let item =
+                        self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
                     if let hir::ItemKind::Struct(ref struct_def, _)
                     | hir::ItemKind::Union(ref struct_def, _) = item.kind
                     {
                         for field in struct_def.fields() {
                             let field_vis =
                                 self.tcx.visibility(self.tcx.hir().local_def_id(field.hir_id));
-                            if field_vis.is_accessible_from(module, self.tcx) {
+                            if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
                                 self.reach(field.hir_id, level).ty();
                             }
                         }
@@ -616,7 +617,7 @@ fn update_visibility_of_intermediate_use_statements(
                             continue;
                         }
                         if let hir::ItemKind::Use(..) = item.kind {
-                            self.update(item.hir_id(), Some(AccessLevel::Exported));
+                            self.update(item.def_id, Some(AccessLevel::Exported));
                         }
                     }
                 }
@@ -665,47 +666,48 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         };
 
         // Update level of the item itself.
-        let item_level = self.update(item.hir_id(), inherited_item_level);
+        let item_level = self.update(item.def_id, inherited_item_level);
 
         // Update levels of nested things.
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in def.variants {
-                    let variant_level = self.update(variant.id, item_level);
+                    let variant_level =
+                        self.update(self.tcx.hir().local_def_id(variant.id), item_level);
                     if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-                        self.update(ctor_hir_id, item_level);
+                        self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
                     }
                     for field in variant.data.fields() {
-                        self.update(field.hir_id, variant_level);
+                        self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
                     }
                 }
             }
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some() || impl_item_ref.vis.node.is_pub() {
-                        self.update(impl_item_ref.id.hir_id(), item_level);
+                        self.update(impl_item_ref.id.def_id, item_level);
                     }
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
-                    self.update(trait_item_ref.id.hir_id(), item_level);
+                    self.update(trait_item_ref.id.def_id, item_level);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
                 if let Some(ctor_hir_id) = def.ctor_hir_id() {
-                    self.update(ctor_hir_id, item_level);
+                    self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
                 }
                 for field in def.fields() {
                     if field.vis.node.is_pub() {
-                        self.update(field.hir_id, item_level);
+                        self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
                     }
                 }
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
                     if foreign_item.vis.node.is_pub() {
-                        self.update(foreign_item.id.hir_id(), item_level);
+                        self.update(foreign_item.id.def_id, item_level);
                     }
                 }
             }
@@ -789,7 +791,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     self.reach(item.hir_id(), item_level).generics().predicates().ty().trait_ref();
 
                     for impl_item_ref in impl_.items {
-                        let impl_item_level = self.get(impl_item_ref.id.hir_id());
+                        let impl_item_level = self.get(impl_item_ref.id.def_id);
                         if impl_item_level.is_some() {
                             self.reach(impl_item_ref.id.hir_id(), impl_item_level)
                                 .generics()
@@ -806,21 +808,21 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     self.reach(item.hir_id(), item_level).generics().predicates();
                 }
                 for variant in def.variants {
-                    let variant_level = self.get(variant.id);
+                    let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
                     if variant_level.is_some() {
                         for field in variant.data.fields() {
                             self.reach(field.hir_id, variant_level).ty();
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.update(item.hir_id(), variant_level);
+                        self.update(item.def_id, variant_level);
                     }
                 }
             }
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let foreign_item_level = self.get(foreign_item.id.hir_id());
+                    let foreign_item_level = self.get(foreign_item.id.def_id);
                     if foreign_item_level.is_some() {
                         self.reach(foreign_item.id.hir_id(), foreign_item_level)
                             .generics()
@@ -834,7 +836,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 if item_level.is_some() {
                     self.reach(item.hir_id(), item_level).generics().predicates();
                     for field in struct_def.fields() {
-                        let field_level = self.get(field.hir_id);
+                        let field_level = self.get(self.tcx.hir().local_def_id(field.hir_id));
                         if field_level.is_some() {
                             self.reach(field.hir_id, field_level).ty();
                         }
@@ -867,8 +869,7 @@ fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
                     if export.vis == ty::Visibility::Public {
                         if let Some(def_id) = export.res.opt_def_id() {
                             if let Some(def_id) = def_id.as_local() {
-                                let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                                self.update(hir_id, Some(AccessLevel::Exported));
+                                self.update(def_id, Some(AccessLevel::Exported));
                             }
                         }
                     }
@@ -888,32 +889,35 @@ fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
             // `#[macro_export]`-ed `macro_rules!` are `Public` since they
             // ignore their containing path to always appear at the crate root.
             if md.ast.macro_rules {
-                self.update(md.hir_id(), Some(AccessLevel::Public));
+                self.update(md.def_id, Some(AccessLevel::Public));
             }
             return;
         }
 
-        let macro_module_def_id = ty::DefIdTree::parent(self.tcx, md.def_id.to_def_id()).unwrap();
-        let hir_id = macro_module_def_id
-            .as_local()
-            .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
-        let mut module_id = match hir_id {
-            Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
-            // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
-            _ => return,
-        };
-        let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
-        let new_level = self.update(md.hir_id(), level);
+        let macro_module_def_id =
+            ty::DefIdTree::parent(self.tcx, md.def_id.to_def_id()).unwrap().expect_local();
+        if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
+            // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
+            return;
+        }
+
+        let level = if md.vis.node.is_pub() { self.get(macro_module_def_id) } else { None };
+        let new_level = self.update(md.def_id, level);
         if new_level.is_none() {
             return;
         }
 
+        // Since we are starting from an externally visible module,
+        // all the parents in the loop below are also guaranteed to be modules.
+        let mut module_def_id = macro_module_def_id;
         loop {
-            let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id);
-            if changed_reachability || module_id == hir::CRATE_HIR_ID {
+            let changed_reachability =
+                self.update_macro_reachable(module_def_id, macro_module_def_id);
+            if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
-            module_id = self.tcx.hir().get_parent_node(module_id);
+            module_def_id =
+                ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local();
         }
     }
 }
@@ -971,8 +975,7 @@ fn visit_def_id(
             if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
                 (self.tcx().visibility(def_id.to_def_id()), self.access_level)
             {
-                let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
-                self.ev.update(hir_id, self.access_level);
+                self.ev.update(def_id, self.access_level);
             }
         }
         ControlFlow::CONTINUE
@@ -1449,7 +1452,7 @@ fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
         }
     }
 
-    fn trait_is_public(&self, trait_id: hir::HirId) -> bool {
+    fn trait_is_public(&self, trait_id: LocalDefId) -> bool {
         // FIXME: this would preferably be using `exported_items`, but all
         // traits are exported currently (see `EmbargoVisitor.exported_trait`).
         self.access_levels.is_public(trait_id)
@@ -1463,8 +1466,8 @@ fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
         }
     }
 
-    fn item_is_public(&self, id: &hir::HirId, vis: &hir::Visibility<'_>) -> bool {
-        self.access_levels.is_reachable(*id) || vis.node.is_pub()
+    fn item_is_public(&self, def_id: LocalDefId, vis: &hir::Visibility<'_>) -> bool {
+        self.access_levels.is_reachable(def_id) || vis.node.is_pub()
     }
 }
 
@@ -1524,7 +1527,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::ForeignMod { .. } => {}
 
             hir::ItemKind::Trait(.., ref bounds, _) => {
-                if !self.trait_is_public(item.hir_id()) {
+                if !self.trait_is_public(item.def_id) {
                     return;
                 }
 
@@ -1564,10 +1567,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let not_private_trait = impl_.of_trait.as_ref().map_or(
                     true, // no trait counts as public trait
                     |tr| {
-                        let did = tr.path.res.def_id();
-
-                        if let Some(did) = did.as_local() {
-                            self.trait_is_public(self.tcx.hir().local_def_id_to_hir_id(did))
+                        if let Some(def_id) = tr.path.res.def_id().as_local() {
+                            self.trait_is_public(def_id)
                         } else {
                             true // external traits must be public
                         }
@@ -1587,7 +1588,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                         let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                         match impl_item.kind {
                             hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
-                                self.access_levels.is_reachable(impl_item_ref.id.hir_id())
+                                self.access_levels.is_reachable(impl_item_ref.id.def_id)
                             }
                             hir::ImplItemKind::TyAlias(_) => false,
                         }
@@ -1607,10 +1608,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                                 match impl_item.kind {
                                     hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
-                                        if self.item_is_public(
-                                            &impl_item.hir_id(),
-                                            &impl_item.vis,
-                                        ) =>
+                                        if self
+                                            .item_is_public(impl_item.def_id, &impl_item.vis) =>
                                     {
                                         intravisit::walk_impl_item(self, impl_item)
                                     }
@@ -1651,7 +1650,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
-                        if self.item_is_public(&impl_item_ref.id.hir_id(), &impl_item_ref.vis) {
+                        if self.item_is_public(impl_item_ref.id.def_id, &impl_item_ref.vis) {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
                                 AssocItemKind::Const => {
@@ -1678,7 +1677,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::TyAlias(..) => return,
 
             // Not at all public, so we don't care.
-            _ if !self.item_is_public(&item.hir_id(), &item.vis) => {
+            _ if !self.item_is_public(item.def_id, &item.vis) => {
                 return;
             }
 
@@ -1714,7 +1713,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        if self.access_levels.is_reachable(item.hir_id()) {
+        if self.access_levels.is_reachable(item.def_id) {
             intravisit::walk_foreign_item(self, item)
         }
     }
@@ -1734,7 +1733,7 @@ fn visit_variant(
         g: &'tcx hir::Generics<'tcx>,
         item_id: hir::HirId,
     ) {
-        if self.access_levels.is_reachable(v.id) {
+        if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
             self.in_variant = true;
             intravisit::walk_variant(self, v, g, item_id);
             self.in_variant = false;
@@ -2150,7 +2149,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
             break;
         }
     }
-    visitor.update(hir::CRATE_HIR_ID, Some(AccessLevel::Public));
+    visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
 
     tcx.arena.alloc(visitor.access_levels)
 }
index 0ad360c7d89c37bdccc8997d24460b49f51f00e3..ace7cffd16dafb3c22168a5fc8edcc89bc79e34e 100644 (file)
@@ -282,6 +282,16 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.def_id().krate == LOCAL_CRATE
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.def_span(self.0.def_id())
+    }
+}
+
 impl<'tcx> Key for GenericArg<'tcx> {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
index 34302c3fb429f214ed25390dedebaaf9cd0cf5ad..aea48bf3da8df7d8b08298bf52cca598abbcd91f 100644 (file)
@@ -255,16 +255,17 @@ fn process_method(
         &mut self,
         sig: &'tcx hir::FnSig<'tcx>,
         body: Option<hir::BodyId>,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
         ident: Ident,
         generics: &'tcx hir::Generics<'tcx>,
         vis: &hir::Visibility<'tcx>,
         span: Span,
     ) {
-        debug!("process_method: {}:{}", hir_id, ident);
+        debug!("process_method: {:?}:{}", def_id, ident);
 
         let map = &self.tcx.hir();
-        self.nest_typeck_results(map.local_def_id(hir_id), |v| {
+        let hir_id = map.local_def_id_to_hir_id(def_id);
+        self.nest_typeck_results(def_id, |v| {
             if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
                 if let Some(body) = body {
                     v.process_formals(map.body(body).params, &method_data.qualname);
@@ -275,7 +276,7 @@ fn process_method(
                     fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None);
                 method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
 
-                v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data);
+                v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, def_id), method_data);
             }
 
             // walk arg and return types
@@ -301,7 +302,10 @@ fn process_struct_field_def(
     ) {
         let field_data = self.save_ctxt.get_field_data(field, parent_id);
         if let Some(field_data) = field_data {
-            self.dumper.dump_def(&access_from!(self.save_ctxt, field, field.hir_id), field_data);
+            self.dumper.dump_def(
+                &access_from!(self.save_ctxt, field, self.tcx.hir().local_def_id(field.hir_id)),
+                field_data,
+            );
         }
     }
 
@@ -366,7 +370,7 @@ fn process_fn(
                 v.process_formals(body.params, &fn_data.qualname);
                 v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), fn_data);
             }
 
             for arg in decl.inputs {
@@ -390,7 +394,7 @@ fn process_static_or_const_item(
         self.nest_typeck_results(item.def_id, |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), var_data);
             }
             v.visit_ty(&typ);
             v.visit_expr(expr);
@@ -399,7 +403,7 @@ fn process_static_or_const_item(
 
     fn process_assoc_const(
         &mut self,
-        hir_id: hir::HirId,
+        def_id: LocalDefId,
         ident: Ident,
         typ: &'tcx hir::Ty<'tcx>,
         expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -407,15 +411,15 @@ fn process_assoc_const(
         vis: &hir::Visibility<'tcx>,
         attrs: &'tcx [ast::Attribute],
     ) {
-        let qualname =
-            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
+        let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
 
         if !self.span.filter_generated(ident.span) {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
             let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt);
             let span = self.span_from_span(ident.span);
 
             self.dumper.dump_def(
-                &access_from_vis!(self.save_ctxt, vis, hir_id),
+                &access_from_vis!(self.save_ctxt, vis, def_id),
                 Def {
                     kind: DefKind::Const,
                     id: id_from_hir_id(hir_id, &self.save_ctxt),
@@ -434,7 +438,7 @@ fn process_assoc_const(
         }
 
         // walk type and init value
-        self.nest_typeck_results(self.tcx.hir().local_def_id(hir_id), |v| {
+        self.nest_typeck_results(def_id, |v| {
             v.visit_ty(typ);
             if let Some(expr) = expr {
                 v.visit_expr(expr);
@@ -484,7 +488,7 @@ fn process_struct(
             let span = self.span_from_span(item.ident.span);
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.hir_id()),
+                &access_from!(self.save_ctxt, item, item.def_id),
                 Def {
                     kind,
                     id: id_from_def_id(item.def_id.to_def_id()),
@@ -525,7 +529,7 @@ fn process_enum(
         };
         down_cast_data!(enum_data, DefData, item.span);
 
-        let access = access_from!(self.save_ctxt, item, item.hir_id());
+        let access = access_from!(self.save_ctxt, item, item.def_id);
 
         for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
@@ -660,7 +664,7 @@ fn process_trait(
                 methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
             let attrs = self.tcx.hir().attrs(item.hir_id());
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.hir_id()),
+                &access_from!(self.save_ctxt, item, item.def_id),
                 Def {
                     kind: DefKind::Trait,
                     id,
@@ -723,7 +727,7 @@ fn process_trait(
     fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
             down_cast_data!(mod_data, DefData, item.span);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.hir_id()), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.def_id), mod_data);
         }
     }
 
@@ -985,7 +989,7 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                 let respan = respan(vis_span, hir::VisibilityKind::Public);
                 let attrs = self.tcx.hir().attrs(trait_item.hir_id());
                 self.process_assoc_const(
-                    trait_item.hir_id(),
+                    trait_item.def_id,
                     trait_item.ident,
                     &ty,
                     body,
@@ -1001,7 +1005,7 @@ fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_i
                 self.process_method(
                     sig,
                     body,
-                    trait_item.hir_id(),
+                    trait_item.def_id,
                     trait_item.ident,
                     &trait_item.generics,
                     &respan,
@@ -1058,7 +1062,7 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                 let body = self.tcx.hir().body(body);
                 let attrs = self.tcx.hir().attrs(impl_item.hir_id());
                 self.process_assoc_const(
-                    impl_item.hir_id(),
+                    impl_item.def_id,
                     impl_item.ident,
                     &ty,
                     Some(&body.value),
@@ -1071,7 +1075,7 @@ fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: D
                 self.process_method(
                     sig,
                     Some(body),
-                    impl_item.hir_id(),
+                    impl_item.def_id,
                     impl_item.ident,
                     &impl_item.generics,
                     &impl_item.vis,
@@ -1146,7 +1150,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Use(path, hir::UseKind::Single) => {
                 let sub_span = path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
-                    let access = access_from!(self.save_ctxt, item, item.hir_id());
+                    let access = access_from!(self.save_ctxt, item, item.def_id);
                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
                     let parent =
@@ -1175,7 +1179,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 // we don't want to track anyway, since it's probably macro-internal `use`
                 if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
                     if !self.span.filter_generated(item.span) {
-                        let access = access_from!(self.save_ctxt, item, item.hir_id());
+                        let access = access_from!(self.save_ctxt, item, item.def_id);
                         let span = self.span_from_span(sub_span);
                         let parent =
                             self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
@@ -1248,7 +1252,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item, item.hir_id()),
+                        &access_from!(self.save_ctxt, item, item.def_id),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1432,7 +1436,7 @@ fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        let access = access_from!(self.save_ctxt, item, item.hir_id());
+        let access = access_from!(self.save_ctxt, item, item.def_id);
 
         match item.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
index ec23a0769af778294d87a689b1cc3fdb0e2e8c1b..95a7b0994b8ade388b041d22c910f94d1265f10f 100644 (file)
@@ -1172,6 +1172,8 @@ mod parse {
         "compile without linking"),
     no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+    no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
+        "prevent automatic injection of the profiler_builtins crate"),
     normalize_docs: bool = (false, parse_bool, [TRACKED],
         "normalize associated items in rustdoc when generating documentation"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
@@ -1217,8 +1219,8 @@ mod parse {
     profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "file path to emit profiling data at runtime when using 'profile' \
         (default based on relative source path)"),
-    profiler_runtime: Option<String> = (Some(String::from("profiler_builtins")), parse_opt_string, [TRACKED],
-        "name of the profiler runtime crate to automatically inject, or None to disable"),
+    profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
+        "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing (default: no)"),
     query_stats: bool = (false, parse_bool, [UNTRACKED],
index 9ab6dbb1ea9065e709bfa228fbf62f4bebc25318..fe87867d2996cdf210798ee0624baf24b513c87c 100644 (file)
@@ -500,6 +500,10 @@ pub fn diagnostic(&self) -> &rustc_errors::Handler {
         &self.parse_sess.span_diagnostic
     }
 
+    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+        self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
+    }
+
     /// Analogous to calling methods on the given `DiagnosticBuilder`, but
     /// deduplicates on lint ID, span (if any), and message for this `Session`
     fn diag_once<'a, 'b>(
index 1ac489f600a4049c2bc5ac466177af5847d713fe..3f5d8273b38b8829bf5b216fc9ad2f1943465f88 100644 (file)
         expected,
         expf32,
         expf64,
+        explicit_generic_args_with_impl_trait,
         export_name,
         expr,
         extended_key_value_attributes,
@@ -1599,6 +1600,10 @@ pub fn as_u32(self) -> u32 {
         self.0.as_u32()
     }
 
+    pub fn len(self) -> usize {
+        with_interner(|interner| interner.get(self).len())
+    }
+
     pub fn is_empty(self) -> bool {
         self == kw::Empty
     }
index c134af44992de8e96a6655e633f26c9168f77235..3f713ce3c39145d238864de5bbf11601c37362d0 100644 (file)
@@ -1603,6 +1603,8 @@ fn maybe_report_ambiguity(
                     let generics = self.tcx.generics_of(*def_id);
                     if generics.params.iter().any(|p| p.name != kw::SelfUpper)
                         && !snippet.ends_with('>')
+                        && !generics.has_impl_trait()
+                        && !self.tcx.fn_trait_kind_from_lang_item(*def_id).is_some()
                     {
                         // FIXME: To avoid spurious suggestions in functions where type arguments
                         // where already supplied, we check the snippet to make sure it doesn't
index 693384602a75f7090aa2b245c57126c5d1b29df2..585fcf795b7f5fb2cd0cf22615edfbfcffc68183 100644 (file)
@@ -756,16 +756,17 @@ fn vtable_trait_first_method_offset<'tcx>(
 }
 
 /// Find slot offset for trait vptr within vtable entries of another trait
-/// FIXME: This function is not yet used. Remove `#[allow(dead_code)]` when it's used in upcoming pr.
-#[allow(dead_code)]
-fn vtable_trait_vptr_slot_offset<'tcx>(
+pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
     tcx: TyCtxt<'tcx>,
     key: (
-        ty::PolyTraitRef<'tcx>, // trait_to_be_found
-        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+        ty::PolyTraitRef<'tcx>, // trait owning vtable
+        ty::PolyTraitRef<'tcx>, // super trait ref
     ),
 ) -> Option<usize> {
-    let (trait_to_be_found, trait_owning_vtable) = key;
+    let (trait_owning_vtable, super_trait_ref) = key;
+    let super_trait_did = super_trait_ref.def_id();
+    // FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
+    // multiple times.
 
     let vtable_segment_callback = {
         let mut vptr_offset = 0;
@@ -776,7 +777,7 @@ fn vtable_trait_vptr_slot_offset<'tcx>(
                 }
                 VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                     vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
-                    if trait_ref == trait_to_be_found {
+                    if trait_ref.def_id() == super_trait_did {
                         if emit_vptr {
                             return ControlFlow::Break(Some(vptr_offset));
                         } else {
@@ -810,6 +811,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_entries,
+        vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
         mir_abstract_const: |tcx, def_id| {
             let def_id = def_id.expect_local();
index eb6265dec89c08bd4ba8147908db7fab87f4b349..fd0544a47bb7c3e6ed06a3bc34b600e9d9c4cd8b 100644 (file)
@@ -459,7 +459,32 @@ pub(crate) fn check_generic_arg_count(
 
         let default_counts = gen_params.own_defaults();
         let param_counts = gen_params.own_counts();
-        let named_type_param_count = param_counts.types - has_self as usize;
+
+        // Subtracting from param count to ensure type params synthesized from `impl Trait`
+        // cannot be explictly specified even with `explicit_generic_args_with_impl_trait`
+        // feature enabled.
+        let synth_type_param_count = if tcx.features().explicit_generic_args_with_impl_trait {
+            gen_params
+                .params
+                .iter()
+                .filter(|param| {
+                    matches!(
+                        param.kind,
+                        ty::GenericParamDefKind::Type {
+                            synthetic: Some(
+                                hir::SyntheticTyParamKind::ImplTrait
+                                    | hir::SyntheticTyParamKind::FromAttr
+                            ),
+                            ..
+                        }
+                    )
+                })
+                .count()
+        } else {
+            0
+        };
+        let named_type_param_count =
+            param_counts.types - has_self as usize - synth_type_param_count;
         let infer_lifetimes =
             gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params();
 
@@ -617,20 +642,13 @@ pub(crate) fn check_impl_trait(
         seg: &hir::PathSegment<'_>,
         generics: &ty::Generics,
     ) -> bool {
-        let explicit = !seg.infer_args;
-        let impl_trait = generics.params.iter().any(|param| {
-            matches!(
-                param.kind,
-                ty::GenericParamDefKind::Type {
-                    synthetic: Some(
-                        hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
-                    ),
-                    ..
-                }
-            )
-        });
+        if seg.infer_args || tcx.features().explicit_generic_args_with_impl_trait {
+            return false;
+        }
+
+        let impl_trait = generics.has_impl_trait();
 
-        if explicit && impl_trait {
+        if impl_trait {
             let spans = seg
                 .args()
                 .args
index d056f2c90f988270b4d0a4556d76ebb62a87de85..dee81510b795b8942f368ed91c77f91044e23650 100644 (file)
     StatementAsExpression,
 };
 
-macro_rules! create_maybe_get_coercion_reason {
-    ($fn_name:ident, $node:expr) => {
-        pub(crate) fn $fn_name(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
-            let node = $node(self.tcx.hir(), hir_id);
-            if let hir::Node::Block(block) = node {
-                // check that the body's parent is an fn
-                let parent = self.tcx.hir().get(
-                    self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)),
-                );
-                if let (
-                    Some(expr),
-                    hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }),
-                ) = (&block.expr, parent)
-                {
-                    // check that the `if` expr without `else` is the fn body's expr
-                    if expr.span == sp {
-                        return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
-                            let span = fn_decl.output.span();
-                            let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
-                            Some((
-                                span,
-                                format!("expected `{}` because of this return type", snippet),
-                            ))
-                        });
-                    }
-                }
-            }
-            if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
-                return Some((pat.span, "expected because of this assignment".to_string()));
-            }
-            None
-        }
-    };
-}
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_match(
         &self,
@@ -154,7 +119,7 @@ pub fn check_match(
                     expr.span,
                     &arms[0].body,
                     &mut coercion,
-                    |hir_id, span| self.maybe_get_coercion_reason(hir_id, span),
+                    |hir_id, span| self.coercion_reason_match(hir_id, span),
                 ) {
                 tcx.ty_error()
             } else {
@@ -373,23 +338,56 @@ pub(crate) fn if_fallback_coercion<F, T>(
         error
     }
 
-    create_maybe_get_coercion_reason!(
-        maybe_get_coercion_reason,
-        |hir: rustc_middle::hir::map::Map<'a>, id| {
-            let arm_id = hir.get_parent_node(id);
-            let match_id = hir.get_parent_node(arm_id);
-            let containing_id = hir.get_parent_node(match_id);
-            hir.get(containing_id)
-        }
-    );
+    pub(crate) fn coercion_reason_if(
+        &self,
+        hir_id: hir::HirId,
+        span: Span,
+    ) -> Option<(Span, String)> {
+        self.coercion_reason_inner(hir_id, span, 1)
+    }
 
-    create_maybe_get_coercion_reason!(
-        maybe_get_coercion_reason_if,
-        |hir: rustc_middle::hir::map::Map<'a>, id| {
-            let rslt = hir.get_parent_node(hir.get_parent_node(id));
-            hir.get(rslt)
+    pub(crate) fn coercion_reason_match(
+        &self,
+        hir_id: hir::HirId,
+        span: Span,
+    ) -> Option<(Span, String)> {
+        self.coercion_reason_inner(hir_id, span, 2)
+    }
+
+    fn coercion_reason_inner(
+        &self,
+        hir_id: hir::HirId,
+        span: Span,
+        parent_index: usize,
+    ) -> Option<(Span, String)> {
+        let hir = self.tcx.hir();
+        let mut parent_iter = hir.parent_iter(hir_id);
+        let (_, node) = parent_iter.nth(parent_index)?;
+        match node {
+            hir::Node::Block(block) => {
+                let expr = block.expr?;
+                // check that the body's parent is an fn
+                let (_, parent) = parent_iter.nth(1)?;
+                if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) = parent {
+                    // check that the `if` expr without `else` is the fn body's expr
+                    if expr.span == span {
+                        let (fn_decl, _) = self.get_fn_decl(hir_id)?;
+                        let span = fn_decl.output.span();
+                        let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
+                        return Some((
+                            span,
+                            format!("expected `{}` because of this return type", snippet),
+                        ));
+                    }
+                }
+                None
+            }
+            hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) => {
+                Some((pat.span, "expected because of this assignment".to_string()))
+            }
+            _ => None,
         }
-    );
+    }
 
     pub(crate) fn if_cause(
         &self,
index b5db3331d044781bca42a36d6956cd2d9ed2d39e..ba99e0c03d8e2d4895b2de7787f94892337cfd8a 100644 (file)
@@ -1220,6 +1220,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             match e.kind() {
                 ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
                 ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+                ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
                 ty::Array(t, _clen)
                     if matches!(
                         t.kind(),
index 08258aac96f2f39032daeba61048d690a11e7005..e95884ae23b9397343ffb21ba2b067c67cd448b3 100644 (file)
@@ -838,7 +838,7 @@ fn check_then_else(
             self.diverges.set(cond_diverges | then_diverges & else_diverges);
         } else {
             self.if_fallback_coercion(sp, then_expr, &mut coerce, |hir_id, span| {
-                self.maybe_get_coercion_reason_if(hir_id, span)
+                self.coercion_reason_if(hir_id, span)
             });
 
             // If the condition is false we can't diverge.
index 981a040e66072991b67be655ec52e41b9d2ca113..db77d155a2bae1bebf17736745f2b8ea6cb155ee 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::Ident;
 use rustc_span::{BytePos, DUMMY_SP};
+use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 use ty::VariantDef;
 
@@ -1769,7 +1770,7 @@ fn check_pat_slice(
             // The expected type must be an array or slice, but was neither, so error.
             _ => {
                 if !expected.references_error() {
-                    self.error_expected_array_or_slice(span, expected);
+                    self.error_expected_array_or_slice(span, expected, ti);
                 }
                 let err = self.tcx.ty_error();
                 (err, Some(err), err)
@@ -1882,7 +1883,7 @@ fn error_scrutinee_unfixed_length(&self, span: Span) {
         .emit();
     }
 
-    fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>) {
+    fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
         let mut err = struct_span_err!(
             self.tcx.sess,
             span,
@@ -1894,6 +1895,19 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>) {
             if let ty::Array(..) | ty::Slice(..) = ty.kind() {
                 err.help("the semantics of slice patterns changed recently; see issue #62254");
             }
+        } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
+            .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..)))
+        {
+            if let (Some(span), true) = (ti.span, ti.origin_expr) {
+                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                    err.span_suggestion(
+                        span,
+                        "consider slicing here",
+                        format!("{}[..]", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
         }
         err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
         err.emit();
index ce74d6fec9eae95deadc97795c8f2773e19bc4cf..06cb33b9ebf4b3d7079a5a49e949b43710c7a3ee 100644 (file)
@@ -2776,8 +2776,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
         } else if tcx.sess.check_name(attr, sym::rustc_allocator) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
-        } else if tcx.sess.check_name(attr, sym::unwind) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
         } else if tcx.sess.check_name(attr, sym::ffi_returns_twice) {
             if tcx.is_foreign_item(id) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
@@ -2829,7 +2827,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 .emit();
             }
         } else if tcx.sess.check_name(attr, sym::rustc_allocator_nounwind) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
         } else if tcx.sess.check_name(attr, sym::naked) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
         } else if tcx.sess.check_name(attr, sym::no_mangle) {
@@ -3200,6 +3198,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
     }
 
+    // Any linkage to LLVM intrinsics for now forcibly marks them all as never
+    // unwinds since LLVM sometimes can't handle codegen which `invoke`s
+    // intrinsic functions.
+    if let Some(name) = &codegen_fn_attrs.link_name {
+        if name.as_str().starts_with("llvm.") {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+        }
+    }
+
     codegen_fn_attrs
 }
 
index 4ea7dfc0735546d1260baab8de9cdc3ea0184020..be12f90464084306b2b1b8beaba0984936b16320 100644 (file)
@@ -77,7 +77,6 @@ fn $method(&mut self, other: &$u) {
 }
 
 /// Create a zero-size type similar to a closure type, but named.
-#[unstable(feature = "std_internals", issue = "none")]
 macro_rules! impl_fn_for_zst {
     ($(
         $( #[$attr: meta] )*
index 25970722c2dadc8766086f567ad5c41b1ee0133d..222ef34b6aa8a82eb77cb4e01071193aad440adf 100644 (file)
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
 #![no_core]
+//
+// Lints:
+#![deny(rust_2021_incompatible_or_patterns)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![warn(deprecated_in_future)]
-#![warn(missing_docs)]
 #![warn(missing_debug_implementations)]
+#![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
-#![feature(rustc_allow_const_fn_unstable)]
-#![feature(allow_internal_unstable)]
-#![feature(arbitrary_self_types)]
-#![feature(asm)]
-#![feature(bool_to_option)]
-#![feature(cfg_target_has_atomic)]
-#![feature(const_heap)]
+//
+// Library features for const fns:
+#![feature(const_align_of_val)]
 #![feature(const_alloc_layout)]
 #![feature(const_arguments_as_str)]
 #![feature(const_assert_type)]
-#![feature(const_discriminant)]
+#![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
-#![feature(const_intrinsic_copy)]
-#![feature(const_intrinsic_forget)]
-#![feature(const_float_classify)]
+#![feature(const_discriminant)]
 #![feature(const_float_bits_conv)]
-#![feature(const_int_unchecked_arith)]
+#![feature(const_float_classify)]
+#![feature(const_heap)]
 #![feature(const_inherent_unchecked_arith)]
-#![feature(const_mut_refs)]
-#![feature(const_refs_to_cell)]
-#![feature(const_panic)]
-#![feature(const_pin)]
-#![cfg_attr(bootstrap, feature(const_fn_union))]
-#![feature(const_impl_trait)]
-#![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![feature(const_int_unchecked_arith)]
+#![feature(const_intrinsic_copy)]
+#![feature(const_intrinsic_forget)]
+#![feature(const_likely)]
+#![feature(const_maybe_uninit_as_ptr)]
+#![feature(const_maybe_uninit_assume_init)]
 #![feature(const_option)]
-#![feature(const_precise_live_drops)]
+#![feature(const_pin)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_raw_ptr_comparison)]
-#![feature(const_raw_ptr_deref)]
+#![feature(const_size_of_val)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
-#![feature(const_size_of_val)]
 #![feature(const_swap)]
-#![feature(const_align_of_val)]
 #![feature(const_type_id)]
 #![feature(const_type_name)]
-#![feature(const_likely)]
 #![feature(const_unreachable_unchecked)]
-#![feature(const_maybe_uninit_assume_init)]
-#![feature(const_maybe_uninit_as_ptr)]
-#![feature(custom_inner_attributes)]
+#![feature(duration_consts_2)]
+#![feature(ptr_metadata)]
+#![feature(slice_ptr_get)]
+#![feature(variant_count)]
+//
+// Language features:
+#![feature(abi_unadjusted)]
+#![feature(allow_internal_unstable)]
+#![feature(asm)]
+#![feature(associated_type_bounds)]
+#![feature(auto_traits)]
+#![feature(cfg_target_has_atomic)]
+#![feature(const_fn_floating_point_arithmetic)]
+#![feature(const_fn_fn_ptr_basics)]
+#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_transmute))]
+#![cfg_attr(bootstrap, feature(const_fn_union))]
+#![feature(const_impl_trait)]
+#![feature(const_mut_refs)]
+#![feature(const_panic)]
+#![feature(const_precise_live_drops)]
+#![feature(const_raw_ptr_deref)]
+#![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
-#![feature(duration_consts_2)]
+#![feature(exhaustive_patterns)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
 #![feature(llvm_asm)]
+#![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(nll)]
-#![feature(exhaustive_patterns)]
 #![feature(no_core)]
-#![feature(auto_traits)]
-#![feature(pin_deref_mut)]
+#![feature(no_coverage)] // rust-lang/rust#84605
+#![feature(no_niche)] // rust-lang/rust#68303
+#![feature(platform_intrinsics)]
 #![feature(prelude_import)]
-#![feature(ptr_metadata)]
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd)]
+#![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
 #![feature(simd_ffi)]
-#![feature(min_specialization)]
 #![feature(staged_api)]
-#![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
-#![feature(str_split_as_str)]
-#![feature(str_split_inclusive_as_str)]
-#![feature(char_indices_offset)]
 #![feature(trait_alias)]
 #![feature(transparent_unions)]
 #![feature(try_blocks)]
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
-#![feature(unwind_attributes)]
-#![feature(variant_count)]
-#![feature(tbm_target_feature)]
-#![feature(sse4a_target_feature)]
-#![feature(arm_target_feature)]
-#![feature(powerpc_target_feature)]
-#![feature(mips_target_feature)]
+//
+// Target features:
 #![feature(aarch64_target_feature)]
-#![feature(wasm_target_feature)]
+#![feature(adx_target_feature)]
+#![feature(arm_target_feature)]
 #![feature(avx512_target_feature)]
 #![feature(cmpxchg16b_target_feature)]
-#![feature(rtm_target_feature)]
 #![feature(f16c_target_feature)]
 #![feature(hexagon_target_feature)]
-#![cfg_attr(bootstrap, feature(const_fn_transmute))]
-#![feature(abi_unadjusted)]
-#![feature(adx_target_feature)]
-#![feature(associated_type_bounds)]
-#![feature(const_caller_location)]
-#![feature(slice_ptr_get)]
-#![feature(no_niche)] // rust-lang/rust#68303
-#![feature(no_coverage)] // rust-lang/rust#84605
-#![deny(unsafe_op_in_unsafe_fn)]
-#![deny(rust_2021_incompatible_or_patterns)]
+#![feature(mips_target_feature)]
+#![feature(powerpc_target_feature)]
+#![feature(rtm_target_feature)]
+#![feature(sse4a_target_feature)]
+#![feature(tbm_target_feature)]
+#![feature(wasm_target_feature)]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
index 6e8f753ce500a32f805fae177887c72b729bdde3..0bc646995c7c7a13b1d3f91320e25f68e7aa114d 100644 (file)
@@ -1132,9 +1132,9 @@ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
         #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
-        #[inline]
+        #[inline(always)]
         pub const fn wrapping_neg(self) -> Self {
-            self.overflowing_neg().0
+            (0 as $SelfT).wrapping_sub(self)
         }
 
         /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
index 6c43d6d62128e71be7944f8ce9e35850920b6038..9788404dd05bf58f6c18ba5ac18e8d2735595595 100644 (file)
@@ -847,7 +847,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     use self::ParseIntError as PIE;
 
     assert!(
-        radix >= 2 && radix <= 36,
+        (2..=36).contains(&radix),
         "from_str_radix_int: must lie in the range `[2, 36]` - found {}",
         radix
     );
index 91f07c63aa945c28e690a5905f87609d6bad7d4e..ae113a47e95d61a0b7712471012694045fb6207f 100644 (file)
@@ -1246,9 +1246,9 @@ pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self {
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
         #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
-        #[inline]
+        #[inline(always)]
         pub const fn wrapping_neg(self) -> Self {
-            self.overflowing_neg().0
+            (0 as $SelfT).wrapping_sub(self)
         }
 
         /// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
index 8057ff0759107a14d339a028972c4077017b7858..d4e9c384f93021ced4d79096bf4f709a1dd45135 100644 (file)
 //! assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]);
 //! ```
 //!
+//! ## Comparison operators
+//!
+//! If `T` implements [`PartialOrd`] then [`Option<T>`] will derive its
+//! [`PartialOrd`] implementation.  With this order, [`None`] compares as
+//! less than any [`Some`], and two [`Some`] compare the same way as their
+//! contained values would in `T`.  If `T` also implements
+//! [`Ord`], then so does [`Option<T>`].
+//!
+//! ```
+//! assert!(None < Some(0));
+//! assert!(Some(0) < Some(1));
+//! ```
+//!
 //! ## Iterating over `Option`
 //!
 //! An [`Option`] can be iterated over. This can be helpful if you need an
index 32b6920b59d2285f01c854ff404de343d2f2f06e..98a4cb59a66291b1043b02c813a5c9f511cb3afa 100644 (file)
@@ -596,6 +596,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     /// enables more aggressive compiler optimizations.
     ///
     /// [`wrapping_add`]: #method.wrapping_add
+    /// [allocated object]: crate::ptr#allocated-object
     ///
     /// # Examples
     ///
index 53aaa5219b1d4c0b3b8c6f219f85723dcccc35b5..861790e8a4099cd03c2f325c6745373c1f2e9628 100644 (file)
 //! [`and_then`]: Result::and_then
 //! [`or_else`]: Result::or_else
 //!
+//! ## Comparison operators
+//!
+//! If `T` and `E` both implement [`PartialOrd`] then [`Result<T, E>`] will
+//! derive its [`PartialOrd`] implementation.  With this order, an [`Ok`]
+//! compares as less than any [`Err`], while two [`Ok`] or two [`Err`]
+//! compare as their contained values would in `T` or `E` respectively.  If `T`
+//! and `E` both also implement [`Ord`], then so does [`Result<T, E>`].
+//!
+//! ```
+//! assert!(Ok(1) < Err(0));
+//! let x: Result<i32, ()> = Ok(0);
+//! let y = Ok(1);
+//! assert!(x < y);
+//! let x: Result<(), i32> = Err(0);
+//! let y = Err(1);
+//! assert!(x < y);
+//! ```
+//!
 //! ## Iterating over `Result`
 //!
 //! A [`Result`] can be iterated over. This can be helpful if you need an
index 791a88dd97f288b7f74304a9244792f04466bc46..cf15756868e655fb021d012a9e75df7ab4e63ddc 100644 (file)
@@ -185,8 +185,9 @@ fn nth(&mut self, n: usize) -> Option<$elem> {
                 }
             }
 
+            #[inline]
             fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-                let advance = cmp::min(n, len!(self));
+                let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.post_inc_start(advance as isize) };
                 if advance == n { Ok(()) } else { Err(advance) }
@@ -381,7 +382,7 @@ fn nth_back(&mut self, n: usize) -> Option<$elem> {
 
             #[inline]
             fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-                let advance = cmp::min(n, len!(self));
+                let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.pre_dec_end(advance as isize) };
                 if advance == n { Ok(()) } else { Err(advance) }
diff --git a/library/core/src/stream/from_iter.rs b/library/core/src/stream/from_iter.rs
new file mode 100644 (file)
index 0000000..eb9a0fd
--- /dev/null
@@ -0,0 +1,38 @@
+use crate::pin::Pin;
+
+use crate::stream::Stream;
+use crate::task::{Context, Poll};
+
+/// A stream that was created from iterator.
+///
+/// This stream is created by the [`from_iter`] function.
+/// See it documentation for more.
+///
+/// [`from_iter`]: fn.from_iter.html
+#[unstable(feature = "stream_from_iter", issue = "81798")]
+#[derive(Clone, Debug)]
+pub struct FromIter<I> {
+    iter: I,
+}
+
+#[unstable(feature = "stream_from_iter", issue = "81798")]
+impl<I> Unpin for FromIter<I> {}
+
+/// Converts an iterator into a stream.
+#[unstable(feature = "stream_from_iter", issue = "81798")]
+pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> {
+    FromIter { iter: iter.into_iter() }
+}
+
+#[unstable(feature = "stream_from_iter", issue = "81798")]
+impl<I: Iterator> Stream for FromIter<I> {
+    type Item = I::Item;
+
+    fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        Poll::Ready(self.iter.next())
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
index 0df18af65ebf04cc740f77931871df0bd5dfc637..58dc8e1e5e6067b701ed1d0147adda3456f90f03 100644 (file)
 //! warning: unused result that must be used: streams do nothing unless polled
 //! ```
 
+mod from_iter;
 mod stream;
 
+pub use from_iter::{from_iter, FromIter};
 pub use stream::Stream;
index 3622bc8294b0829bc10790e11e102987d5246bcb..14b454da4f46f58675e6069509107218cf9fad79 100644 (file)
 #![feature(panic_unwind)]
 #![feature(staged_api)]
 #![feature(std_internals)]
-#![feature(unwind_attributes)]
 #![feature(abi_thiscall)]
 #![feature(rustc_attrs)]
 #![panic_runtime]
 #![feature(panic_runtime)]
+#![feature(c_unwind)]
 // `real_imp` is unused with Miri, so silence warnings.
 #![cfg_attr(miri, allow(dead_code))]
 
@@ -98,8 +98,7 @@
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[rustc_std_internal_symbol]
-#[unwind(allowed)]
-pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
+pub unsafe extern "C-unwind" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
     let payload = Box::from_raw((*payload).take_box());
 
     imp::panic(payload)
index 754dbb77af6ca42d71ce2ad89b607c7cc04c5760..9f1eb411ff66032519bcd865c05996943f299b4c 100644 (file)
@@ -233,15 +233,14 @@ pub struct _TypeDescriptor {
 // support capturing exceptions with std::exception_ptr, which we can't support
 // because Box<dyn Any> isn't clonable.
 macro_rules! define_cleanup {
-    ($abi:tt) => {
+    ($abi:tt $abi2:tt) => {
         unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
             if let Exception { data: Some(b) } = e.read() {
                 drop(b);
                 super::__rust_drop_panic();
             }
         }
-        #[unwind(allowed)]
-        unsafe extern $abi fn exception_copy(_dest: *mut Exception,
+        unsafe extern $abi2 fn exception_copy(_dest: *mut Exception,
                                              _src: *mut Exception)
                                              -> *mut Exception {
             panic!("Rust panics cannot be copied");
@@ -250,9 +249,9 @@ macro_rules! define_cleanup {
 }
 cfg_if::cfg_if! {
    if #[cfg(target_arch = "x86")] {
-       define_cleanup!("thiscall");
+       define_cleanup!("thiscall" "thiscall-unwind");
    } else {
-       define_cleanup!("C");
+       define_cleanup!("C" "C-unwind");
    }
 }
 
@@ -307,8 +306,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
         ptr!(exception_copy) as u32,
     );
 
-    extern "system" {
-        #[unwind(allowed)]
+    extern "system-unwind" {
         fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;
     }
 
index b968d44fe488d4d573b021d54f7c2bb57dac428c..7001e827ad8456778b1225f190a2fcdf596551d2 100644 (file)
@@ -109,6 +109,7 @@ fn next(
                 fn drop($self: $S::Literal);
                 fn clone($self: &$S::Literal) -> $S::Literal;
                 fn from_str(s: &str) -> Result<$S::Literal, ()>;
+                fn to_string($self: &$S::Literal) -> String;
                 fn debug_kind($self: &$S::Literal) -> String;
                 fn symbol($self: &$S::Literal) -> String;
                 fn suffix($self: &$S::Literal) -> Option<String>;
index 8138c3882fc14eb5ba8139afc235452be9520fc9..f25e257bf3168e3d6e7d4aad7ef8f16dbb93f309 100644 (file)
@@ -348,13 +348,13 @@ pub fn source(&self) -> Span {
     /// Gets the starting line/column in the source file for this span.
     #[unstable(feature = "proc_macro_span", issue = "54725")]
     pub fn start(&self) -> LineColumn {
-        self.0.start()
+        self.0.start().add_1_to_column()
     }
 
     /// Gets the ending line/column in the source file for this span.
     #[unstable(feature = "proc_macro_span", issue = "54725")]
     pub fn end(&self) -> LineColumn {
-        self.0.end()
+        self.0.end().add_1_to_column()
     }
 
     /// Creates a new span encompassing `self` and `other`.
@@ -432,12 +432,18 @@ pub struct LineColumn {
     /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
     #[unstable(feature = "proc_macro_span", issue = "54725")]
     pub line: usize,
-    /// The 0-indexed column (in UTF-8 characters) in the source file on which
-    /// the span starts or ends (inclusive).
+    /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source
+    /// file on which the span starts or ends (inclusive).
     #[unstable(feature = "proc_macro_span", issue = "54725")]
     pub column: usize,
 }
 
+impl LineColumn {
+    fn add_1_to_column(self) -> Self {
+        LineColumn { line: self.line, column: self.column + 1 }
+    }
+}
+
 #[unstable(feature = "proc_macro_span", issue = "54725")]
 impl !Send for LineColumn {}
 #[unstable(feature = "proc_macro_span", issue = "54725")]
@@ -1195,7 +1201,7 @@ fn from_str(src: &str) -> Result<Self, LexError> {
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl ToString for Literal {
     fn to_string(&self) -> String {
-        TokenStream::from(TokenTree::from(self.clone())).to_string()
+        self.0.to_string()
     }
 }
 
index ca86e569bc1278a845bb0368b577f52906c2b9ad..132733a0525106034097eb4889776bdc2b5cf29a 100644 (file)
@@ -87,6 +87,19 @@ impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> Default for SyncOnceCell<T> {
+    /// Creates a new empty cell.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// fn main() {
+    ///     assert_eq!(SyncOnceCell::<()>::new(), SyncOnceCell::default());
+    /// }
+    /// ```
     fn default() -> SyncOnceCell<T> {
         SyncOnceCell::new()
     }
@@ -118,6 +131,23 @@ fn clone(&self) -> SyncOnceCell<T> {
 
 #[unstable(feature = "once_cell", issue = "74465")]
 impl<T> From<T> for SyncOnceCell<T> {
+    /// Create a new cell with its contents set to `value`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// # fn main() -> Result<(), i32> {
+    /// let a = SyncOnceCell::from(3);
+    /// let b = SyncOnceCell::new();
+    /// b.set(3)?;
+    /// assert_eq!(a, b);
+    /// Ok(())
+    /// # }
+    /// ```
     fn from(value: T) -> Self {
         let cell = Self::new();
         match cell.set(value) {
index 21a1ee137efad87f037b7631b933469d73f28674..9dd99e44e809b57782671c3ef96b0637d78a0471 100644 (file)
 #![feature(auto_traits)]
 #![feature(bench_black_box)]
 #![feature(box_syntax)]
+#![feature(c_unwind)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
 #![feature(cfg_eval)]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(unsafe_cell_raw_get)]
-#![feature(unwind_attributes)]
 #![feature(unwrap_infallible)]
 #![feature(vec_into_raw_parts)]
 #![feature(vec_spare_capacity)]
index a23e29c5c7622291a8d5ce3e8e8915de40cd4828..ac92cfe19cd334a5428b4fb907b8adaed5eb6985 100644 (file)
@@ -84,13 +84,59 @@ pub struct Ipv4Addr {
 /// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
 /// They are usually represented as eight 16-bit segments.
 ///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
 /// The size of an `Ipv6Addr` struct may vary depending on the target operating
 /// system.
 ///
 /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
 ///
+/// # Embedding IPv4 Addresses
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
+/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
+///
+/// Both types of addresses are not assigned any special meaning by this implementation,
+/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
+/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
+/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
+///
+/// ### IPv4-Compatible IPv6 Addresses
+///
+/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
+/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|0000|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
+///
+/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
+///
+/// ### IPv4-Mapped IPv6 Addresses
+///
+/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
+/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|FFFF|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
+///
+/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
+///
 /// # Textual representation
 ///
 /// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
@@ -333,6 +379,29 @@ pub const fn is_ipv4(&self) -> bool {
     pub const fn is_ipv6(&self) -> bool {
         matches!(self, IpAddr::V6(_))
     }
+
+    /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped IPv6 addresses, otherwise it
+    /// return `self` as-is.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
 }
 
 impl Ipv4Addr {
@@ -766,13 +835,14 @@ pub const fn is_documentation(&self) -> bool {
         }
     }
 
-    /// Converts this address to an IPv4-compatible [`IPv6` address].
+    /// Converts this address to an [IPv4-compatible] [`IPv6` address].
     ///
     /// `a.b.c.d` becomes `::a.b.c.d`
     ///
-    /// This isn't typically the method you want; these addresses don't typically
-    /// function on modern systems. Use `to_ipv6_mapped` instead.
+    /// Note that IPv4-compatible addresses have been officially deprecated.
+    /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
     ///
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
     /// [`IPv6` address]: Ipv6Addr
     ///
     /// # Examples
@@ -795,10 +865,11 @@ pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
         }
     }
 
-    /// Converts this address to an IPv4-mapped [`IPv6` address].
+    /// Converts this address to an [IPv4-mapped] [`IPv6` address].
     ///
     /// `a.b.c.d` becomes `::ffff:a.b.c.d`
     ///
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
     /// [`IPv6` address]: Ipv6Addr
     ///
     /// # Examples
@@ -1201,11 +1272,13 @@ pub const fn is_unspecified(&self) -> bool {
         u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
     }
 
-    /// Returns [`true`] if this is a loopback address (::1).
+    /// Returns [`true`] if this is the [loopback address] (`::1`),
+    /// as defined in [IETF RFC 4291 section 2.5.3].
     ///
-    /// This property is defined in [IETF RFC 4291].
+    /// Contrary to IPv4, in IPv6 there is only one loopback address.
     ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
     ///
     /// # Examples
     ///
@@ -1476,13 +1549,14 @@ pub const fn is_multicast(&self) -> bool {
         (self.segments()[0] & 0xff00) == 0xff00
     }
 
-    /// Converts this address to an [`IPv4` address] if it's an "IPv4-mapped IPv6 address"
-    /// defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
+    /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
+    /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
     ///
     /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
     /// All addresses *not* starting with `::ffff` will return `None`.
     ///
     /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4-mapped]: Ipv6Addr
     /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
     ///
     /// # Examples
@@ -1509,12 +1583,19 @@ pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
         }
     }
 
-    /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is
-    /// neither IPv4-compatible or IPv4-mapped.
+    /// Converts this address to an [`IPv4` address] if it is either
+    /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
+    /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
+    /// otherwise returns [`None`].
     ///
     /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`
+    /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
     ///
-    /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4 address]: Ipv4Addr
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
+    /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
+    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
     ///
     /// # Examples
     ///
@@ -1540,6 +1621,28 @@ pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
         }
     }
 
+    /// Converts this address to an `IpAddr::V4` if it is a IPv4-mapped addresses, otherwise it
+    /// returns self wrapped in a `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+
     /// Returns the sixteen eight-bit integers the IPv6 address consists of.
     ///
     /// ```
index 5f43393e585835d8d69299ce382d0d3e2ad4196e..7de70091becf4f1188437962cdae2e40cd375907 100644 (file)
 #[allow(improper_ctypes)]
 extern "C" {
     fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
+}
 
+#[allow(improper_ctypes)]
+extern "C-unwind" {
     /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not
     /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations
     /// when using the "abort" panic runtime).
-    #[unwind(allowed)]
     fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
 }
 
@@ -460,7 +462,6 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
 
 /// Entry point of panics from the libcore crate (`panic_impl` lang item).
 #[cfg_attr(not(test), panic_handler)]
-#[unwind(allowed)]
 pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     struct PanicPayload<'a> {
         inner: &'a fmt::Arguments<'a>,
index 1488bf94841ded3fda921ead4e983140a24ea0f4..bc61f472a2b0501fcbda5f5e4c01a3a61ed58fee 100644 (file)
@@ -164,16 +164,23 @@ pub fn set_name(name: &CStr) {
         }
     }
 
+    #[cfg(target_os = "haiku")]
+    pub fn set_name(name: &CStr) {
+        unsafe {
+            let thread_self = libc::find_thread(ptr::null_mut());
+            libc::rename_thread(thread_self, name.as_ptr());
+        }
+    }
+
     #[cfg(any(
         target_env = "newlib",
-        target_os = "haiku",
         target_os = "l4re",
         target_os = "emscripten",
         target_os = "redox",
         target_os = "vxworks"
     ))]
     pub fn set_name(_name: &CStr) {
-        // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name.
+        // Newlib, Emscripten, and VxWorks have no way to set a thread name.
     }
 
     pub fn sleep(dur: Duration) {
index c7107b5d0a3ef2cc4daa1b97fd5a2f7ada96475b..079f00a5753f1d7617b8d55407631b5390594d32 100644 (file)
 fn arm_linux() {
     println!("neon: {}", is_arm_feature_detected!("neon"));
     println!("pmull: {}", is_arm_feature_detected!("pmull"));
+    println!("crypto: {}", is_arm_feature_detected!("crypto"));
+    println!("crc: {}", is_arm_feature_detected!("crc"));
+    println!("aes: {}", is_arm_feature_detected!("aes"));
+    println!("sha2: {}", is_arm_feature_detected!("sha2"));
 }
 
 #[test]
 #[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
 fn aarch64_linux() {
-    println!("fp: {}", is_aarch64_feature_detected!("fp"));
-    println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
     println!("neon: {}", is_aarch64_feature_detected!("neon"));
     println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
+    println!("pmull: {}", is_aarch64_feature_detected!("pmull"));
+    println!("fp: {}", is_aarch64_feature_detected!("fp"));
+    println!("fp16: {}", is_aarch64_feature_detected!("fp16"));
     println!("sve: {}", is_aarch64_feature_detected!("sve"));
     println!("crc: {}", is_aarch64_feature_detected!("crc"));
     println!("lse: {}", is_aarch64_feature_detected!("lse"));
+    println!("lse2: {}", is_aarch64_feature_detected!("lse2"));
     println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
     println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
+    println!("rcpc2: {}", is_aarch64_feature_detected!("rcpc2"));
     println!("dotprod: {}", is_aarch64_feature_detected!("dotprod"));
     println!("tme: {}", is_aarch64_feature_detected!("tme"));
+    println!("fhm: {}", is_aarch64_feature_detected!("fhm"));
+    println!("dit: {}", is_aarch64_feature_detected!("dit"));
+    println!("flagm: {}", is_aarch64_feature_detected!("flagm"));
+    println!("ssbs: {}", is_aarch64_feature_detected!("ssbs"));
+    println!("sb: {}", is_aarch64_feature_detected!("sb"));
+    println!("pauth: {}", is_aarch64_feature_detected!("pauth"));
+    println!("dpb: {}", is_aarch64_feature_detected!("dpb"));
+    println!("dpb2: {}", is_aarch64_feature_detected!("dpb2"));
+    println!("sve2: {}", is_aarch64_feature_detected!("sve2"));
+    println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes"));
+    println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4"));
+    println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3"));
+    println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm"));
+    println!("frintts: {}", is_aarch64_feature_detected!("frintts"));
+    println!("i8mm: {}", is_aarch64_feature_detected!("i8mm"));
+    println!("f32mm: {}", is_aarch64_feature_detected!("f32mm"));
+    println!("f64mm: {}", is_aarch64_feature_detected!("f64mm"));
+    println!("bf16: {}", is_aarch64_feature_detected!("bf16"));
+    println!("rand: {}", is_aarch64_feature_detected!("rand"));
+    println!("bti: {}", is_aarch64_feature_detected!("bti"));
+    println!("mte: {}", is_aarch64_feature_detected!("mte"));
+    println!("jsconv: {}", is_aarch64_feature_detected!("jsconv"));
+    println!("fcma: {}", is_aarch64_feature_detected!("fcma"));
+    println!("aes: {}", is_aarch64_feature_detected!("aes"));
+    println!("sha2: {}", is_aarch64_feature_detected!("sha2"));
+    println!("sha3: {}", is_aarch64_feature_detected!("sha3"));
+    println!("sm4: {}", is_aarch64_feature_detected!("sm4"));
 }
 
 #[test]
index 3001c75a1d2a81d2a76bef139c69387cb2ebb820..c158cfd38e20d855f5d6ca8a5a101eefb82604a8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3001c75a1d2a81d2a76bef139c69387cb2ebb820
+Subproject commit c158cfd38e20d855f5d6ca8a5a101eefb82604a8
index eaeec72fbb55b473230e5100cff49ec2c33aa3b1..9e52802450682137789e05161593441cad620451 100644 (file)
@@ -3,8 +3,8 @@
 #![feature(link_cfg)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(unwind_attributes)]
 #![feature(static_nobundle)]
+#![feature(c_unwind)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 
 cfg_if::cfg_if! {
index faf554d285a9a294d57dec8d4d6290ed831fd34e..196be74decba4e4fb9c454f3fdf7a50ede26585e 100644 (file)
@@ -81,9 +81,10 @@ pub enum _Unwind_Context {}
     all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
     link(name = "unwind", kind = "static")
 )]
-extern "C" {
-    #[unwind(allowed)]
+extern "C-unwind" {
     pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
+}
+extern "C" {
     pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
     pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
     pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
@@ -230,9 +231,10 @@ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
     #[cfg_attr(all(feature = "llvm-libunwind",
                    any(target_os = "fuchsia", target_os = "linux")),
                link(name = "unwind", kind = "static"))]
-    extern "C" {
-        #[unwind(allowed)]
+    extern "C-unwind" {
         pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
+    }
+    extern "C" {
         pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                  trace_argument: *mut c_void)
                                  -> _Unwind_Reason_Code;
@@ -242,8 +244,7 @@ pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
     #[cfg_attr(all(feature = "llvm-libunwind",
                    any(target_os = "fuchsia", target_os = "linux")),
                link(name = "unwind", kind = "static"))]
-    extern "C" {
-        #[unwind(allowed)]
+    extern "C-unwind" {
         pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
     }
 
index f2e38a7eab6bc8c92f7de53d4f935bb74c61d035..3faf38c66ec8bb4b4126d686143bbfc1c7bdb87a 100644 (file)
@@ -464,7 +464,8 @@ class RustBuild(object):
             # LLVM more often than necessary.
             #
             # This git command finds that commit SHA, looking for bors-authored
-            # merges that modified src/llvm-project.
+            # merges that modified src/llvm-project or other relevant version
+            # stamp files.
             #
             # This works even in a repository that has not yet initialized
             # submodules.
@@ -472,8 +473,8 @@ class RustBuild(object):
                 "git", "rev-parse", "--show-toplevel",
             ]).decode(sys.getdefaultencoding()).strip()
             llvm_sha = subprocess.check_output([
-                "git", "log", "--author=bors", "--format=%H", "-n1",
-                "--no-patch", "--first-parent",
+                "git", "rev-list", "--author=bors@rust-lang.org", "-n1",
+                "--merges", "--first-parent", "HEAD",
                 "--",
                 "{}/src/llvm-project".format(top_level),
                 "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level),
@@ -665,7 +666,10 @@ class RustBuild(object):
 
         # Look for a version to compare to based on the current commit.
         # Only commits merged by bors will have CI artifacts.
-        merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"]
+        merge_base = [
+            "git", "rev-list", "--author=bors@rust-lang.org", "-n1",
+            "--merges", "--first-parent", "HEAD"
+        ]
         commit = subprocess.check_output(merge_base, universal_newlines=True).strip()
 
         # Warn if there were changes to the compiler or standard library since the ancestor commit.
diff --git a/src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md b/src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md
new file mode 100644 (file)
index 0000000..479571d
--- /dev/null
@@ -0,0 +1,53 @@
+# `explicit_generic_args_with_impl_trait`
+
+The tracking issue for this feature is: [#83701]
+
+[#83701]: https://github.com/rust-lang/rust/issues/83701
+
+------------------------
+
+The `explicit_generic_args_with_impl_trait` feature gate lets you specify generic arguments even
+when `impl Trait` is used in argument position.
+
+A simple example is:
+
+```rust
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".to_string());
+}
+```
+
+This is currently rejected:
+
+```text
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
+ --> src/main.rs:6:11
+  |
+6 |     foo::<str>("".to_string());
+  |           ^^^ explicit generic argument not allowed
+
+```
+
+However it would compile if `explicit_generic_args_with_impl_trait` is enabled.
+
+Note that the synthetic type parameters from `impl Trait` are still implicit and you
+cannot explicitly specify these:
+
+```rust,compile_fail
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+fn bar<T: ?Sized, F: AsRef<T>>(_f: F) {}
+
+fn main() {
+    bar::<str, _>("".to_string()); // Okay
+    bar::<str, String>("".to_string()); // Okay
+
+    foo::<str>("".to_string()); // Okay
+    foo::<str, String>("".to_string()); // Error, you cannot specify `impl Trait` explicitly
+}
+```
diff --git a/src/doc/unstable-book/src/language-features/trait-upcasting.md b/src/doc/unstable-book/src/language-features/trait-upcasting.md
new file mode 100644 (file)
index 0000000..3697ae3
--- /dev/null
@@ -0,0 +1,27 @@
+# `trait_upcasting`
+
+The tracking issue for this feature is: [#65991]
+
+[#65991]: https://github.com/rust-lang/rust/issues/65991
+
+------------------------
+
+The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a
+trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo`
+so long as `Bar: Foo`.
+
+```rust,edition2018
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo {}
+
+trait Bar: Foo {}
+
+impl Foo for i32 {}
+
+impl<T: Foo + ?Sized> Bar for T {}
+
+let bar: &dyn Bar = &123;
+let foo: &dyn Foo = bar;
+```
index e950891ef92bd504e4b7ed496d3a90a717e9e7bb..8ff600d5334fd0f18c772a5007d027c25679da9b 100644 (file)
@@ -402,7 +402,7 @@ assert_eq!(a, 5);
 
 This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
 
-This example show a few thing:
+This example shows a few things:
 
 First that the same number can be used as a label multiple times in the same inline block.
 
index 8f74a48547d8833c0f88a12e6ec8ac111cda1af4..207c89cbfe87e7d2386e2ec254bd3e8c785860c1 100644 (file)
@@ -98,7 +98,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     visibility: Inherited,
                     def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                     kind: box ImplItem(Impl {
-                        span: Span::from_rustc_span(self.cx.tcx.def_span(impl_def_id)),
+                        span: Span::new(self.cx.tcx.def_span(impl_def_id)),
                         unsafety: hir::Unsafety::Normal,
                         generics: (
                             self.cx.tcx.generics_of(impl_def_id),
index b3b89e6e673a29f1a438e3ce3d6d9ebaeab5e17b..43979423ae615822a01763363820ba07c98153aa 100644 (file)
@@ -517,7 +517,7 @@ fn build_module(
         }
     }
 
-    let span = clean::Span::from_rustc_span(cx.tcx.def_span(did));
+    let span = clean::Span::new(cx.tcx.def_span(did));
     clean::Module { items, span }
 }
 
index 75ea30bb565f1b8c250e76d2babe04596a501740..3d65fcedaf4e53470d7c6b502195b8be01e2756f 100644 (file)
@@ -95,7 +95,8 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
-        let span = Span::from_rustc_span({
+
+        let span = Span::new({
             let where_outer = self.where_outer(cx.tcx);
             let sm = cx.sess().source_map();
             let outer = sm.lookup_char_pos(where_outer.lo());
@@ -675,11 +676,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
                         if let Some(((_, trait_did, name), rhs)) =
                             proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                         {
-                            impl_trait_proj.entry(param_idx).or_default().push((
-                                trait_did.into(),
-                                name,
-                                rhs,
-                            ));
+                            impl_trait_proj
+                                .entry(param_idx)
+                                .or_default()
+                                .push((trait_did, name, rhs));
                         }
 
                         return None;
index 2460fa127f116324dfaa239fec29e2d2e636b278..22e4d21c87bdf0405594ec2c0030b3e91da844c2 100644 (file)
@@ -343,7 +343,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
 rustc_data_structures::static_assert_size!(Item, 56);
 
 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
-    Span::from_rustc_span(def_id.as_local().map_or_else(
+    Span::new(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
         |local| {
             let hir = tcx.hir();
@@ -1614,7 +1614,7 @@ impl Type {
 impl Type {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
-            ResolvedPath { did, .. } => return Some(did.into()),
+            ResolvedPath { did, .. } => return Some(did),
             DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache),
             Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
@@ -1943,10 +1943,11 @@ impl Visibility {
 crate struct Span(rustc_span::Span);
 
 impl Span {
-    crate fn from_rustc_span(sp: rustc_span::Span) -> Self {
-        // Get the macro invocation instead of the definition,
-        // in case the span is result of a macro expansion.
-        // (See rust-lang/rust#39726)
+    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
+    /// span will be updated to point to the macro invocation instead of the macro definition.
+    ///
+    /// (See rust-lang/rust#39726)
+    crate fn new(sp: rustc_span::Span) -> Self {
         Self(sp.source_callsite())
     }
 
index abd1fd2bf39a29c13702beaf484680ae232f53f8..e44158bc042308da91fec47203100a9fc539f1a3 100644 (file)
@@ -276,6 +276,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     crate show_type_layout: bool,
     crate unstable_features: rustc_feature::UnstableFeatures,
     crate emit: Vec<EmitType>,
+    /// If `true`, HTML source pages will generate links for items to their definition.
+    crate generate_link_to_definition: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -655,6 +657,15 @@ fn println_condition(condition: Condition) {
         let generate_redirect_map = matches.opt_present("generate-redirect-map");
         let show_type_layout = matches.opt_present("show-type-layout");
         let nocapture = matches.opt_present("nocapture");
+        let generate_link_to_definition = matches.opt_present("generate-link-to-definition");
+
+        if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
+            diag.struct_err(
+                "--generate-link-to-definition option can only be used with HTML output format",
+            )
+            .emit();
+            return Err(1);
+        }
 
         let (lint_opts, describe_lints, lint_cap) =
             get_cmd_lint_options(matches, error_format, &debugging_opts);
@@ -721,6 +732,7 @@ fn println_condition(condition: Condition) {
                     crate_name.as_deref(),
                 ),
                 emit,
+                generate_link_to_definition,
             },
             crate_name,
             output_format,
index 0689d72e4e0cf7187f19059995b839bd5071f541..46aa961722780ab1fa18cb98a1a130076d4d1d76 100644 (file)
@@ -374,15 +374,8 @@ impl<'tcx> DocContext<'tcx> {
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
-    let access_levels = tcx.privacy_access_levels(());
-    // Convert from a HirId set to a DefId set since we don't always have easy access
-    // to the map from defid -> hirid
     let access_levels = AccessLevels {
-        map: access_levels
-            .map
-            .iter()
-            .map(|(&k, &v)| (tcx.hir().local_def_id(k).to_def_id(), v))
-            .collect(),
+        map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
     };
 
     let mut ctxt = DocContext {
index 5ea2cdc2ad9093a239b8615303e409af1b828a72..3d267ca50334dc9136ee115d0523759ec1f48f7e 100644 (file)
@@ -228,7 +228,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 if i.blanket_impl.is_none() {
                     self.cache
                         .implementors
-                        .entry(did.into())
+                        .entry(did)
                         .or_default()
                         .push(Impl { impl_item: item.clone() });
                 }
index 0291236abdfa6f86119729a85d1393f76744a101..eb7c12d13c339029bacf8566c62837f88dae3071 100644 (file)
@@ -484,7 +484,11 @@ fn print<'a, 'tcx: 'a>(
     NotInExternalCache,
 }
 
-crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
+crate fn href_with_root_path(
+    did: DefId,
+    cx: &Context<'_>,
+    root_path: Option<&str>,
+) -> Result<(String, ItemType, Vec<String>), HrefError> {
     let cache = &cx.cache();
     let relative_to = &cx.current;
     fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
@@ -495,6 +499,7 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
         return Err(HrefError::Private);
     }
 
+    let mut is_remote = false;
     let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
         Some(&(ref fqp, shortty)) => (fqp, shortty, {
             let module_fqp = to_module_fqp(shortty, fqp);
@@ -508,6 +513,7 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
                     shortty,
                     match cache.extern_locations[&did.krate] {
                         ExternalLocation::Remote(ref s) => {
+                            is_remote = true;
                             let s = s.trim_end_matches('/');
                             let mut s = vec![s];
                             s.extend(module_fqp[..].iter().map(String::as_str));
@@ -522,6 +528,12 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
             }
         }
     };
+    if !is_remote {
+        if let Some(root_path) = root_path {
+            let root = root_path.trim_end_matches('/');
+            url_parts.insert(0, root);
+        }
+    }
     let last = &fqp.last().unwrap()[..];
     let filename;
     match shortty {
@@ -536,6 +548,10 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
     Ok((url_parts.join("/"), shortty, fqp.to_vec()))
 }
 
+crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
+    href_with_root_path(did, cx, None)
+}
+
 /// Both paths should only be modules.
 /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
 /// both need `../iter/trait.Iterator.html` to get at the iterator trait.
@@ -688,7 +704,7 @@ fn tybounds<'a, 'tcx: 'a>(
     text: &'a str,
     cx: &'cx Context<'_>,
 ) -> impl fmt::Display + 'a {
-    let parts = href(did.into(), cx);
+    let parts = href(did, cx);
     display_fn(move |f| {
         if let Ok((url, short_ty, fqp)) = parts {
             write!(
@@ -921,7 +937,7 @@ fn fmt_type<'cx>(
                 //        everything comes in as a fully resolved QPath (hard to
                 //        look at).
                 box clean::ResolvedPath { did, .. } => {
-                    match href(did.into(), cx) {
+                    match href(did, cx) {
                         Ok((ref url, _, ref path)) if !f.alternate() => {
                             write!(
                                 f,
index 33b1d98313ce3cd3c5efb3cc3404f26f1fdeab36..3cdb1352bef956045502b1d557e4d49ffe2c7209 100644 (file)
@@ -6,15 +6,28 @@
 //! Use the `render_with_highlighting` to highlight some rust code.
 
 use crate::html::escape::Escape;
+use crate::html::render::Context;
 
-use std::fmt::Display;
+use std::fmt::{Display, Write};
 use std::iter::Peekable;
 
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-
-use super::format::Buffer;
+use rustc_span::{BytePos, Span, DUMMY_SP};
+
+use super::format::{self, Buffer};
+use super::render::LinkFromSrc;
+
+/// This type is needed in case we want to render links on items to allow to go to their definition.
+crate struct ContextInfo<'a, 'b, 'c> {
+    crate context: &'a Context<'b>,
+    /// This span contains the current file we're going through.
+    crate file_span: Span,
+    /// This field is used to know "how far" from the top of the directory we are to link to either
+    /// documentation pages or other source pages.
+    crate root_path: &'c str,
+}
 
 /// Highlights `src`, returning the HTML output.
 crate fn render_with_highlighting(
@@ -25,6 +38,7 @@
     tooltip: Option<(Option<Edition>, &str)>,
     edition: Edition,
     extra_content: Option<Buffer>,
+    context_info: Option<ContextInfo<'_, '_, '_>>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
     if let Some((edition_info, class)) = tooltip {
@@ -41,7 +55,7 @@
     }
 
     write_header(out, class, extra_content);
-    write_code(out, &src, edition);
+    write_code(out, &src, edition, context_info);
     write_footer(out, playground_button);
 }
 
@@ -57,16 +71,33 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
     }
 }
 
-fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
+/// Convert the given `src` source code into HTML by adding classes for highlighting.
+///
+/// This code is used to render code blocks (in the documentation) as well as the source code pages.
+///
+/// Some explanations on the last arguments:
+///
+/// In case we are rendering a code block and not a source code file, `context_info` will be `None`.
+/// To put it more simply: if `context_info` is `None`, the code won't try to generate links to an
+/// item definition.
+///
+/// More explanations about spans and how we use them here are provided in the
+fn write_code(
+    out: &mut Buffer,
+    src: &str,
+    edition: Edition,
+    context_info: Option<ContextInfo<'_, '_, '_>>,
+) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src, edition).highlight(&mut |highlight| {
-        match highlight {
-            Highlight::Token { text, class } => string(out, Escape(text), class),
-            Highlight::EnterSpan { class } => enter_span(out, class),
-            Highlight::ExitSpan => exit_span(out),
-        };
-    });
+    Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
+        .highlight(&mut |highlight| {
+            match highlight {
+                Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+                Highlight::EnterSpan { class } => enter_span(out, class),
+                Highlight::ExitSpan => exit_span(out),
+            };
+        });
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -82,14 +113,14 @@ enum Class {
     KeyWord,
     // Keywords that do pointer/reference stuff.
     RefKeyWord,
-    Self_,
+    Self_(Span),
     Op,
     Macro,
     MacroNonTerminal,
     String,
     Number,
     Bool,
-    Ident,
+    Ident(Span),
     Lifetime,
     PreludeTy,
     PreludeVal,
@@ -105,20 +136,29 @@ fn as_html(self) -> &'static str {
             Class::Attribute => "attribute",
             Class::KeyWord => "kw",
             Class::RefKeyWord => "kw-2",
-            Class::Self_ => "self",
+            Class::Self_(_) => "self",
             Class::Op => "op",
             Class::Macro => "macro",
             Class::MacroNonTerminal => "macro-nonterminal",
             Class::String => "string",
             Class::Number => "number",
             Class::Bool => "bool-val",
-            Class::Ident => "ident",
+            Class::Ident(_) => "ident",
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
             Class::QuestionMark => "question-mark",
         }
     }
+
+    /// In case this is an item which can be converted into a link to a definition, it'll contain
+    /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
+    fn get_span(self) -> Option<Span> {
+        match self {
+            Self::Ident(sp) | Self::Self_(sp) => Some(sp),
+            _ => None,
+        }
+    }
 }
 
 enum Highlight<'a> {
@@ -144,14 +184,19 @@ fn next(&mut self) -> Option<(TokenKind, &'a str)> {
     }
 }
 
-fn get_real_ident_class(text: &str, edition: Edition) -> Class {
-    match text {
+/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
+fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+    let ignore: &[&str] =
+        if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
+    if ignore.iter().any(|k| *k == text) {
+        return None;
+    }
+    Some(match text {
         "ref" | "mut" => Class::RefKeyWord,
-        "self" | "Self" => Class::Self_,
         "false" | "true" => Class::Bool,
         _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
-        _ => Class::Ident,
-    }
+        _ => return None,
+    })
 }
 
 /// Processes program tokens, classifying strings of text by highlighting
@@ -163,11 +208,14 @@ struct Classifier<'a> {
     in_macro_nonterminal: bool,
     edition: Edition,
     byte_pos: u32,
+    file_span: Span,
     src: &'a str,
 }
 
 impl<'a> Classifier<'a> {
-    fn new(src: &str, edition: Edition) -> Classifier<'_> {
+    /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
+    /// file span which will be used later on by the `span_correspondance_map`.
+    fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
         let tokens = TokenIter { src }.peekable();
         Classifier {
             tokens,
@@ -176,10 +224,18 @@ fn new(src: &str, edition: Edition) -> Classifier<'_> {
             in_macro_nonterminal: false,
             edition,
             byte_pos: 0,
+            file_span,
             src,
         }
     }
 
+    /// Convenient wrapper to create a [`Span`] from a position in the file.
+    fn new_span(&self, lo: u32, text: &str) -> Span {
+        let hi = lo + text.len() as u32;
+        let file_lo = self.file_span.lo();
+        self.file_span.with_lo(file_lo + BytePos(lo)).with_hi(file_lo + BytePos(hi))
+    }
+
     /// Concatenate colons and idents as one when possible.
     fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
         let start = self.byte_pos as usize;
@@ -201,17 +257,17 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
                 if has_ident {
                     return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
                 } else {
-                    return vec![(TokenKind::Colon, pos, pos + nb)];
+                    return vec![(TokenKind::Colon, start, pos + nb)];
                 }
             }
 
-            if let Some((Class::Ident, text)) = self.tokens.peek().map(|(token, text)| {
+            if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
                 if *token == TokenKind::Ident {
-                    let class = get_real_ident_class(text, edition);
+                    let class = get_real_ident_class(text, edition, true);
                     (class, text)
                 } else {
                     // Doesn't matter which Class we put in here...
-                    (Class::Comment, text)
+                    (Some(Class::Comment), text)
                 }
             }) {
                 // We only "add" the colon if there is an ident behind.
@@ -221,7 +277,7 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
             } else if nb > 0 && has_ident {
                 return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
             } else if nb > 0 {
-                return vec![(TokenKind::Colon, pos, pos + nb)];
+                return vec![(TokenKind::Colon, start, start + nb)];
             } else if has_ident {
                 return vec![(TokenKind::Ident, start, pos)];
             } else {
@@ -230,11 +286,15 @@ fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
         }
     }
 
-    /// Wraps the tokens iteration to ensure that the byte_pos is always correct.
-    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
+    /// Wraps the tokens iteration to ensure that the `byte_pos` is always correct.
+    ///
+    /// It returns the token's kind, the token as a string and its byte position in the source
+    /// string.
+    fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
         if let Some((kind, text)) = self.tokens.next() {
+            let before = self.byte_pos;
             self.byte_pos += text.len() as u32;
-            Some((kind, text))
+            Some((kind, text, before))
         } else {
             None
         }
@@ -254,23 +314,36 @@ fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
                 .unwrap_or(false)
             {
                 let tokens = self.get_full_ident_path();
-                for (token, start, end) in tokens {
-                    let text = &self.src[start..end];
-                    self.advance(token, text, sink);
+                for (token, start, end) in &tokens {
+                    let text = &self.src[*start..*end];
+                    self.advance(*token, text, sink, *start as u32);
                     self.byte_pos += text.len() as u32;
                 }
+                if !tokens.is_empty() {
+                    continue;
+                }
             }
-            if let Some((token, text)) = self.next() {
-                self.advance(token, text, sink);
+            if let Some((token, text, before)) = self.next() {
+                self.advance(token, text, sink, before);
             } else {
                 break;
             }
         }
     }
 
-    /// Single step of highlighting. This will classify `token`, but maybe also
-    /// a couple of following ones as well.
-    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
+    /// Single step of highlighting. This will classify `token`, but maybe also a couple of
+    /// following ones as well.
+    ///
+    /// `before` is the position of the given token in the `source` string and is used as "lo" byte
+    /// in case we want to try to generate a link for this token using the
+    /// `span_correspondance_map`.
+    fn advance(
+        &mut self,
+        token: TokenKind,
+        text: &'a str,
+        sink: &mut dyn FnMut(Highlight<'a>),
+        before: u32,
+    ) {
         let lookahead = self.peek();
         let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
         let class = match token {
@@ -401,19 +474,22 @@ fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(High
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match get_real_ident_class(text, self.edition) {
-                Class::Ident => match text {
+            TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+                None => match text {
                     "Option" | "Result" => Class::PreludeTy,
                     "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                     _ if self.in_macro_nonterminal => {
                         self.in_macro_nonterminal = false;
                         Class::MacroNonTerminal
                     }
-                    _ => Class::Ident,
+                    "self" | "Self" => Class::Self_(self.new_span(before, text)),
+                    _ => Class::Ident(self.new_span(before, text)),
                 },
-                c => c,
+                Some(c) => c,
             },
-            TokenKind::RawIdent | TokenKind::UnknownPrefix => Class::Ident,
+            TokenKind::RawIdent | TokenKind::UnknownPrefix => {
+                Class::Ident(self.new_span(before, text))
+            }
             TokenKind::Lifetime { .. } => Class::Lifetime,
         };
         // Anything that didn't return above is the simple case where we the
@@ -446,13 +522,75 @@ fn exit_span(out: &mut Buffer) {
 ///     enter_span(Foo), string("text", None), exit_span()
 ///     string("text", Foo)
 /// ```
+///
 /// The latter can be thought of as a shorthand for the former, which is more
 /// flexible.
-fn string<T: Display>(out: &mut Buffer, text: T, klass: Option<Class>) {
-    match klass {
-        None => write!(out, "{}", text),
-        Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text),
+///
+/// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function
+/// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then
+/// generate a link for this element (which corresponds to where its definition is located).
+fn string<T: Display>(
+    out: &mut Buffer,
+    text: T,
+    klass: Option<Class>,
+    context_info: &Option<ContextInfo<'_, '_, '_>>,
+) {
+    let klass = match klass {
+        None => return write!(out, "{}", text),
+        Some(klass) => klass,
+    };
+    let def_span = match klass.get_span() {
+        Some(d) => d,
+        None => {
+            write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text);
+            return;
+        }
+    };
+    let mut text_s = text.to_string();
+    if text_s.contains("::") {
+        text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
+            match t {
+                "self" | "Self" => write!(
+                    &mut path,
+                    "<span class=\"{}\">{}</span>",
+                    Class::Self_(DUMMY_SP).as_html(),
+                    t
+                ),
+                "crate" | "super" => {
+                    write!(&mut path, "<span class=\"{}\">{}</span>", Class::KeyWord.as_html(), t)
+                }
+                t => write!(&mut path, "{}", t),
+            }
+            .expect("Failed to build source HTML path");
+            path
+        });
+    }
+    if let Some(context_info) = context_info {
+        if let Some(href) =
+            context_info.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
+                let context = context_info.context;
+                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+                // one to the documentation page and one to the source definition.
+                // FIXME: currently, external items only generate a link to their documentation,
+                // a link to their definition can be generated using this:
+                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+                match href {
+                    LinkFromSrc::Local(span) => context
+                        .href_from_span(*span)
+                        .map(|s| format!("{}{}", context_info.root_path, s)),
+                    LinkFromSrc::External(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(context_info.root_path))
+                            .ok()
+                            .map(|(url, _, _)| url)
+                    }
+                }
+            })
+        {
+            write!(out, "<a class=\"{}\" href=\"{}\">{}</a>", klass.as_html(), href, text_s);
+            return;
+        }
     }
+    write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text_s);
 }
 
 #[cfg(test)]
diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html
new file mode 100644 (file)
index 0000000..abc2db1
--- /dev/null
@@ -0,0 +1,4 @@
+<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>;
+<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>;
+<span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="ident"><span class="kw">super</span>::b::foo</span>;
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="ident"><span class="self">Self</span>::whatever</span>;
\ No newline at end of file
index 8d23477bbcb8cc359f64a8f36d5d91ff3484565f..866caea9256096757deb7b404527950e3a4cedc6 100644 (file)
@@ -23,7 +23,7 @@
     <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
     <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
     <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
-    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std</span><span class="ident">::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
+    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
     <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>();
 
     <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="ident">s</span> {
index a505865b149c4bc91e0ee1e4480686c38df96502..68592ae96c187b273eebb1c5d76c417b0fa86954 100644 (file)
@@ -22,7 +22,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018);
+            write_code(&mut out, src, Edition::Edition2018, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -36,7 +36,21 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018);
+        write_code(&mut html, src, Edition::Edition2018, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
+
+#[test]
+fn test_keyword_highlight() {
+    create_default_session_globals_then(|| {
+        let src = "use crate::a::foo;
+use self::whatever;
+let x = super::b::foo;
+let y = Self::whatever;";
+
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018, None);
+        expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
+    });
+}
index b8756d2526edf1a78c89178e8a72d8c71b21e8ed..472323daf3017ae594eebe2a42b091a0cd505f98 100644 (file)
@@ -330,6 +330,7 @@ fn dont_escape(c: u8) -> bool {
             tooltip,
             edition,
             None,
+            None,
         );
         Some(Event::Html(s.into_inner().into()))
     }
index 0734d2670ccfae7b07379fc8630d3408937a67f2..1c083522beaa901f3409a9de0bb084911100de2c 100644 (file)
@@ -42,7 +42,7 @@
                 name: item.name.unwrap().to_string(),
                 path: fqp[..fqp.len() - 1].join("::"),
                 desc,
-                parent: Some(did.into()),
+                parent: Some(did),
                 parent_idx: None,
                 search_type: get_index_search_type(&item, tcx),
                 aliases: item.attrs.get_doc_aliases(),
index b6c3220901f06ad4289f50311357ebbf525084dc..6ce0828e159402b867eb447921efc0d2e6ada44c 100644 (file)
 use super::cache::{build_index, ExternalLocation};
 use super::print_item::{full_path, item_path, print_item};
 use super::write_shared::write_shared;
-use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
+use super::{
+    collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
+    BASIC_KEYWORDS,
+};
 
 use crate::clean;
 use crate::clean::ExternalCrate;
@@ -46,7 +49,7 @@
     pub(crate) current: Vec<String>,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
-    pub(super) dst: PathBuf,
+    crate dst: PathBuf,
     /// A flag, which when `true`, will render pages which redirect to the
     /// real location of an item. This is used to allow external links to
     /// publicly reused items to redirect to the right location.
@@ -58,7 +61,7 @@
     /// Issue for improving the situation: [#82381][]
     ///
     /// [#82381]: https://github.com/rust-lang/rust/issues/82381
-    pub(super) shared: Rc<SharedContext<'tcx>>,
+    crate shared: Rc<SharedContext<'tcx>>,
     /// The [`Cache`] used during rendering.
     ///
     /// Ideally the cache would be in [`SharedContext`], but it's mutated
     /// It's immutable once in `Context`, so it's not as bad that it's not in
     /// `SharedContext`.
     // FIXME: move `cache` to `SharedContext`
-    pub(super) cache: Rc<Cache>,
+    crate cache: Rc<Cache>,
+    /// This flag indicates whether `[src]` links should be generated or not. If
+    /// the source files are present in the html rendering, then this will be
+    /// `true`.
+    crate include_sources: bool,
 }
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
     /// This describes the layout of each page, and is not modified after
     /// creation of the context (contains info like the favicon and added html).
     crate layout: layout::Layout,
-    /// This flag indicates whether `[src]` links should be generated or not. If
-    /// the source files are present in the html rendering, then this will be
-    /// `true`.
-    crate include_sources: bool,
     /// The local file sources we've emitted and their respective url-paths.
     crate local_sources: FxHashMap<PathBuf, String>,
     /// Show the memory layout of types in the docs.
     redirections: Option<RefCell<FxHashMap<String, String>>>,
 
     pub(crate) templates: tera::Tera,
+
+    /// Correspondance map used to link types used in the source code pages to allow to click on
+    /// links to jump to the type's definition.
+    crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
 }
 
 impl SharedContext<'_> {
@@ -293,15 +300,19 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
     pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
-        if item.span(self.tcx()).is_dummy() {
+        self.href_from_span(item.span(self.tcx()))
+    }
+
+    crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+        if span.is_dummy() {
             return None;
         }
         let mut root = self.root_path();
         let mut path = String::new();
-        let cnum = item.span(self.tcx()).cnum(self.sess());
+        let cnum = span.cnum(self.sess());
 
         // We can safely ignore synthetic `SourceFile`s.
-        let file = match item.span(self.tcx()).filename(self.sess()) {
+        let file = match span.filename(self.sess()) {
             FileName::Real(ref path) => path.local_path_if_available().to_path_buf(),
             _ => return None,
         };
@@ -339,8 +350,8 @@ pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
             (&*symbol, &path)
         };
 
-        let loline = item.span(self.tcx()).lo(self.sess()).line;
-        let hiline = item.span(self.tcx()).hi(self.sess()).line;
+        let loline = span.lo(self.sess()).line;
+        let hiline = span.hi(self.sess()).line;
         let lines =
             if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
         Some(format!(
@@ -362,9 +373,9 @@ fn descr() -> &'static str {
     const RUN_ON_MODULE: bool = true;
 
     fn init(
-        mut krate: clean::Crate,
+        krate: clean::Crate,
         options: RenderOptions,
-        mut cache: Cache,
+        cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         // need to save a copy of the options for rendering the index page
@@ -385,6 +396,7 @@ fn init(
             unstable_features,
             generate_redirect_map,
             show_type_layout,
+            generate_link_to_definition,
             ..
         } = options;
 
@@ -444,13 +456,21 @@ fn init(
                 _ => {}
             }
         }
+
+        let (mut krate, local_sources, matches) = collect_spans_and_sources(
+            tcx,
+            krate,
+            &src_root,
+            include_sources,
+            generate_link_to_definition,
+        );
+
         let (sender, receiver) = channel();
         let mut scx = SharedContext {
             tcx,
             collapsed: krate.collapsed,
             src_root,
-            include_sources,
-            local_sources: Default::default(),
+            local_sources,
             issue_tracker_base_url,
             layout,
             created_dirs: Default::default(),
@@ -466,6 +486,7 @@ fn init(
             redirections: if generate_redirect_map { Some(Default::default()) } else { None },
             show_type_layout,
             templates,
+            span_correspondance_map: matches,
         };
 
         // Add the default themes to the `Vec` of stylepaths
@@ -483,12 +504,6 @@ fn init(
 
         let dst = output;
         scx.ensure_dir(&dst)?;
-        if emit_crate {
-            krate = sources::render(&dst, &mut scx, krate)?;
-        }
-
-        // Build our search index
-        let index = build_index(&krate, &mut cache, tcx);
 
         let mut cx = Context {
             current: Vec::new(),
@@ -497,8 +512,16 @@ fn init(
             id_map: RefCell::new(id_map),
             shared: Rc::new(scx),
             cache: Rc::new(cache),
+            include_sources,
         };
 
+        if emit_crate {
+            krate = sources::render(&mut cx, krate)?;
+        }
+
+        // Build our search index
+        let index = build_index(&krate, Rc::get_mut(&mut cx.cache).unwrap(), tcx);
+
         // Write shared runs within a flock; disable thread dispatching of IO temporarily.
         Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
         write_shared(&cx, &krate, index, &md_opts)?;
@@ -514,6 +537,7 @@ fn make_child_renderer(&self) -> Self {
             id_map: RefCell::new(IdMap::new()),
             shared: Rc::clone(&self.shared),
             cache: Rc::clone(&self.cache),
+            include_sources: self.include_sources,
         }
     }
 
index c05ea81ac1f36ca772e81e9362de6163beeef3bd..fd2e18a8be77f0d3933d14c4e1174076649ec3d6 100644 (file)
 
 mod context;
 mod print_item;
+mod span_map;
 mod write_shared;
 
 crate use context::*;
+crate use span_map::{collect_spans_and_sources, LinkFromSrc};
 
 use std::collections::VecDeque;
 use std::default::Default;
index 5c30d8bbd173ceb46249add58f346fd9fec05ad4..f31305c76e642582b3306cdd3d07f1b02d5ba526 100644 (file)
@@ -119,7 +119,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
     // [src] link in the downstream documentation will actually come back to
     // this page, and this link will be auto-clicked. The `id` attribute is
     // used to find the link to auto-click.
-    if cx.shared.include_sources && !item.is_primitive() {
+    if cx.include_sources && !item.is_primitive() {
         write_srclink(cx, item, buf);
     }
 
@@ -1081,6 +1081,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             None,
             it.span(cx.tcx()).inner().edition(),
             None,
+            None,
         );
     });
     document(w, cx, it, None)
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
new file mode 100644 (file)
index 0000000..b35cd45
--- /dev/null
@@ -0,0 +1,164 @@
+use crate::clean;
+use crate::html::sources;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
+use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
+
+use std::path::{Path, PathBuf};
+
+/// This enum allows us to store two different kinds of information:
+///
+/// In case the `span` definition comes from the same crate, we can simply get the `span` and use
+/// it as is.
+///
+/// Otherwise, we store the definition `DefId` and will generate a link to the documentation page
+/// instead of the source code directly.
+#[derive(Debug)]
+crate enum LinkFromSrc {
+    Local(clean::Span),
+    External(DefId),
+}
+
+/// This function will do at most two things:
+///
+/// 1. Generate a `span` correspondance map which links an item `span` to its definition `span`.
+/// 2. Collect the source code files.
+///
+/// It returns the `krate`, the source code files and the `span` correspondance map.
+///
+/// Note about the `span` correspondance map: the keys are actually `(lo, hi)` of `span`s. We don't
+/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we
+/// only keep the `lo` and `hi`.
+crate fn collect_spans_and_sources(
+    tcx: TyCtxt<'_>,
+    krate: clean::Crate,
+    src_root: &Path,
+    include_sources: bool,
+    generate_link_to_definition: bool,
+) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+    let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
+
+    if include_sources {
+        if generate_link_to_definition {
+            intravisit::walk_crate(&mut visitor, tcx.hir().krate());
+        }
+        let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate);
+        (krate, sources, visitor.matches)
+    } else {
+        (krate, Default::default(), Default::default())
+    }
+}
+
+struct SpanMapVisitor<'tcx> {
+    crate tcx: TyCtxt<'tcx>,
+    crate matches: FxHashMap<Span, LinkFromSrc>,
+}
+
+impl<'tcx> SpanMapVisitor<'tcx> {
+    /// This function is where we handle `hir::Path` elements and add them into the "span map".
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, path_span: Option<Span>) {
+        let info = match path.res {
+            // FIXME: For now, we only handle `DefKind` if it's not `DefKind::TyParam` or
+            // `DefKind::Macro`. Would be nice to support them too alongside the other `DefKind`
+            // (such as primitive types!).
+            Res::Def(kind, def_id) if kind != DefKind::TyParam => {
+                if matches!(kind, DefKind::Macro(_)) {
+                    return;
+                }
+                Some(def_id)
+            }
+            Res::Local(_) => None,
+            Res::Err => return,
+            _ => return,
+        };
+        if let Some(span) = self.tcx.hir().res_span(path.res) {
+            self.matches.insert(
+                path_span.unwrap_or_else(|| path.span),
+                LinkFromSrc::Local(clean::Span::new(span)),
+            );
+        } else if let Some(def_id) = info {
+            self.matches
+                .insert(path_span.unwrap_or_else(|| path.span), LinkFromSrc::External(def_id));
+        }
+    }
+}
+
+impl Visitor<'tcx> for SpanMapVisitor<'tcx> {
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::All(self.tcx.hir())
+    }
+
+    fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
+        if !matches!(p.kind, GenericParamKind::Type { .. }) {
+            return;
+        }
+        for bound in p.bounds {
+            if let Some(trait_ref) = bound.trait_ref() {
+                self.handle_path(&trait_ref.path, None);
+            }
+        }
+    }
+
+    fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
+        self.handle_path(path, None);
+        intravisit::walk_path(self, path);
+    }
+
+    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
+        // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
+        // file, we want to link to it. Otherwise no need to create a link.
+        if !span.overlaps(m.inner) {
+            // Now that we confirmed it's a file import, we want to get the span for the module
+            // name only and not all the "mod foo;".
+            if let Some(node) = self.tcx.hir().find(id) {
+                match node {
+                    Node::Item(item) => {
+                        self.matches
+                            .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
+                    }
+                    _ => {}
+                }
+            }
+        }
+        intravisit::walk_mod(self, m, id);
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        match expr.kind {
+            ExprKind::MethodCall(segment, method_span, _, _) => {
+                if let Some(hir_id) = segment.hir_id {
+                    let hir = self.tcx.hir();
+                    let body_id = hir.enclosing_body_owner(hir_id);
+                    let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+                        self.tcx.typeck_body(
+                            hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+                        )
+                    });
+                    if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+                        self.matches.insert(
+                            method_span,
+                            match hir.span_if_local(def_id) {
+                                Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+                                None => LinkFromSrc::External(def_id),
+                            },
+                        );
+                    }
+                }
+            }
+            _ => {}
+        }
+        intravisit::walk_expr(self, expr);
+    }
+
+    fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
+        self.handle_path(path, None);
+        intravisit::walk_use(self, path, id);
+    }
+}
index 94a902a2d05225cb434b56454759d8b387457d31..c16769c474a2124b5abf63d5ddf17d41427f1bbc 100644 (file)
@@ -175,9 +175,45 @@ pub(super) fn write_shared(
         cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
     };
 
+    fn add_background_image_to_css(
+        cx: &Context<'_>,
+        css: &mut String,
+        rule: &str,
+        file: &'static str,
+    ) {
+        css.push_str(&format!(
+            "{} {{ background-image: url({}); }}",
+            rule,
+            SharedResource::ToolchainSpecific { basename: file }
+                .path(cx)
+                .file_name()
+                .unwrap()
+                .to_str()
+                .unwrap()
+        ))
+    }
+
+    // Add all the static files. These may already exist, but we just
+    // overwrite them anyway to make sure that they're fresh and up-to-date.
+    let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
+    add_background_image_to_css(
+        cx,
+        &mut rustdoc_css,
+        "details.undocumented[open] > summary::before, \
+         details.rustdoc-toggle[open] > summary::before, \
+         details.rustdoc-toggle[open] > summary.hideme::before",
+        "toggle-minus.svg",
+    );
+    add_background_image_to_css(
+        cx,
+        &mut rustdoc_css,
+        "details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
+        "toggle-plus.svg",
+    );
+    write_minify("rustdoc.css", &rustdoc_css)?;
+
     // Add all the static files. These may already exist, but we just
     // overwrite them anyway to make sure that they're fresh and up-to-date.
-    write_minify("rustdoc.css", static_files::RUSTDOC_CSS)?;
     write_minify("settings.css", static_files::SETTINGS_CSS)?;
     write_minify("noscript.css", static_files::NOSCRIPT_CSS)?;
 
@@ -217,6 +253,8 @@ pub(super) fn write_shared(
     write_toolchain("wheel.svg", static_files::WHEEL_SVG)?;
     write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?;
     write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
+    write_toolchain("toggle-minus.svg", static_files::TOGGLE_MINUS_PNG)?;
+    write_toolchain("toggle-plus.svg", static_files::TOGGLE_PLUS_PNG)?;
 
     let mut themes: Vec<&String> = themes.iter().collect();
     themes.sort();
@@ -234,7 +272,7 @@ pub(super) fn write_shared(
     write_minify("search.js", static_files::SEARCH_JS)?;
     write_minify("settings.js", static_files::SETTINGS_JS)?;
 
-    if cx.shared.include_sources {
+    if cx.include_sources {
         write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
     }
 
@@ -360,7 +398,7 @@ fn to_json_string(&self) -> String {
         }
     }
 
-    if cx.shared.include_sources {
+    if cx.include_sources {
         let mut hierarchy = Hierarchy::new(OsString::new());
         for source in cx
             .shared
index 80dd7a7a952f0071fd6501cb29053b6894a7b9fc..73916e204d9426aa805a9e8915f0ac5bdcccd83f 100644 (file)
@@ -5,8 +5,10 @@
 use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::layout;
-use crate::html::render::{SharedContext, BASIC_KEYWORDS};
+use crate::html::render::{Context, BASIC_KEYWORDS};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use std::fs;
 use std::path::{Component, Path, PathBuf};
 
-crate fn render(
-    dst: &Path,
-    scx: &mut SharedContext<'_>,
-    krate: clean::Crate,
-) -> Result<clean::Crate, Error> {
+crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> {
     info!("emitting source files");
-    let dst = dst.join("src").join(&*krate.name.as_str());
-    scx.ensure_dir(&dst)?;
-    let mut folder = SourceCollector { dst, scx };
+    let dst = cx.dst.join("src").join(&*krate.name.as_str());
+    cx.shared.ensure_dir(&dst)?;
+    let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
     Ok(folder.fold_crate(krate))
 }
 
+crate fn collect_local_sources<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    src_root: &Path,
+    krate: clean::Crate,
+) -> (clean::Crate, FxHashMap<PathBuf, String>) {
+    let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
+
+    let krate = lsc.fold_crate(krate);
+    (krate, lsc.local_sources)
+}
+
+struct LocalSourcesCollector<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    local_sources: FxHashMap<PathBuf, String>,
+    src_root: &'a Path,
+}
+
+fn is_real_and_local(span: clean::Span, sess: &Session) -> bool {
+    span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE
+}
+
+impl LocalSourcesCollector<'_, '_> {
+    fn add_local_source(&mut self, item: &clean::Item) {
+        let sess = self.tcx.sess;
+        let span = item.span(self.tcx);
+        // skip all synthetic "files"
+        if !is_real_and_local(span, sess) {
+            return;
+        }
+        let filename = span.filename(sess);
+        let p = match filename {
+            FileName::Real(ref file) => match file.local_path() {
+                Some(p) => p.to_path_buf(),
+                _ => return,
+            },
+            _ => return,
+        };
+        if self.local_sources.contains_key(&*p) {
+            // We've already emitted this source
+            return;
+        }
+
+        let mut href = String::new();
+        clean_path(&self.src_root, &p, false, |component| {
+            href.push_str(&component.to_string_lossy());
+            href.push('/');
+        });
+
+        let src_fname = p.file_name().expect("source has no filename").to_os_string();
+        let mut fname = src_fname.clone();
+        fname.push(".html");
+        href.push_str(&fname.to_string_lossy());
+        self.local_sources.insert(p, href);
+    }
+}
+
+impl DocFolder for LocalSourcesCollector<'_, '_> {
+    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+        self.add_local_source(&item);
+
+        // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
+        // we could return None here without having to walk the rest of the crate.
+        Some(self.fold_item_recur(item))
+    }
+}
+
 /// Helper struct to render all source code to HTML pages
 struct SourceCollector<'a, 'tcx> {
-    scx: &'a mut SharedContext<'tcx>,
+    cx: &'a mut Context<'tcx>,
 
     /// Root destination to place all HTML output into
     dst: PathBuf,
+    emitted_local_sources: FxHashSet<PathBuf>,
 }
 
 impl DocFolder for SourceCollector<'_, '_> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+        let tcx = self.cx.tcx();
+        let span = item.span(tcx);
+        let sess = tcx.sess;
+
         // If we're not rendering sources, there's nothing to do.
         // If we're including source files, and we haven't seen this file yet,
         // then we need to render it out to the filesystem.
-        if self.scx.include_sources
-            // skip all synthetic "files"
-            && item.span(self.scx.tcx).filename(self.sess()).is_real()
-            // skip non-local files
-            && item.span(self.scx.tcx).cnum(self.sess()) == LOCAL_CRATE
-        {
-            let filename = item.span(self.scx.tcx).filename(self.sess());
+        if self.cx.include_sources && is_real_and_local(span, sess) {
+            let filename = span.filename(sess);
+            let span = span.inner();
+            let pos = sess.source_map().lookup_source_file(span.lo());
+            let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_pos);
             // If it turns out that we couldn't read this file, then we probably
             // can't read any of the files (generating html output from json or
             // something like that), so just don't include sources for the
             // entire crate. The other option is maintaining this mapping on a
             // per-file basis, but that's probably not worth it...
-            self.scx.include_sources = match self.emit_source(&filename) {
+            self.cx.include_sources = match self.emit_source(&filename, file_span) {
                 Ok(()) => true,
                 Err(e) => {
-                    self.scx.tcx.sess.span_err(
-                        item.span(self.scx.tcx).inner(),
+                    self.cx.shared.tcx.sess.span_err(
+                        span,
                         &format!(
                             "failed to render source code for `{}`: {}",
                             filename.prefer_local(),
-                            e
+                            e,
                         ),
                     );
                     false
@@ -73,12 +140,12 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
 }
 
 impl SourceCollector<'_, 'tcx> {
-    fn sess(&self) -> &'tcx Session {
-        &self.scx.tcx.sess
-    }
-
     /// Renders the given filename into its corresponding HTML source file.
-    fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
+    fn emit_source(
+        &mut self,
+        filename: &FileName,
+        file_span: rustc_span::Span,
+    ) -> Result<(), Error> {
         let p = match *filename {
             FileName::Real(ref file) => {
                 if let Some(local_path) = file.local_path() {
@@ -89,7 +156,7 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
             }
             _ => return Ok(()),
         };
-        if self.scx.local_sources.contains_key(&*p) {
+        if self.emitted_local_sources.contains(&*p) {
             // We've already emitted this source
             return Ok(());
         }
@@ -107,20 +174,17 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
         // Create the intermediate directories
         let mut cur = self.dst.clone();
         let mut root_path = String::from("../../");
-        let mut href = String::new();
-        clean_path(&self.scx.src_root, &p, false, |component| {
+        clean_path(&self.cx.shared.src_root, &p, false, |component| {
             cur.push(component);
             root_path.push_str("../");
-            href.push_str(&component.to_string_lossy());
-            href.push('/');
         });
-        self.scx.ensure_dir(&cur)?;
+
+        self.cx.shared.ensure_dir(&cur)?;
 
         let src_fname = p.file_name().expect("source has no filename").to_os_string();
         let mut fname = src_fname.clone();
         fname.push(".html");
         cur.push(&fname);
-        href.push_str(&fname.to_string_lossy());
 
         let title = format!("{} - source", src_fname.to_string_lossy());
         let desc = format!("Source of the Rust file `{}`.", filename.prefer_remapped());
@@ -128,23 +192,25 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
             title: &title,
             css_class: "source",
             root_path: &root_path,
-            static_root_path: self.scx.static_root_path.as_deref(),
+            static_root_path: self.cx.shared.static_root_path.as_deref(),
             description: &desc,
             keywords: BASIC_KEYWORDS,
-            resource_suffix: &self.scx.resource_suffix,
-            extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)],
-            static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
+            resource_suffix: &self.cx.shared.resource_suffix,
+            extra_scripts: &[&format!("source-files{}", self.cx.shared.resource_suffix)],
+            static_extra_scripts: &[&format!("source-script{}", self.cx.shared.resource_suffix)],
         };
         let v = layout::render(
-            &self.scx.templates,
-            &self.scx.layout,
+            &self.cx.shared.templates,
+            &self.cx.shared.layout,
             &page,
             "",
-            |buf: &mut _| print_src(buf, contents, self.scx.edition()),
-            &self.scx.style_files,
+            |buf: &mut _| {
+                print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+            },
+            &self.cx.shared.style_files,
         );
-        self.scx.fs.write(&cur, v.as_bytes())?;
-        self.scx.local_sources.insert(p, href);
+        self.cx.shared.fs.write(&cur, v.as_bytes())?;
+        self.emitted_local_sources.insert(p);
         Ok(())
     }
 }
@@ -178,7 +244,14 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
 
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
+fn print_src(
+    buf: &mut Buffer,
+    s: &str,
+    edition: Edition,
+    file_span: rustc_span::Span,
+    context: &Context<'_>,
+    root_path: &str,
+) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
     let mut cols = 0;
@@ -192,5 +265,14 @@ fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
         writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
     }
     line_numbers.write_str("</pre>");
-    highlight::render_with_highlighting(s, buf, None, None, None, edition, Some(line_numbers));
+    highlight::render_with_highlighting(
+        s,
+        buf,
+        None,
+        None,
+        None,
+        edition,
+        Some(line_numbers),
+        Some(highlight::ContextInfo { context, file_span, root_path }),
+    );
 }
index 91243a4086ced2f2fc2fa9948ede2b0ffb2beb80..bbc48f49e63e184d98b6438af0213a627d81b5f4 100644 (file)
@@ -450,6 +450,10 @@ nav.sub {
        border-bottom-left-radius: 5px;
 }
 
+.example-wrap > pre.rust a:hover {
+       text-decoration: underline;
+}
+
 .rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
        width: 100%;
        overflow-x: auto;
@@ -1508,11 +1512,35 @@ details.rustdoc-toggle > summary.hideme > span {
 }
 
 details.rustdoc-toggle > summary::before {
-       content: "[+]";
-       font-weight: 300;
-       font-size: 0.8em;
-       letter-spacing: 1px;
+       content: "";
        cursor: pointer;
+       width: 17px;
+       height: max(17px, 1.1em);
+       background-repeat: no-repeat;
+       background-position: top left;
+       display: inline-block;
+       vertical-align: middle;
+       opacity: .5;
+}
+
+/* Screen readers see the text version at the end the line.
+       Visual readers see the icon at the start of the line, but small and transparent. */
+details.rustdoc-toggle > summary::after {
+       content: "Expand";
+       overflow: hidden;
+       width: 0;
+       height: 0;
+       position: absolute;
+}
+
+details.rustdoc-toggle > summary.hideme::after {
+       /* "hideme" toggles already have a description when they're contracted */
+       content: "";
+}
+
+details.rustdoc-toggle > summary:focus::before,
+details.rustdoc-toggle > summary:hover::before {
+       opacity: 1;
 }
 
 details.rustdoc-toggle.top-doc > summary,
@@ -1560,20 +1588,44 @@ details.rustdoc-toggle[open] > summary.hideme > span {
        display: none;
 }
 
-details.rustdoc-toggle[open] > summary::before {
-       content: "[−]";
-       display: inline;
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+       width: 17px;
+       height: max(17px, 1.1em);
+       background-repeat: no-repeat;
+       background-position: top left;
+       display: inline-block;
+       content: "";
+}
+
+details.rustdoc-toggle[open] > summary::after,
+details.rustdoc-toggle[open] > summary.hideme::after {
+       content: "Collapse";
 }
 
 details.undocumented > summary::before {
-       content: "[+] Show hidden undocumented items";
+       padding-left: 17px;
+       height: max(17px, 1.1em);
+       background-repeat: no-repeat;
+       background-position: top left;
+       content: "Show hidden undocumented items";
        cursor: pointer;
        font-size: 16px;
        font-weight: 300;
+       opacity: .5;
+}
+
+details.undocumented > summary:focus::before,
+details.undocumented > summary:hover::before {
+       opacity: 1;
 }
 
 details.undocumented[open] > summary::before {
-       content: "[−] Hide undocumented items";
+       padding-left: 17px;
+       height: max(17px, 1.1em);
+       background-repeat: no-repeat
+       background-position: top left;
+       content: "Hide undocumented items";
 }
 
 /* Media Queries */
index df386fb66a33f4c9d309d03e97ba441fa062b59e..849924ea5501e1d92f85bbc8be650907a4e11fbb 100644 (file)
@@ -229,6 +229,11 @@ details.undocumented > summary::before {
        color: #999;
 }
 
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
+       filter: invert(100%);
+}
+
 #crate-search {
        color: #c5c5c5;
        background-color: #141920;
index c8a5dbdc66aaf98832a0f07e6d7fb0b46994db7b..c26122e4bffb5844ad3617806026713877a65597 100644 (file)
@@ -194,6 +194,11 @@ details.undocumented > summary::before {
        color: #999;
 }
 
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
+       filter: invert(100%);
+}
+
 #crate-search {
        color: #111;
        background-color: #f0f0f0;
diff --git a/src/librustdoc/html/static/images/toggle-minus.svg b/src/librustdoc/html/static/images/toggle-minus.svg
new file mode 100644 (file)
index 0000000..7315478
--- /dev/null
@@ -0,0 +1 @@
+<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>
\ No newline at end of file
diff --git a/src/librustdoc/html/static/images/toggle-plus.svg b/src/librustdoc/html/static/images/toggle-plus.svg
new file mode 100644 (file)
index 0000000..08b1703
--- /dev/null
@@ -0,0 +1 @@
+<svg width="17" height="17" shape-rendering="crispEdges" stroke="#000" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>
\ No newline at end of file
index 2ec7e66234ddd21061e8050b5ed6ca6bda77fc31..6f3d08ea655691350729431fad47730689b2edf2 100644 (file)
 /// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
 crate static DOWN_ARROW_SVG: &[u8] = include_bytes!("static/images/down-arrow.svg");
 
+/// The file contents of `toggle-minus.svg`, the icon used for opened toggles.
+crate static TOGGLE_MINUS_PNG: &[u8] = include_bytes!("static/images/toggle-minus.svg");
+
+/// The file contents of `toggle-plus.svg`, the icon used for closed toggles.
+crate static TOGGLE_PLUS_PNG: &[u8] = include_bytes!("static/images/toggle-plus.svg");
+
 /// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
 /// output.
 crate static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt");
index fa755777584f3cdacb58abe4cc4aa6722ce4d7e9..a98725e683cb6d678052602bf490dfc5b0fec64d 100644 (file)
@@ -607,6 +607,13 @@ fn opts() -> Vec<RustcOptGroup> {
         unstable("nocapture", |o| {
             o.optflag("", "nocapture", "Don't capture stdout and stderr of tests")
         }),
+        unstable("generate-link-to-definition", |o| {
+            o.optflag(
+                "",
+                "generate-link-to-definition",
+                "Make the identifiers in the HTML source code pages navigable",
+            )
+        }),
     ]
 }
 
index ddb7b85d34a0483aae6300ae5695d99affdf3e66..cbe528a5ae0adfeb08547e8603453b6ea6f77736 100644 (file)
@@ -293,7 +293,7 @@ fn variant_field(
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
-            module_id: module_id.into(),
+            module_id: module_id,
             partial_res: None,
             unresolved: path_str.into(),
         };
@@ -521,7 +521,7 @@ fn resolve<'path>(
                     // but the disambiguator logic expects the associated item.
                     // Store the kind in a side channel so that only the disambiguator logic looks at it.
                     if let Some((kind, id)) = side_channel {
-                        self.kind_side_channel.set(Some((kind, id.into())));
+                        self.kind_side_channel.set(Some((kind, id)));
                     }
                     Ok((res, Some(fragment)))
                 };
@@ -1244,11 +1244,8 @@ fn resolve_link(
                     item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
                 })
             {
-                let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
-                let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
-
-                if self.cx.tcx.privacy_access_levels(()).is_exported(hir_src)
-                    && !self.cx.tcx.privacy_access_levels(()).is_exported(hir_dst)
+                if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
+                    && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
                 {
                     privacy_error(self.cx, &diag_info, &path_str);
                 }
@@ -1268,7 +1265,7 @@ fn resolve_link(
                     // doesn't allow statements like `use str::trim;`, making this a (hopefully)
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
-                    verify(kind, id.into())?;
+                    verify(kind, id)?;
 
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
@@ -1306,9 +1303,9 @@ fn resolve_link(
                 Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
             }
             Res::Def(kind, id) => {
-                verify(kind, id.into())?;
+                verify(kind, id)?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
-                Some(ItemLink { link: ori_link.link, link_text, did: Some(id.into()), fragment })
+                Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
             }
         }
     }
@@ -1886,7 +1883,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
                             if let Some(res) =
-                                collector.check_full_res(ns, &start, module_id.into(), &None)
+                                collector.check_full_res(ns, &start, module_id, &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
index 91c495a2bbc069d95cb1c898657bcc3dcdfd7cb1..eefe50caa345e85548377051cc9e7d10bb0c1a08 100644 (file)
@@ -45,7 +45,7 @@
 
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
                 if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
-                    let impls = get_auto_trait_and_blanket_impls(cx, def_id.into());
+                    let impls = get_auto_trait_and_blanket_impls(cx, def_id);
                     new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
                 }
             });
index d74b3b4627284321b391a4de5363ef2517e3a5aa..e28910355357b29b50eb9c69fcbab79ee60b743c 100644 (file)
@@ -192,7 +192,7 @@ fn maybe_inline_local(
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.map.insert(did.into(), AccessLevel::Public);
+                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
                     }
                 }
             }
@@ -204,7 +204,7 @@ fn maybe_inline_local(
             None => return false,
         };
 
-        let is_private = !self.cx.cache.access_levels.is_public(res_did.into());
+        let is_private = !self.cx.cache.access_levels.is_public(res_did);
         let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
 
         // Only inline if requested or if the item would otherwise be stripped.
index e038ed704513d900656259f6f1aa77f8a15f5d15..668d023af96a5512e758227d048a0ce426d4e878 100644 (file)
@@ -4,7 +4,7 @@
 
 #![crate_type = "lib"]
 #![feature(c_variadic)]
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 #![no_std]
 use core::ffi::VaList;
 
@@ -13,7 +13,6 @@
     fn foreign_c_variadic_1(_: VaList, ...);
 }
 
-#[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_0() {
     // Ensure that we correctly call foreign C-variadic functions.
     // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0)
 
 // Ensure that we do not remove the `va_list` passed to the foreign function when
 // removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
-#[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
     // CHECK: call void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap)
     foreign_c_variadic_1(ap);
 }
 
-#[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
     // CHECK: call void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
     foreign_c_variadic_1(ap, 42i32);
 }
-#[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
     // CHECK: call void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
     foreign_c_variadic_1(ap, 2i32, 42i32);
 }
 
-#[unwind(aborts)] // FIXME(#58794)
 pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
     // CHECK: call void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
     foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
index 7ff9c0d15e003a871234cdae8908bd2e345fd3a1..b89c590add0d788cde7517b53375f59f0318620b 100644 (file)
@@ -10,6 +10,7 @@
 // ignore-riscv64 FIXME
 
 #![crate_type = "lib"]
+#![feature(c_unwind)]
 
 extern "C" {
     fn bar();
index f09770af2cb0426145ac75eb82541af7a2156225..b36e9ae88f4550d6bce58a39f64a0456d9032a0a 100644 (file)
@@ -4,7 +4,7 @@
 
 // We need a function which is normally called through the PLT.
 extern "C" {
-    // CHECK: Function Attrs: nounwind nonlazybind
+    // CHECK: Function Attrs:{{.*}}nonlazybind
     fn getenv(name: *const u8) -> *mut u8;
 }
 
diff --git a/src/test/codegen/try-panic-abort.rs b/src/test/codegen/try-panic-abort.rs
deleted file mode 100644 (file)
index 166d2bb..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// compile-flags: -C panic=abort -O
-
-#![crate_type = "lib"]
-#![feature(unwind_attributes, core_intrinsics)]
-
-extern "C" {
-    #[unwind(allow)]
-    fn bar(data: *mut u8);
-}
-extern "Rust" {
-    fn catch(data: *mut u8, exception: *mut u8);
-}
-
-// CHECK-LABEL: @foo
-#[no_mangle]
-pub unsafe fn foo() -> i32 {
-    // CHECK: call void @bar
-    // CHECK: ret i32 0
-    std::intrinsics::r#try(|x| bar(x), 0 as *mut u8, |x, y| catch(x, y))
-}
index afd65ff6741a654e62669b7a148fe6a28d40a4eb..398937a04c9236bfade8d7defb02ae9858665700 100644 (file)
@@ -1,18 +1,22 @@
-// compile-flags: -C panic=abort -C opt-level=0
+// compile-flags: -C panic=abort
 
-// Test that `nounwind` atributes are applied to `C-unwind` extern functions when the
-// code is compiled with `panic=abort`.  We disable optimizations above to prevent LLVM from
-// inferring the attribute.
+// Test that `nounwind` atributes are not applied to `C-unwind` extern functions
+// even when the code is compiled with `panic=abort`.
 
 #![crate_type = "lib"]
 #![feature(c_unwind)]
 
-// CHECK: @rust_item_that_can_unwind() unnamed_addr #0 {
+extern "C-unwind" {
+    fn may_unwind();
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #0
 #[no_mangle]
-pub extern "C-unwind" fn rust_item_that_can_unwind() {
+pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() {
+    may_unwind();
 }
 
 // Now, make sure that the LLVM attributes for this functions are correct.  First, make
 // sure that the first item is correctly marked with the `nounwind` attribute:
 //
-// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+// CHECK-NOT: attributes #0 = { {{.*}}nounwind{{.*}} }
diff --git a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs
new file mode 100644 (file)
index 0000000..9a4b3d3
--- /dev/null
@@ -0,0 +1,16 @@
+// compile-flags: -C opt-level=0 -Cpanic=abort
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+
+// We disable optimizations to prevent LLVM from infering the attribute.
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @foo
+#[no_mangle]
+pub extern "C" fn foo() {}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @bar
+#[no_mangle]
+pub fn bar() {}
diff --git a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
new file mode 100644 (file)
index 0000000..2783c83
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-flags: -C opt-level=0
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+
+// We disable optimizations to prevent LLVM from infering the attribute.
+
+extern "C" {
+    fn bar();
+}
+
+// CHECK-NOT: Function Attrs:{{.*}}nounwind
+pub unsafe extern "C" fn foo() {
+    bar();
+}
+
+// Note that this test will get removed when `C-unwind` is fully stabilized
diff --git a/src/test/codegen/unwind-abis/nounwind.rs b/src/test/codegen/unwind-abis/nounwind.rs
new file mode 100644 (file)
index 0000000..cfc1403
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-flags: -C opt-level=0 -Cpanic=abort
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+// We disable optimizations to prevent LLVM from infering the attribute.
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @foo
+#[no_mangle]
+pub extern "C" fn foo() {}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: @bar
+#[no_mangle]
+pub fn bar() {}
diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs
new file mode 100644 (file)
index 0000000..05d97f3
--- /dev/null
@@ -0,0 +1,16 @@
+// compile-flags: -C panic=abort
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+extern "C-unwind" {
+    fn bar();
+}
+
+// CHECK: Function Attrs:{{.*}}nounwind
+// CHECK-NEXT: define{{.*}}void @foo
+// CHECK: call void @llvm.trap()
+#[no_mangle]
+pub unsafe extern "C" fn foo() {
+    bar();
+}
index 487de20671a2c0bffda69955eab1be4ac79926b6..c939235fb5006c121d4afa0c5402b0e2a21a58d9 100644 (file)
@@ -2,19 +2,15 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
 #![crate_type = "lib"]
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 
 // Make sure these all do *not* get the attribute.
 // We disable optimizations to prevent LLVM from infering the attribute.
 // CHECK-NOT: nounwind
 
 // "C" ABI
-// pub extern fn foo() {} // FIXME right now we don't abort-on-panic but add `nounwind` nevertheless
-#[unwind(allowed)]
-pub extern "C" fn foo_allowed() {}
+pub extern "C-unwind" fn foo_unwind() {}
 
 // "Rust"
 // (`extern "Rust"` could be removed as all `fn` get it implicitly; we leave it in for clarity.)
-pub extern "Rust" fn bar() {}
-#[unwind(allowed)]
-pub extern "Rust" fn bar_allowed() {}
+pub fn bar() {}
index e28397eb1392d02c39fca5e539f51961573169ed..e33e3e80521c1935c0c837038122c8e4b641aaa2 100644 (file)
@@ -2,41 +2,21 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
 #![crate_type = "lib"]
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 
 extern "C" {
-// CHECK: Function Attrs:{{.*}}nounwind
-// CHECK-NEXT: declare{{.*}}void @extern_fn
+    // CHECK: Function Attrs:{{.*}}nounwind
+    // CHECK-NEXT: declare{{.*}}void @extern_fn
     fn extern_fn();
-// CHECK-NOT: Function Attrs:{{.*}}nounwind
-// CHECK: declare{{.*}}void @unwinding_extern_fn
-    #[unwind(allowed)]
-    fn unwinding_extern_fn();
-// CHECK-NOT: nounwind
-// CHECK: declare{{.*}}void @aborting_extern_fn
-    #[unwind(aborts)]
-    fn aborting_extern_fn(); // FIXME: we want to have the attribute here
 }
 
-extern "Rust" {
-// CHECK-NOT: nounwind
-// CHECK: declare{{.*}}void @rust_extern_fn
-    fn rust_extern_fn();
-// CHECK-NOT: nounwind
-// CHECK: declare{{.*}}void @rust_unwinding_extern_fn
-    #[unwind(allowed)]
-    fn rust_unwinding_extern_fn();
-// CHECK-NOT: nounwind
-// CHECK: declare{{.*}}void @rust_aborting_extern_fn
-    #[unwind(aborts)]
-    fn rust_aborting_extern_fn(); // FIXME: we want to have the attribute here
+extern "C-unwind" {
+    // CHECK-NOT: nounwind
+    // CHECK: declare{{.*}}void @c_unwind_extern_fn
+    fn c_unwind_extern_fn();
 }
 
 pub unsafe fn force_declare() {
     extern_fn();
-    unwinding_extern_fn();
-    aborting_extern_fn();
-    rust_extern_fn();
-    rust_unwinding_extern_fn();
-    rust_aborting_extern_fn();
+    c_unwind_extern_fn();
 }
index 52e705fdbeba8eeeefd14a0364c91f885ca029d3..f72a12a5be0bca7852fa387310b4356a8253ea3b 100644 (file)
@@ -2,46 +2,47 @@
 + // MIR for `main` after SimplifyCfg-early-opt
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_cfg.rs:5:11: 5:11
-      let mut _1: ();                      // in scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
-      let mut _2: bool;                    // in scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
-      let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:7:18: 9:10
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_cfg.rs:7:11: 7:11
+      let mut _1: ();                      // in scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
+      let mut _2: bool;                    // in scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+      let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10
   
       bb0: {
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
+-         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
 -     }
 - 
 -     bb1: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         _2 = bar() -> bb2;               // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
-+         _2 = bar() -> bb1;               // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+-         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
++         _2 = bar() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
-                                           // + span: $DIR/simplify_cfg.rs:7:12: 7:15
+                                           // + span: $DIR/simplify_cfg.rs:9:12: 9:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
 -     bb2: {
--         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+-         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
 +     bb1: {
-+         switchInt(move _2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
++         switchInt(move _2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
       }
   
 -     bb3: {
 +     bb2: {
-          _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:9: 9:10
-          return;                          // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
+          _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
+          return;                          // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2
       }
   
 -     bb4: {
 +     bb3: {
-          _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:9:10: 9:10
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:9: 9:10
-          goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
--     }
-- 
+          _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
+          goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
+      }
+  
 -     bb5 (cleanup): {
--         resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
++     bb4 (cleanup): {
+          resume;                          // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
       }
   }
   
index fef3ae2e461d8304dd31813a7ab0ed8b094e587a..9857322053ff93572ad0d7bb1ecee4e4021cfd6e 100644 (file)
@@ -2,71 +2,71 @@
 + // MIR for `main` after SimplifyCfg-initial
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_cfg.rs:5:11: 5:11
-      let mut _1: ();                      // in scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
-      let mut _2: bool;                    // in scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
-      let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:7:18: 9:10
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify_cfg.rs:7:11: 7:11
+      let mut _1: ();                      // in scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
+      let mut _2: bool;                    // in scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+      let mut _3: !;                       // in scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10
   
       bb0: {
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
-+         falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
+-         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
++         falseUnwind -> [real: bb1, cleanup: bb5]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
       }
   
       bb1: {
--         falseUnwind -> [real: bb2, cleanup: bb10]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
+-         falseUnwind -> [real: bb2, cleanup: bb10]; // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
 -     }
 - 
 -     bb2: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         _2 = bar() -> [return: bb3, unwind: bb10]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
-+         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
+-         _2 = bar() -> [return: bb3, unwind: bb10]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
++         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
-                                           // + span: $DIR/simplify_cfg.rs:7:12: 7:15
+                                           // + span: $DIR/simplify_cfg.rs:9:12: 9:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
 -     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+-         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
 +     bb2: {
-+         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
++         switchInt(move _2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
       }
   
 -     bb4: {
 +     bb3: {
-          _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
--         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
-+         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:9: 9:10
-+         return;                          // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
+          _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
+-         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:10:13: 10:18
++         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
++         return;                          // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2
       }
   
 -     bb5: {
 +     bb4: {
-          _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:9:10: 9:10
--         goto -> bb8;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+          _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:11:10: 11:10
+-         goto -> bb8;                     // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
 -     }
 - 
 -     bb6: {
--         unreachable;                     // scope 0 at $DIR/simplify_cfg.rs:7:18: 9:10
+-         unreachable;                     // scope 0 at $DIR/simplify_cfg.rs:9:18: 11:10
 -     }
 - 
 -     bb7: {
--         goto -> bb8;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+-         goto -> bb8;                     // scope 0 at $DIR/simplify_cfg.rs:9:9: 11:10
 -     }
 - 
 -     bb8: {
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:9: 9:10
--         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
-+         goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
+-         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
++         goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:8:5: 12:6
       }
   
 -     bb9: {
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:9:9: 9:10
--         return;                          // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:11:9: 11:10
+-         return;                          // scope 0 at $DIR/simplify_cfg.rs:13:2: 13:2
 -     }
 - 
 -     bb10 (cleanup): {
 +     bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
+          resume;                          // scope 0 at $DIR/simplify_cfg.rs:7:1: 13:2
       }
   }
   
index c464005c4480de2dd7a5a48b57cdea3abf285dce..cf7eac4403a284530add300a15e06f49f1285f65 100644 (file)
@@ -1,4 +1,6 @@
 // Test that the goto chain starting from bb0 is collapsed.
+// compile-flags: -Cpanic=abort
+// no-prefer-dynamic
 
 // EMIT_MIR simplify_cfg.main.SimplifyCfg-initial.diff
 // EMIT_MIR simplify_cfg.main.SimplifyCfg-early-opt.diff
index 3b5d5eb42270277e09575ce6dd5679a6936cf553..00f46f42a078324a8bbd6fe8947f8f84c120d8e2 100644 (file)
@@ -1,70 +1,69 @@
-    1|       |#![feature(unwind_attributes)]
+    1|       |#![feature(c_unwind)]
     2|       |#![allow(unused_assignments)]
     3|       |
-    4|       |#[unwind(aborts)]
-    5|     12|fn might_abort(should_abort: bool) {
-    6|     12|    if should_abort {
-    7|      0|        println!("aborting...");
-    8|      0|        panic!("panics and aborts");
-    9|     12|    } else {
-   10|     12|        println!("Don't Panic");
-   11|     12|    }
-   12|     12|}
-   13|       |
-   14|      1|fn main() -> Result<(), u8> {
-   15|      1|    let mut countdown = 10;
-   16|     11|    while countdown > 0 {
-   17|     10|        if countdown < 5 {
-   18|      4|            might_abort(false);
-   19|      6|        }
-   20|       |        // See discussion (below the `Notes` section) on coverage results for the closing brace.
-   21|     10|        if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
+    4|     12|extern "C" fn might_abort(should_abort: bool) {
+    5|     12|    if should_abort {
+    6|      0|        println!("aborting...");
+    7|      0|        panic!("panics and aborts");
+    8|     12|    } else {
+    9|     12|        println!("Don't Panic");
+   10|     12|    }
+   11|     12|}
+   12|       |
+   13|      1|fn main() -> Result<(), u8> {
+   14|      1|    let mut countdown = 10;
+   15|     11|    while countdown > 0 {
+   16|     10|        if countdown < 5 {
+   17|      4|            might_abort(false);
+   18|      6|        }
+   19|       |        // See discussion (below the `Notes` section) on coverage results for the closing brace.
+   20|     10|        if countdown < 5 { might_abort(false); } // Counts for different regions on one line.
                                        ^4                     ^6
-   22|       |        // For the following example, the closing brace is the last character on the line.
-   23|       |        // This shows the character after the closing brace is highlighted, even if that next
-   24|       |        // character is a newline.
-   25|     10|        if countdown < 5 { might_abort(false); }
+   21|       |        // For the following example, the closing brace is the last character on the line.
+   22|       |        // This shows the character after the closing brace is highlighted, even if that next
+   23|       |        // character is a newline.
+   24|     10|        if countdown < 5 { might_abort(false); }
                                        ^4                     ^6
-   26|     10|        countdown -= 1;
-   27|       |    }
-   28|      1|    Ok(())
-   29|      1|}
-   30|       |
-   31|       |// Notes:
-   32|       |//   1. Compare this program and its coverage results to those of the similar tests
-   33|       |//      `panic_unwind.rs` and `try_error_result.rs`.
-   34|       |//   2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`.
-   35|       |//   3. The test does not invoke the abort. By executing to a successful completion, the coverage
-   36|       |//      results show where the program did and did not execute.
-   37|       |//   4. If the program actually aborted, the coverage counters would not be saved (which "works as
-   38|       |//      intended"). Coverage results would show no executed coverage regions.
-   39|       |//   6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
-   40|       |//      (on Linux at least).
-   41|       |
-   42|       |/*
-   43|       |
-   44|       |Expect the following coverage results:
-   45|       |
-   46|       |```text
-   47|       |    16|     11|    while countdown > 0 {
-   48|       |    17|     10|        if countdown < 5 {
-   49|       |    18|      4|            might_abort(false);
-   50|       |    19|      6|        }
-   51|       |```
-   52|       |
-   53|       |This is actually correct.
-   54|       |
-   55|       |The condition `countdown < 5` executed 10 times (10 loop iterations).
-   56|       |
-   57|       |It evaluated to `true` 4 times, and executed the `might_abort()` call.
-   58|       |
-   59|       |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
-   60|       |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
-   61|       |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
-   62|       |non-true condition.
-   63|       |
-   64|       |As another example of why this is important, say the condition was `countdown < 50`, which is always
-   65|       |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
-   66|       |The closing brace would have a count of `0`, highlighting the missed coverage.
-   67|       |*/
+   25|     10|        countdown -= 1;
+   26|       |    }
+   27|      1|    Ok(())
+   28|      1|}
+   29|       |
+   30|       |// Notes:
+   31|       |//   1. Compare this program and its coverage results to those of the similar tests
+   32|       |//      `panic_unwind.rs` and `try_error_result.rs`.
+   33|       |//   2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`.
+   34|       |//   3. The test does not invoke the abort. By executing to a successful completion, the coverage
+   35|       |//      results show where the program did and did not execute.
+   36|       |//   4. If the program actually aborted, the coverage counters would not be saved (which "works as
+   37|       |//      intended"). Coverage results would show no executed coverage regions.
+   38|       |//   6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status
+   39|       |//      (on Linux at least).
+   40|       |
+   41|       |/*
+   42|       |
+   43|       |Expect the following coverage results:
+   44|       |
+   45|       |```text
+   46|       |    16|     11|    while countdown > 0 {
+   47|       |    17|     10|        if countdown < 5 {
+   48|       |    18|      4|            might_abort(false);
+   49|       |    19|      6|        }
+   50|       |```
+   51|       |
+   52|       |This is actually correct.
+   53|       |
+   54|       |The condition `countdown < 5` executed 10 times (10 loop iterations).
+   55|       |
+   56|       |It evaluated to `true` 4 times, and executed the `might_abort()` call.
+   57|       |
+   58|       |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit
+   59|       |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s
+   60|       |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the
+   61|       |non-true condition.
+   62|       |
+   63|       |As another example of why this is important, say the condition was `countdown < 50`, which is always
+   64|       |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called.
+   65|       |The closing brace would have a count of `0`, highlighting the missed coverage.
+   66|       |*/
 
index 8569513e8425b19704879c584298ca63fe5332df..48983ba4358fb6c21d7baf6bf86fe7d66d2274aa 100644 (file)
    18|      2|        println!("BOOM times {}!!!", self.strength);
    19|      2|    }
   ------------------
-  | <generics::Firework<i32> as core::ops::drop::Drop>::drop:
+  | <generics::Firework<f64> as core::ops::drop::Drop>::drop:
   |   17|      1|    fn drop(&mut self) {
   |   18|      1|        println!("BOOM times {}!!!", self.strength);
   |   19|      1|    }
   ------------------
-  | <generics::Firework<f64> as core::ops::drop::Drop>::drop:
+  | <generics::Firework<i32> as core::ops::drop::Drop>::drop:
   |   17|      1|    fn drop(&mut self) {
   |   18|      1|        println!("BOOM times {}!!!", self.strength);
   |   19|      1|    }
index 018d264234468af4ca4a4415f9baf139b97fe9f0..768dcb2f6084cdc36abe9452ec3e499d3fb6747f 100644 (file)
    18|      2|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
    19|      2|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
index 52c6ff333e4ea7c24efe83cd0538d61bb6e77a40..3dac43df8f30d80f83b11494b46060cf20428b8c 100644 (file)
@@ -1,8 +1,7 @@
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 #![allow(unused_assignments)]
 
-#[unwind(aborts)]
-fn might_abort(should_abort: bool) {
+extern "C" fn might_abort(should_abort: bool) {
     if should_abort {
         println!("aborting...");
         panic!("panics and aborts");
index b5c8c1962a8ecc229af0ca5c8d265518aa4820e9..c279cf7e8bf10bcb77e5b150b909f00563a0149f 100644 (file)
@@ -4,7 +4,7 @@
 
 // For linking libstdc++ on MinGW
 #![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
@@ -18,22 +18,21 @@ fn drop(&mut self) {
 
 extern "C" {
     fn test_cxx_exception();
+}
 
-    #[unwind(allowed)]
-    fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool);
+extern "C-unwind" {
+    fn cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool);
 }
 
 #[no_mangle]
-#[unwind(allowed)]
-extern "C" fn rust_catch_callback(cb: extern "C" fn(), rust_ok: &mut bool) {
+extern "C-unwind" fn rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool) {
     let _drop = DropCheck(rust_ok);
     cb();
     unreachable!("should have unwound instead of returned");
 }
 
 fn test_rust_panic() {
-    #[unwind(allowed)]
-    extern "C" fn callback() {
+    extern "C-unwind" fn callback() {
         println!("throwing rust panic");
         panic!(1234i32);
     }
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs
new file mode 100644 (file)
index 0000000..87620d7
--- /dev/null
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used on nightly.
+
+// compile-flags: --generate-link-to-definition
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr
new file mode 100644 (file)
index 0000000..a8ddf91
--- /dev/null
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `generate-link-to-definition`
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs
new file mode 100644 (file)
index 0000000..8f4f561
--- /dev/null
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --output-format json
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr
new file mode 100644 (file)
index 0000000..4c8c607
--- /dev/null
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs
new file mode 100644 (file)
index 0000000..da51420
--- /dev/null
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --show-coverage
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr
new file mode 100644 (file)
index 0000000..4c8c607
--- /dev/null
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc/auxiliary/source-code-bar.rs b/src/test/rustdoc/auxiliary/source-code-bar.rs
new file mode 100644 (file)
index 0000000..8700d68
--- /dev/null
@@ -0,0 +1,17 @@
+//! just some other file. :)
+
+use crate::Foo;
+
+pub struct Bar {
+    field: Foo,
+}
+
+pub struct Bar2 {
+    field: crate::Foo,
+}
+
+pub mod sub {
+    pub trait Trait {
+        fn tadam() {}
+    }
+}
diff --git a/src/test/rustdoc/auxiliary/source_code.rs b/src/test/rustdoc/auxiliary/source_code.rs
new file mode 100644 (file)
index 0000000..72a5c1a
--- /dev/null
@@ -0,0 +1 @@
+pub struct SourceCode;
diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs
new file mode 100644 (file)
index 0000000..e3ae79c
--- /dev/null
@@ -0,0 +1,44 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
+// aux-build:source_code.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate source_code;
+
+// @has 'src/foo/check-source-code-urls-to-def.rs.html'
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
+#[path = "auxiliary/source-code-bar.rs"]
+pub mod bar;
+
+// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5-7"]' 4
+use bar::Bar;
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13-17"]' 'self'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
+use bar::sub::{self, Trait};
+
+pub struct Foo;
+
+impl Foo {
+    fn hello(&self) {}
+}
+
+fn babar() {}
+
+// @has - '//a/@href' '/struct.String.html'
+// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5
+// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
+pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
+    let x = 12;
+    let y: Foo = Foo;
+    let z: Bar = bar::Bar { field: Foo };
+    babar();
+    // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#24"]' 'hello'
+    y.hello();
+}
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
+pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V) {
+}
diff --git a/src/test/ui/asm/naked-functions-ffi.rs b/src/test/ui/asm/naked-functions-ffi.rs
new file mode 100644 (file)
index 0000000..5b2a8ed
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+// only-x86_64
+#![feature(asm)]
+#![feature(naked_functions)]
+#![crate_type = "lib"]
+
+#[naked]
+pub extern "C" fn naked(p: char) -> u128 {
+    //~^ WARN uses type `char`
+    //~| WARN uses type `u128`
+    unsafe { asm!("", options(noreturn)); }
+}
diff --git a/src/test/ui/asm/naked-functions-ffi.stderr b/src/test/ui/asm/naked-functions-ffi.stderr
new file mode 100644 (file)
index 0000000..a6772ba
--- /dev/null
@@ -0,0 +1,20 @@
+warning: `extern` fn uses type `char`, which is not FFI-safe
+  --> $DIR/naked-functions-ffi.rs:8:28
+   |
+LL | pub extern "C" fn naked(p: char) -> u128 {
+   |                            ^^^^ not FFI-safe
+   |
+   = note: `#[warn(improper_ctypes_definitions)]` on by default
+   = help: consider using `u32` or `libc::wchar_t` instead
+   = note: the `char` type has no C equivalent
+
+warning: `extern` fn uses type `u128`, which is not FFI-safe
+  --> $DIR/naked-functions-ffi.rs:8:37
+   |
+LL | pub extern "C" fn naked(p: char) -> u128 {
+   |                                     ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/asm/naked-functions-unused.rs b/src/test/ui/asm/naked-functions-unused.rs
new file mode 100644 (file)
index 0000000..e1f2362
--- /dev/null
@@ -0,0 +1,81 @@
+// only-x86_64
+#![deny(unused)]
+#![feature(asm)]
+#![feature(naked_functions)]
+#![crate_type = "lib"]
+
+pub trait Trait {
+    extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize;
+    extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize;
+}
+
+pub mod normal {
+    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+        //~^ ERROR unused variable: `a`
+        //~| ERROR unused variable: `b`
+        unsafe { asm!("", options(noreturn)); }
+    }
+
+    pub struct Normal;
+
+    impl Normal {
+        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+
+    impl super::Trait for Normal {
+        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+}
+
+pub mod naked {
+    #[naked]
+    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+        unsafe { asm!("", options(noreturn)); }
+    }
+
+    pub struct Naked;
+
+    impl Naked {
+        #[naked]
+        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        #[naked]
+        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+
+    impl super::Trait for Naked {
+        #[naked]
+        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        #[naked]
+        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+}
diff --git a/src/test/ui/asm/naked-functions-unused.stderr b/src/test/ui/asm/naked-functions-unused.stderr
new file mode 100644 (file)
index 0000000..8403533
--- /dev/null
@@ -0,0 +1,69 @@
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:13:37
+   |
+LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+   |                                     ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: the lint level is defined here
+  --> $DIR/naked-functions-unused.rs:2:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:13:47
+   |
+LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+   |                                               ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:22:43
+   |
+LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:22:53
+   |
+LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+   |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:28:46
+   |
+LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+   |                                              ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:28:56
+   |
+LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+   |                                                        ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:36:45
+   |
+LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                             ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:36:55
+   |
+LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                                       ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:42:48
+   |
+LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:42:58
+   |
+LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
index a46ca4544a68fbd46d3ece6d71449fbbece4fc54..7075995c2cfff5bd34568b0018c6ba2c40b0fe7b 100644 (file)
@@ -167,3 +167,46 @@ pub extern "C" fn valid_b() {
 pub unsafe extern "C" fn valid_att_syntax() {
     asm!("", options(noreturn, att_syntax));
 }
+
+#[naked]
+pub unsafe extern "C" fn inline_none() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_hint() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline(always)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_always() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline(never)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_never() {
+    asm!("", options(noreturn));
+}
+
+#[naked]
+#[inline]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+#[inline(always)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+#[inline(never)]
+//~^ WARN naked functions cannot be inlined
+//~| WARN this was previously accepted
+pub unsafe extern "C" fn inline_all() {
+    asm!("", options(noreturn));
+}
index 9a82da8d90d3c1179eb48d6a244204e2fb31613d..2a186a69ff4608b5ae6c4848d94f72c3350d90a0 100644 (file)
@@ -296,5 +296,59 @@ LL | pub unsafe extern "Rust" fn rust_abi() {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-error: aborting due to 8 previous errors; 19 warnings emitted
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:177:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:185:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:193:1
+   |
+LL | #[inline(never)]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:201:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:204:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+warning: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:207:1
+   |
+LL | #[inline(never)]
+   | ^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
+
+error: aborting due to 8 previous errors; 25 warnings emitted
 
index a5ebb80c836205a34c7fb7afa61e10f98e9f0078..bf18eee4e07ed3ada762875c5dc9cbc48d64ddb6 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between th
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                    ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
-   | 
+   |
   ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
 LL | pub unsafe auto trait Send {
@@ -20,7 +20,7 @@ error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
-   | 
+   |
   ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL | pub trait Iterator {
@@ -37,7 +37,7 @@ error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                                                                             ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
-   | 
+   |
   ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
 LL | pub unsafe auto trait Sync {
index 919b18632e61c1283b517432d034f092de2bca3b..46d472cdf80dbec9e5b14ce831c8ad4631848ac5 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
    |
 LL |     type A: Iterator<Item: Debug>;
    |                            ^^^^^ `<<Self as Case1>::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   | 
+   |
   ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    |
 LL | pub trait Debug {
@@ -20,7 +20,7 @@ error[E0277]: the trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is n
    |
 LL | pub trait Foo { type Out: Baz<Assoc: Default>; }
    |                                      ^^^^^^^ the trait `Default` is not implemented for `<<Self as Foo>::Out as Baz>::Assoc`
-   | 
+   |
   ::: $SRC_DIR/core/src/default.rs:LL:COL
    |
 LL | pub trait Default: Sized {
index 73ef567ffae6db158edd31d1f79f17644e2dd4c5..e837150c05d8bae7f364e12a29cb1b392a2498ed 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
    |
 LL |     type Ty = Vec<[u8]>;
    |               ^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
index 8fdca54d2d8b8ab6552b11680f31a3a46feb5b23..0afc380293370a54fb2e80a4a48d3f44a3e6c2ea 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}
    |                      ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL
    |
 LL | pub trait Add<Rhs = Self> {
index 654a3bcc92dd83dc6b7b3eb387056c65aa52bbdd..4dc5cafb98614ca06db17d11b52e75f3c7d6962d 100644 (file)
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/dont-suggest-missing-await.rs:14:18
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |         take_u32(x)
    |                  ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/dont-suggest-missing-await.rs:7:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
index 04f191cc5e8cb4cd72d44f71d80e3d6c96a5797d..d75e927696e106c369966d7d632d2e031b55cbbf 100644 (file)
@@ -12,16 +12,19 @@ LL |     fun(async {}, async {});
 error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:12:16
    |
-LL | async fn one() {}
-   |                - checked the `Output` of this `async fn`, expected opaque type
-LL | async fn two() {}
-   |                - checked the `Output` of this `async fn`, found opaque type
-...
 LL |     fun(one(), two());
    |                ^^^^^ expected opaque type, found a different opaque type
    |
-   = note: while checking the return type of the `async fn`
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/generator-desc.rs:5:16
+   |
+LL | async fn one() {}
+   |                ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/generator-desc.rs:6:16
+   |
+LL | async fn two() {}
+   |                ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:5:16>)
               found opaque type `impl Future` (opaque type at <$DIR/generator-desc.rs:6:16>)
    = help: consider `await`ing on both `Future`s
@@ -34,7 +37,7 @@ LL |     fun((async || {})(), (async || {})());
    |                   --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
    |                   |
    |                   the expected `async` closure body
-   | 
+   |
   ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
    |
 LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
index 9fe3313ee6cc67b6be36c46226102ecf0488df6c..220f0774e2d54281eeead56b5ba7ba1933bfc7f7 100644 (file)
@@ -57,6 +57,8 @@ async fn struct_() -> Struct {
 
 async fn tuple() -> Tuple {
     //~^ NOTE checked the `Output` of this `async fn`, expected opaque type
+    //~| NOTE while checking the return type of the `async fn`
+    //~| NOTE in this expansion of desugaring of `async` block or function
     Tuple(1i32)
 }
 
@@ -92,7 +94,6 @@ async fn match_() {
         Tuple(_) => {} //~ ERROR mismatched types
         //~^ NOTE expected opaque type, found struct `Tuple`
         //~| NOTE expected opaque type `impl Future`
-        //~| NOTE while checking the return type of the `async fn`
     }
 }
 
index ba97e135790c16a0ded828d8426afe0448f178c2..9fb2d5bc6cb42d098ce1e27ff67e5a1076854b62 100644 (file)
@@ -16,7 +16,7 @@ LL |     foo().await?;
    |          ^^^^^^
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/issue-61076.rs:65:5
+  --> $DIR/issue-61076.rs:67:5
    |
 LL |     t?;
    |     ^^ the `?` operator cannot be applied to type `T`
@@ -33,7 +33,7 @@ LL |     t.await?;
    |      ^^^^^^
 
 error[E0609]: no field `0` on type `impl Future`
-  --> $DIR/issue-61076.rs:76:26
+  --> $DIR/issue-61076.rs:78:26
    |
 LL |     let _: i32 = tuple().0;
    |                          ^ field not available in `impl Future`, but it is available in its `Output`
@@ -44,7 +44,7 @@ LL |     let _: i32 = tuple().await.0;
    |                         ^^^^^^
 
 error[E0609]: no field `a` on type `impl Future`
-  --> $DIR/issue-61076.rs:80:28
+  --> $DIR/issue-61076.rs:82:28
    |
 LL |     let _: i32 = struct_().a;
    |                            ^ field not available in `impl Future`, but it is available in its `Output`
@@ -55,7 +55,7 @@ LL |     let _: i32 = struct_().await.a;
    |                           ^^^^^^
 
 error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
-  --> $DIR/issue-61076.rs:84:15
+  --> $DIR/issue-61076.rs:86:15
    |
 LL |     struct_().method();
    |               ^^^^^^ method not found in `impl Future`
@@ -66,15 +66,16 @@ LL |     struct_().await.method();
    |               ^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/issue-61076.rs:92:9
+  --> $DIR/issue-61076.rs:94:9
    |
-LL | async fn tuple() -> Tuple {
-   |                     ----- checked the `Output` of this `async fn`, expected opaque type
-...
 LL |         Tuple(_) => {}
    |         ^^^^^^^^ expected opaque type, found struct `Tuple`
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-61076.rs:58:21
+   |
+LL | async fn tuple() -> Tuple {
+   |                     ^^^^^ checked the `Output` of this `async fn`, expected opaque type
    = note: expected opaque type `impl Future`
                    found struct `Tuple`
 help: consider `await`ing on the `Future`
index 52245b63128abe89d98668ac3616fec3c730c5c2..b586207a25ffde9411ada59feac9632e540c4124 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `Option<&str>: AsRef<Path>` is not satisfied
    |
 LL |             let mut f = File::open(path.to_str())?;
    |                                    ^^^^^^^^^^^^^ the trait `AsRef<Path>` is not implemented for `Option<&str>`
-   | 
+   |
   ::: $SRC_DIR/std/src/fs.rs:LL:COL
    |
 LL |     pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
index ea5c90a81d4f9ae7503958197b6e334a2ea3360a..39e50a106acab5571cda72024dc6a41ca06939d4 100644 (file)
@@ -6,7 +6,7 @@ LL | fn g(_: impl Send) {}
 ...
 LL |     g(issue_67893::run())
    |     ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
-   | 
+   |
   ::: $DIR/auxiliary/issue_67893.rs:7:20
    |
 LL | pub async fn run() {
index 0756a4d59c19b1fe3d19f16d72d540a7bb1d9e70..0714e666d387f4baa323f9ef698355efe75f4360 100644 (file)
@@ -6,7 +6,7 @@ LL | struct Sleep;
 ...
 LL |         self.sleep.poll(cx)
    |                    ^^^^ method not found in `Sleep`
-   | 
+   |
   ::: $SRC_DIR/core/src/future/future.rs:LL:COL
    |
 LL |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
index 483e52536a1b4eb8ba6d785ed957a8be35a6e6be..9d742049046b22a674196b19be37fb311af2a63d 100644 (file)
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await-closure.rs:16:18
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |         take_u32(x)
    |                  ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await-closure.rs:8:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
index 14b5ee95ee8ba6fa3df34fb88be34eadf9e23886..890f66c58d0f89fce20840d8681d2fac1551fd95 100644 (file)
@@ -1,13 +1,14 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:12:14
    |
-LL | async fn make_u32() -> u32 {
-   |                        --- checked the `Output` of this `async fn`, found opaque type
-...
 LL |     take_u32(x)
    |              ^ expected `u32`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await.rs:5:24
+   |
+LL | async fn make_u32() -> u32 {
+   |                        ^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `u32`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -18,13 +19,14 @@ LL |     take_u32(x.await)
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:22:5
    |
-LL | async fn dummy() {}
-   |                  - checked the `Output` of this `async fn`, found opaque type
-...
 LL |     dummy()
    |     ^^^^^^^ expected `()`, found opaque type
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await.rs:18:18
+   |
+LL | async fn dummy() {}
+   |                  ^ checked the `Output` of this `async fn`, found opaque type
    = note: expected unit type `()`
             found opaque type `impl Future`
 help: consider `await`ing on the `Future`
index 1d4b0d5b2b130e7dd5123e042de82cf692ccdb16..01a07ad3b0ee461fe9bbcd15c4da9963cc470118 100644 (file)
@@ -2,10 +2,12 @@ error: non-ASCII character in byte constant
   --> $DIR/key-value-non-ascii.rs:3:19
    |
 LL | #[rustc_dummy = b"ffi.rs"]
-   |                   ^
-   |                   |
-   |                   byte constant must be ASCII
-   |                   help: use a \xHH escape for a non-ASCII byte: `\xFB03`
+   |                   ^ byte constant must be ASCII
+   |
+help: if you meant to use the UTF-8 encoding of 'ffi', use \xHH escapes
+   |
+LL | #[rustc_dummy = b"/xEF/xAC/x83.rs"]
+   |                   ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 7821dc02bde3c45528ca1a993d00e4890cd85607..e7ecd0079f08d35aaba9b88db696206ff5fd725e 100644 (file)
@@ -6,7 +6,7 @@ LL |         let a = $c;
    |                 |
    |                 move occurs because `D` has type `A`, which does not implement the `Copy` trait
    |                 help: consider borrowing here: `&$c`
-   | 
+   |
   ::: $DIR/move-error-snippets.rs:21:1
    |
 LL | sss!();
index 78f62592960ffe844f4c9bb6d5384e09e970bb29..14e28174a295d8b85b0c8af361d6f60a0a5668c2 100644 (file)
@@ -75,7 +75,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -91,7 +91,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -107,7 +107,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -123,7 +123,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -139,7 +139,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
    |
 LL |     const SIZE: usize = core::mem::size_of::<Self>();
    |                                              ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
index 0d1d747272d1894412041736013c1fc330ef489c..64946c316cd1e78ac69f81884d6b1db709bdb4fc 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: `T` cannot be sent between threads safely
    |
 LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely
-   | 
+   |
   ::: $DIR/auxiliary/trait_superkinds_in_metadata.rs:7:58
    |
 LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { }
index ec7ee74aef29adc21b6df7ff11039e2bc5d54d65..b399f729f6506fb0bd0577bbf1a0ed68639a2391 100644 (file)
@@ -63,7 +63,7 @@ error[E0412]: cannot find type `F` in this scope
    |
 LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
    |                                                ^
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
 LL | pub trait Fn<Args>: FnMut<Args> {
index da5e25c0d18fa7061a71e23b7a46dda98fc8cace..b4e5db74e03486d1522d7a27c8f5f3c0a4c91843 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: `std::sync::mpsc::Receiver<()>` cannot be shared between threads s
    |
 LL |     let t = thread::spawn(|| {
    |             ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
-   | 
+   |
   ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
 LL |     F: Send + 'static,
@@ -18,7 +18,7 @@ error[E0277]: `Sender<()>` cannot be shared between threads safely
    |
 LL |     thread::spawn(|| tx.send(()).unwrap());
    |     ^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely
-   | 
+   |
   ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
 LL |     F: Send + 'static,
index a9f1d0eb657183adfeced65c396dc702e2ae9085..cc2c9c8681bccf997962bf3a8ddc325fac9b274c 100644 (file)
@@ -5,7 +5,7 @@ LL | pub const fn is_zst<T: ?Sized>() -> usize {
    |                     - this type parameter needs to be `std::marker::Sized`
 LL |     if std::mem::size_of::<T>() == 0 {
    |                            ^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
index 84b2665d5bfeddb5d3f7183686267c0efae32ce6..ce7ec4d90b6bf628d6e4c0ca59e29bf7ea05373a 100644 (file)
@@ -3,7 +3,7 @@ error: unconstrained generic constant
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
    |
 LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
@@ -16,7 +16,7 @@ error: unconstrained generic constant
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
    |
 LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
@@ -29,7 +29,7 @@ error: unconstrained generic constant
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
    |
 LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
@@ -42,7 +42,7 @@ error: unconstrained generic constant
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
    |
 LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
index 92541779213a4e33e90286785f2ac7e490358626..04503495bc62afef6f2405cde17fc6b12418c0fa 100644 (file)
@@ -6,12 +6,12 @@ LL |     unsafe { copy_nonoverlapping(src, dst, count) }
    |              |
    |              memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   | 
+   |
   ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
    |         --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   | 
+   |
   ::: $DIR/out_of_bounds_read.rs:13:33
    |
 LL |     const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
@@ -25,17 +25,17 @@ LL |     unsafe { copy_nonoverlapping(src, dst, count) }
    |              |
    |              memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   | 
+   |
   ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
    |         --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   | 
+   |
   ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
 LL |         unsafe { read(self) }
    |                  ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/out_of_bounds_read.rs:14:39
    |
 LL |     const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
@@ -49,17 +49,17 @@ LL |     unsafe { copy_nonoverlapping(src, dst, count) }
    |              |
    |              memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
    |              inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
-   | 
+   |
   ::: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
    |
 LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
    |         --------------------------------------------- inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   | 
+   |
   ::: $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
    |
 LL |         unsafe { read(self) }
    |                  ---------- inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/out_of_bounds_read.rs:15:37
    |
 LL |     const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
diff --git a/src/test/ui/consts/const-eval/partial_ptr_overwrite.rs b/src/test/ui/consts/const-eval/partial_ptr_overwrite.rs
new file mode 100644 (file)
index 0000000..5371f9f
--- /dev/null
@@ -0,0 +1,15 @@
+// Test for the behavior described in <https://github.com/rust-lang/rust/issues/87184>.
+#![feature(const_mut_refs, const_raw_ptr_deref)]
+
+const PARTIAL_OVERWRITE: () = {
+    let mut p = &42;
+    unsafe {
+        let ptr: *mut _ = &mut p;
+        *(ptr as *mut u8) = 123; //~ ERROR any use of this value
+        //~| unable to overwrite parts of a pointer
+        //~| WARN previously accepted
+    }
+    let x = *p;
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr b/src/test/ui/consts/const-eval/partial_ptr_overwrite.stderr
new file mode 100644 (file)
index 0000000..a18c7e7
--- /dev/null
@@ -0,0 +1,20 @@
+error: any use of this value will cause an error
+  --> $DIR/partial_ptr_overwrite.rs:8:9
+   |
+LL | / const PARTIAL_OVERWRITE: () = {
+LL | |     let mut p = &42;
+LL | |     unsafe {
+LL | |         let ptr: *mut _ = &mut p;
+LL | |         *(ptr as *mut u8) = 123;
+   | |         ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4
+...  |
+LL | |     let x = *p;
+LL | | };
+   | |__-
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to previous error
+
index 766a0c49be68afcf9fc85d3f2481faabf17bd2ce..89b5135fd37e386ab609e711f7619a340522e38e 100644 (file)
@@ -1,12 +1,11 @@
-#![feature(unwind_attributes, const_panic)]
+#![feature(c_unwind, const_panic, const_extern_fn)]
 
-#[unwind(aborts)]
-const fn foo() {
+const extern "C" fn foo() {
     panic!() //~ ERROR evaluation of constant value failed
 }
 
 const _: () = foo();
-// Ensure that the CTFE engine handles calls to `#[unwind(aborts)]` gracefully
+// Ensure that the CTFE engine handles calls to `extern "C"` aborting gracefully
 
 fn main() {
     let _ = foo();
index e3b871ee529bef3a7f3d58cf68581a464e43c6be..78ebd36abd86b14dcf8c28df78029d6aa2c50fab 100644 (file)
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/unwind-abort.rs:5:5
+  --> $DIR/unwind-abort.rs:4:5
    |
 LL |     panic!()
    |     ^^^^^^^^
    |     |
-   |     the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
+   |     the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:4:5
    |     inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
 ...
 LL | const _: () = foo();
-   |               ----- inside `_` at $DIR/unwind-abort.rs:8:15
+   |               ----- inside `_` at $DIR/unwind-abort.rs:7:15
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index ecdd0ca3f54c1bf995b840caf38afa1c3d50d99a..65cb3d74b233e3b20e97fd2d7229002b0ab587dc 100644 (file)
@@ -6,7 +6,7 @@ LL |     unsafe { intrinsics::unreachable() }
    |              |
    |              entering unreachable code
    |              inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL
-   | 
+   |
   ::: $DIR/const_unsafe_unreachable_ub.rs:7:18
    |
 LL |         false => std::hint::unreachable_unchecked(),
index f79dc454a83a08355f19a64adf35e617f32241d6..36db6b7865af2cf6333f773503889bb3a0e1a88c 100644 (file)
@@ -6,7 +6,7 @@ LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | |
    | calling non-const function `<Vec<i32> as Drop>::drop`
    | inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   | 
+   |
   ::: $DIR/drop.rs:18:1
    |
 LL | };
index 663bfbdade0ce932c660dadb1203daec2d16eee1..2478ff081d770ed1f86f8b3f6594f18527111f51 100644 (file)
@@ -12,7 +12,7 @@ LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                  |
    |                  0x2a is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_from_ub.rs:24:14
    |
 LL |     unsafe { (42 as *const u8).offset_from(&5u8) as usize }
index 66a2722ed4acd1d244f4c9818fe1589ddb35875f..4c3f373e0801c03eadb6f1610e86bdc046dda6ac 100644 (file)
@@ -6,7 +6,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  overflowing in-bounds pointer arithmetic
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:8:46
    |
 LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) };
@@ -20,7 +20,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:9:43
    |
 LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) };
@@ -34,7 +34,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:10:45
    |
 LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) };
@@ -48,7 +48,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  overflowing in-bounds pointer arithmetic
    |                  inside `ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:12:43
    |
 LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) };
@@ -62,7 +62,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  overflowing in-bounds pointer arithmetic
    |                  inside `ptr::const_ptr::<impl *const u16>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:13:44
    |
 LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
@@ -76,7 +76,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  overflowing in-bounds pointer arithmetic
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:14:56
    |
 LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) };
@@ -90,7 +90,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  overflowing in-bounds pointer arithmetic
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:15:57
    |
 LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) };
@@ -104,7 +104,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:16:49
    |
 LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) };
@@ -118,7 +118,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:18:50
    |
 LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) };
@@ -132,7 +132,7 @@ LL |         unsafe { intrinsics::offset(self, count) as *mut T }
    |                  |
    |                  0x1 is not a valid pointer
    |                  inside `ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:19:42
    |
 LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) };
@@ -146,7 +146,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: 0x0 is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:22:50
    |
 LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
@@ -160,7 +160,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  0x7f..f is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/offset_ub.rs:25:47
    |
 LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) };
index 6ae24c179ff1c838dff09e859328d831bdc7b74f..a28ae521d5b9a94a61993bb580356b06281c01b6 100644 (file)
@@ -6,7 +6,7 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  |
    |                  pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   | 
+   |
   ::: $DIR/ptr_comparisons.rs:61:34
    |
 LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
index f9011f908a75e90ae3cc0d875fb8fe6d0db48ec5..d9d0b91011d9a9e5c757b2a7d7b4614ff0e04ed2 100644 (file)
@@ -1,10 +1,9 @@
 // check-pass
 
-#![feature(unwind_attributes, const_panic)]
+#![feature(c_unwind, const_panic, const_extern_fn)]
 
-// `#[unwind(aborts)]` is okay for a `const fn`. We don't unwind in const-eval anyways.
-#[unwind(aborts)]
-const fn foo() {
+// We don't unwind in const-eval anyways.
+const extern "C" fn foo() {
     panic!()
 }
 
index 4f015bf2148beb45179c980024b6706238f8b9cc..ff9e87250c75dc81b7b353feaf2c23926c0e98f8 100644 (file)
@@ -3,7 +3,7 @@ error[E0658]: destructuring assignments are unstable
    |
 LL |         _
    |         ^
-   | 
+   |
   ::: $DIR/main.rs:5:5
    |
 LL |     underscore!();
@@ -18,7 +18,7 @@ error: in expressions, `_` can only be used on the left-hand side of an assignme
    |
 LL |         _
    |         ^ `_` not allowed here
-   | 
+   |
   ::: $DIR/main.rs:5:5
    |
 LL |     underscore!();
index 0a764053824562e9e265d3172dfb7bb7a0531b72..6267fad4372a44f5f3abe256589a71be85d088ff 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq,PartialEq)]
 ...
 LL |      x: Error
    |      ^^^^^^^^ the trait `Eq` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index c17e2c518aa76246498c77ecafed04f9a6140bc8..5dc407340019128f4dbcf5797611734140ea2199 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq,PartialEq)]
 ...
 LL |      Error
    |      ^^^^^ the trait `Eq` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index 7a7640b40f627980bcaedd7aa7b3b0dca9fa4b15..5fd21e2cd79008ce87d43bb97b683354eb258ba9 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq,PartialEq)]
 LL | struct Struct {
 LL |     x: Error
    |     ^^^^^^^^ the trait `Eq` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index 35932986b0499660fd2f6b6e1b8621a7e3b76be4..d96687f8bf2e274fd5027d727d2aab150d145f8c 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq,PartialEq)]
 LL | struct Struct(
 LL |     Error
    |     ^^^^^ the trait `Eq` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index 4616dadbe6bf7e7998c272f08901bcaf1aaa284b..557431ab5bc2a220b4e957cb2a366e59d8f8966e 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Hash)]
 ...
 LL |      x: Error
    |      ^^^^^^^^ the trait `Hash` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index ffc7f7bb7daafd2640ad7b97f02c3e09057efafe..531ad59ca3bf9a8d8a63bc2327a75817ca0de7d9 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Hash)]
 ...
 LL |      Error
    |      ^^^^^ the trait `Hash` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index 14aebb4faace9b898f8c929941712391f45e6452..2852a448c43fc2f072c44a42628f68c579c86166 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Hash)]
 LL | struct Struct {
 LL |     x: Error
    |     ^^^^^^^^ the trait `Hash` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index 50139dc3f0a7950824461cdbeb5d6d6d4724b1fd..93ae1b29702e997152d5c8cc61d4f05e4d79d89f 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Hash)]
 LL | struct Struct(
 LL |     Error
    |     ^^^^^ the trait `Hash` is not implemented for `Error`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index 485a91d02758a0dd260bb0b7aaaf906d459f0582..bfb673f86f4183b327c530783f09379347c21262 100644 (file)
@@ -3,7 +3,7 @@ error: cannot find derive macro `Eqr` in this scope
    |
 LL | #[derive(Eqr)]
    |          ^^^ help: a derive macro with a similar name exists: `Eq`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub macro Eq($item:item) {
@@ -14,7 +14,7 @@ error: cannot find derive macro `Eqr` in this scope
    |
 LL | #[derive(Eqr)]
    |          ^^^ help: a derive macro with a similar name exists: `Eq`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub macro Eq($item:item) {
index 28663563c6ccdf1079aea69293ca1398d0613f09..04d45758578a395c10f00cc79e4fb94072875a33 100644 (file)
@@ -37,7 +37,7 @@ error: macro expansion ends with an incomplete expression: expected one of `move
    |
 LL |     ($i: ident) => ($i)
    |                       ^ expected one of `move`, `|`, or `||`
-   | 
+   |
   ::: $DIR/edition-keywords-2018-2015-parsing.rs:24:8
    |
 LL |     if passes_ident!(async) == 1 {}
index cda7e65e437e85e1f31803096da47d7d1b4fd710..af11a505ccf36663e244830dcc067aa658ad990e 100644 (file)
@@ -37,7 +37,7 @@ error: macro expansion ends with an incomplete expression: expected one of `move
    |
 LL |     ($i: ident) => ($i)
    |                       ^ expected one of `move`, `|`, or `||`
-   | 
+   |
   ::: $DIR/edition-keywords-2018-2018-parsing.rs:24:8
    |
 LL |     if passes_ident!(async) == 1 {}
index 6292ed446978deed996fcd7e7ff972f51659b14e..5ee8cbd912b0e2e22dbcf5b9a881babca6cfaaee 100644 (file)
@@ -6,7 +6,7 @@ LL | struct Empty1 {}
 ...
 LL |     let e1 = Empty1;
    |              ^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
@@ -29,7 +29,7 @@ LL | struct Empty1 {}
 ...
 LL |     let e1 = Empty1();
    |              ^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
@@ -67,7 +67,7 @@ error[E0423]: expected value, found struct `XEmpty1`
    |
 LL |     let xe1 = XEmpty1;
    |               ^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
 LL | pub struct XEmpty1 {}
@@ -89,7 +89,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found struct `XE
    |
 LL |     let xe1 = XEmpty1();
    |               ^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
 LL | pub struct XEmpty1 {}
index 3570012fc37523583ff27b0b8670805f3d2f3d2c..5c02b62969fe7c652e26fa7671c7ba68a70b0560 100644 (file)
@@ -12,7 +12,7 @@ error[E0532]: expected unit struct, unit variant or constant, found struct varia
    |
 LL |         XE::XEmpty3 => ()
    |         ^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
 LL |     XEmpty3 {},
index 3bd3f6a9644a12f02c3252564df7beb5a5fe67a2..4bac2dfe76f282d34f32df3493a3eb0626e7deb4 100644 (file)
@@ -6,7 +6,7 @@ LL | struct Empty1 {}
 ...
 LL |         Empty1() => ()
    |         ^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
@@ -26,7 +26,7 @@ error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
    |
 LL |         XEmpty1() => ()
    |         ^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
 LL | pub struct XEmpty1 {}
@@ -52,7 +52,7 @@ LL | struct Empty1 {}
 ...
 LL |         Empty1(..) => ()
    |         ^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
@@ -72,7 +72,7 @@ error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
    |
 LL |         XEmpty1(..) => ()
    |         ^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:1:1
    |
 LL | pub struct XEmpty1 {}
index aac872ba0eccafe48bcd27fd123d479373b7ce10..cc2feb86d8e5b469ac85fcd04b05a58ec106bae0 100644 (file)
@@ -12,7 +12,7 @@ error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::
    |
 LL |         XE::XEmpty3() => ()
    |         ^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
 LL |     XEmpty3 {},
@@ -44,7 +44,7 @@ error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::
    |
 LL |         XE::XEmpty3(..) => ()
    |         ^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:6:5
    |
 LL |     XEmpty3 {},
index 7b0d9717e63a2bfeff13615842e12727a09271e0..9b5c8422de55dfd79c4727d4c2f18b32f84b87f7 100644 (file)
@@ -30,7 +30,7 @@ error[E0532]: expected unit struct, unit variant or constant, found tuple varian
    |
 LL |         XE::XEmpty5 => (),
    |         ^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
 LL |     XEmpty4,
index a704e1fae497cb0065dc867d0a29d43214806921..839d3a84103fab7e1fab634dce1713146a819ddd 100644 (file)
@@ -6,7 +6,7 @@ LL | struct Empty2;
 ...
 LL |         Empty2() => ()
    |         ^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
@@ -26,7 +26,7 @@ error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2
    |
 LL |         XEmpty2() => ()
    |         ^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
@@ -51,7 +51,7 @@ LL | struct Empty2;
 ...
 LL |         Empty2(..) => ()
    |         ^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
@@ -71,7 +71,7 @@ error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2
    |
 LL |         XEmpty2(..) => ()
    |         ^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
@@ -102,7 +102,7 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XE
    |
 LL |         XE::XEmpty4() => (),
    |         ^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
 LL |     XEmpty4,
@@ -133,7 +133,7 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XE
    |
 LL |         XE::XEmpty4(..) => (),
    |         ^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
 LL |     XEmpty4,
index 7b3deb1579aff837d46a2a25d356bea262c3245e..fd0215e72ee24acb16a54ad9f088bbc8be1c219f 100644 (file)
@@ -3,7 +3,7 @@ error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
    |
 LL |     match x { }
    |           ^ patterns `None` and `Some(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     None,
index b9f2702e8887603909fc4344456ae293aac02f9c..a945a4be708548ee60b2f8def16704154c85d57e 100644 (file)
@@ -3,7 +3,7 @@ error[E0005]: refutable pattern in local binding: `None` not covered
    |
 LL |     let Some(y) = x;
    |         ^^^^^^^ pattern `None` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     None,
index ec3452b1ddfa69fddfdb55b6dd788d61ce5f6551..957e79a9f398183c55f94d9561520b4efdc0e02a 100644 (file)
@@ -3,7 +3,7 @@ error[E0005]: refutable pattern in `for` loop binding: `None` not covered
    |
 LL |     for Some(x) in xs {}
    |         ^^^^^^^ pattern `None` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     None,
index f4a2330da177381d8e4dd887d5dbe68f629d3170..2f5dab7eb0559793c0f63af8eab3b18b804c28ee 100644 (file)
@@ -84,7 +84,7 @@ error[E0624]: associated function `pub_crate` is private
    |
 LL |     r.pub_crate();
    |       ^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:114:9
    |
 LL |         pub(crate) fn pub_crate(&self) -> i32 { self.d_priv }
@@ -95,7 +95,7 @@ error[E0624]: associated function `pub_mod` is private
    |
 LL |     r.pub_mod();
    |       ^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:116:9
    |
 LL |         pub(in m) fn pub_mod(&self) -> i32 { self.d_priv }
@@ -106,7 +106,7 @@ error[E0624]: associated function `private` is private
    |
 LL |     r.private();
    |       ^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:118:9
    |
 LL |         fn private(&self) -> i32 { self.d_priv }
@@ -135,7 +135,7 @@ error[E0624]: associated function `pub_crate` is private
    |
 LL |     t.pub_crate();
    |       ^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:129:9
    |
 LL |         pub(crate) fn pub_crate(&self) -> i32 { self.0 }
@@ -146,7 +146,7 @@ error[E0624]: associated function `pub_mod` is private
    |
 LL |     t.pub_mod();
    |       ^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:130:9
    |
 LL |         pub(in m) fn pub_mod(&self) -> i32 { self.0 }
@@ -157,7 +157,7 @@ error[E0624]: associated function `private` is private
    |
 LL |     t.private();
    |       ^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub-and-stability.rs:131:9
    |
 LL |         fn private(&self) -> i32 { self.0 }
index 2dacb94bcc07a7dad743f01c0b6674f888abec0a..912252fd34a2e6035b52e3774b572af8fd93d59d 100644 (file)
@@ -138,7 +138,7 @@ error[E0277]: the trait bound `<<Self as _Tr3>::A as Iterator>::Item: Copy` is n
    |
 LL |     type A: Iterator<Item: Copy>;
    |                            ^^^^ the trait `Copy` is not implemented for `<<Self as _Tr3>::A as Iterator>::Item`
-   | 
+   |
   ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
 LL | pub trait Copy: Clone {
index e079c2ddcee2643ffb8e4cfae7c82a045a13f1eb..74629d3e7e64a15336dec63d1ab7388f6f3e9bcd 100644 (file)
@@ -3,7 +3,7 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
    |
 LL |     let Ok(_x) = foo();
    |         ^^^^^^ pattern `Err(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
index 987cde191cbb98431dc46b85f41800f15ecb026d..2bccec458944130b655b71983e0f8f84a51f3ade 100644 (file)
@@ -4,7 +4,13 @@ error[E0310]: the parameter type `U` may not live long enough
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/feature-gate-infer_static_outlives_requirements.rs:7:15
+   |
+LL | struct Bar<T: 'static> {
+   |               ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs
deleted file mode 100644 (file)
index cd348de..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// ignore-wasm32-bare compiled with panic=abort by default
-// compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals
-
-#![crate_type = "lib"]
-
-extern "C" {
-    // CHECK: Function Attrs: nounwind
-    // CHECK-NEXT: declare void @extern_fn
-    fn extern_fn();
-    // CHECK-NOT: Function Attrs: nounwind
-    // CHECK: declare void @unwinding_extern_fn
-    #[unwind(allowed)] //~ ERROR the `#[unwind]` attribute is an experimental feature
-    fn unwinding_extern_fn();
-}
-
-pub unsafe fn force_declare() {
-    extern_fn();
-    unwinding_extern_fn();
-}
diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr
deleted file mode 100644 (file)
index 8e78955..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[unwind]` attribute is an experimental feature
-  --> $DIR/feature-gate-unwind-attributes.rs:12:5
-   |
-LL |     #[unwind(allowed)]
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58760 <https://github.com/rust-lang/rust/issues/58760> for more information
-   = help: add `#![feature(unwind_attributes)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 8e3c2f67ed165aa126f24765f021fde607cbd862..05cc6c012177b5b2818ab05057715f877ed9aa6a 100644 (file)
@@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
    |
 LL |    Pin::new(&mut gen).resume(());
    |                       ^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/generator.rs:LL:COL
    |
 LL | pub enum GeneratorState<Y, R> {
index d96c5f4540ef5f3ac0043104bf830a6bd637d501..57ccadc7b8d04c5c7d779b810b268cec02d84de6 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `(): AsRef<()>` is not satisfied
    |
 LL |     type Bar = ();
    |     ^^^^^^^^^^^^^^ the trait `AsRef<()>` is not implemented for `()`
-   | 
+   |
   ::: $DIR/auxiliary/foo_defn.rs:6:15
    |
 LL |     type Bar: AsRef<()>;
index 2106b214fec03559aef50d9d3b0842bb6bb03d57..f5b92beb3b225e6afaaa7c349bd82f2134d378da 100644 (file)
@@ -11,7 +11,13 @@ LL | | {
 ...  |
 LL | |
 LL | | }
-   | |_^ ...so that the type `T` will meet its required lifetime bounds
+   | |_^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/issue-86483.rs:7:16
+   |
+LL |     for<'a> T: 'a,
+   |                ^^
 
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:5
@@ -20,7 +26,13 @@ LL | pub trait IceIce<T>
    |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
 ...
 LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/issue-86483.rs:7:16
+   |
+LL |     for<'a> T: 'a,
+   |                ^^
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:32
index d2482b2998b9ba8ca812434839c2b263678f33dd..8237d3718c298dc80d172fa11f2baa4fad45a861 100644 (file)
@@ -4,7 +4,7 @@ error[E0477]: the type `&'b ()` does not fulfill the required lifetime
 LL |     type Item<'a> = &'b ();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: type must outlive the lifetime `'a` as defined on the associated item at 8:15
+note: type must outlive the lifetime `'a` as defined on the associated item at 8:15 as required by this binding
   --> $DIR/unsatisfied-outlives-bound.rs:8:15
    |
 LL |     type Item<'a> = &'b ();
@@ -16,7 +16,11 @@ error[E0477]: the type `&'a ()` does not fulfill the required lifetime
 LL |     type Item<'a> = &'a ();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/unsatisfied-outlives-bound.rs:13:20
+   |
+LL |     type Item<'a>: 'static;
+   |                    ^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs
new file mode 100644 (file)
index 0000000..832a3e3
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str, String>("".to_string()); //~ ERROR E0107
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
new file mode 100644 (file)
index 0000000..3add042
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0107]: this function takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/explicit-generic-args-for-impl.rs:6:5
+   |
+LL |     foo::<str, String>("".to_string());
+   |     ^^^        ------ help: remove this generic argument
+   |     |
+   |     expected 1 generic argument
+   |
+note: function defined here, with 1 generic parameter: `T`
+  --> $DIR/explicit-generic-args-for-impl.rs:3:4
+   |
+LL | fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+   |    ^^^ -
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs
new file mode 100644 (file)
index 0000000..a6585bc
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".to_string());
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs
new file mode 100644 (file)
index 0000000..0e4d698
--- /dev/null
@@ -0,0 +1,7 @@
+// gate-test-explicit_generic_args_with_impl_trait
+
+fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".to_string()); //~ ERROR E0632
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr
new file mode 100644 (file)
index 0000000..6adc4e6
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
+  --> $DIR/feature-gate.rs:6:11
+   |
+LL |     foo::<str>("".to_string());
+   |           ^^^ explicit generic argument not allowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0632`.
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs
new file mode 100644 (file)
index 0000000..e2ee638
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn f<T: ?Sized>(_: impl AsRef<T>, _: impl AsRef<T>) {}
+
+fn main() {
+    f::<[u8]>("a", b"a");
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs
new file mode 100644 (file)
index 0000000..ffb0582
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {}
+
+fn main() {
+    f::<[u8]>("a", b"a");
+    //~^ ERROR: this function takes 2 generic arguments but 1 generic argument was supplied
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
new file mode 100644 (file)
index 0000000..233b474
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+  --> $DIR/not-enough-args.rs:6:5
+   |
+LL |     f::<[u8]>("a", b"a");
+   |     ^   ---- supplied 1 generic argument
+   |     |
+   |     expected 2 generic arguments
+   |
+note: function defined here, with 2 generic parameters: `T`, `U`
+  --> $DIR/not-enough-args.rs:3:4
+   |
+LL | fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {}
+   |    ^ -          -
+help: add missing generic argument
+   |
+LL |     f::<[u8], U>("a", b"a");
+   |             ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
index 0e1ccd8d0d6d682870c8d3f0c4e318dc77a954ec..6af91480e3a6e511ae958402b20cac5bb69530f9 100644 (file)
@@ -31,7 +31,7 @@ error[E0643]: method `hash` has incompatible signature for trait
    |
 LL |     fn hash(&self, hasher: &mut impl Hasher) {}
    |                                 ^^^^^^^^^^^ expected generic parameter, found `impl Trait`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index f42d66d12435c2e933f6053d2970aec5d56a8728..5e432e76496041bc2f475aba5dcdfa6c49b2e616 100644 (file)
@@ -8,7 +8,7 @@ LL |         let f: F = async { 1 };
    |                -   ^^^^^^^^^^^ expected opaque type, found a different opaque type
    |                |
    |                expected due to this
-   | 
+   |
   ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
    |
 LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
index b993115502fd5f8cde39577ec156aa9a5e18824c..30afc8646de3d1b8de4b7f908efdcda7bdf33a7e 100644 (file)
@@ -66,7 +66,7 @@ error[E0599]: no method named `method` found for type `i32` in the current scope
    |
 LL |     1i32.method();
    |          ^^^^^^ method not found in `i32`
-   | 
+   |
   ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12
    |
 LL |         fn method(&self) {}
index bd5872833500834b014eaa41ba82682b4c67adbc..b15efd6c770eb2ccae0e8f5faec1fda60c067b42 100644 (file)
@@ -3,7 +3,7 @@ error: `impl` item signature doesn't match `trait` item signature
    |
 LL |     fn deref(&self) -> &dyn Trait {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/deref.rs:LL:COL
    |
 LL |     fn deref(&self) -> &Self::Target;
diff --git a/src/test/ui/inference/issue-86162-1.rs b/src/test/ui/inference/issue-86162-1.rs
new file mode 100644 (file)
index 0000000..5a547eb
--- /dev/null
@@ -0,0 +1,9 @@
+// Regression test of #86162.
+
+fn foo(x: impl Clone) {}
+fn gen<T>() -> T { todo!() }
+
+fn main() {
+    foo(gen()); //<- Do not suggest `foo::<impl Clone>()`!
+    //~^ ERROR: type annotations needed
+}
diff --git a/src/test/ui/inference/issue-86162-1.stderr b/src/test/ui/inference/issue-86162-1.stderr
new file mode 100644 (file)
index 0000000..f4e2161
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-86162-1.rs:7:5
+   |
+LL | fn foo(x: impl Clone) {}
+   |                ----- required by this bound in `foo`
+...
+LL |     foo(gen()); //<- Do not suggest `foo::<impl Clone>()`!
+   |     ^^^ cannot infer type for type parameter `impl Clone` declared on the function `foo`
+   |
+   = note: cannot satisfy `_: Clone`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/inference/issue-86162-2.rs b/src/test/ui/inference/issue-86162-2.rs
new file mode 100644 (file)
index 0000000..b8c75dd
--- /dev/null
@@ -0,0 +1,14 @@
+// Regression test of #86162.
+
+fn gen<T>() -> T { todo!() }
+
+struct Foo;
+
+impl Foo {
+    fn bar(x: impl Clone) {}
+}
+
+fn main() {
+    Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
+    //~^ ERROR: type annotations needed
+}
diff --git a/src/test/ui/inference/issue-86162-2.stderr b/src/test/ui/inference/issue-86162-2.stderr
new file mode 100644 (file)
index 0000000..19f741e
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-86162-2.rs:12:5
+   |
+LL |     fn bar(x: impl Clone) {}
+   |                    ----- required by this bound in `Foo::bar`
+...
+LL |     Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
+   |     ^^^^^^^^ cannot infer type for type parameter `impl Clone` declared on the associated function `bar`
+   |
+   = note: cannot satisfy `_: Clone`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
index dd43da11664453e0108bbac3f294459934adf965..af6e0053117786043288cb4d9b97d9f6b210c328 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
    |
 LL |     catch_unwind(|| { x.set(23); });
    |     ^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
-   | 
+   |
   ::: $SRC_DIR/std/src/panic.rs:LL:COL
    |
 LL | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
index 6269ccb73e06f13b2d306f5197fb65b81edc02e6..42953bd8d2c2e09a961040a0dd1fff8bdf36af9e 100644 (file)
@@ -3,7 +3,7 @@ error[E0573]: expected type, found variant `NoResult`
    |
 LL |     fn new() -> NoResult<MyEnum, String> {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL | pub enum Result<T, E> {
@@ -57,7 +57,7 @@ error[E0573]: expected type, found variant `NoResult`
    |
 LL | fn newer() -> NoResult<foo::MyEnum, String> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL | pub enum Result<T, E> {
index 5fed02164b5b704b482f1026f53e7024ceaeb6f4..b9e9bfe1b8cb174bf4190808de2c9b7df964d399 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation
    |
 LL |     fn iceman(c: Vec<[i32]>) {}
    |                  ^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
index c864381e6b0a629d9779de007a76361cefe74fec..e9aa8e27089aac5ba9605a0f76f22e7b9d13eab9 100644 (file)
@@ -5,7 +5,7 @@ LL | #[derive(Hash)]
    |          ---- in this derive macro expansion
 LL | struct Foo(Bar);
    |            ^^^ the trait `Hash` is not implemented for `Bar`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn hash<H: Hasher>(&self, state: &mut H);
index 47f28d7c443fcce61b15e9860a0f4659223d2eca..1d2816feda948e9fbb6695d1c2f99885b7e48541 100644 (file)
@@ -3,7 +3,7 @@ error[E0624]: associated function `foo` is private
    |
 LL |         Foo::foo(&f);
    |              ^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/issue-21202.rs:4:9
    |
 LL |         fn foo(&self) { }
index fa42611d0b32e656f904ff9d7adeeab33ace2314..9a38d49cd0c9624b4cef872e80f2ec750a0f0e11 100644 (file)
@@ -3,7 +3,7 @@ error[E0530]: match bindings cannot shadow unit variants
    |
 LL |         None @ _ => {}
    |         ^^^^ cannot be named the same as a unit variant
-   | 
+   |
   ::: $SRC_DIR/std/src/prelude/mod.rs:LL:COL
    |
 LL |     pub use super::v1::*;
index 0b7ffc39646a6d223558aa3a1d427bcc6d2d6ed5..8b7871ce3118605598e8887618bdff46550d98f4 100644 (file)
@@ -12,12 +12,12 @@ error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std:
    |
 LL |         .collect();
    |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
    |
 LL | pub struct Cloned<I> {
    | -------------------- doesn't satisfy `_: Iterator`
-   | 
+   |
   ::: $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
    |
 LL | pub struct TakeWhile<I, P> {
index 3a3767c349d651a65d7dd877b67aa1198de0005d..caf7530b85af1fd1501b94b2b28b2d8bdfec3a36 100644 (file)
@@ -3,7 +3,7 @@ error[E0599]: no method named `a` found for unit type `()` in the current scope
    |
 LL |     ().a();
    |        ^ method not found in `()`
-   | 
+   |
   ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8
    |
 LL |     fn a(&self) {}
index 62aacee811110503b084cb877ab3dbdb60970573..e917958c05e40254e5ef59d07ede77b30b32ed7a 100644 (file)
@@ -4,7 +4,11 @@ error[E0477]: the type `&'a u32` does not fulfill the required lifetime
 LL |     let x = foo::<&'a u32>();
    |             ^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/issue-54943.rs:1:11
+   |
+LL | fn foo<T: 'static>() { }
+   |           ^^^^^^^
 
 error: aborting due to previous error
 
index e6b0fffce663dae0044dc9299e3126767d43178a..013a440ed0457efbc9c987dfbad6cb0a31c93c52 100644 (file)
@@ -3,7 +3,7 @@ error[E0599]: no method named `trait_method` found for struct `FooStruct` in the
    |
 LL |     reexported_trait::FooStruct.trait_method();
    |                                 ^^^^^^^^^^^^ method not found in `FooStruct`
-   | 
+   |
   ::: $DIR/auxiliary/reexported-trait.rs:3:12
    |
 LL |         fn trait_method(&self) {
@@ -20,7 +20,7 @@ error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in t
    |
 LL |     reexported_trait::FooStruct.trait_method_b();
    |                                 ^^^^^^^^^^^^^^ method not found in `FooStruct`
-   | 
+   |
   ::: $DIR/auxiliary/reexported-trait.rs:7:12
    |
 LL |         fn trait_method_b(&self) {
index 149562f8fb31c7e61d832fc8e1e9fcf1c2350628..9bddc2c41a310960bf19f53ef7977a7ce150e661 100644 (file)
@@ -18,7 +18,7 @@ error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be kn
    |
 LL |     foo((), drop)
    |             ^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub fn drop<T>(_x: T) {}
index 4dd6b4bbb68bebe0c6f39d8f841fed16d5fb0358..b1ba89f6cbecf5a365cae573490fec5af5cc4fb3 100644 (file)
@@ -3,7 +3,7 @@ error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bo
    |
 LL |     let _ = Struct::<A>::new().clone();
    |                                ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $DIR/auxiliary/issue-69725.rs:2:1
    |
 LL | pub struct Struct<A>(A);
index 0520eada499d9552f734357d0258fdee8958af2c..ecff8b42b0ea77ea814af524045732a534cab569 100644 (file)
@@ -3,7 +3,7 @@ error[E0412]: cannot find type `Fo` in this scope
    |
 LL | impl Fo {
    |      ^^ help: a trait with a similar name exists: `Fn`
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
 LL | pub trait Fn<Args>: FnMut<Args> {
index ee15826d189417733605d84161cccb0924275ad5..95b2f447102ad1c0f7f6b0790be9d85895f60235 100644 (file)
@@ -9,7 +9,7 @@ error[E0412]: cannot find type `F` in this scope
    |
 LL |     _func: F,
    |            ^
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
 LL | pub trait Fn<Args>: FnMut<Args> {
index aa72fda3670ca922deaf2dd5f0c20decf20994db..b2b709760807169b37c5adeb29faad37c3209447 100644 (file)
@@ -16,7 +16,11 @@ error[E0477]: the type `&'a (dyn Dummy + Sync + 'a)` does not fulfill the requir
 LL |     assert_send::<&'a (dyn Dummy + Sync)>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/kindck-send-object1.rs:5:23
+   |
+LL | fn assert_send<T:Send+'static>() { }
+   |                       ^^^^^^^
 
 error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
   --> $DIR/kindck-send-object1.rs:29:5
index a0e8fc70b6acd939e7aee2adc2261ab24f2b4050..a7e382479021aeb8767c6b46391f0ecb8476eb30 100644 (file)
@@ -3,7 +3,7 @@ error[E0080]: values of the type `[u8; SIZE]` are too big for the current archit
    |
 LL |     intrinsics::size_of::<T>()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   | 
+   |
   ::: $DIR/issue-55878.rs:7:26
    |
 LL |     println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
index 4d8a8edf4c9eae503c8d9bca3dcfe16c9a4a60dd..438375951493bfe42ead7e3756cb1af7e506bd29 100644 (file)
@@ -21,7 +21,7 @@ LL | |  }
 ...
 LL |        ping!();
    |        -------- in this macro invocation (#1)
-   | 
+   |
   ::: $DIR/auxiliary/ping.rs:5:1
    |
 LL |  / macro_rules! ping {
@@ -43,7 +43,7 @@ LL | |  }
 ...
 LL |        deep!();
    |        -------- in this macro invocation (#1)
-   | 
+   |
   ::: $DIR/auxiliary/ping.rs:5:1
    |
 LL |  / macro_rules! ping {
index 94eb8dc0cd4cb003cab9f1b32945c2d654d12db0..3e8cfb3f0e97fba429aca99931f3de4959c64d86 100644 (file)
@@ -3,7 +3,7 @@ error: cannot find macro `printlx` in this scope
    |
 LL |     printlx!("oh noes!");
    |     ^^^^^^^ help: a macro with a similar name exists: `println`
-   | 
+   |
   ::: $SRC_DIR/std/src/macros.rs:LL:COL
    |
 LL | macro_rules! println {
index 523f08d547ebc1595d3a8ab65c4d7bdc853b1132..1abb501ec8051a6dfbca8bd603b15741f27557d1 100644 (file)
@@ -3,7 +3,7 @@ error: cannot find macro `inline` in this scope
    |
 LL |     inline!();
    |     ^^^^^^ help: a macro with a similar name exists: `line`
-   | 
+   |
   ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
    |
 LL |     macro_rules! line {
index 888fb913fb71c5ede67e4b72638a17a6274d9269..326001fc15a9a0b1a6386109bad67daa8a3cc07c 100644 (file)
@@ -3,7 +3,7 @@ error: cannot find macro `macro_two` in this scope
    |
 LL |     macro_two!();
    |     ^^^^^^^^^ help: a macro with a similar name exists: `macro_one`
-   | 
+   |
   ::: $DIR/auxiliary/two_macros.rs:2:1
    |
 LL | macro_rules! macro_one { () => ("one") }
index ba096a9080ae2b409ca29bca453475b76cd8ec12..0eafb2d7587db12bca9e355662b710a17e97a0a0 100644 (file)
@@ -21,7 +21,7 @@ error[E0277]: the trait bound `Test1: Clone` is not satisfied
    |
 LL | #[derive(Copy(Bad))]
    |          ^^^^ the trait `Clone` is not implemented for `Test1`
-   | 
+   |
   ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
 LL | pub trait Copy: Clone {
@@ -34,7 +34,7 @@ error[E0277]: the trait bound `Test2: Clone` is not satisfied
    |
 LL | #[derive(Copy="bad")]
    |          ^^^^ the trait `Clone` is not implemented for `Test2`
-   | 
+   |
   ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
 LL | pub trait Copy: Clone {
diff --git a/src/test/ui/malformed/malformed-unwind-1.rs b/src/test/ui/malformed/malformed-unwind-1.rs
deleted file mode 100644 (file)
index 009695b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(unwind_attributes)]
-
-#[unwind] //~ ERROR malformed `unwind` attribute
-extern "C" fn f1() {}
-
-#[unwind = ""] //~ ERROR malformed `unwind` attribute
-extern "C" fn f2() {}
-
-fn main() {}
diff --git a/src/test/ui/malformed/malformed-unwind-1.stderr b/src/test/ui/malformed/malformed-unwind-1.stderr
deleted file mode 100644 (file)
index 0a553e8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: malformed `unwind` attribute input
-  --> $DIR/malformed-unwind-1.rs:3:1
-   |
-LL | #[unwind]
-   | ^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]`
-
-error: malformed `unwind` attribute input
-  --> $DIR/malformed-unwind-1.rs:6:1
-   |
-LL | #[unwind = ""]
-   | ^^^^^^^^^^^^^^ help: must be of the form: `#[unwind(allowed|aborts)]`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/malformed/malformed-unwind-2.rs b/src/test/ui/malformed/malformed-unwind-2.rs
deleted file mode 100644 (file)
index 9aafc7c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(unwind_attributes)]
-
-#[unwind(allowed, aborts)]
-//~^ ERROR malformed `unwind` attribute
-extern "C" fn f1() {}
-
-#[unwind(unsupported)]
-//~^ ERROR malformed `unwind` attribute
-extern "C" fn f2() {}
-
-fn main() {}
diff --git a/src/test/ui/malformed/malformed-unwind-2.stderr b/src/test/ui/malformed/malformed-unwind-2.stderr
deleted file mode 100644 (file)
index 28512bf..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0633]: malformed `unwind` attribute input
-  --> $DIR/malformed-unwind-2.rs:3:1
-   |
-LL | #[unwind(allowed, aborts)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid argument
-   |
-help: the allowed arguments are `allowed` and `aborts`
-   |
-LL | #[unwind(allowed)]
-   |
-LL | #[unwind(aborts)]
-   |
-
-error[E0633]: malformed `unwind` attribute input
-  --> $DIR/malformed-unwind-2.rs:7:1
-   |
-LL | #[unwind(unsupported)]
-   | ^^^^^^^^^^^^^^^^^^^^^^ invalid argument
-   |
-help: the allowed arguments are `allowed` and `aborts`
-   |
-LL | #[unwind(allowed)]
-   |
-LL | #[unwind(aborts)]
-   |
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0633`.
index 961234cf7e8540b9369cc5bf1fc6e0145f3d3ac2..1ebd2b00aee0c64d45477d91495aade22a17b653 100644 (file)
@@ -6,7 +6,7 @@ LL |     intrinsics::size_of::<T>()
    |     |
    |     size_of called on unsized type `dyn Debug`
    |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   | 
+   |
   ::: $DIR/issue-80742.rs:23:10
    |
 LL |     [u8; size_of::<T>() + 1]: ,
@@ -26,7 +26,7 @@ LL | | }
 ...
 LL |       let dst = Inline::<dyn Debug>::new(0);
    |                                      ^^^ function or associated item cannot be called on `Inline<dyn Debug>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
    |
 LL |   pub trait Debug {
@@ -43,7 +43,7 @@ LL |     intrinsics::size_of::<T>()
    |     |
    |     size_of called on unsized type `dyn Debug`
    |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   | 
+   |
   ::: $DIR/issue-80742.rs:15:10
    |
 LL |     [u8; size_of::<T>() + 1]: ,
index 69ae3d8cbd0e54e505bc83c7baf712c95dd6c396..67e8ee2283689d9c2d09d942005c30238d84618a 100644 (file)
@@ -14,7 +14,7 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                       |
    |                                       doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
    |                                       doesn't satisfy `_: FnMut<(&&str,)>`
-   | 
+   |
   ::: $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL
    |
 LL | pub struct Filter<I, P> {
index ded3173f45b2e1c380e44a751cb9a5ab47f54833..71e35b445ef817b9383063609897ad7a9d074dfc 100644 (file)
@@ -24,7 +24,7 @@ error[E0423]: expected value, found type alias `xm1::S`
    |
 LL |     check(xm1::S);
    |           ^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/namespace-mix.rs:3:5
    |
 LL |     pub struct TS();
@@ -73,7 +73,7 @@ error[E0423]: expected value, found struct variant `xm7::V`
    |
 LL |     check(xm7::V);
    |           ^^^^^^
-   | 
+   |
   ::: $DIR/auxiliary/namespace-mix.rs:6:9
    |
 LL |         V {},
index eba00c5a9454e613a5d7cb9cf0ead5d1b6b36d35..88253bad194c979be74a2594861b764fd4498bac 100644 (file)
@@ -5,7 +5,12 @@ LL |     bar::<T::Output>()
    |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'a>>::Output: 'a`...
-   = note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds
+   = note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/projection-where-clause-env-wrong-bound.rs:29:8
+   |
+LL |     T: 'a,
+   |        ^^
 
 error: aborting due to previous error
 
index 34b83859a6bd2e346a996f628c8ceb066db44bee..9f7fc030aa981613176777600ee7a0e8724d6da3 100644 (file)
@@ -5,7 +5,12 @@ LL |     bar::<<T as MyTrait<'a>>::Output>()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'a>>::Output: 'a`...
-   = note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds
+   = note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/projection-where-clause-env-wrong-lifetime.rs:20:8
+   |
+LL |     T: 'a,
+   |        ^^
 
 error: aborting due to previous error
 
index 2ee32029b40dc7fba74392577eb1838c24759eb3..c35692d6eabc9e29e18e84cc309f942fc205502b 100644 (file)
@@ -10,7 +10,7 @@ LL | |         let y = x;
 LL | |         println!("{:?}", y);
 LL | |     });
    | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`
-   | 
+   |
   ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
 LL |       F: Send + 'static,
index 2aea607e95489d9a6a9e2b46783e7623d0f134ba..1f6ad64c071f514d0aaf78b47d3216bba5327d1d 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 
 #![allow(unused_must_use)]
-#![feature(unwind_attributes)]
+#![feature(c_unwind)]
 #![feature(panic_always_abort)]
 // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
 // we never unwind through them.
@@ -9,23 +9,17 @@
 // ignore-emscripten no processes
 // ignore-sgx no processes
 
-use std::{env, panic};
-use std::io::prelude::*;
 use std::io;
+use std::io::prelude::*;
 use std::process::{exit, Command, Stdio};
 use std::sync::{Arc, Barrier};
 use std::thread;
+use std::{env, panic};
 
-#[unwind(aborts)] // FIXME(#58794) should work even without the attribute
 extern "C" fn panic_in_ffi() {
     panic!("Test");
 }
 
-#[unwind(aborts)]
-extern "Rust" fn panic_in_rust_abi() {
-    panic!("TestRust");
-}
-
 fn should_have_aborted() {
     io::stdout().write(b"This should never be printed.\n");
     let _ = io::stdout().flush();
@@ -37,18 +31,17 @@ fn bomb_out_but_not_abort(msg: &str) {
 }
 
 fn test() {
-    let _ = panic::catch_unwind(|| { panic_in_ffi(); });
-    should_have_aborted();
-}
-
-fn testrust() {
-    let _ = panic::catch_unwind(|| { panic_in_rust_abi(); });
+    let _ = panic::catch_unwind(|| {
+        panic_in_ffi();
+    });
     should_have_aborted();
 }
 
 fn test_always_abort() {
     panic::always_abort();
-    let _ = panic::catch_unwind(|| { panic!(); });
+    let _ = panic::catch_unwind(|| {
+        panic!();
+    });
     should_have_aborted();
 }
 
@@ -56,7 +49,7 @@ fn test_always_abort_thread() {
     let barrier = Arc::new(Barrier::new(2));
     let thr = {
         let barrier = barrier.clone();
-        thread::spawn(move ||{
+        thread::spawn(move || {
             barrier.wait();
             panic!("in thread");
         })
@@ -70,7 +63,6 @@ fn test_always_abort_thread() {
 fn main() {
     let tests: &[(_, fn())] = &[
         ("test", test),
-        ("testrust", testrust),
         ("test_always_abort", test_always_abort),
         ("test_always_abort_thread", test_always_abort_thread),
     ];
@@ -78,17 +70,21 @@ fn main() {
     let args: Vec<String> = env::args().collect();
     if args.len() > 1 {
         // This is inside the self-executed command.
-        for (a,f) in tests {
-            if &args[1] == a { return f() }
+        for (a, f) in tests {
+            if &args[1] == a {
+                return f();
+            }
         }
         bomb_out_but_not_abort("bad test");
     }
 
     let execute_self_expecting_abort = |arg| {
         let mut p = Command::new(&args[0])
-                            .stdout(Stdio::piped())
-                            .stdin(Stdio::piped())
-                            .arg(arg).spawn().unwrap();
+            .stdout(Stdio::piped())
+            .stdin(Stdio::piped())
+            .arg(arg)
+            .spawn()
+            .unwrap();
         let status = p.wait().unwrap();
         assert!(!status.success());
         // Any reasonable platform can distinguish a process which
@@ -96,7 +92,7 @@ fn main() {
         assert_ne!(status.code(), Some(1));
     };
 
-    for (a,_f) in tests {
+    for (a, _f) in tests {
         execute_self_expecting_abort(a);
     }
 }
index 55be113e16b99eb4d9fac3a63478a2fa98eedf8c..b9fb42088d9d385359561f7c8cec94c8f72b8290 100644 (file)
@@ -36,10 +36,12 @@ error: non-ASCII character in byte constant
   --> $DIR/byte-literals.rs:10:7
    |
 LL |     b'é';
-   |       ^
-   |       |
-   |       byte constant must be ASCII
-   |       help: use a \xHH escape for a non-ASCII byte: `\xE9`
+   |       ^ byte constant must be ASCII
+   |
+help: if you meant to use the unicode code point for 'é', use a \xHH escape
+   |
+LL |     b'\xE9';
+   |       ^^^^
 
 error[E0763]: unterminated byte constant
   --> $DIR/byte-literals.rs:11:6
index 3a5a8b331d339dd1db09b29745c6dbfeb6875089..4f22a16224f0c3f2b9fc4bc9f4588b19ea0189d4 100644 (file)
@@ -24,10 +24,12 @@ error: non-ASCII character in byte constant
   --> $DIR/byte-string-literals.rs:6:7
    |
 LL |     b"é";
-   |       ^
-   |       |
-   |       byte constant must be ASCII
-   |       help: use a \xHH escape for a non-ASCII byte: `\xE9`
+   |       ^ byte constant must be ASCII
+   |
+help: if you meant to use the unicode code point for 'é', use a \xHH escape
+   |
+LL |     b"\xE9";
+   |       ^^^^
 
 error: raw byte string must be ASCII
   --> $DIR/byte-string-literals.rs:7:10
index cf3727c9d579d22447005d760edd68cdd2682434..9b7bd1559cddf6bd57b8f0c6c4a80a01a28c4f9c 100644 (file)
@@ -42,7 +42,7 @@ LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq!
 LL | 
 LL | fn main() {}
    | ^^ unexpected token
-   | 
+   |
   ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
    |
 LL |     ($left:expr, $right:expr $(,)?) => ({
diff --git a/src/test/ui/parser/issue-87635.rs b/src/test/ui/parser/issue-87635.rs
new file mode 100644 (file)
index 0000000..da74c18
--- /dev/null
@@ -0,0 +1,9 @@
+struct Foo {}
+
+impl Foo {
+    pub fn bar()
+    //~^ ERROR: expected `;`, found `}`
+    //~| ERROR: associated function in `impl` without body
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-87635.stderr b/src/test/ui/parser/issue-87635.stderr
new file mode 100644 (file)
index 0000000..920a9f9
--- /dev/null
@@ -0,0 +1,19 @@
+error: expected `;`, found `}`
+  --> $DIR/issue-87635.rs:4:17
+   |
+LL |     pub fn bar()
+   |                 ^ help: add `;` here
+...
+LL | }
+   | - unexpected token
+
+error: associated function in `impl` without body
+  --> $DIR/issue-87635.rs:4:5
+   |
+LL |     pub fn bar()
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the function: `{ <body> }`
+
+error: aborting due to 2 previous errors
+
index e0098793e1f217c077904724a792ca7a55899553..903b4de6ef47c3edfd44f5f984aca0e7030d1a22 100644 (file)
@@ -1,13 +1,39 @@
+#![allow(unused, dead_code)]
+
 fn foo() -> u32 {
     return 'label: loop { break 'label 42; };
 }
 
 fn bar() -> u32 {
     loop { break 'label: loop { break 'label 42; }; }
-    //~^ ERROR expected identifier, found keyword `loop`
-    //~| ERROR expected type, found keyword `loop`
+    //~^ ERROR: parentheses are required around this expression to avoid confusion
+    //~| HELP: wrap the expression in parentheses
+}
+
+fn baz() -> u32 {
+    'label: loop {
+        break 'label
+        //~^ WARNING: this labeled break expression is easy to confuse with an unlabeled break
+            loop { break 42; };
+            //~^ HELP: wrap this expression in parentheses
+    };
+
+    'label2: loop {
+        break 'label2 'inner: loop { break 42; };
+        // no warnings or errors here
+    }
 }
 
 pub fn main() {
-    foo();
+    // Regression test for issue #86948, as resolved in #87026:
+    let a = 'first_loop: loop {
+        break 'first_loop 1;
+    };
+    let b = loop {
+        break 'inner_loop: loop {
+        //~^ ERROR: parentheses are required around this expression to avoid confusion
+        //~| HELP: wrap the expression in parentheses
+            break 'inner_loop 1;
+        };
+    };
 }
index 7275841ebb808da6eb92da54862be7b2af5b7c96..6f3320e283cdbb2a39207c546610459de036c977 100644 (file)
@@ -1,23 +1,47 @@
-error: expected identifier, found keyword `loop`
-  --> $DIR/lifetime_starts_expressions.rs:6:26
+error: parentheses are required around this expression to avoid confusion with a labeled break expression
+  --> $DIR/lifetime_starts_expressions.rs:8:18
    |
 LL |     loop { break 'label: loop { break 'label 42; }; }
-   |                          ^^^^ expected identifier, found keyword
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: you can escape reserved keywords to use them as identifiers
+help: wrap the expression in parentheses
    |
-LL |     loop { break 'label: r#loop { break 'label 42; }; }
-   |                          ^^^^^^
+LL |     loop { break ('label: loop { break 'label 42; }); }
+   |                  ^                                 ^
 
-error: expected type, found keyword `loop`
-  --> $DIR/lifetime_starts_expressions.rs:6:26
+error: parentheses are required around this expression to avoid confusion with a labeled break expression
+  --> $DIR/lifetime_starts_expressions.rs:33:15
    |
-LL |     loop { break 'label: loop { break 'label 42; }; }
-   |                        - ^^^^ expected type
-   |                        |
-   |                        help: maybe write a path separator here: `::`
+LL |           break 'inner_loop: loop {
+   |  _______________^
+LL | |
+LL | |
+LL | |             break 'inner_loop 1;
+LL | |         };
+   | |_________^
+   |
+help: wrap the expression in parentheses
+   |
+LL |         break ('inner_loop: loop {
+LL |
+LL |
+LL |             break 'inner_loop 1;
+LL |         });
+   |
+
+warning: this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression
+  --> $DIR/lifetime_starts_expressions.rs:15:9
+   |
+LL | /         break 'label
+LL | |
+LL | |             loop { break 42; };
+   | |______________________________^
+   |
+   = note: `#[warn(break_with_label_and_loop)]` on by default
+help: wrap this expression in parentheses
    |
-   = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+LL |             (loop { break 42; });
+   |             ^                  ^
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
index f515525123e03ff42d3129b901e98fa466125309..4a987cb6c0311c94dfb1e7e7887fd22052b897e0 100644 (file)
@@ -12,7 +12,7 @@ error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
    |
 LL |     match Some(Some(North)) {
    |           ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
index cd157debcd4cf86fd28cacaca67736794abfe48c..4efb41978a241c08b722efe30c4c0e2d647664b3 100644 (file)
@@ -3,7 +3,7 @@ error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not co
    |
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
index c953cd314406e2c3fb72bccc1e7a09760ff8f7e3..1ca0a33bf37d90e03c7804d2fe53f4c067de86f1 100644 (file)
@@ -27,7 +27,7 @@ error[E0004]: non-exhaustive patterns: `Some(_)` not covered
    |
 LL |     match Some(10) {
    |           ^^^^^^^^ pattern `Some(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
index 216abfc68b812c41b5e40eaadd2803d418c9795a..d0c0c6b8bb593526c39a7bb0917999fed933040e 100644 (file)
@@ -363,7 +363,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     let a = other::A(());
    |                    ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -380,7 +380,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     let b = other::B(2);
    |                    ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -397,7 +397,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let c = other::C(2, 3);
    |                    ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -414,7 +414,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     let other::A(()) = a;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -431,7 +431,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     let other::A(_) = a;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -448,7 +448,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     match a { other::A(()) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -465,7 +465,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     match a { other::A(_) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -482,7 +482,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     let other::B(_) = b;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -499,7 +499,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     let other::B(_b) = b;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -516,7 +516,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     match b { other::B(_) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -533,7 +533,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     match b { other::B(_b) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -550,7 +550,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     match b { other::B(1) => {}
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -567,7 +567,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |         other::B(_) => {} }
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -584,7 +584,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let other::C(_, _) = c;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -601,7 +601,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let other::C(_a, _) = c;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -618,7 +618,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let other::C(_, _b) = c;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -635,7 +635,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let other::C(_a, _b) = c;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -652,7 +652,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     match c { other::C(_, _) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -669,7 +669,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     match c { other::C(_a, _) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -686,7 +686,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     match c { other::C(_, _b) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -703,7 +703,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     match c { other::C(_a, _b) => {} }
    |                      ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
@@ -720,7 +720,7 @@ error[E0603]: tuple struct constructor `A` is private
    |
 LL |     let a2 = other::A;
    |                     ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:1:14
    |
 LL | pub struct A(());
@@ -737,7 +737,7 @@ error[E0603]: tuple struct constructor `B` is private
    |
 LL |     let b2 = other::B;
    |                     ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:2:14
    |
 LL | pub struct B(isize);
@@ -754,7 +754,7 @@ error[E0603]: tuple struct constructor `C` is private
    |
 LL |     let c2 = other::C;
    |                     ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy_tuple_struct.rs:3:14
    |
 LL | pub struct C(pub isize, isize);
index 65329329933635e1e52aea8b8e627fcb230d12f2..93f6a7f2f6167ebb10aee9ad8cd1c290f642dbb9 100644 (file)
@@ -3,7 +3,7 @@ error[E0624]: associated function `nap` is private
    |
 LL |   nyan.nap();
    |        ^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/cci_class_5.rs:8:9
    |
 LL |         fn nap(&self) {}
index 6950667f1ea0ba6810c373afdef82cac1f9c1a6b..0f6003c4247675de580983127f07c3599730b171 100644 (file)
@@ -87,7 +87,7 @@ error[E0624]: associated function `g` is private
    |
 LL |     u.g();
    |       ^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub_restricted.rs:14:5
    |
 LL |     pub(crate) fn g(&self) {}
@@ -98,7 +98,7 @@ error[E0624]: associated function `h` is private
    |
 LL |     u.h();
    |       ^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/pub_restricted.rs:15:5
    |
 LL |     crate fn h(&self) {}
index 4105236b7f2d35c85ab5b697b765de7478f00d16..93551ebaf82d598416d68dcc58bfea5953f904d2 100644 (file)
@@ -1,9 +1,15 @@
 use proc_macro::Literal;
 
 pub fn test() {
+    test_display_literal();
     test_parse_literal();
 }
 
+fn test_display_literal() {
+    assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10");
+    assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize");
+}
+
 fn test_parse_literal() {
     assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
     assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
@@ -12,7 +18,10 @@ fn test_parse_literal() {
     assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
     assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
     assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
+    assert_eq!("-10ulong".parse::<Literal>().unwrap().to_string(), "-10ulong");
 
+    assert!("true".parse::<Literal>().is_err());
+    assert!(".8".parse::<Literal>().is_err());
     assert!("0 1".parse::<Literal>().is_err());
     assert!("'a".parse::<Literal>().is_err());
     assert!(" 0".parse::<Literal>().is_err());
@@ -20,4 +29,6 @@ fn test_parse_literal() {
     assert!("/* comment */0".parse::<Literal>().is_err());
     assert!("0/* comment */".parse::<Literal>().is_err());
     assert!("0// comment".parse::<Literal>().is_err());
+    assert!("- 10".parse::<Literal>().is_err());
+    assert!("-'x'".parse::<Literal>().is_err());
 }
diff --git a/src/test/ui/proc-macro/auxiliary/assert-span-pos.rs b/src/test/ui/proc-macro/auxiliary/assert-span-pos.rs
new file mode 100644 (file)
index 0000000..455c5c7
--- /dev/null
@@ -0,0 +1,37 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_diagnostic, proc_macro_span)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Span};
+
+fn lit_span(tt: TokenTree) -> (Span, String) {
+    match tt {
+        TokenTree::Literal(..) |
+        TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()),
+        _ => panic!("expected a literal in token tree, got: {:?}", tt)
+    }
+}
+
+#[proc_macro]
+pub fn assert_span_pos(input: TokenStream) -> TokenStream {
+    let mut tokens = input.into_iter();
+    let (sp1, str1) = lit_span(tokens.next().expect("first argument"));
+    let _ = tokens.next();
+    let (_sp2, str2) = lit_span(tokens.next().expect("second argument"));
+
+    let line: usize = str1.parse().unwrap();
+    let col: usize = str2.parse().unwrap();
+
+    let sp1s = sp1.start();
+    if (line, col) != (sp1s.line, sp1s.column) {
+        let msg = format!("line/column mismatch: ({}, {}) != ({}, {})", line, col,
+            sp1s.line, sp1s.column);
+        sp1.error(msg).emit();
+    }
+
+    "".parse().unwrap()
+}
index 070b066721350956fb1c3fa83d6c3add1b43988f..001b345204d3441d251edcdcceb4e71bdf30a20b 100644 (file)
@@ -3,7 +3,7 @@ warning: using an old version of `time-macros-impl`
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:27:5
    |
 LL |     impl_macros!(Foo);
@@ -20,7 +20,7 @@ warning: using an old version of `time-macros-impl`
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:44:5
    |
 LL |     impl_macros!(Foo);
@@ -36,7 +36,7 @@ warning: using an old version of `js-sys`
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:46:5
    |
 LL |     arrays!(Foo);
@@ -52,7 +52,7 @@ warning: using an old version of `actix-web`
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:55:5
    |
 LL |     tuple_from_req!(Foo);
@@ -68,7 +68,7 @@ warning: using an old version of `actix-web`
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:63:5
    |
 LL |     tuple_from_req!(Foo);
@@ -87,7 +87,7 @@ warning: using an old version of `time-macros-impl`
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:27:5
    |
 LL |     impl_macros!(Foo);
@@ -105,7 +105,7 @@ warning: using an old version of `time-macros-impl`
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:44:5
    |
 LL |     impl_macros!(Foo);
@@ -122,7 +122,7 @@ warning: using an old version of `js-sys`
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:46:5
    |
 LL |     arrays!(Foo);
@@ -139,7 +139,7 @@ warning: using an old version of `actix-web`
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:55:5
    |
 LL |     tuple_from_req!(Foo);
@@ -156,7 +156,7 @@ warning: using an old version of `actix-web`
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
-   | 
+   |
   ::: $DIR/group-compat-hack.rs:63:5
    |
 LL |     tuple_from_req!(Foo);
index 0af1b4a182295daa91afeb1960c7e38a58394eb4..071e103742e665744d736866c72dd7bb0152ad71 100644 (file)
@@ -144,7 +144,7 @@ LL |     parent_source_spans!($($tokens)*);
 ...
 LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
@@ -160,7 +160,7 @@ LL |     parent_source_spans!($($tokens)*);
 ...
 LL |     two!("yay", "rust");
    |     -------------------- in this macro invocation
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
@@ -176,7 +176,7 @@ LL |     parent_source_spans!($($tokens)*);
 ...
 LL |     three!("hip", "hop");
    |     --------------------- in this macro invocation
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
index c5fbf0d1d99a498496a56f1022a51f1e61e8c61a..e518c6ab8003232a8e3a70e62ba1b00213d570f8 100644 (file)
@@ -3,7 +3,7 @@ error: cannot find macro `bang_proc_macrp` in this scope
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro`
-   | 
+   |
   ::: $DIR/auxiliary/test-macros.rs:15:1
    |
 LL | pub fn empty(_: TokenStream) -> TokenStream {
@@ -50,7 +50,7 @@ error: cannot find derive macro `Dlona` in this scope
    |
 LL | #[derive(Dlona)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clona`
-   | 
+   |
   ::: $DIR/auxiliary/derive-clona.rs:11:1
    |
 LL | pub fn derive_clonea(input: TokenStream) -> TokenStream {
@@ -61,7 +61,7 @@ error: cannot find derive macro `Dlona` in this scope
    |
 LL | #[derive(Dlona)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clona`
-   | 
+   |
   ::: $DIR/auxiliary/derive-clona.rs:11:1
    |
 LL | pub fn derive_clonea(input: TokenStream) -> TokenStream {
@@ -72,7 +72,7 @@ error: cannot find derive macro `Dlone` in this scope
    |
 LL | #[derive(Dlone)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
-   | 
+   |
   ::: $SRC_DIR/core/src/clone.rs:LL:COL
    |
 LL | pub macro Clone($item:item) {
@@ -83,7 +83,7 @@ error: cannot find derive macro `Dlone` in this scope
    |
 LL | #[derive(Dlone)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
-   | 
+   |
   ::: $SRC_DIR/core/src/clone.rs:LL:COL
    |
 LL | pub macro Clone($item:item) {
@@ -100,7 +100,7 @@ error: cannot find attribute `attr_proc_macra` in this scope
    |
 LL | #[attr_proc_macra]
    |   ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro`
-   | 
+   |
   ::: $DIR/auxiliary/test-macros.rs:20:1
    |
 LL | pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
@@ -111,7 +111,7 @@ error: cannot find derive macro `FooWithLongNan` in this scope
    |
 LL | #[derive(FooWithLongNan)]
    |          ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName`
-   | 
+   |
   ::: $DIR/auxiliary/derive-foo.rs:11:1
    |
 LL | pub fn derive_foo(input: TokenStream) -> TokenStream {
@@ -122,7 +122,7 @@ error: cannot find derive macro `FooWithLongNan` in this scope
    |
 LL | #[derive(FooWithLongNan)]
    |          ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName`
-   | 
+   |
   ::: $DIR/auxiliary/derive-foo.rs:11:1
    |
 LL | pub fn derive_foo(input: TokenStream) -> TokenStream {
diff --git a/src/test/ui/proc-macro/span-absolute-posititions.rs b/src/test/ui/proc-macro/span-absolute-posititions.rs
new file mode 100644 (file)
index 0000000..6d70fe6
--- /dev/null
@@ -0,0 +1,24 @@
+// aux-build:assert-span-pos.rs
+// ignore-tidy-tab
+extern crate assert_span_pos;
+
+assert_span_pos::assert_span_pos!(5, 35);
+
+// Test space indentation
+    assert_span_pos::assert_span_pos!(8, 39);
+// Test tab indentation
+       assert_span_pos::assert_span_pos!(10, 36);
+
+// Two tests to ensure the promise of the docs that the column is the number
+// of UTF-8 bytes instead of some other number like number of code points.
+
+// Test that multi byte UTF-8 characters indeed count as multiple bytes
+/*🌈*/assert_span_pos::assert_span_pos!(16, 40);
+// Test with a complete grapheme cluster
+/*🏳️‍🌈*/assert_span_pos::assert_span_pos!(18, 43);
+
+// Test that the macro actually emits an error on a mismatch:
+assert_span_pos::assert_span_pos!(0, 35); //~ ERROR line/column mismatch: (0, 35) != (21, 35)
+assert_span_pos::assert_span_pos!(22, 0); //~ ERROR line/column mismatch: (22, 0) != (22, 35)
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/span-absolute-posititions.stderr b/src/test/ui/proc-macro/span-absolute-posititions.stderr
new file mode 100644 (file)
index 0000000..6aca44a
--- /dev/null
@@ -0,0 +1,14 @@
+error: line/column mismatch: (0, 35) != (21, 35)
+  --> $DIR/span-absolute-posititions.rs:21:35
+   |
+LL | assert_span_pos::assert_span_pos!(0, 35);
+   |                                   ^
+
+error: line/column mismatch: (22, 0) != (22, 35)
+  --> $DIR/span-absolute-posititions.rs:22:35
+   |
+LL | assert_span_pos::assert_span_pos!(22, 0);
+   |                                   ^^
+
+error: aborting due to 2 previous errors
+
index c3904d62c8df38c0ce536e8594f0bca9bc54ffa0..11ee20e846d320d85af5fec3ae148ee1d92bc65a 100644 (file)
@@ -6,7 +6,7 @@ LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> Tok
 ...
 LL |             field: MissingType
    |                    ^^^^^^^^^^^ not found in this scope
-   | 
+   |
   ::: $DIR/span-from-proc-macro.rs:8:1
    |
 LL | #[error_from_attribute]
@@ -20,7 +20,7 @@ LL | pub fn error_from_derive(_input: TokenStream) -> TokenStream {
 ...
 LL |             Variant(OtherMissingType)
    |                     ^^^^^^^^^^^^^^^^ not found in this scope
-   | 
+   |
   ::: $DIR/span-from-proc-macro.rs:11:10
    |
 LL | #[derive(ErrorFromDerive)]
@@ -34,7 +34,7 @@ LL | pub fn other_error_from_bang(_input: TokenStream) -> TokenStream {
 LL |     custom_quote::custom_quote! {
 LL |         my_ident
    |         ^^^^^^^^ not found in this scope
-   | 
+   |
   ::: $DIR/span-from-proc-macro.rs:16:5
    |
 LL |     other_error_from_bang!();
@@ -50,7 +50,7 @@ LL |             let bang_error: bool = 25;
 ...
 LL | pub fn error_from_bang(_input: TokenStream) -> TokenStream {
    | ---------------------------------------------------------- in this expansion of `error_from_bang!`
-   | 
+   |
   ::: $DIR/span-from-proc-macro.rs:15:5
    |
 LL |     error_from_bang!();
index b282fa7803f03a119cc1b5eb0b3c88975f1a3da2..53453ea04ddb46a31e107412d633e3a588c83138 100644 (file)
@@ -23,7 +23,7 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi
    |
 LL |     let range = *arr..;
    |                 ^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/range.rs:LL:COL
    |
 LL | pub struct RangeFrom<Idx> {
index dfb69a3cc1b425e11b43d61095ce4b938eb3ed9c..f904a0ecd11cd135d94fafd7afdb0e71086add7f 100644 (file)
@@ -3,7 +3,7 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
    |
 LL |     let Ok(x) = res;
    |         ^^^^^ pattern `Err(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
index 03da33ae11ffe1ab5e15e8c7e02c5b4d95e0ffa2..52802848d563c7db642fb33fc4adcc196ad32eb8 100644 (file)
@@ -4,7 +4,11 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
 LL |     type Value = &'a i32;
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:5:17
+   |
+LL |     type Value: 'a;
+   |                 ^^
 
 error[E0477]: the type `&'a i32` does not fulfill the required lifetime
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:20:5
@@ -12,7 +16,7 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
 LL |     type Value = &'a i32;
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-note: type must outlive the lifetime `'b` as defined on the impl at 19:10
+note: type must outlive the lifetime `'b` as defined on the impl at 19:10 as required by this binding
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:10
    |
 LL | impl<'a, 'b> Foo<'b> for &'a i64 {
index d8efeac5b8a30bc022ce72663bbc9148786ec3c9..a03210db6df03fd011a6b459c6da3f9d0b586949 100644 (file)
@@ -4,7 +4,11 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
 LL |     type Value = &'a i32;
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:5:17
+   |
+LL |     type Value: 'static;
+   |                 ^^^^^^^
 
 error: aborting due to previous error
 
index 930bf608ac4a55b90e9fc877ec0591a8b15a361e..68b90eee72d6d8ef41ded713bd624e76f3267c48 100644 (file)
@@ -4,7 +4,11 @@ error[E0477]: the type `&'a isize` does not fulfill the required lifetime
 LL |     assert_send::<&'a isize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error[E0477]: the type `&'a str` does not fulfill the required lifetime
   --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
@@ -12,7 +16,11 @@ error[E0477]: the type `&'a str` does not fulfill the required lifetime
 LL |     assert_send::<&'a str>();
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
   --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
@@ -20,7 +28,11 @@ error[E0477]: the type `&'a [isize]` does not fulfill the required lifetime
 LL |     assert_send::<&'a [isize]>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
   --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
@@ -28,7 +40,11 @@ error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime
 LL |     assert_send::<Box<&'a isize>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
   --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
@@ -36,7 +52,11 @@ error[E0477]: the type `*const &'a isize` does not fulfill the required lifetime
 LL |     assert_send::<*const &'a isize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
   --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
@@ -44,7 +64,11 @@ error[E0477]: the type `*mut &'a isize` does not fulfill the required lifetime
 LL |     assert_send::<*mut &'a isize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:6:18
+   |
+LL | fn assert_send<T:'static>() { }
+   |                  ^^^^^^^
 
 error: aborting due to 6 previous errors
 
index e5a80cbd54758c0fd22f4a2eabcec80c1567ea04..5b692cdcc0ecc77ebc6444265cb2730e7b9c092a 100644 (file)
@@ -23,7 +23,13 @@ LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
 LL |     box B(&*v) as Box<X>
-   |         ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |         ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-close-object-into-object-5.rs:9:17
+   |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+   |                 ^^
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:11
index 4ca5ac291d5bef33a6d08e6b3b7edf8638bc378d..97a3947bc0a2a049f7e213612ffc7bc6fab180a5 100644 (file)
@@ -5,7 +5,12 @@ LL |         check_bound(x, self)
    |         ^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `Self: 'a`...
-   = note: ...so that the type `Self` will meet its required lifetime bounds
+   = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait-self.rs:12:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
 
 error: aborting due to previous error
 
index 196ee8ca7c0b59a43d2afab6939ede59a1664593..fd1090d2dbd170d4c0835a05ca2e07ccf8494647 100644 (file)
@@ -4,7 +4,13 @@ error[E0309]: the parameter type `A` may not live long enough
 LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
    |            - help: consider adding an explicit lifetime bound...: `A: 'a`
 LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait.rs:12:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:37:5
@@ -12,7 +18,13 @@ error[E0309]: the parameter type `A` may not live long enough
 LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
    |               -- help: consider adding an explicit lifetime bound...: `A: 'a +`
 LL |     check_bound(x, a)
-   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-infer-bound-from-trait.rs:12:21
+   |
+LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
+   |                     ^^
 
 error: aborting due to 2 previous errors
 
index 6c519d73480252dda6b224ffa7e111beb5c87219..8df84067e67417333536b86a8ffbe6ea40addc29 100644 (file)
@@ -12,7 +12,7 @@ error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Mad
    |
 LL |     let homura = issue_19452_aux::Homura::Madoka;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `issue_19452_aux::Homura::Madoka { /* fields */ }`
-   | 
+   |
   ::: $DIR/auxiliary/issue-19452-aux.rs:2:5
    |
 LL |     Madoka { age: u32 }
index 3c76f2684a70228f37f3f538e7d353e9014250c0..a7f10f7719eacc1620f9a5230a183f4a879bd134 100644 (file)
@@ -18,7 +18,7 @@ error[E0412]: cannot find type `Opiton` in this scope
    |
 LL | type B = Opiton<u8>; // Misspelled type name from the prelude.
    |          ^^^^^^ help: an enum with a similar name exists: `Option`
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL | pub enum Option<T> {
index a72f69cf1cd8d48a713069f3141e4d0602b684e3..e5d6f7e9e24f0627091909bfa437fd67acf17a42 100644 (file)
@@ -103,7 +103,7 @@ error[E0603]: tuple struct constructor `S` is private
    |
 LL |     xcrate::m::S;
    |                ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy-struct-ctor.rs:2:18
    |
 LL |     pub struct S(u8);
@@ -120,7 +120,7 @@ error[E0603]: tuple struct constructor `Z` is private
    |
 LL |     xcrate::m::n::Z;
    |                   ^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:28
    |
 LL |         pub(in m) struct Z(pub(in m::n) u8);
index e33253b19c4bdba4d396239783a1d85cf8be7a49..e32d89fe6beebf4a0f044f5d2e7c6f61119bcb89 100644 (file)
@@ -7,7 +7,7 @@ LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
 LL | |     "0".parse()
 LL | | }
    | |_^ `main` can only return types that implement `Termination`
-   | 
+   |
   ::: $SRC_DIR/test/src/lib.rs:LL:COL
    |
 LL |   pub fn assert_test_result<T: Termination>(result: T) {
index d023ba3096e68ee0b85998869d2c802304f8a508..141363fc32caa5cd35b632c8d571dfb194e97ad8 100644 (file)
@@ -15,7 +15,7 @@ error[E0603]: tuple struct constructor `TupleStruct` is private
    |
 LL |     let ts_explicit = structs::TupleStruct(640, 480);
    |                                ^^^^^^^^^^^ private tuple struct constructor
-   | 
+   |
   ::: $DIR/auxiliary/structs.rs:11:24
    |
 LL | pub struct TupleStruct(pub u16, pub u16);
index 746c1fd4aceb7d77f7cb5c01f1d539705f9b8c3d..d21a94a0d6498ff76bf84681859c290aacfda54f 100644 (file)
@@ -30,7 +30,7 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
    |
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
-   | 
+   |
   ::: $DIR/auxiliary/uninhabited.rs:17:23
    |
 LL |     #[non_exhaustive] Tuple(!),
index 46e84dc09a3ead2763e20474005eea5717082be2..cc3dc6c29b90461fad6f236e9c09b3261a5ecca4 100644 (file)
@@ -30,7 +30,7 @@ error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covere
    |
 LL |     match x {}
    |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
-   | 
+   |
   ::: $DIR/auxiliary/uninhabited.rs:17:23
    |
 LL |     #[non_exhaustive] Tuple(!),
index a449fac11930d8ce0571b2bace6738863aa20da3..1f387a042e66672698a5d0f4e44d691f69a45686 100644 (file)
@@ -4,7 +4,13 @@ error[E0310]: the parameter type `U` may not live long enough
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/dont-infer-static.rs:10:15
+   |
+LL | struct Bar<T: 'static> {
+   |               ^^^^^^^
 
 error: aborting due to previous error
 
index 44812a51778a74d133e47992181a87213bac3e31..71caeefabac3468cb3fc39538c07e8ceca6f3217 100644 (file)
@@ -12,7 +12,13 @@ error[E0309]: the parameter type `T` may not live long enough
 LL | impl<'a, T> Trait<'a, T> for u32 {
    |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = RefOk<'a, T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-struct-not-wf.rs:16:20
+   |
+LL | struct RefOk<'a, T:'a> {
+   |                    ^^
 
 error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
   --> $DIR/regions-struct-not-wf.rs:25:5
index ad9b8af00e467b5173d083e73968f6ea8d2f5b11..7a63e6f6e686a06687458fd2384c46c25e6cacec 100644 (file)
@@ -3,7 +3,7 @@ error[E0599]: no method named `try_into` found for type `u8` in the current scop
    |
 LL |         let _: u32 = 3u8.try_into().unwrap();
    |                          ^^^^^^^^ method not found in `u8`
-   | 
+   |
   ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
 LL |     fn try_into(self) -> Result<T, Self::Error>;
index 50a4bfd9f518aa784fbc099c5c306c8a1e11172a..fa9d35ee4df854b5c207085c9e4c014faaa25fe2 100644 (file)
 
 #[repr(simd)]
 #[derive(Copy, Clone)]
-struct S<const N: usize>([f32; N]);
+struct A<const N: usize>([f32; N]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct B<T>([T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct C<T, const N: usize>([T; N]);
 
 
 extern "platform-intrinsic" {
@@ -29,7 +37,23 @@ fn add(self, rhs: f32x4) -> f32x4 {
     }
 }
 
-impl ops::Add for S<4> {
+impl ops::Add for A<4> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        unsafe { simd_add(self, rhs) }
+    }
+}
+
+impl ops::Add for B<f32> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        unsafe { simd_add(self, rhs) }
+    }
+}
+
+impl ops::Add for C<f32, 4> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -39,19 +63,23 @@ fn add(self, rhs: Self) -> Self {
 
 
 pub fn main() {
-    let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32);
+    let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32];
+    let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32];
 
     // lame-o
-    let f32x4(x, y, z, w) = add(lr, lr);
-    assert_eq!(x, 2.0f32);
-    assert_eq!(y, 4.0f32);
-    assert_eq!(z, 6.0f32);
-    assert_eq!(w, 8.0f32);
-
-    let lr2 = S::<4>([1.0f32, 2.0f32, 3.0f32, 4.0f32]);
-    let [x, y, z, w] = add(lr2, lr2).0;
-    assert_eq!(x, 2.0f32);
-    assert_eq!(y, 4.0f32);
-    assert_eq!(z, 6.0f32);
-    assert_eq!(w, 8.0f32);
+    let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32);
+    let f32x4(a0, a1, a2, a3) = add(a, a);
+    assert_eq!(a0, 2.0f32);
+    assert_eq!(a1, 4.0f32);
+    assert_eq!(a2, 6.0f32);
+    assert_eq!(a3, 8.0f32);
+
+    let a = A(x);
+    assert_eq!(add(a, a).0, y);
+
+    let b = B(x);
+    assert_eq!(add(b, b).0, y);
+
+    let c = C(x);
+    assert_eq!(add(c, c).0, y);
 }
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.rs
new file mode 100644 (file)
index 0000000..0bc73b1
--- /dev/null
@@ -0,0 +1,14 @@
+// build-fail
+
+#![feature(repr_simd)]
+
+struct E;
+
+// error-pattern:monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E`
+
+#[repr(simd)]
+struct S<T>([T; 4]);
+
+fn main() {
+    let _v: Option<S<E>> = None;
+}
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr b/src/test/ui/simd/simd-type-generic-monomorphisation-non-primitive.stderr
new file mode 100644 (file)
index 0000000..9e8f06b
--- /dev/null
@@ -0,0 +1,4 @@
+error: monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E`
+
+error: aborting due to previous error
+
index 68d8911a4351cbbde4250393b16b31a21950eee9..1787b0ee19ad6977e6e0e310a10dd28f1455fd2a 100644 (file)
@@ -6,7 +6,7 @@ LL | |             () => { parse error }
    | |                           ^^^^^ expected one of `!` or `::`
 LL | |         }
    | |_________- in this expansion of `transitive_dep_two::parse_error!`
-   | 
+   |
   ::: $DIR/transitive-dep-span.rs:13:1
    |
 LL |   transitive_dep_two::parse_error!();
index 6a825c534b5e211f6256e6a12c96c32dedac65fd..d6163a5a7cfe3d2900d51421bd8816c56558b5d8 100644 (file)
@@ -15,7 +15,7 @@ error: cannot find attribute `tests` in this scope
    |
 LL | #[tests]
    |   ^^^^^ help: an attribute macro with a similar name exists: `test`
-   | 
+   |
   ::: $SRC_DIR/core/src/macros/mod.rs:LL:COL
    |
 LL |     pub macro test($item:item) {
index 59ccb29e0901a88e7e8340fdcc478f9a2d09b189..7bdc8e00f447dc2ec308fd02fa5f922cb51161a2 100644 (file)
@@ -3,7 +3,7 @@ error[E0573]: expected type, found module `result`
    |
 LL | impl result {
    |      ^^^^^^ help: an enum with a similar name exists: `Result`
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL | pub enum Result<T, E> {
index 119599c22a63b01066263c13aa9cf1f9cdda515b..c4eeb3aaa5709362b769c2ba70f28f0ef00c0edb 100644 (file)
@@ -77,7 +77,7 @@ LL | /     async {
 LL | |         42
 LL | |     }
    | |_____^ expected struct `Pin`, found opaque type
-   | 
+   |
   ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
    |
 LL |   pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
index 9f89dcd912e1db29b6021abf8ba387d6a77d286d..42ca3a78d8f9f70ef5c222f7a7f18c30461711f9 100644 (file)
@@ -3,7 +3,7 @@ error: the `min` method cannot be invoked on a trait object
    |
 LL |      t.min().unwrap()
    |        ^^^
-   | 
+   |
   ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
 LL |         Self: Sized,
index a2b9b9d14ab090f27d85d5ef0eb3c35ac4c7ccff..bac8de7987256058de5b5f0312b41cdffd326ee6 100644 (file)
@@ -3,7 +3,7 @@ error[E0599]: no method named `finish` found for struct `DefaultHasher` in the c
    |
 LL |     h.finish()
    |       ^^^^^^ method not found in `DefaultHasher`
-   | 
+   |
   ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL
    |
 LL |     fn finish(&self) -> u64;
index f90765870873010b5d5562e90cb4e85ec9554ee8..1e0aa9ce40d18c18c96ae0b3f3f0c189e64749ea 100644 (file)
@@ -13,13 +13,12 @@ LL | |         _ => cx.answer_str("hi"),
    | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
 LL | |     }
    | |_____- `match` arms have incompatible types
-   | 
-  ::: $DIR/auxiliary/issue-81839.rs:6:49
    |
-LL |       pub async fn answer_str(&self, _s: &str) -> Test {
-   |                                                   ---- checked the `Output` of this `async fn`, found opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/auxiliary/issue-81839.rs:6:49
    |
-   = note: while checking the return type of the `async fn`
+LL |     pub async fn answer_str(&self, _s: &str) -> Test {
+   |                                                 ^^^^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 
index ca7562beb1f7b03c68887712d12acbd71f1fe251..4eab2df30801e4e0ef5b40d123a43a07e8ef009f 100644 (file)
@@ -15,12 +15,16 @@ LL |         [&v] => {},
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/match-ergonomics.rs:8:9
    |
+LL |     match x {
+   |           - help: consider slicing here: `x[..]`
 LL |         [&v] => {},
    |         ^^^^ pattern cannot match with input type `Vec<i32>`
 
 error[E0529]: expected an array or slice, found `Vec<i32>`
   --> $DIR/match-ergonomics.rs:20:9
    |
+LL |     match x {
+   |           - help: consider slicing here: `x[..]`
 LL |         [v] => {},
    |         ^^^ pattern cannot match with input type `Vec<i32>`
 
index 3b2cff3140d639c45f64a85e52e71e92bfa8b944..990a4469764f0410168430c3c02a73a5047705eb 100644 (file)
@@ -14,8 +14,14 @@ fn extra_semicolon() {
 }
 
 async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
 async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
 //~| NOTE checked the `Output` of this `async fn`, found opaque type
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
 
 async fn async_extra_semicolon_same() {
     let _ = match true { //~ NOTE `match` arms have incompatible types
@@ -26,7 +32,6 @@ async fn async_extra_semicolon_same() {
         false => async_dummy(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
         //~| NOTE expected type `()`
-        //~| NOTE while checking the return type of the `async fn`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -40,7 +45,6 @@ async fn async_extra_semicolon_different() {
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
         //~| NOTE expected type `()`
-        //~| NOTE while checking the return type of the `async fn`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -53,7 +57,6 @@ async fn async_different_futures() {
         //~^ NOTE expected opaque type, found a different opaque type
         //~| NOTE expected type `impl Future`
         //~| NOTE distinct uses of `impl Trait` result in different opaque types
-        //~| NOTE while checking the return type of the `async fn`
     };
 }
 
index e31ea9679b51dca13f6af09618a6050f4d6531cb..9e64b539f0fdc1a0db05036b98095dc5981d8fd6 100644 (file)
@@ -1,9 +1,6 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:26:18
+  --> $DIR/match-prev-arm-needing-semi.rs:32:18
    |
-LL |   async fn async_dummy() {}
-   |                          - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => {
@@ -18,7 +15,11 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:16:24
+   |
+LL | async fn async_dummy() {}
+   |                        ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -31,11 +32,8 @@ LL |             async_dummy()
    |                         --
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:40:18
+  --> $DIR/match-prev-arm-needing-semi.rs:45:18
    |
-LL |   async fn async_dummy2() {}
-   |                           - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => {
@@ -50,7 +48,11 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+   |
+LL | async fn async_dummy2() {}
+   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `()`
            found opaque type `impl Future`
 help: consider `await`ing on the `Future`
@@ -66,11 +68,8 @@ LL |         false => Box::new(async_dummy2()),
    |
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:52:18
+  --> $DIR/match-prev-arm-needing-semi.rs:56:18
    |
-LL |   async fn async_dummy2() {}
-   |                           - checked the `Output` of this `async fn`, found opaque type
-...
 LL |       let _ = match true {
    |  _____________-
 LL | |         true => async_dummy(),
@@ -83,9 +82,13 @@ LL | |
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: while checking the return type of the `async fn`
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+   |
+LL | async fn async_dummy2() {}
+   |                         ^ checked the `Output` of this `async fn`, found opaque type
    = note:     expected type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
-           found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:17:25>)
+           found opaque type `impl Future` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:19:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
diff --git a/src/test/ui/suggestions/multibyte-escapes.rs b/src/test/ui/suggestions/multibyte-escapes.rs
new file mode 100644 (file)
index 0000000..fd5d46a
--- /dev/null
@@ -0,0 +1,18 @@
+// Regression test for #87397.
+
+fn main() {
+    b'µ';
+    //~^ ERROR: non-ASCII character in byte constant
+    //~| HELP: if you meant to use the unicode code point for 'µ', use a \xHH escape
+    //~| NOTE: byte constant must be ASCII
+
+    b'字';
+    //~^ ERROR: non-ASCII character in byte constant
+    //~| NOTE: this multibyte character does not fit into a single byte
+    //~| NOTE: byte constant must be ASCII
+
+    b"字";
+    //~^ ERROR: non-ASCII character in byte constant
+    //~| HELP: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
+    //~| NOTE: byte constant must be ASCII
+}
diff --git a/src/test/ui/suggestions/multibyte-escapes.stderr b/src/test/ui/suggestions/multibyte-escapes.stderr
new file mode 100644 (file)
index 0000000..bb4f8e8
--- /dev/null
@@ -0,0 +1,33 @@
+error: non-ASCII character in byte constant
+  --> $DIR/multibyte-escapes.rs:4:7
+   |
+LL |     b'µ';
+   |       ^ byte constant must be ASCII
+   |
+help: if you meant to use the unicode code point for 'µ', use a \xHH escape
+   |
+LL |     b'\xB5';
+   |       ^^^^
+
+error: non-ASCII character in byte constant
+  --> $DIR/multibyte-escapes.rs:9:7
+   |
+LL |     b'字';
+   |       ^^
+   |       |
+   |       byte constant must be ASCII
+   |       this multibyte character does not fit into a single byte
+
+error: non-ASCII character in byte constant
+  --> $DIR/multibyte-escapes.rs:14:7
+   |
+LL |     b"字";
+   |       ^^ byte constant must be ASCII
+   |
+help: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
+   |
+LL |     b"\xE5\xAD\x97";
+   |       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index 4d1b5306bb130120b748809e34ebdd1726fe326a..07fdffd8bedec050bcf48f5486d3b0314a988fff 100644 (file)
@@ -16,7 +16,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis
    |
 LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
-   | 
+   |
   ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
@@ -29,7 +29,7 @@ error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::
    |
 LL |     writeln!(fp, "hello world").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
diff --git a/src/test/ui/suggestions/pattern-slice-vec.fixed b/src/test/ui/suggestions/pattern-slice-vec.fixed
new file mode 100644 (file)
index 0000000..447337c
--- /dev/null
@@ -0,0 +1,27 @@
+// Regression test for #87017.
+
+// run-rustfix
+
+fn main() {
+    fn foo() -> Vec<i32> { vec![1, 2, 3] }
+
+    if let [_, _, _] = foo()[..] {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    if let [] = &foo()[..] {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    if let [] = foo()[..] {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    let v = vec![];
+    match &v[..] {
+    //~^ HELP: consider slicing here
+        [5] => {}
+        //~^ ERROR: expected an array or slice
+        _ => {}
+    }
+}
diff --git a/src/test/ui/suggestions/pattern-slice-vec.rs b/src/test/ui/suggestions/pattern-slice-vec.rs
new file mode 100644 (file)
index 0000000..1153ca0
--- /dev/null
@@ -0,0 +1,27 @@
+// Regression test for #87017.
+
+// run-rustfix
+
+fn main() {
+    fn foo() -> Vec<i32> { vec![1, 2, 3] }
+
+    if let [_, _, _] = foo() {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    if let [] = &foo() {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    if let [] = foo() {}
+    //~^ ERROR: expected an array or slice
+    //~| HELP: consider slicing here
+
+    let v = vec![];
+    match &v {
+    //~^ HELP: consider slicing here
+        [5] => {}
+        //~^ ERROR: expected an array or slice
+        _ => {}
+    }
+}
diff --git a/src/test/ui/suggestions/pattern-slice-vec.stderr b/src/test/ui/suggestions/pattern-slice-vec.stderr
new file mode 100644 (file)
index 0000000..403a816
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:8:12
+   |
+LL |     if let [_, _, _] = foo() {}
+   |            ^^^^^^^^^   ----- help: consider slicing here: `foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:12:12
+   |
+LL |     if let [] = &foo() {}
+   |            ^^   ------ help: consider slicing here: `&foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<i32>`
+  --> $DIR/pattern-slice-vec.rs:16:12
+   |
+LL |     if let [] = foo() {}
+   |            ^^   ----- help: consider slicing here: `foo()[..]`
+   |            |
+   |            pattern cannot match with input type `Vec<i32>`
+
+error[E0529]: expected an array or slice, found `Vec<_>`
+  --> $DIR/pattern-slice-vec.rs:23:9
+   |
+LL |     match &v {
+   |           -- help: consider slicing here: `&v[..]`
+LL |
+LL |         [5] => {}
+   |         ^^^ pattern cannot match with input type `Vec<_>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0529`.
index e68152d5fc3aa7006495013fd672e89567bf8ea9..8384f952b684959af6f910cc523e20e42cbfbe5c 100644 (file)
@@ -27,7 +27,7 @@ error[E0599]: the method `read_until` exists for struct `BufReader<&T>`, but its
    |
 LL |         stream_reader.read_until(b'\n', &mut buffer).expect("Reading into buffer failed");
    |                       ^^^^^^^^^^ method cannot be called on `BufReader<&T>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/std/src/io/buffered/bufreader.rs:LL:COL
    |
 LL | pub struct BufReader<R> {
index 589ee1a474ad6e2f5bf4e834c6ceeac4d54989d8..65aab97d3d71612521a0531aa481d289e07f2615 100644 (file)
@@ -9,7 +9,7 @@ fn foo(d: impl Debug + 'static) {
 //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
 }
 
-fn bar(d: impl Debug + 'static) {
+fn bar(d: impl Debug + 'static) { //~ NOTE ...that is required by this bound
     println!("{:?}", d)
 }
 
index 9a87129fbf28ad2ff402e081d9a4f312f05f088b..fb1848d130f772914efc8750925a6cf51d34a6ed 100644 (file)
@@ -9,7 +9,7 @@ fn foo(d: impl Debug) {
 //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds
 }
 
-fn bar(d: impl Debug + 'static) {
+fn bar(d: impl Debug + 'static) { //~ NOTE ...that is required by this bound
     println!("{:?}", d)
 }
 
index 643dac25724972168904f14bebbcc95168c4e2ff..e4a247993c29b67df00219f1961e5f1bb888acfe 100644 (file)
@@ -5,7 +5,13 @@ LL | fn foo(d: impl Debug) {
    |           ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static`
 LL |
 LL |     bar(d);
-   |     ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
+   |     ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/suggest-impl-trait-lifetime.rs:12:24
+   |
+LL | fn bar(d: impl Debug + 'static) {
+   |                        ^^^^^^^
 
 error: aborting due to previous error
 
index 9890597b7bd5bc23e95ab4908324c337f243f3f4..fd967604624cb9ca863f40e90670e16201a9e89a 100644 (file)
@@ -30,3 +30,4 @@ LL |     A
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0625`.
index 08bf593a5a748d92c1058a33d55036d04c3ad879..712050a25fcfe59a8c4eca01bf7bb95207ed2294 100644 (file)
@@ -40,5 +40,5 @@ LL |     std::mem::swap(x, &mut STATIC_VAR_2)
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0013, E0133, E0658.
+Some errors have detailed explanations: E0013, E0133, E0625, E0658.
 For more information about an error, try `rustc --explain E0013`.
index 7cf872eb6ac6907553e32a62343fcd55354eb4fc..bfdd121012ae0491ac05b24c5751c849dc80c5e7 100644 (file)
@@ -3,7 +3,7 @@ error[E0404]: expected trait, found struct `String`
    |
 LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
    |                                              ^^^^^^ not a trait
-   | 
+   |
   ::: $SRC_DIR/alloc/src/string.rs:LL:COL
    |
 LL | pub trait ToString {
@@ -23,7 +23,7 @@ error[E0404]: expected trait, found struct `String`
    |
 LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
    |                                                      ^^^^^^ not a trait
-   | 
+   |
   ::: $SRC_DIR/alloc/src/string.rs:LL:COL
    |
 LL | pub trait ToString {
@@ -43,7 +43,7 @@ error[E0404]: expected trait, found struct `String`
    |
 LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
    |                                             ^^^^^^ not a trait
-   | 
+   |
   ::: $SRC_DIR/alloc/src/string.rs:LL:COL
    |
 LL | pub trait ToString {
@@ -63,7 +63,7 @@ error[E0404]: expected trait, found struct `String`
    |
 LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
    |                                                         ^^^^^^ not a trait
-   | 
+   |
   ::: $SRC_DIR/alloc/src/string.rs:LL:COL
    |
 LL | pub trait ToString {
index 5a9d4286ce6d10fe715c6fed1ec337d139b48bf0..58e34cfe15c3d311cd0bb5cb729d1c0900b7e01d 100644 (file)
@@ -14,7 +14,7 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila
    |
 LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
    |            ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
@@ -40,7 +40,7 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila
    |
 LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
    |                                     ^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
 LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
index 0adb20d4828777f1269e37f960b880de3d4bbae5..91552d4ea07d4e3177c7e475651406b74add05da 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied
    |
 LL | fn explode(x: Foo<usize>) {}
    |               ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
-   | 
+   |
   ::: $DIR/auxiliary/on_structs_and_enums_xc.rs:5:18
    |
 LL | pub struct Foo<T:Trait> {
@@ -14,7 +14,7 @@ error[E0277]: the trait bound `f32: Trait` is not satisfied
    |
 LL | fn kaboom(y: Bar<f32>) {}
    |              ^^^^^^^^ the trait `Trait` is not implemented for `f32`
-   | 
+   |
   ::: $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16
    |
 LL | pub enum Bar<T:Trait> {
index ada2445c1c96259871914cd9f06756dbb9468f3a..7d54a559e8b7ee0064112b55c6d47b76e3aafdbf 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `f64: Trait` is not satisfied
    |
 LL |     let bar: Bar<f64> = return;
    |              ^^^^^^^^ the trait `Trait` is not implemented for `f64`
-   | 
+   |
   ::: $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16
    |
 LL | pub enum Bar<T:Trait> {
index c48f2f0efcfb23d44314b5dc206448429393400e..ce163b501b79b5c2a16bd2e6723f100fb22a3fb2 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `Foo: main::a::Bar` is not satisfied
    |
 LL |         a::try_foo(foo);
    |                    ^^^ the trait `main::a::Bar` is not implemented for `Foo`
-   | 
+   |
   ::: $DIR/auxiliary/crate_a1.rs:3:24
    |
 LL | pub fn try_foo(x: impl Bar) {}
@@ -21,7 +21,7 @@ error[E0277]: the trait bound `DoesNotImplementTrait: main::a::Bar` is not satis
    |
 LL |         a::try_foo(implements_no_traits);
    |                    ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait`
-   | 
+   |
   ::: $DIR/auxiliary/crate_a1.rs:3:24
    |
 LL | pub fn try_foo(x: impl Bar) {}
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `ImplementsWrongTraitConditionally<isize>: main::a
    |
 LL |         a::try_foo(other_variant_implements_mismatched_trait);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally<isize>`
-   | 
+   |
   ::: $DIR/auxiliary/crate_a1.rs:3:24
    |
 LL | pub fn try_foo(x: impl Bar) {}
@@ -50,7 +50,7 @@ error[E0277]: the trait bound `ImplementsTraitForUsize<isize>: main::a::Bar` is
    |
 LL |         a::try_foo(other_variant_implements_correct_trait);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize<isize>`
-   | 
+   |
   ::: $DIR/auxiliary/crate_a1.rs:3:24
    |
 LL | pub fn try_foo(x: impl Bar) {}
diff --git a/src/test/ui/traits/issue-85735.rs b/src/test/ui/traits/issue-85735.rs
new file mode 100644 (file)
index 0000000..16e874e
--- /dev/null
@@ -0,0 +1,13 @@
+// Regression test for the invalid suggestion in #85735 (the
+// underlying issue #21974 still exists here).
+
+trait Foo {}
+impl<'a, 'b, T> Foo for T
+where
+    T: FnMut(&'a ()),
+    //~^ ERROR: type annotations needed [E0283]
+    T: FnMut(&'b ()),
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-85735.stderr b/src/test/ui/traits/issue-85735.stderr
new file mode 100644 (file)
index 0000000..7b3d7f8
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-85735.rs:7:8
+   |
+LL |     T: FnMut(&'a ()),
+   |        ^^^^^^^^^^^^^ cannot infer type for type parameter `T`
+   |
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait FnMut<Args>: FnOnce<Args> {
+   | ----------------------------------- required by this bound in `FnMut`
+   |
+   = note: cannot satisfy `T: FnMut<(&'a (),)>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
index cf867ef78c3b1fc32f2b480b566b90ef6fd5d3d3..91c4136a752fb4398da7bd4d9ed24d0fcb12d9f5 100644 (file)
@@ -3,7 +3,7 @@ error[E0275]: overflow evaluating the requirement `Option<_>: Sized`
    |
 LL |     iso(left, right)
    |     ^^^
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL | pub enum Option<T> {
index 1005231d396e703b357fff71b2b4ccfd0b005543..d1778a284dad838549d8e4a0d6a9c1552f51b129 100644 (file)
@@ -6,7 +6,7 @@ LL |     let _errors = TcpListener::bind(&bad);
    |                                     |
    |                                     the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
    |                                     help: consider adding dereference here: `&*bad`
-   | 
+   |
   ::: $SRC_DIR/std/src/net/tcp.rs:LL:COL
    |
 LL |     pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
index 47f287807d4b935584352d7a369db2bcd03f3bee..c34e3261fe185afb36b94bed5a8047b4b3f1cbce 100644 (file)
@@ -6,7 +6,7 @@ LL | fn check<T: Iterator, U: ?Sized>() {
 LL |     // suggest a where-clause, if needed
 LL |     mem::size_of::<U>();
    |                    ^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -25,7 +25,7 @@ LL | fn check<T: Iterator, U: ?Sized>() {
 ...
 LL |     mem::size_of::<Misc<U>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -90,7 +90,7 @@ error[E0277]: the size for values of type `[T]` cannot be known at compilation t
    |
 LL |     mem::size_of::<[T]>();
    |                    ^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
@@ -103,7 +103,7 @@ error[E0277]: the size for values of type `[&U]` cannot be known at compilation
    |
 LL |     mem::size_of::<[&U]>();
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL | pub const fn size_of<T>() -> usize {
diff --git a/src/test/ui/traits/trait-upcasting/basic.rs b/src/test/ui/traits/trait-upcasting/basic.rs
new file mode 100644 (file)
index 0000000..484a222
--- /dev/null
@@ -0,0 +1,87 @@
+// run-pass
+
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar: Foo {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Baz: Bar {
+    fn c(&self) -> i32 {
+        30
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Baz for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+fn main() {
+    let baz: &dyn Baz = &1;
+    let _: &dyn std::fmt::Debug = baz;
+    assert_eq!(*baz, 1);
+    assert_eq!(baz.a(), 100);
+    assert_eq!(baz.b(), 200);
+    assert_eq!(baz.c(), 300);
+    assert_eq!(baz.z(), 11);
+    assert_eq!(baz.y(), 12);
+    assert_eq!(baz.w(), 21);
+
+    let bar: &dyn Bar = baz;
+    let _: &dyn std::fmt::Debug = bar;
+    assert_eq!(*bar, 1);
+    assert_eq!(bar.a(), 100);
+    assert_eq!(bar.b(), 200);
+    assert_eq!(bar.z(), 11);
+    assert_eq!(bar.y(), 12);
+    assert_eq!(bar.w(), 21);
+
+    let foo: &dyn Foo = baz;
+    let _: &dyn std::fmt::Debug = foo;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+
+    let foo: &dyn Foo = bar;
+    let _: &dyn std::fmt::Debug = foo;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+}
diff --git a/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.rs b/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.rs
new file mode 100644 (file)
index 0000000..511e415
--- /dev/null
@@ -0,0 +1,13 @@
+trait A: B + A {}
+//~^ ERROR cycle detected when computing the super predicates of `A` [E0391]
+
+trait B {}
+
+impl A for () {}
+
+impl B for () {}
+
+fn main() {
+    let a: Box<dyn A> = Box::new(());
+    let _b: Box<dyn B> = a;
+}
diff --git a/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr b/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr
new file mode 100644 (file)
index 0000000..ac00572
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0391]: cycle detected when computing the super predicates of `A`
+  --> $DIR/cyclic-trait-resolution.rs:1:1
+   |
+LL | trait A: B + A {}
+   | ^^^^^^^^^^^^^^
+   |
+note: ...which requires computing the super traits of `A`...
+  --> $DIR/cyclic-trait-resolution.rs:1:14
+   |
+LL | trait A: B + A {}
+   |              ^
+   = note: ...which again requires computing the super predicates of `A`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/cyclic-trait-resolution.rs:1:1
+   |
+LL | trait A: B + A {}
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/traits/trait-upcasting/diamond.rs b/src/test/ui/traits/trait-upcasting/diamond.rs
new file mode 100644 (file)
index 0000000..e4e23c1
--- /dev/null
@@ -0,0 +1,115 @@
+// run-pass
+
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar1: Foo {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Bar2: Foo {
+    fn c(&self) -> i32 {
+        30
+    }
+
+    fn v(&self) -> i32 {
+        31
+    }
+}
+
+trait Baz: Bar1 + Bar2 {
+    fn d(&self) -> i32 {
+        40
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar1 for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Bar2 for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+impl Baz for i32 {
+    fn d(&self) -> i32 {
+        400
+    }
+}
+
+fn main() {
+    let baz: &dyn Baz = &1;
+    let _: &dyn std::fmt::Debug = baz;
+    assert_eq!(*baz, 1);
+    assert_eq!(baz.a(), 100);
+    assert_eq!(baz.b(), 200);
+    assert_eq!(baz.c(), 300);
+    assert_eq!(baz.d(), 400);
+    assert_eq!(baz.z(), 11);
+    assert_eq!(baz.y(), 12);
+    assert_eq!(baz.w(), 21);
+    assert_eq!(baz.v(), 31);
+
+    let bar1: &dyn Bar1 = baz;
+    let _: &dyn std::fmt::Debug = bar1;
+    assert_eq!(*bar1, 1);
+    assert_eq!(bar1.a(), 100);
+    assert_eq!(bar1.b(), 200);
+    assert_eq!(bar1.z(), 11);
+    assert_eq!(bar1.y(), 12);
+    assert_eq!(bar1.w(), 21);
+
+    let bar2: &dyn Bar2 = baz;
+    let _: &dyn std::fmt::Debug = bar2;
+    assert_eq!(*bar2, 1);
+    assert_eq!(bar2.a(), 100);
+    assert_eq!(bar2.c(), 300);
+    assert_eq!(bar2.z(), 11);
+    assert_eq!(bar2.y(), 12);
+    assert_eq!(bar2.v(), 31);
+
+    let foo: &dyn Foo = baz;
+    let _: &dyn std::fmt::Debug = foo;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+
+    let foo: &dyn Foo = bar1;
+    let _: &dyn std::fmt::Debug = foo;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+
+    let foo: &dyn Foo = bar2;
+    let _: &dyn std::fmt::Debug = foo;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+}
diff --git a/src/test/ui/traits/trait-upcasting/invalid-upcast.rs b/src/test/ui/traits/trait-upcasting/invalid-upcast.rs
new file mode 100644 (file)
index 0000000..2402245
--- /dev/null
@@ -0,0 +1,87 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Baz {
+    fn c(&self) -> i32 {
+        30
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Baz for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+fn main() {
+    let baz: &dyn Baz = &1;
+    let _: &dyn std::fmt::Debug = baz;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Send = baz;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Sync = baz;
+    //~^ ERROR mismatched types [E0308]
+
+    let bar: &dyn Bar = baz;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn std::fmt::Debug = bar;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Send = bar;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Sync = bar;
+    //~^ ERROR mismatched types [E0308]
+
+    let foo: &dyn Foo = baz;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn std::fmt::Debug = foo;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Send = foo;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Sync = foo;
+    //~^ ERROR mismatched types [E0308]
+
+    let foo: &dyn Foo = bar;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn std::fmt::Debug = foo;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Send = foo;
+    //~^ ERROR mismatched types [E0308]
+    let _: &dyn Sync = foo;
+    //~^ ERROR mismatched types [E0308]
+}
diff --git a/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr b/src/test/ui/traits/trait-upcasting/invalid-upcast.stderr
new file mode 100644 (file)
index 0000000..b4530ed
--- /dev/null
@@ -0,0 +1,168 @@
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:54:35
+   |
+LL |     let _: &dyn std::fmt::Debug = baz;
+   |            --------------------   ^^^ expected trait `Debug`, found trait `Baz`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Debug`
+              found reference `&dyn Baz`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:56:24
+   |
+LL |     let _: &dyn Send = baz;
+   |            ---------   ^^^ expected trait `Send`, found trait `Baz`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Send`
+              found reference `&dyn Baz`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:58:24
+   |
+LL |     let _: &dyn Sync = baz;
+   |            ---------   ^^^ expected trait `Sync`, found trait `Baz`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Sync`
+              found reference `&dyn Baz`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:61:25
+   |
+LL |     let bar: &dyn Bar = baz;
+   |              --------   ^^^ expected trait `Bar`, found trait `Baz`
+   |              |
+   |              expected due to this
+   |
+   = note: expected reference `&dyn Bar`
+              found reference `&dyn Baz`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:63:35
+   |
+LL |     let _: &dyn std::fmt::Debug = bar;
+   |            --------------------   ^^^ expected trait `Debug`, found trait `Bar`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Debug`
+              found reference `&dyn Bar`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:65:24
+   |
+LL |     let _: &dyn Send = bar;
+   |            ---------   ^^^ expected trait `Send`, found trait `Bar`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Send`
+              found reference `&dyn Bar`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:67:24
+   |
+LL |     let _: &dyn Sync = bar;
+   |            ---------   ^^^ expected trait `Sync`, found trait `Bar`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Sync`
+              found reference `&dyn Bar`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:70:25
+   |
+LL |     let foo: &dyn Foo = baz;
+   |              --------   ^^^ expected trait `Foo`, found trait `Baz`
+   |              |
+   |              expected due to this
+   |
+   = note: expected reference `&dyn Foo`
+              found reference `&dyn Baz`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:72:35
+   |
+LL |     let _: &dyn std::fmt::Debug = foo;
+   |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Debug`
+              found reference `&dyn Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:74:24
+   |
+LL |     let _: &dyn Send = foo;
+   |            ---------   ^^^ expected trait `Send`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Send`
+              found reference `&dyn Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:76:24
+   |
+LL |     let _: &dyn Sync = foo;
+   |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Sync`
+              found reference `&dyn Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:79:25
+   |
+LL |     let foo: &dyn Foo = bar;
+   |              --------   ^^^ expected trait `Foo`, found trait `Bar`
+   |              |
+   |              expected due to this
+   |
+   = note: expected reference `&dyn Foo`
+              found reference `&dyn Bar`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:81:35
+   |
+LL |     let _: &dyn std::fmt::Debug = foo;
+   |            --------------------   ^^^ expected trait `Debug`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Debug`
+              found reference `&dyn Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:83:24
+   |
+LL |     let _: &dyn Send = foo;
+   |            ---------   ^^^ expected trait `Send`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Send`
+              found reference `&dyn Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/invalid-upcast.rs:85:24
+   |
+LL |     let _: &dyn Sync = foo;
+   |            ---------   ^^^ expected trait `Sync`, found trait `Foo`
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&dyn Sync`
+              found reference `&dyn Foo`
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/trait-upcasting/lifetime.rs b/src/test/ui/traits/trait-upcasting/lifetime.rs
new file mode 100644 (file)
index 0000000..052f090
--- /dev/null
@@ -0,0 +1,96 @@
+// run-pass
+// ignore-compare-mode-nll
+
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar: Foo {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Baz: Bar {
+    fn c(&self) -> i32 {
+        30
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Baz for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+// Note: upcast lifetime means a shorter lifetime.
+fn upcast_baz<'a: 'b, 'b, T>(v: Box<dyn Baz + 'a>, _l: &'b T) -> Box<dyn Baz + 'b> {
+    v
+}
+fn upcast_bar<'a: 'b, 'b, T>(v: Box<dyn Bar + 'a>, _l: &'b T) -> Box<dyn Bar + 'b> {
+    v
+}
+fn upcast_foo<'a: 'b, 'b, T>(v: Box<dyn Foo + 'a>, _l: &'b T) -> Box<dyn Foo + 'b> {
+    v
+}
+
+fn main() {
+    let v = Box::new(1);
+    let l = &(); // dummy lifetime (shorter than `baz`)
+
+    let baz: Box<dyn Baz> = v.clone();
+    let u = upcast_baz(baz, &l);
+    assert_eq!(*u, 1);
+    assert_eq!(u.a(), 100);
+    assert_eq!(u.b(), 200);
+    assert_eq!(u.c(), 300);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let bar: Box<dyn Bar> = baz;
+    let u = upcast_bar(bar, &l);
+    assert_eq!(*u, 1);
+    assert_eq!(u.a(), 100);
+    assert_eq!(u.b(), 200);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let foo: Box<dyn Foo> = baz;
+    let u = upcast_foo(foo, &l);
+    assert_eq!(*u, 1);
+    assert_eq!(u.a(), 100);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let bar: Box<dyn Bar> = baz;
+    let foo: Box<dyn Foo> = bar;
+    let u = upcast_foo(foo, &l);
+    assert_eq!(*u, 1);
+    assert_eq!(u.a(), 100);
+}
diff --git a/src/test/ui/traits/trait-upcasting/replace-vptr.rs b/src/test/ui/traits/trait-upcasting/replace-vptr.rs
new file mode 100644 (file)
index 0000000..1164e43
--- /dev/null
@@ -0,0 +1,49 @@
+// run-pass
+
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait A {
+    fn foo_a(&self);
+}
+
+trait B {
+    fn foo_b(&self);
+}
+
+trait C: A + B {
+    fn foo_c(&self);
+}
+
+struct S(i32);
+
+impl A for S {
+    fn foo_a(&self) {
+        unreachable!();
+    }
+}
+
+impl B for S {
+    fn foo_b(&self) {
+        assert_eq!(42, self.0);
+    }
+}
+
+impl C for S {
+    fn foo_c(&self) {
+        unreachable!();
+    }
+}
+
+fn invoke_inner(b: &dyn B) {
+    b.foo_b();
+}
+
+fn invoke_outer(c: &dyn C) {
+    invoke_inner(c);
+}
+
+fn main() {
+    let s = S(42);
+    invoke_outer(&s);
+}
diff --git a/src/test/ui/traits/trait-upcasting/struct.rs b/src/test/ui/traits/trait-upcasting/struct.rs
new file mode 100644 (file)
index 0000000..0f3cb28
--- /dev/null
@@ -0,0 +1,174 @@
+// run-pass
+
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+use std::rc::Rc;
+use std::sync::Arc;
+
+trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar: Foo {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Baz: Bar {
+    fn c(&self) -> i32 {
+        30
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Baz for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+fn test_box() {
+    let v = Box::new(1);
+
+    let baz: Box<dyn Baz> = v.clone();
+    assert_eq!(*baz, 1);
+    assert_eq!(baz.a(), 100);
+    assert_eq!(baz.b(), 200);
+    assert_eq!(baz.c(), 300);
+    assert_eq!(baz.z(), 11);
+    assert_eq!(baz.y(), 12);
+    assert_eq!(baz.w(), 21);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let bar: Box<dyn Bar> = baz;
+    assert_eq!(*bar, 1);
+    assert_eq!(bar.a(), 100);
+    assert_eq!(bar.b(), 200);
+    assert_eq!(bar.z(), 11);
+    assert_eq!(bar.y(), 12);
+    assert_eq!(bar.w(), 21);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let foo: Box<dyn Foo> = baz;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+
+    let baz: Box<dyn Baz> = v.clone();
+    let bar: Box<dyn Bar> = baz;
+    let foo: Box<dyn Foo> = bar;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+}
+
+fn test_rc() {
+    let v = Rc::new(1);
+
+    let baz: Rc<dyn Baz> = v.clone();
+    assert_eq!(*baz, 1);
+    assert_eq!(baz.a(), 100);
+    assert_eq!(baz.b(), 200);
+    assert_eq!(baz.c(), 300);
+    assert_eq!(baz.z(), 11);
+    assert_eq!(baz.y(), 12);
+    assert_eq!(baz.w(), 21);
+
+    let baz: Rc<dyn Baz> = v.clone();
+    let bar: Rc<dyn Bar> = baz;
+    assert_eq!(*bar, 1);
+    assert_eq!(bar.a(), 100);
+    assert_eq!(bar.b(), 200);
+    assert_eq!(bar.z(), 11);
+    assert_eq!(bar.y(), 12);
+    assert_eq!(bar.w(), 21);
+
+    let baz: Rc<dyn Baz> = v.clone();
+    let foo: Rc<dyn Foo> = baz;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+
+    let baz: Rc<dyn Baz> = v.clone();
+    let bar: Rc<dyn Bar> = baz;
+    let foo: Rc<dyn Foo> = bar;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+}
+
+fn test_arc() {
+    let v = Arc::new(1);
+
+    let baz: Arc<dyn Baz> = v.clone();
+    assert_eq!(*baz, 1);
+    assert_eq!(baz.a(), 100);
+    assert_eq!(baz.b(), 200);
+    assert_eq!(baz.c(), 300);
+    assert_eq!(baz.z(), 11);
+    assert_eq!(baz.y(), 12);
+    assert_eq!(baz.w(), 21);
+
+    let baz: Arc<dyn Baz> = v.clone();
+    let bar: Arc<dyn Bar> = baz;
+    assert_eq!(*bar, 1);
+    assert_eq!(bar.a(), 100);
+    assert_eq!(bar.b(), 200);
+    assert_eq!(bar.z(), 11);
+    assert_eq!(bar.y(), 12);
+    assert_eq!(bar.w(), 21);
+
+    let baz: Arc<dyn Baz> = v.clone();
+    let foo: Arc<dyn Foo> = baz;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+
+    let baz: Arc<dyn Baz> = v.clone();
+    let bar: Arc<dyn Bar> = baz;
+    let foo: Arc<dyn Foo> = bar;
+    assert_eq!(*foo, 1);
+    assert_eq!(foo.a(), 100);
+    assert_eq!(foo.z(), 11);
+    assert_eq!(foo.y(), 12);
+}
+
+fn main() {
+    test_box();
+    test_rc();
+    test_arc();
+}
diff --git a/src/test/ui/traits/trait-upcasting/subtrait-method.rs b/src/test/ui/traits/trait-upcasting/subtrait-method.rs
new file mode 100644 (file)
index 0000000..3508e15
--- /dev/null
@@ -0,0 +1,70 @@
+#![feature(trait_upcasting)]
+#![allow(incomplete_features)]
+
+trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
+    fn a(&self) -> i32 {
+        10
+    }
+
+    fn z(&self) -> i32 {
+        11
+    }
+
+    fn y(&self) -> i32 {
+        12
+    }
+}
+
+trait Bar: Foo {
+    fn b(&self) -> i32 {
+        20
+    }
+
+    fn w(&self) -> i32 {
+        21
+    }
+}
+
+trait Baz: Bar {
+    fn c(&self) -> i32 {
+        30
+    }
+}
+
+impl Foo for i32 {
+    fn a(&self) -> i32 {
+        100
+    }
+}
+
+impl Bar for i32 {
+    fn b(&self) -> i32 {
+        200
+    }
+}
+
+impl Baz for i32 {
+    fn c(&self) -> i32 {
+        300
+    }
+}
+
+fn main() {
+    let baz: &dyn Baz = &1;
+
+    let bar: &dyn Bar = baz;
+    bar.c();
+    //~^ ERROR no method named `c` found for reference `&dyn Bar` in the current scope [E0599]
+
+    let foo: &dyn Foo = baz;
+    foo.b();
+    //~^ ERROR no method named `b` found for reference `&dyn Foo` in the current scope [E0599]
+    foo.c();
+    //~^ ERROR no method named `c` found for reference `&dyn Foo` in the current scope [E0599]
+
+    let foo: &dyn Foo = bar;
+    foo.b();
+    //~^ ERROR no method named `b` found for reference `&dyn Foo` in the current scope [E0599]
+    foo.c();
+    //~^ ERROR no method named `c` found for reference `&dyn Foo` in the current scope [E0599]
+}
diff --git a/src/test/ui/traits/trait-upcasting/subtrait-method.stderr b/src/test/ui/traits/trait-upcasting/subtrait-method.stderr
new file mode 100644 (file)
index 0000000..8c69011
--- /dev/null
@@ -0,0 +1,68 @@
+error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope
+  --> $DIR/subtrait-method.rs:56:9
+   |
+LL |     bar.c();
+   |         ^ help: there is an associated function with a similar name: `a`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Baz` defines an item `c`, perhaps you need to implement it
+  --> $DIR/subtrait-method.rs:28:1
+   |
+LL | trait Baz: Bar {
+   | ^^^^^^^^^^^^^^
+
+error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
+  --> $DIR/subtrait-method.rs:60:9
+   |
+LL |     foo.b();
+   |         ^ help: there is an associated function with a similar name: `a`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Bar` defines an item `b`, perhaps you need to implement it
+  --> $DIR/subtrait-method.rs:18:1
+   |
+LL | trait Bar: Foo {
+   | ^^^^^^^^^^^^^^
+
+error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
+  --> $DIR/subtrait-method.rs:62:9
+   |
+LL |     foo.c();
+   |         ^ help: there is an associated function with a similar name: `a`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Baz` defines an item `c`, perhaps you need to implement it
+  --> $DIR/subtrait-method.rs:28:1
+   |
+LL | trait Baz: Bar {
+   | ^^^^^^^^^^^^^^
+
+error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
+  --> $DIR/subtrait-method.rs:66:9
+   |
+LL |     foo.b();
+   |         ^ help: there is an associated function with a similar name: `a`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Bar` defines an item `b`, perhaps you need to implement it
+  --> $DIR/subtrait-method.rs:18:1
+   |
+LL | trait Bar: Foo {
+   | ^^^^^^^^^^^^^^
+
+error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
+  --> $DIR/subtrait-method.rs:68:9
+   |
+LL |     foo.c();
+   |         ^ help: there is an associated function with a similar name: `a`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Baz` defines an item `c`, perhaps you need to implement it
+  --> $DIR/subtrait-method.rs:28:1
+   |
+LL | trait Baz: Bar {
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index e5ef0d0d59f73fd3d4912adc2814bdaaaee3ac08..0d8bbf1ce98c130e7c38bf2ec3ac84b064eebf45 100644 (file)
@@ -3,7 +3,7 @@ error[E0412]: cannot find type `F` in this scope
    |
 LL | impl F {
    |      ^ help: a trait with a similar name exists: `Fn`
-   | 
+   |
   ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
    |
 LL | pub trait Fn<Args>: FnMut<Args> {
index 4f2f9e070fe520562ae662771b2698bd1dc7648e..b92ceb479bd3b3b2c15a05fbb0698b12c02348a1 100644 (file)
@@ -3,7 +3,7 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
    |
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
@@ -57,7 +57,7 @@ error[E0004]: non-exhaustive patterns: `Err(_)` not covered
    |
 LL |     let _ = match x {
    |                   ^ pattern `Err(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
@@ -71,7 +71,7 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
    |
 LL |     let Ok(x) = x;
    |         ^^^^^ pattern `Err(_)` not covered
-   | 
+   |
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
index 41e828c6d95153acb6e1421d7afd507d1d904623..9c4ee28a2adb433635d8bad58fc99c47dcb9412d 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied
    |
 LL | #[derive(Clone)]
    |          ^^^^^ the trait `Copy` is not implemented for `U1`
-   | 
+   |
   ::: $SRC_DIR/core/src/clone.rs:LL:COL
    |
 LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
index 41e828c6d95153acb6e1421d7afd507d1d904623..9c4ee28a2adb433635d8bad58fc99c47dcb9412d 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied
    |
 LL | #[derive(Clone)]
    |          ^^^^^ the trait `Copy` is not implemented for `U1`
-   | 
+   |
   ::: $SRC_DIR/core/src/clone.rs:LL:COL
    |
 LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
index c2fd8545f63ada897814cd02881adeb6f4107b64..1d768315d9f65d293014e5e1b19231113fabbce6 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq)]
 LL | union U2 {
 LL |     a: PartialEqNotEq,
    |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index c2fd8545f63ada897814cd02881adeb6f4107b64..1d768315d9f65d293014e5e1b19231113fabbce6 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Eq)]
 LL | union U2 {
 LL |     a: PartialEqNotEq,
    |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
-   | 
+   |
   ::: $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub struct AssertParamIsEq<T: Eq + ?Sized> {
index 9edf5827511525d3b5e48f2b20e411dc3347499b..c3d7d41ca35fbb8b9942bb906dbdcf8026598117 100644 (file)
@@ -1,4 +1,7 @@
 // run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
diff --git a/src/test/ui/union/union-drop.thirunsafeck.stderr b/src/test/ui/union/union-drop.thirunsafeck.stderr
deleted file mode 100644 (file)
index 9766ae4..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-warning: unnecessary `unsafe` block
-  --> $DIR/union-drop.rs:27:9
-   |
-LL |         unsafe { CHECK += 1; }
-   |         ^^^^^^ unnecessary `unsafe` block
-   |
-   = note: `#[warn(unused_unsafe)]` on by default
-
-warning: unnecessary `unsafe` block
-  --> $DIR/union-drop.rs:33:9
-   |
-LL |         unsafe { CHECK += 1; }
-   |         ^^^^^^ unnecessary `unsafe` block
-
-warning: unnecessary `unsafe` block
-  --> $DIR/union-drop.rs:40:5
-   |
-LL |     unsafe {
-   |     ^^^^^^ unnecessary `unsafe` block
-
-warning: 3 warnings emitted
-
index 6a355dd2562862003d8bc26663c1ef93cddb6cbd..5c40787febfb76498c19eff2762d28aa7f36af45 100644 (file)
@@ -9,7 +9,7 @@ LL |   trait Foo {
 ...
 LL |       let _z = y.clone();
    |                  ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
    |
 LL | / pub struct Box<
index a4421bcf8097e6ff17cde0c2f78cda6907ad7eb3..8e0804ebf9be93401918c40519db312a6c9eaaf6 100644 (file)
@@ -6,7 +6,7 @@ LL |   struct R {
 ...
 LL |       let _j = i.clone();
    |                  ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds
-   | 
+   |
   ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
    |
 LL | / pub struct Box<
diff --git a/src/test/ui/unsafe/issue-87414-query-cycle.rs b/src/test/ui/unsafe/issue-87414-query-cycle.rs
new file mode 100644 (file)
index 0000000..99e40ba
--- /dev/null
@@ -0,0 +1,15 @@
+// Regression test for #87414.
+
+// check-pass
+// compile-flags: -Zthir-unsafeck
+
+fn bad<T>() -> Box<dyn Iterator<Item = [(); { |x: u32| { x }; 4 }]>> { todo!() }
+
+fn foo() -> [(); { |x: u32| { x }; 4 }] { todo!() }
+fn bar() { let _: [(); { |x: u32| { x }; 4 }]; }
+
+// This one should not cause any errors either:
+unsafe fn unsf() {}
+fn bad2<T>() -> Box<dyn Iterator<Item = [(); { unsafe { || { unsf() } }; 4 }]>> { todo!() }
+
+fn main() {}
diff --git a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr
new file mode 100644 (file)
index 0000000..cd338ac
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:20:5
+   |
+LL |     foo.a += 5;
+   |     ^^^^^^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:21:5
+   |
+LL |     foo.b += Dropping;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:22:5
+   |
+LL |     foo.b = Dropping;
+   |     ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:23:5
+   |
+LL |     foo.a;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:25:5
+   |
+LL |     foo.b;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:27:13
+   |
+LL |     foo.b = foo.b;
+   |             ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:27:5
+   |
+LL |     foo.b = foo.b;
+   |     ^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/union-assignop.rs b/src/test/ui/unsafe/union-assignop.rs
new file mode 100644 (file)
index 0000000..c4be20a
--- /dev/null
@@ -0,0 +1,30 @@
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![feature(untagged_unions)]
+
+use std::ops::AddAssign;
+
+struct Dropping;
+impl AddAssign for Dropping {
+    fn add_assign(&mut self, _: Self) {}
+}
+
+union Foo {
+    a: u8, // non-dropping
+    b: Dropping, // treated as dropping
+}
+
+fn main() {
+    let mut foo = Foo { a: 42 };
+    foo.a += 5; //~ ERROR access to union field is unsafe
+    foo.b += Dropping; //~ ERROR access to union field is unsafe
+    foo.b = Dropping; //~ ERROR assignment to union field that might need dropping is unsafe
+    foo.a; //~ ERROR access to union field is unsafe
+    let foo = Foo { a: 42 };
+    foo.b; //~ ERROR access to union field is unsafe
+    let mut foo = Foo { a: 42 };
+    foo.b = foo.b;
+    //~^ ERROR access to union field is unsafe
+    //~| ERROR assignment to union field that might need dropping
+}
diff --git a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr
new file mode 100644 (file)
index 0000000..71de421
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:20:5
+   |
+LL |     foo.a += 5;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:21:5
+   |
+LL |     foo.b += Dropping;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:22:5
+   |
+LL |     foo.b = Dropping;
+   |     ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:23:5
+   |
+LL |     foo.a;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:25:5
+   |
+LL |     foo.b;
+   |     ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:27:5
+   |
+LL |     foo.b = foo.b;
+   |     ^^^^^^^^^^^^^ assignment to union field that might need dropping
+   |
+   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:27:13
+   |
+LL |     foo.b = foo.b;
+   |             ^^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
index bc30fc90f3a28c261ae257ad9d36c533d354ed86..918e5feb28657bf2084f1d2c9383078bb8f3b8b3 100644 (file)
@@ -3,7 +3,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
    |
 LL | impl Foo for Option<[u8]> {}
    |              ^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
+   |
   ::: $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL | pub enum Option<T> {
index 69b414cc8f92363ff1bcac98f75dee6f7507f796..0eabc592aa41e190eeefbf4d34fddc6803fbcc4d 100644 (file)
@@ -3,7 +3,7 @@ error[E0624]: associated function `static_meth_struct` is private
    |
 LL |     let _ = xc_private_method_lib::Struct::static_meth_struct();
    |                                            ^^^^^^^^^^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/xc-private-method-lib.rs:8:5
    |
 LL |     fn static_meth_struct() -> Struct {
@@ -14,7 +14,7 @@ error[E0624]: associated function `static_meth_enum` is private
    |
 LL |     let _ = xc_private_method_lib::Enum::static_meth_enum();
    |                                          ^^^^^^^^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/xc-private-method-lib.rs:23:5
    |
 LL |     fn static_meth_enum() -> Enum {
index 685ce0e0a186fc668d92225936fadd30e22ec8ed..b569882f8c1595cf94ac453fb0540e2ee4e06192 100644 (file)
@@ -3,7 +3,7 @@ error[E0624]: associated function `meth_struct` is private
    |
 LL |     let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct();
    |                                                    ^^^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/xc-private-method-lib.rs:12:5
    |
 LL |     fn meth_struct(&self) -> isize {
@@ -14,7 +14,7 @@ error[E0624]: associated function `meth_enum` is private
    |
 LL |     let _ = xc_private_method_lib::Enum::Variant1(20).meth_enum();
    |                                                       ^^^^^^^^^ private associated function
-   | 
+   |
   ::: $DIR/auxiliary/xc-private-method-lib.rs:27:5
    |
 LL |     fn meth_enum(&self) -> isize {
index 3dc8b90795c4d5522738c88fa891bd4a2af273a1..cee314568887c5d21859ed4de4f807b35813b4e2 100644 (file)
@@ -3,7 +3,7 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields
    |
 LL |     let _ = xcrate_unit_struct::StructWithFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }`
-   | 
+   |
   ::: $DIR/auxiliary/xcrate_unit_struct.rs:20:1
    |
 LL | pub struct StructWithFields {
index 1e19b7b21d8bf0fe387029852b8afa4d6df12add..ab63a9e2dfa0b8b7b39211e0ca96c52d17101212 100644 (file)
@@ -54,6 +54,7 @@
 static TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-apple-ios",
+    "aarch64-apple-ios-sim",
     "aarch64-fuchsia",
     "aarch64-linux-android",
     "aarch64-pc-windows-msvc",
index d21c22870e58499d6c31f1bef3bf1255eb021666..cc17afbb0067b1f57d8882640f63b2168d5b7624 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d21c22870e58499d6c31f1bef3bf1255eb021666
+Subproject commit cc17afbb0067b1f57d8882640f63b2168d5b7624
index c39829fdc7aad2b6bbc3e4885a3ed39d45750e80..a3a3603c4c0ee5617b86c3c2a5e63f4116cce09b 100644 (file)
@@ -21,6 +21,7 @@
 use rustc_parse::parser::ForceCollect;
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
 use rustc_span::{sym, FileName, Pos};
@@ -231,7 +232,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                     fpu.visit_expr(&body.value);
                     lint_for_missing_headers(
                         cx,
-                        item.hir_id(),
+                        item.def_id,
                         item.span,
                         sig,
                         headers,
@@ -258,7 +259,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte
         let headers = check_attrs(cx, &self.valid_idents, attrs);
         if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
             if !in_external_macro(cx.tcx.sess, item.span) {
-                lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, None, None);
+                lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, None, None);
             }
         }
     }
@@ -279,7 +280,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
             fpu.visit_expr(&body.value);
             lint_for_missing_headers(
                 cx,
-                item.hir_id(),
+                item.def_id,
                 item.span,
                 sig,
                 headers,
@@ -292,14 +293,14 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
 
 fn lint_for_missing_headers<'tcx>(
     cx: &LateContext<'tcx>,
-    hir_id: hir::HirId,
+    def_id: LocalDefId,
     span: impl Into<MultiSpan> + Copy,
     sig: &hir::FnSig<'_>,
     headers: DocHeaders,
     body_id: Option<hir::BodyId>,
     panic_span: Option<Span>,
 ) {
-    if !cx.access_levels.is_exported(hir_id) {
+    if !cx.access_levels.is_exported(def_id) {
         return; // Private functions do not require doc comments
     }
     if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
@@ -321,6 +322,7 @@ fn lint_for_missing_headers<'tcx>(
         );
     }
     if !headers.errors {
+        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
         if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
             span_lint(
                 cx,
index 32b95745b64d1092a3032bbc44c6848518ac93e3..174260fabd228688c47943efa52d9cae07f84481 100644 (file)
@@ -297,7 +297,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
                 check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
             }
         }
index e00126046c0223fcaf5142e92f554caa572267dd..bb4684ce38b3d7eba4b74988aa8fe5cad9ddf05f 100644 (file)
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if_chain! {
             if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
-            if cx.access_levels.is_exported(item.hir_id());
+            if cx.access_levels.is_exported(item.def_id);
             let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
             then {
index 7f4fb68cf2f6f16be8c4725809ad3c8ad05ae3d9..ea6193acbe84518ade96aef8d33277b5c5bedac7 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
-use rustc_hir::def_id::DefIdSet;
+use rustc_hir::def_id::{DefIdSet, LocalDefId};
 use rustc_hir::{self as hir, def::Res, intravisit, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::{
@@ -22,7 +22,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let attr = must_use_attr(attrs);
     if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
@@ -33,7 +33,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.hir_id(),
+                item.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this function could have a `#[must_use]` attribute",
             );
@@ -43,7 +43,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 
 pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         let attr = must_use_attr(attrs);
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
                 sig.decl,
                 cx.tcx.hir().body(*body_id),
                 item.span,
-                item.hir_id(),
+                item.def_id,
                 item.span.with_hi(sig.decl.output.span().hi()),
                 "this method could have a `#[must_use]` attribute",
             );
@@ -65,7 +65,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
 
 pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir().attrs(item.hir_id());
@@ -80,7 +80,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte
                     sig.decl,
                     body,
                     item.span,
-                    item.hir_id(),
+                    item.def_id,
                     item.span.with_hi(sig.decl.output.span().hi()),
                     "this method could have a `#[must_use]` attribute",
                 );
@@ -132,7 +132,7 @@ fn check_must_use_candidate<'tcx>(
     decl: &'tcx hir::FnDecl<'_>,
     body: &'tcx hir::Body<'_>,
     item_span: Span,
-    item_id: hir::HirId,
+    item_id: LocalDefId,
     fn_span: Span,
     msg: &str,
 ) {
@@ -141,7 +141,7 @@ fn check_must_use_candidate<'tcx>(
         || in_external_macro(cx.sess(), item_span)
         || returns_unit(decl)
         || !cx.access_levels.is_exported(item_id)
-        || is_must_use_ty(cx, return_ty(cx, item_id))
+        || is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
     {
         return;
     }
index af759a48e10ca117d2f41aa62732df586d0b0723..f83789bb2199e0e2bfff2fb35eb2d64297c1e7ac 100644 (file)
@@ -1,6 +1,7 @@
 use rustc_hir::{self as hir, intravisit, HirIdSet};
 use rustc_lint::LateContext;
 use rustc_middle::{hir::map::Map, ty};
+use rustc_span::def_id::LocalDefId;
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::type_is_unsafe_function;
@@ -21,13 +22,13 @@ pub(super) fn check_fn(
         intravisit::FnKind::Closure => return,
     };
 
-    check_raw_ptr(cx, unsafety, decl, body, hir_id);
+    check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
 }
 
 pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.hir_id());
+        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
     }
 }
 
@@ -36,10 +37,10 @@ fn check_raw_ptr(
     unsafety: hir::Unsafety,
     decl: &'tcx hir::FnDecl<'tcx>,
     body: &'tcx hir::Body<'tcx>,
-    hir_id: hir::HirId,
+    def_id: LocalDefId,
 ) {
     let expr = &body.value;
-    if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(hir_id) {
+    if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
             .zip(decl.inputs.iter())
             .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
index c073f312d386f3fc0d0155e7f9693bd4912e441b..13863ec8381bba34f37939e66b4e3abe8cdbe40b 100644 (file)
@@ -15,7 +15,7 @@
 
 pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if is_public {
             check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
@@ -25,7 +25,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 
 pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
             check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
@@ -35,7 +35,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
 
 pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.hir_id());
+        let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         if is_public {
             check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
index fcc43cce6ce4b9568c43c9f6a3c19a9ca82e0e33..6b407c7bb6724b5d288ab5dbb61d2af55960c941 100644 (file)
@@ -112,7 +112,7 @@ fn suggestion<'tcx>(
             }
         }
 
-        if !cx.access_levels.is_exported(item.hir_id()) {
+        if !cx.access_levels.is_exported(item.def_id) {
             return;
         }
 
index b66d7a9f7294f5844add5ca01daafb0c501283f8..a2cbfb1a05eeaec47f6d5979995dcbd4c3383129 100644 (file)
@@ -131,7 +131,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
             if item.ident.name == sym::len;
             if let ImplItemKind::Fn(sig, _) = &item.kind;
             if sig.decl.implicit_self.has_implicit_self();
-            if cx.access_levels.is_exported(item.hir_id());
+            if cx.access_levels.is_exported(item.def_id);
             if matches!(sig.decl.output, FnRetTy::Return(_));
             if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
             if imp.of_trait.is_none();
@@ -207,7 +207,7 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
         }
     }
 
-    if cx.access_levels.is_exported(visited_trait.hir_id())
+    if cx.access_levels.is_exported(visited_trait.def_id)
         && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
     {
         let mut current_and_super_traits = DefIdSet::default();
@@ -331,11 +331,7 @@ fn check_for_is_empty(
             None,
             None,
         ),
-        Some(is_empty)
-            if !cx
-                .access_levels
-                .is_exported(cx.tcx.hir().local_def_id_to_hir_id(is_empty.def_id.expect_local())) =>
-        {
+        Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => {
             (
                 format!(
                     "{} `{}` has a public `len` method, but a private `is_empty` method",
index 5aa29424349f108bb6f22d6d6561855756ae0c1a..1909fabb22fe77c35785145f963935cd29fbdc8d 100644 (file)
@@ -1903,7 +1903,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
 
             then {
                 // if this impl block implements a trait, lint in trait definition instead
-                if !implements_trait && cx.access_levels.is_exported(impl_item.hir_id()) {
+                if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
                     // check missing trait implementations
                     for method_config in &TRAIT_METHODS {
                         if name == method_config.method_name &&
@@ -1935,7 +1935,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
 
                 if sig.decl.implicit_self.has_implicit_self()
                     && !(self.avoid_breaking_exported_api
-                        && cx.access_levels.is_exported(impl_item.hir_id()))
+                        && cx.access_levels.is_exported(impl_item.def_id))
                 {
                     wrong_self_convention::check(
                         cx,
index be5b4b4006ffd6758083407838c2796d33569979..977e6d966e873779cd4d72e909278e2cbced50ea 100644 (file)
@@ -87,7 +87,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             return;
         }
 
-        if !cx.access_levels.is_exported(it.hir_id()) {
+        if !cx.access_levels.is_exported(it.def_id) {
             return;
         }
         match it.kind {
@@ -140,7 +140,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         }
 
         // If the item being implemented is not exported, then we don't need #[inline]
-        if !cx.access_levels.is_exported(impl_item.hir_id()) {
+        if !cx.access_levels.is_exported(impl_item.def_id) {
             return;
         }
 
@@ -155,7 +155,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         };
 
         if let Some(trait_def_id) = trait_def_id {
-            if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.hir_id()) {
+            if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id) {
                 // If a trait is being implemented for an item, and the
                 // trait is not exported, we don't need #[inline]
                 return;
index 5c63d245bf1202238528872f48b3c3c098df509f..0ad616a39d266bf9657b6875a0c05ce793b1348e 100644 (file)
@@ -99,7 +99,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                         if_chain! {
                             if sig.decl.inputs.is_empty();
                             if name == sym::new;
-                            if cx.access_levels.is_reachable(id);
+                            if cx.access_levels.is_reachable(impl_item.def_id);
                             let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if TyS::same_type(self_ty, return_ty(cx, id));
index f738ac2541788ca53ce1f620b14670b92eefe64c..1222a95d4eaa86852021c60f6cac6bf61dd923ba 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{sym, Span};
 use rustc_target::abi::LayoutOf;
 use rustc_target::spec::abi::Abi;
@@ -134,13 +135,12 @@ pub fn new(
         }
     }
 
-    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
-        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
+        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
             return;
         }
-        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 
-        let fn_sig = cx.tcx.fn_sig(fn_def_id);
+        let fn_sig = cx.tcx.fn_sig(def_id);
         let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
 
         let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
@@ -231,7 +231,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte
         }
 
         if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
-            self.check_poly_fn(cx, item.hir_id(), &*method_sig.decl, None);
+            self.check_poly_fn(cx, item.def_id, &*method_sig.decl, None);
         }
     }
 
@@ -278,6 +278,6 @@ fn check_fn(
             }
         }
 
-        self.check_poly_fn(cx, hir_id, decl, Some(span));
+        self.check_poly_fn(cx, cx.tcx.hir().local_def_id(hir_id), decl, Some(span));
     }
 }
index 59a55b9dffad4ed09a032383b2a0676187ad5d79..ed2e1f90fa597a76737ddfaf9b38fc7bfd1cebc8 100644 (file)
@@ -41,7 +41,7 @@ pub struct RedundantPubCrate {
 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let VisibilityKind::Crate { .. } = item.vis.node {
-            if !cx.access_levels.is_exported(item.hir_id()) {
+            if !cx.access_levels.is_exported(item.def_id) {
                 if let Some(false) = self.is_exported.last() {
                     let span = item.span.with_hi(item.ident.span.hi());
                     let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
@@ -64,7 +64,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         }
 
         if let ItemKind::Mod { .. } = item.kind {
-            self.is_exported.push(cx.access_levels.is_exported(item.hir_id()));
+            self.is_exported.push(cx.access_levels.is_exported(item.def_id));
         }
     }
 
index 7a62b21937ff04a4fbfb3e5aca2d5212fc556d12..5ca861a14bf2d121ebf180ebc893e00d790bf726 100644 (file)
@@ -81,7 +81,8 @@ fn check_fn(
         // Abort if public function/method or closure.
         match fn_kind {
             FnKind::ItemFn(..) | FnKind::Method(..) => {
-                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+                let def_id = cx.tcx.hir().local_def_id(hir_id);
+                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
                     return;
                 }
             },
index 7fa0e23ee73eae572a8d4e8b8965f0809c46d812..dbf335a70c83118eee6fcc88f1829ab6e6baffd8 100644 (file)
@@ -104,7 +104,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
         if in_external_macro(cx.sess(), it.span)
-            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id))
         {
             return;
         }
index 453e3ef7dab5aad6450bee09b2c02de94c5b18cb..99ec9c1707aad74b4a4a6d301f27fb1c19733f58 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 453e3ef7dab5aad6450bee09b2c02de94c5b18cb
+Subproject commit 99ec9c1707aad74b4a4a6d301f27fb1c19733f58
index 0f40e0ef6e634eadea5e0bbf99eccf1d11eda4f6..da36ce0e69002442d5bafd6c910af73770bfad8f 100644 (file)
@@ -9,6 +9,6 @@ clap = "2.25.0"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.11"
+version = "0.4.12"
 default-features = false
 features = ["search"]