]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #65140 - petrochenkov:disapp, r=nikomatsakis
authorbors <bors@rust-lang.org>
Thu, 10 Oct 2019 12:02:47 +0000 (12:02 +0000)
committerbors <bors@rust-lang.org>
Thu, 10 Oct 2019 12:02:47 +0000 (12:02 +0000)
resolve: Remove an incorrect assert

Fixes https://github.com/rust-lang/rust/issues/64803.

476 files changed:
CODE_OF_CONDUCT.md
Cargo.lock
config.toml.example
src/bootstrap/builder.rs
src/bootstrap/test.rs
src/ci/docker/asmjs/Dockerfile
src/ci/docker/disabled/wasm32-exp/Dockerfile [new file with mode: 0644]
src/ci/docker/disabled/wasm32-exp/node.sh [new file with mode: 0755]
src/ci/docker/disabled/wasm32/Dockerfile
src/ci/docker/scripts/emscripten-wasm.sh [new file with mode: 0644]
src/ci/docker/scripts/emscripten.sh
src/doc/reference
src/doc/unstable-book/src/language-features/track-caller.md [new file with mode: 0644]
src/liballoc/boxed.rs
src/liballoc/tests/binary_heap.rs
src/liballoc/tests/str.rs
src/liballoc/tests/str.rs.rej [deleted file]
src/liballoc/tests/vec.rs
src/libcore/cell.rs
src/libcore/ffi.rs
src/libcore/hint.rs
src/libcore/macros.rs
src/libcore/option.rs
src/libcore/slice/mod.rs
src/libcore/str/mod.rs
src/librustc/Cargo.toml
src/librustc/dep_graph/graph.rs
src/librustc/error_codes.rs
src/librustc/hir/check_attr.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/mod.rs
src/librustc/infer/opaque_types/mod.rs
src/librustc/infer/region_constraints/leak_check.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/lint/mod.rs
src/librustc/middle/cstore.rs
src/librustc/middle/dead.rs [deleted file]
src/librustc/middle/entry.rs [deleted file]
src/librustc/middle/intrinsicck.rs [deleted file]
src/librustc/middle/liveness.rs [deleted file]
src/librustc/mir/interpret/value.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/mod.rs
src/librustc/traits/project.rs
src/librustc/traits/query/evaluate_obligation.rs
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/specialize/specialization_graph.rs
src/librustc/traits/util.rs
src/librustc/ty/context.rs
src/librustc/ty/flags.rs
src/librustc/ty/fold.rs
src/librustc/ty/instance.rs
src/librustc/ty/layout.rs
src/librustc/ty/outlives.rs
src/librustc/ty/print/obsolete.rs
src/librustc/ty/print/pretty.rs
src/librustc/ty/query/config.rs
src/librustc/ty/query/on_disk_cache.rs
src/librustc/ty/query/plumbing.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/ty/subst.rs
src/librustc/ty/walk.rs
src/librustc/util/common.rs
src/librustc_codegen_llvm/allocator.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_llvm/back/lto.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/consts.rs
src/librustc_codegen_llvm/context.rs
src/librustc_codegen_llvm/debuginfo/gdb.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/debuginfo/mod.rs
src/librustc_codegen_llvm/llvm_util.rs
src/librustc_codegen_llvm/type_of.rs
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/mir/mod.rs
src/librustc_codegen_utils/symbol_names/legacy.rs
src/librustc_codegen_utils/symbol_names/v0.rs
src/librustc_data_structures/Cargo.toml
src/librustc_errors/diagnostic.rs
src/librustc_errors/emitter.rs
src/librustc_errors/lib.rs
src/librustc_errors/styled_buffer.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/save.rs
src/librustc_interface/Cargo.toml
src/librustc_interface/interface.rs
src/librustc_interface/lib.rs
src/librustc_interface/passes.rs
src/librustc_interface/profile/mod.rs [deleted file]
src/librustc_interface/profile/trace.rs [deleted file]
src/librustc_interface/util.rs
src/librustc_lint/error_codes.rs
src/librustc_lint/types.rs
src/librustc_macros/Cargo.toml
src/librustc_macros/src/hash_stable.rs
src/librustc_macros/src/query.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/native_libs.rs
src/librustc_mir/borrow_check/conflict_errors.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/constraint_generation.rs
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
src/librustc_mir/borrow_check/nll/renumber.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/borrow_check/nll/universal_regions.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/as_temp.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/dataflow/impls/storage_liveness.rs
src/librustc_mir/error_codes.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/interpret/intrinsics/type_name.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/item.rs [deleted file]
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/erase_regions.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_passes/Cargo.toml
src/librustc_passes/dead.rs [new file with mode: 0644]
src/librustc_passes/entry.rs [new file with mode: 0644]
src/librustc_passes/error_codes.rs
src/librustc_passes/intrinsicck.rs [new file with mode: 0644]
src/librustc_passes/lib.rs
src/librustc_passes/liveness.rs [new file with mode: 0644]
src/librustc_privacy/error_codes.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/lib.rs
src/librustc_target/abi/call/asmjs.rs [new file with mode: 0644]
src/librustc_target/abi/call/mod.rs
src/librustc_target/abi/call/wasm32.rs
src/librustc_target/abi/call/wasm32_bindgen_compat.rs [deleted file]
src/librustc_target/spec/asmjs_unknown_emscripten.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/wasm32_experimental_emscripten.rs [new file with mode: 0644]
src/librustc_target/spec/wasm32_unknown_emscripten.rs
src/librustc_traits/dropck_outlives.rs
src/librustc_traits/evaluate_obligation.rs
src/librustc_traits/generic_types.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/error_codes.rs
src/librustc_typeck/lib.rs
src/librustdoc/Cargo.toml
src/librustdoc/clean/cfg.rs
src/librustdoc/clean/mod.rs
src/librustdoc/lib.rs
src/libstd/Cargo.toml
src/libstd/collections/hash/map.rs
src/libstd/fs.rs
src/libstd/net/udp.rs
src/libstd/panicking.rs
src/libstd/rt.rs
src/libstd/sys/unix/fast_thread_local.rs
src/libstd/sys/vxworks/rwlock.rs
src/libstd/sys_common/backtrace.rs
src/libstd/thread/mod.rs
src/libstd/time.rs
src/libsyntax/early_buffered_lints.rs
src/libsyntax/error_codes.rs
src/libsyntax/feature_gate/active.rs
src/libsyntax/feature_gate/builtin_attrs.rs
src/libsyntax/feature_gate/check.rs
src/libsyntax/parse/diagnostics.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/parser/expr.rs
src/libsyntax/parse/parser/item.rs
src/libsyntax/parse/parser/pat.rs
src/libsyntax/parse/parser/ty.rs
src/libsyntax/tokenstream.rs
src/libsyntax_ext/source_util.rs
src/libsyntax_pos/symbol.rs
src/libtest/lib.rs
src/libtest/tests.rs
src/test/codegen/c-variadic.rs
src/test/codegen/drop.rs
src/test/codegen/extern-functions.rs
src/test/codegen/external-no-mangle-statics.rs
src/test/codegen/link_section.rs
src/test/codegen/no-output-asm-is-volatile.rs
src/test/codegen/personality_lifetimes.rs
src/test/codegen/repr-transparent-aggregates-2.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
src/test/codegen/union-abi.rs
src/test/compile-fail/weak-lang-item.rs
src/test/incremental/change_crate_dep_kind.rs
src/test/incremental/commandline-args.rs
src/test/incremental/remapped_paths_cc/main.rs
src/test/incremental/span_hash_stable/main.rs
src/test/incremental/spans_in_type_debuginfo.rs
src/test/incremental/spans_significant_w_debuginfo.rs
src/test/mir-opt/box_expr.rs
src/test/mir-opt/generator-storage-dead-unwind.rs
src/test/mir-opt/issue-41110.rs
src/test/mir-opt/issue-62289.rs
src/test/mir-opt/no-spurious-drop-after-call.rs
src/test/mir-opt/packed-struct-drop-aligned.rs
src/test/mir-opt/remove_fake_borrows.rs
src/test/mir-opt/retag.rs
src/test/run-make/wasm-custom-section/Makefile
src/test/run-make/wasm-custom-sections-opt/Makefile
src/test/run-make/wasm-export-all-symbols/Makefile
src/test/run-make/wasm-import-module/Makefile
src/test/run-make/wasm-panic-small/Makefile
src/test/run-make/wasm-symbols-not-exported/Makefile
src/test/run-make/wasm-symbols-not-imported/Makefile
src/test/ui/abi/statics/static-mut-foreign.rs
src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs [new file with mode: 0644]
src/test/ui/async-await/async-borrowck-escaping-block-error.fixed [new file with mode: 0644]
src/test/ui/async-await/async-borrowck-escaping-block-error.rs [new file with mode: 0644]
src/test/ui/async-await/async-borrowck-escaping-block-error.stderr [new file with mode: 0644]
src/test/ui/async-await/async-fn-size-moved-locals.rs
src/test/ui/async-await/async-fn-size-uninit-locals.rs [new file with mode: 0644]
src/test/ui/async-await/async-fn-size.rs
src/test/ui/async-await/issue-60709.rs
src/test/ui/auto-trait-validation.stderr
src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
src/test/ui/binding/match-arm-statics.rs
src/test/ui/builtin-clone-unwind.rs
src/test/ui/c-variadic/variadic-ffi-4.stderr
src/test/ui/catch-unwind-bang.rs
src/test/ui/conflicting-repr-hints.stderr
src/test/ui/const-generics/slice-const-param-mismatch.stderr
src/test/ui/const-generics/types-mismatch-const-args.rs [new file with mode: 0644]
src/test/ui/const-generics/types-mismatch-const-args.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/issue-50814.rs
src/test/ui/consts/const-eval/issue-50814.stderr
src/test/ui/consts/const-eval/issue-64908.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr [new file with mode: 0644]
src/test/ui/consts/const-int-saturating-arith.rs
src/test/ui/debuginfo-lto.rs
src/test/ui/deprecation/deprecation-sanity.stderr
src/test/ui/did_you_mean/issue-40396.rs
src/test/ui/did_you_mean/issue-40396.stderr
src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
src/test/ui/drop/dynamic-drop-async.rs
src/test/ui/drop/dynamic-drop.rs
src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr
src/test/ui/extern/extern-const.fixed
src/test/ui/extern/extern-const.rs
src/test/ui/extern/extern-const.stderr
src/test/ui/feature-gates/feature-gate-repr-simd.stderr
src/test/ui/feature-gates/feature-gate-track_caller.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-track_caller.stderr [new file with mode: 0644]
src/test/ui/generator/issue-58888.rs
src/test/ui/generator/panic-drops.rs
src/test/ui/generator/panic-safe.rs
src/test/ui/generator/resume-after-return.rs
src/test/ui/generator/size-moved-locals.rs
src/test/ui/if/if-no-match-bindings.stderr
src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
src/test/ui/include-single-expr-helper-1.rs [new file with mode: 0644]
src/test/ui/include-single-expr-helper.rs [new file with mode: 0644]
src/test/ui/include-single-expr.rs [new file with mode: 0644]
src/test/ui/include-single-expr.stderr [new file with mode: 0644]
src/test/ui/inner-static-type-parameter.stderr
src/test/ui/intrinsics/intrinsics-integer.rs
src/test/ui/issues/issue-14875.rs
src/test/ui/issues/issue-16683.stderr
src/test/ui/issues/issue-17758.stderr
src/test/ui/issues/issue-20831-debruijn.stderr
src/test/ui/issues/issue-23477.rs
src/test/ui/issues/issue-24687-embed-debuginfo/main.rs
src/test/ui/issues/issue-24945-repeat-dash-opts.rs
src/test/ui/issues/issue-26484.rs
src/test/ui/issues/issue-29948.rs
src/test/ui/issues/issue-33096.rs
src/test/ui/issues/issue-33992.rs
src/test/ui/issues/issue-34569.rs
src/test/ui/issues/issue-35675.stderr
src/test/ui/issues/issue-36856.rs
src/test/ui/issues/issue-3707.stderr
src/test/ui/issues/issue-42210.rs
src/test/ui/issues/issue-43853.rs
src/test/ui/issues/issue-45731.rs
src/test/ui/issues/issue-46519.rs
src/test/ui/issues/issue-48508.rs
src/test/ui/issues/issue-49579.rs
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
src/test/ui/issues/issue-52213.stderr
src/test/ui/issues/issue-52262.rs [new file with mode: 0644]
src/test/ui/issues/issue-52262.stderr [new file with mode: 0644]
src/test/ui/issues/issue-55796.stderr
src/test/ui/issues/issue-58463.rs
src/test/ui/iterators/iter-count-overflow-debug.rs
src/test/ui/iterators/iter-position-overflow-debug.rs
src/test/ui/iterators/iter-step-overflow-debug.rs
src/test/ui/iterators/iter-sum-overflow-debug.rs
src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
src/test/ui/macros/macro-comma-behavior-rpass.rs
src/test/ui/mir/mir_calls_to_shims.rs
src/test/ui/mir/mir_drop_order.rs
src/test/ui/nll/issue-55394.stderr
src/test/ui/nll/normalization-bounds-error.stderr
src/test/ui/nll/type-alias-free-regions.stderr
src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
src/test/ui/no-patterns-in-args-macro.stderr
src/test/ui/no-patterns-in-args.stderr
src/test/ui/not-panic/not-panic-safe.stderr
src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs
src/test/ui/numbers-arithmetic/i128.rs
src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
src/test/ui/numbers-arithmetic/u128-as-f32.rs
src/test/ui/numbers-arithmetic/u128.rs
src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
src/test/ui/panic-runtime/transitive-link-a-bunch.rs
src/test/ui/panic-runtime/want-unwind-got-abort.rs
src/test/ui/panic-runtime/want-unwind-got-abort2.rs
src/test/ui/panic-uninitialized-zeroed.rs
src/test/ui/parser/issue-33413.rs
src/test/ui/parser/issue-33413.stderr
src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs [new file with mode: 0644]
src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr [new file with mode: 0644]
src/test/ui/parser/no-const-fn-in-extern-block.rs [new file with mode: 0644]
src/test/ui/parser/no-const-fn-in-extern-block.stderr [new file with mode: 0644]
src/test/ui/parser/require-parens-for-chained-comparison.rs
src/test/ui/parser/require-parens-for-chained-comparison.stderr
src/test/ui/proc-macro/expand-with-a-macro.rs
src/test/ui/reachable-unnameable-items.rs
src/test/ui/regions/region-object-lifetime-2.stderr
src/test/ui/regions/region-object-lifetime-4.stderr
src/test/ui/regions/region-object-lifetime-in-coercion.stderr
src/test/ui/regions/regions-addr-of-self.stderr
src/test/ui/regions/regions-addr-of-upvar-self.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-close-object-into-object-2.stderr
src/test/ui/regions/regions-close-object-into-object-4.stderr
src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
src/test/ui/regions/regions-creating-enums4.stderr
src/test/ui/regions/regions-escape-method.stderr
src/test/ui/regions/regions-escape-via-trait-or-not.stderr
src/test/ui/regions/regions-free-region-ordering-incorrect.stderr
src/test/ui/regions/regions-infer-call-3.stderr
src/test/ui/regions/regions-nested-fns.stderr
src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
src/test/ui/regions/regions-ret-borrowed-1.stderr
src/test/ui/regions/regions-ret-borrowed.stderr
src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
src/test/ui/regions/regions-trait-object-subtyping.stderr
src/test/ui/reject-specialized-drops-8142.stderr
src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs [new file with mode: 0644]
src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr [new file with mode: 0644]
src/test/ui/resolve/issue-65035-static-with-parent-generics.rs [new file with mode: 0644]
src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr [new file with mode: 0644]
src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs [new file with mode: 0644]
src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs [new file with mode: 0644]
src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr [new file with mode: 0644]
src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-naked.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-naked.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/only-for-fns.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/only-for-fns.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/pass.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/pass.stderr [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr [new file with mode: 0644]
src/test/ui/rfcs/rfc1857-drop-order.rs
src/test/ui/sepcomp/sepcomp-lib-lto.rs
src/test/ui/specialization/auxiliary/cross_crates_defaults.rs
src/test/ui/specialization/issue-36804.rs
src/test/ui/specialization/non-defaulted-item-fail.rs [new file with mode: 0644]
src/test/ui/specialization/non-defaulted-item-fail.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-default-methods.rs
src/test/ui/suggestions/imm-ref-trait-object-literal.rs [new file with mode: 0644]
src/test/ui/suggestions/imm-ref-trait-object-literal.stderr [new file with mode: 0644]
src/test/ui/suggestions/imm-ref-trait-object.rs [new file with mode: 0644]
src/test/ui/suggestions/imm-ref-trait-object.stderr [new file with mode: 0644]
src/test/ui/suggestions/into-str.stderr
src/test/ui/suggestions/mut-borrow-needed-by-trait.rs [new file with mode: 0644]
src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr [new file with mode: 0644]
src/test/ui/suggestions/remove-as_str.rs [new file with mode: 0644]
src/test/ui/suggestions/remove-as_str.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr [new file with mode: 0644]
src/test/ui/test-attrs/test-allow-fail-attr.rs
src/test/ui/test-attrs/test-should-fail-good-message.rs
src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs
src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
src/test/ui/wf/wf-static-method.stderr
src/tools/cargo
src/tools/clippy
src/tools/compiletest/src/header.rs
src/tools/error_index_generator/build.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes_check.rs [new file with mode: 0644]
src/tools/tidy/src/lib.rs
src/tools/tidy/src/main.rs
triagebot.toml

index 58b829e31d6777845ec46ce0cb49d8dfb5edaa26..e3708bc485399fd42b32c6a1c24491771afa1a04 100644 (file)
@@ -1,40 +1,3 @@
 # The Rust Code of Conduct
 
-A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
-
-## Conduct
-
-**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
-
-* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
-* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
-* Please be kind and courteous. There's no need to be mean or rude.
-* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
-* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
-* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
-* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
-* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
-
-## Moderation
-
-
-These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
-
-1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
-2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
-3. Moderators will first respond to such remarks with a warning.
-4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
-5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
-6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
-7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
-8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
-
-In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
-
-And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
-
-The enforcement policies listed above apply to all official Rust venues; including all communication channels (Rust Discord server, Rust Zulip server); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
-
-*Adapted from the [Node.js Policy on Trolling](https://blog.izs.me/2012/08/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
-
-[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
+The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
index 80364515a7cca509dc7f1468c482c748b42d20a9..217ce65c1963cfdfdc1e792bffe8df9f7f21ef6c 100644 (file)
@@ -107,6 +107,12 @@ dependencies = [
  "winapi 0.3.6",
 ]
 
+[[package]]
+name = "autocfg"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
+
 [[package]]
 name = "backtrace"
 version = "0.3.37"
@@ -659,6 +665,16 @@ dependencies = [
  "crossbeam-utils 0.6.5",
 ]
 
+[[package]]
+name = "crossbeam-deque"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
+dependencies = [
+ "crossbeam-epoch 0.7.2",
+ "crossbeam-utils 0.6.5",
+]
+
 [[package]]
 name = "crossbeam-epoch"
 version = "0.3.1"
@@ -993,7 +1009,7 @@ dependencies = [
  "proc-macro2 0.4.30",
  "quote 0.6.12",
  "syn 0.15.35",
- "synstructure",
+ "synstructure 0.10.2",
 ]
 
 [[package]]
@@ -1259,7 +1275,7 @@ version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
 dependencies = [
- "hashbrown",
+ "hashbrown 0.5.0",
  "lazy_static 1.3.0",
  "log",
  "pest",
@@ -1276,10 +1292,19 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
 dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6587d09be37fb98a11cb08b9000a3f592451c1b1b613ca69d949160e313a430a"
+dependencies = [
+ "autocfg",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
- "serde",
 ]
 
 [[package]]
@@ -2791,22 +2816,22 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4"
+checksum = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
 dependencies = [
- "crossbeam-deque 0.6.3",
+ "crossbeam-deque 0.7.1",
  "either",
  "rayon-core",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.5.0"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2"
+checksum = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
 dependencies = [
- "crossbeam-deque 0.6.3",
+ "crossbeam-deque 0.7.1",
  "crossbeam-queue",
  "crossbeam-utils 0.6.5",
  "lazy_static 1.3.0",
@@ -3074,8 +3099,8 @@ dependencies = [
  "num_cpus",
  "parking_lot 0.9.0",
  "polonius-engine",
- "rustc-rayon",
- "rustc-rayon-core",
+ "rustc-rayon 0.3.0",
+ "rustc-rayon-core 0.3.0",
  "rustc_apfloat",
  "rustc_data_structures",
  "rustc_errors",
@@ -3123,8 +3148,8 @@ dependencies = [
  "rustc-ap-graphviz",
  "rustc-ap-serialize",
  "rustc-hash",
- "rustc-rayon",
- "rustc-rayon-core",
+ "rustc-rayon 0.2.0",
+ "rustc-rayon-core 0.2.0",
  "smallvec",
  "stable_deref_trait",
 ]
@@ -3165,7 +3190,7 @@ dependencies = [
  "proc-macro2 0.4.30",
  "quote 0.6.12",
  "syn 0.15.35",
- "synstructure",
+ "synstructure 0.10.2",
 ]
 
 [[package]]
@@ -3263,7 +3288,18 @@ checksum = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363"
 dependencies = [
  "crossbeam-deque 0.2.0",
  "either",
- "rustc-rayon-core",
+ "rustc-rayon-core 0.2.0",
+]
+
+[[package]]
+name = "rustc-rayon"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f32767f90d938f1b7199a174ef249ae1924f6e5bbdb9d112fea141e016f25b3a"
+dependencies = [
+ "crossbeam-deque 0.7.1",
+ "either",
+ "rustc-rayon-core 0.3.0",
 ]
 
 [[package]]
@@ -3278,6 +3314,19 @@ dependencies = [
  "num_cpus",
 ]
 
+[[package]]
+name = "rustc-rayon-core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2427831f0053ea3ea73559c8eabd893133a51b251d142bacee53c62a288cb3"
+dependencies = [
+ "crossbeam-deque 0.7.1",
+ "crossbeam-queue",
+ "crossbeam-utils 0.6.5",
+ "lazy_static 1.3.0",
+ "num_cpus",
+]
+
 [[package]]
 name = "rustc-serialize"
 version = "0.3.24"
@@ -3398,8 +3447,8 @@ dependencies = [
  "log",
  "parking_lot 0.9.0",
  "rustc-hash",
- "rustc-rayon",
- "rustc-rayon-core",
+ "rustc-rayon 0.3.0",
+ "rustc-rayon-core 0.3.0",
  "rustc_index",
  "serialize",
  "smallvec",
@@ -3479,7 +3528,7 @@ dependencies = [
  "log",
  "once_cell",
  "rustc",
- "rustc-rayon",
+ "rustc-rayon 0.3.0",
  "rustc_codegen_ssa",
  "rustc_codegen_utils",
  "rustc_data_structures",
@@ -3546,10 +3595,10 @@ name = "rustc_macros"
 version = "0.1.0"
 dependencies = [
  "itertools 0.8.0",
- "proc-macro2 0.4.30",
- "quote 0.6.12",
- "syn 0.15.35",
- "synstructure",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
+ "synstructure 0.12.1",
 ]
 
 [[package]]
@@ -3613,6 +3662,8 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_errors",
+ "rustc_index",
+ "rustc_target",
  "syntax",
  "syntax_pos",
 ]
@@ -3756,7 +3807,7 @@ version = "0.0.0"
 dependencies = [
  "minifier",
  "pulldown-cmark 0.5.3",
- "rustc-rayon",
+ "rustc-rayon 0.3.0",
  "tempfile",
 ]
 
@@ -4073,7 +4124,7 @@ dependencies = [
  "core",
  "dlmalloc",
  "fortanix-sgx-abi",
- "hashbrown",
+ "hashbrown 0.6.1",
  "libc",
  "panic_abort",
  "panic_unwind",
@@ -4242,6 +4293,18 @@ dependencies = [
  "unicode-xid 0.1.0",
 ]
 
+[[package]]
+name = "synstructure"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
+dependencies = [
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
+ "unicode-xid 0.2.0",
+]
+
 [[package]]
 name = "syntax"
 version = "0.0.0"
index 2e3b714f9228ab76bfdc3811fc71ecb596bd673f..848147c2974c1d77bc1a7c7c4e88c6cb7bef9cfe 100644 (file)
 # but you can also optionally enable the "emscripten" backend for asm.js or
 # make this an empty array (but that probably won't get too far in the
 # bootstrap)
-# FIXME: remove the obsolete emscripten backend option.
 #codegen-backends = ["llvm"]
 
 # This is the name of the directory in which codegen backends will get installed
index 9b43bb0eff0e845c94b0d8a7da8ad4cdd8c60c97..0caf2d9b6db5a3f64db44e2e50e207437b6332c0 100644 (file)
@@ -817,12 +817,22 @@ pub fn cargo(
 
         let mut rustflags = Rustflags::new(&target);
         if stage != 0 {
+            if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
+                cargo.args(s.split_whitespace());
+            }
             rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
         } else {
+            if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") {
+                cargo.args(s.split_whitespace());
+            }
             rustflags.env("RUSTFLAGS_BOOTSTRAP");
             rustflags.arg("--cfg=bootstrap");
         }
 
+        if let Ok(s) = env::var("CARGOFLAGS") {
+            cargo.args(s.split_whitespace());
+        }
+
         match mode {
             Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {},
             Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
@@ -970,7 +980,6 @@ pub fn cargo(
                 Some("-Wl,-rpath,@loader_path/../lib")
             } else if !target.contains("windows") &&
                       !target.contains("wasm32") &&
-                      !target.contains("emscripten") &&
                       !target.contains("fuchsia") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
             } else {
index e09e25de64a34b421b7e95c427b2e126ad8d1e3d..b7ce9c7b39709e34d4e30d987ff5dd5561aa4d4b 100644 (file)
@@ -1047,11 +1047,10 @@ fn run(self, builder: &Builder<'_>) {
         // Also provide `rust_test_helpers` for the host.
         builder.ensure(native::TestHelpers { target: compiler.host });
 
-        // As well as the target, except for plain wasm32, which can't build it
-        if !target.contains("wasm32") || target.contains("emscripten") {
+        // wasm32 can't build the test helpers
+        if !target.contains("wasm32") {
             builder.ensure(native::TestHelpers { target });
         }
-
         builder.ensure(RemoteCopyLibs { compiler, target });
 
         let mut cmd = builder.tool_cmd(Tool::Compiletest);
index d136fae79aa447c4dd830e3981175bc53dae086e..3abaab6b34ef0dece78106d7955dc7f24c084a5d 100644 (file)
@@ -11,8 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
-  xz-utils \
-  bzip2
+  xz-utils
 
 COPY scripts/emscripten.sh /scripts/
 RUN bash /scripts/emscripten.sh
@@ -21,16 +20,28 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/
-ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/
-ENV BINARYEN_ROOT=/emsdk-portable/upstream/
+ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
+ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
+ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
+ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
+ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
 ENV EM_CONFIG=/emsdk-portable/.emscripten
 
 ENV TARGETS=asmjs-unknown-emscripten
 
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS
+ENV RUST_CONFIGURE_ARGS --enable-emscripten --disable-optimize-tests
 
-# This is almost identical to the wasm32-unknown-emscripten target, so
-# running with assertions again is not useful
-ENV NO_DEBUG_ASSERTIONS=1
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
+  src/test/ui \
+  src/test/run-fail \
+  src/libstd \
+  src/liballoc \
+  src/libcore
+
+# Debug assertions in rustc are largely covered by other builders, and LLVM
+# assertions cause this builder to slow down by quite a large amount and don't
+# buy us a huge amount over other builders (not sure if we've ever seen an
+# asmjs-specific backend assertion trip), so disable assertions for these
+# tests.
 ENV NO_LLVM_ASSERTIONS=1
+ENV NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/disabled/wasm32-exp/Dockerfile b/src/ci/docker/disabled/wasm32-exp/Dockerfile
new file mode 100644 (file)
index 0000000..420d47b
--- /dev/null
@@ -0,0 +1,35 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  jq \
+  bzip2
+
+# emscripten
+COPY scripts/emscripten-wasm.sh /scripts/
+COPY wasm32-exp/node.sh /usr/local/bin/node
+RUN bash /scripts/emscripten-wasm.sh
+
+# cache
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# env
+ENV PATH=/wasm-install/emscripten:/wasm-install/bin:$PATH
+ENV EM_CONFIG=/root/.emscripten
+
+ENV TARGETS=wasm32-experimental-emscripten
+
+ENV RUST_CONFIGURE_ARGS --experimental-targets=WebAssembly
+
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS
diff --git a/src/ci/docker/disabled/wasm32-exp/node.sh b/src/ci/docker/disabled/wasm32-exp/node.sh
new file mode 100755 (executable)
index 0000000..aa93897
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+path="$(dirname $1)"
+file="$(basename $1)"
+
+shift
+
+cd "$path"
+exec /node-v8.0.0-linux-x64/bin/node "$file" "$@"
index b2cf862c0a510060d54aa3773761d853dc565e62..0d2bd39303ef8e1191b6986be45d546842b2b734 100644 (file)
@@ -11,9 +11,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
-  xz-utils \
-  bzip2
+  xz-utils
 
+# emscripten
 COPY scripts/emscripten.sh /scripts/
 RUN bash /scripts/emscripten.sh
 
@@ -21,18 +21,12 @@ COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
 ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/
-ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/
-ENV BINARYEN_ROOT=/emsdk-portable/upstream/
+ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
+ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
+ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
+ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
+ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
 ENV EM_CONFIG=/emsdk-portable/.emscripten
 
 ENV TARGETS=wasm32-unknown-emscripten
-
-# FIXME: Re-enable these tests once Cargo stops trying to execute wasms
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
-    --exclude src/libcore \
-    --exclude src/liballoc \
-    --exclude src/libproc_macro \
-    --exclude src/libstd \
-    --exclude src/libterm \
-    --exclude src/libtest
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS
diff --git a/src/ci/docker/scripts/emscripten-wasm.sh b/src/ci/docker/scripts/emscripten-wasm.sh
new file mode 100644 (file)
index 0000000..e4a93d7
--- /dev/null
@@ -0,0 +1,37 @@
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  rm -f /tmp/build.log
+  set -x
+}
+
+# Download last known good emscripten from WebAssembly waterfall
+BUILD=$(curl -fL https://storage.googleapis.com/wasm-llvm/builds/linux/lkgr.json | \
+    jq '.build | tonumber')
+curl -sL https://storage.googleapis.com/wasm-llvm/builds/linux/$BUILD/wasm-binaries.tbz2 | \
+    hide_output tar xvkj
+
+# node 8 is required to run wasm
+cd /
+curl -sL https://nodejs.org/dist/v8.0.0/node-v8.0.0-linux-x64.tar.xz | \
+    tar -xJ
+
+# Make emscripten use wasm-ready node and LLVM tools
+echo "EMSCRIPTEN_ROOT = '/wasm-install/emscripten'" >> /root/.emscripten
+echo "NODE_JS='/usr/local/bin/node'" >> /root/.emscripten
+echo "LLVM_ROOT='/wasm-install/bin'" >> /root/.emscripten
+echo "BINARYEN_ROOT = '/wasm-install'" >> /root/.emscripten
+echo "COMPILER_ENGINE = NODE_JS" >> /root/.emscripten
+echo "JS_ENGINES = [NODE_JS]" >> /root/.emscripten
index 9c7a09e227a474f9302af39e08486f16f98b2311..47196e8939626a69bc82255bac116f0a68981459 100644 (file)
@@ -17,15 +17,20 @@ exit 1
   set -x
 }
 
-git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable
+cd /
+curl -fL https://mozilla-games.s3.amazonaws.com/emscripten/releases/emsdk-portable.tar.gz | \
+    tar -xz
+
 cd /emsdk-portable
-hide_output ./emsdk install 1.38.46-upstream
-./emsdk activate 1.38.46-upstream
+./emsdk update
+hide_output ./emsdk install sdk-1.38.15-64bit
+./emsdk activate sdk-1.38.15-64bit
 
 # Compile and cache libc
 source ./emsdk_env.sh
 echo "main(){}" > a.c
 HOME=/emsdk-portable/ emcc a.c
+HOME=/emsdk-portable/ emcc -s BINARYEN=1 a.c
 rm -f a.*
 
 # Make emsdk usable by any user
index 320d232b206edecb67489316f71a14e31dbc6c08..5b9d2fcefadfc32fceafacfc0dd9441d9b57dd94 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 320d232b206edecb67489316f71a14e31dbc6c08
+Subproject commit 5b9d2fcefadfc32fceafacfc0dd9441d9b57dd94
diff --git a/src/doc/unstable-book/src/language-features/track-caller.md b/src/doc/unstable-book/src/language-features/track-caller.md
new file mode 100644 (file)
index 0000000..afc11a2
--- /dev/null
@@ -0,0 +1,5 @@
+# `track_caller`
+
+The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809).
+
+------------------------
index b2789a535fe498827bd78573e1fdf20d3b34efc3..9b5d9431ae20491b8c10efa8d370f236ffffc4eb 100644 (file)
@@ -871,11 +871,33 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     fn nth(&mut self, n: usize) -> Option<I::Item> {
         (**self).nth(n)
     }
+    fn last(self) -> Option<I::Item> {
+        BoxIter::last(self)
+    }
+}
+
+trait BoxIter {
+    type Item;
+    fn last(self) -> Option<Self::Item>;
+}
+
+impl<I: Iterator + ?Sized> BoxIter for Box<I> {
+    type Item = I::Item;
+    default fn last(self) -> Option<I::Item> {
+        #[inline]
+        fn some<T>(_: Option<T>, x: T) -> Option<T> {
+            Some(x)
+        }
+
+        self.fold(None, some)
+    }
 }
 
+/// Specialization for sized `I`s that uses `I`s implementation of `last()`
+/// instead of the default.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator + Sized> Iterator for Box<I> {
-    fn last(self) -> Option<I::Item> where I: Sized {
+impl<I: Iterator> BoxIter for Box<I> {
+    fn last(self) -> Option<I::Item> {
         (*self).last()
     }
 }
index b8c720264d0abce13e893dc35b461f3e9d685520..0685fa943c0b87a78c4312cb4e8cee7789b0776c 100644 (file)
@@ -1,5 +1,10 @@
+use std::cmp;
 use std::collections::BinaryHeap;
 use std::collections::binary_heap::{Drain, PeekMut};
+use std::panic::{self, AssertUnwindSafe};
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use rand::{thread_rng, seq::SliceRandom};
 
 #[test]
 fn test_iterator() {
@@ -276,15 +281,9 @@ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
 // even if the order may not be correct.
 //
 // Destructors must be called exactly once per element.
-// FIXME: re-enable emscripten once it can unwind again
 #[test]
-#[cfg(not(any(miri, target_os = "emscripten")))] // Miri does not support catching panics
+#[cfg(not(miri))] // Miri does not support catching panics
 fn panic_safe() {
-    use std::cmp;
-    use std::panic::{self, AssertUnwindSafe};
-    use std::sync::atomic::{AtomicUsize, Ordering};
-    use rand::{thread_rng, seq::SliceRandom};
-
     static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
     #[derive(Eq, PartialEq, Ord, Clone, Debug)]
index cb73c7c179cbf2edba72a0337199e1bbd55f092c..4332b2e90fdaf0493deb3f1489137632fa2ede6e 100644 (file)
@@ -483,7 +483,7 @@ fn simple_unicode() {
     }
 
     #[test]
-    #[cfg(not(target_os = "emscripten"))] // hits an OOM
+    #[cfg(not(target_arch = "asmjs"))] // hits an OOM
     #[cfg(not(miri))] // Miri is too slow
     fn simple_big() {
         fn a_million_letter_x() -> String {
diff --git a/src/liballoc/tests/str.rs.rej b/src/liballoc/tests/str.rs.rej
deleted file mode 100644 (file)
index abcba0c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-diff a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs   (rejected hunks)
-@@ -483,7 +483,7 @@ mod slice_index {
-     }
-     #[test]
--    #[cfg(not(target_arch = "asmjs"))] // hits an OOM
-+    #[cfg(not(target_arch = "js"))] // hits an OOM
-     #[cfg(not(miri))] // Miri is too slow
-     fn simple_big() {
-         fn a_million_letter_x() -> String {
index 80537217697adebedb4e1c31fd3b3f79869e2ab6..98d013dfa2b57616889bb8b3150111077fe90fcf 100644 (file)
@@ -944,10 +944,8 @@ fn drain_filter_complex() {
     }
 }
 
-// Miri does not support catching panics
-// FIXME: re-enable emscripten once it can unwind again
 #[test]
-#[cfg(not(any(miri, target_os = "emscripten")))]
+#[cfg(not(miri))] // Miri does not support catching panics
 fn drain_filter_consumed_panic() {
     use std::rc::Rc;
     use std::sync::Mutex;
@@ -997,9 +995,8 @@ fn drop(&mut self) {
     }
 }
 
-// FIXME: Re-enable emscripten once it can catch panics
 #[test]
-#[cfg(not(any(miri, target_os = "emscripten")))] // Miri does not support catching panics
+#[cfg(not(miri))] // Miri does not support catching panics
 fn drain_filter_unconsumed_panic() {
     use std::rc::Rc;
     use std::sync::Mutex;
index 8579dbf353e800e8c287bcfd3eecacc9eb7f9451..fda103a52d8bc851b8fa4d07f277eb27302d425f 100644 (file)
@@ -229,52 +229,6 @@ pub struct Cell<T: ?Sized> {
     value: UnsafeCell<T>,
 }
 
-impl<T:Copy> Cell<T> {
-    /// Returns a copy of the contained value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// let five = c.get();
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get(&self) -> T {
-        unsafe{ *self.value.get() }
-    }
-
-    /// Updates the contained value using a function and returns the new value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(cell_update)]
-    ///
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    /// let new = c.update(|x| x + 1);
-    ///
-    /// assert_eq!(new, 6);
-    /// assert_eq!(c.get(), 6);
-    /// ```
-    #[inline]
-    #[unstable(feature = "cell_update", issue = "50186")]
-    pub fn update<F>(&self, f: F) -> T
-    where
-        F: FnOnce(T) -> T,
-    {
-        let old = self.get();
-        let new = f(old);
-        self.set(new);
-        new
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: ?Sized> Send for Cell<T> where T: Send {}
 
@@ -448,6 +402,52 @@ pub fn into_inner(self) -> T {
     }
 }
 
+impl<T:Copy> Cell<T> {
+    /// Returns a copy of the contained value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    ///
+    /// let five = c.get();
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get(&self) -> T {
+        unsafe{ *self.value.get() }
+    }
+
+    /// Updates the contained value using a function and returns the new value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cell_update)]
+    ///
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    /// let new = c.update(|x| x + 1);
+    ///
+    /// assert_eq!(new, 6);
+    /// assert_eq!(c.get(), 6);
+    /// ```
+    #[inline]
+    #[unstable(feature = "cell_update", issue = "50186")]
+    pub fn update<F>(&self, f: F) -> T
+    where
+        F: FnOnce(T) -> T,
+    {
+        let old = self.get();
+        let new = f(old);
+        self.set(new);
+        new
+    }
+}
+
 impl<T: ?Sized> Cell<T> {
     /// Returns a raw pointer to the underlying data in this cell.
     ///
index 0ea4187ccd4829b414daed1dd0ac1ebb75445039..eda0e7c518c58290b6f212c2319dae92ee038948 100644 (file)
@@ -49,10 +49,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// Basic implementation of a `va_list`.
 // The name is WIP, using `VaListImpl` for now.
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64")),
+              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
           all(target_arch = "aarch64", target_os = "ios"),
-          target_arch = "wasm32",
-          target_arch = "asmjs",
           windows))]
 #[repr(transparent)]
 #[unstable(feature = "c_variadic",
@@ -69,10 +67,8 @@ pub struct VaListImpl<'f> {
 }
 
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64")),
+              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
           all(target_arch = "aarch64", target_os = "ios"),
-          target_arch = "wasm32",
-          target_arch = "asmjs",
           windows))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
@@ -141,6 +137,38 @@ pub struct VaListImpl<'f> {
     _marker: PhantomData<&'f mut &'f c_void>,
 }
 
+/// asm.js ABI implementation of a `va_list`.
+// asm.js uses the PNaCl ABI, which specifies that a `va_list` is
+// an array of 4 32-bit integers, according to the old PNaCl docs at
+// https://web.archive.org/web/20130518054430/https://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Derived-Types
+// and clang does the same in `CreatePNaClABIBuiltinVaListDecl` from `lib/AST/ASTContext.cpp`
+#[cfg(all(target_arch = "asmjs", not(windows)))]
+#[repr(C)]
+#[unstable(feature = "c_variadic",
+           reason = "the `c_variadic` feature has not been properly tested on \
+                     all supported platforms",
+           issue = "44930")]
+#[lang = "va_list"]
+pub struct VaListImpl<'f> {
+    inner: [crate::mem::MaybeUninit<i32>; 4],
+    _marker: PhantomData<&'f mut &'f c_void>,
+}
+
+#[cfg(all(target_arch = "asmjs", not(windows)))]
+#[unstable(feature = "c_variadic",
+           reason = "the `c_variadic` feature has not been properly tested on \
+                     all supported platforms",
+           issue = "44930")]
+impl<'f> fmt::Debug for VaListImpl<'f> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        unsafe {
+            write!(f, "va_list* [{:#x}, {:#x}, {:#x}, {:#x}]",
+                   self.inner[0].read(), self.inner[1].read(),
+                   self.inner[2].read(), self.inner[3].read())
+        }
+    }
+}
+
 /// A wrapper for a `va_list`
 #[repr(transparent)]
 #[derive(Debug)]
@@ -150,18 +178,14 @@ pub struct VaListImpl<'f> {
            issue = "44930")]
 pub struct VaList<'a, 'f: 'a> {
     #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-                  not(target_arch = "x86_64")),
+                  not(target_arch = "x86_64"), not(target_arch = "asmjs")),
               all(target_arch = "aarch64", target_os = "ios"),
-              target_arch = "wasm32",
-              target_arch = "asmjs",
               windows))]
     inner: VaListImpl<'f>,
 
     #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
-                  target_arch = "x86_64"),
+                  target_arch = "x86_64", target_arch = "asmjs"),
               any(not(target_arch = "aarch64"), not(target_os = "ios")),
-              not(target_arch = "wasm32"),
-              not(target_arch = "asmjs"),
               not(windows)))]
     inner: &'a mut VaListImpl<'f>,
 
@@ -169,10 +193,8 @@ pub struct VaList<'a, 'f: 'a> {
 }
 
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64")),
+              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
           all(target_arch = "aarch64", target_os = "ios"),
-          target_arch = "wasm32",
-          target_arch = "asmjs",
           windows))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
@@ -190,10 +212,8 @@ pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> {
 }
 
 #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
-              target_arch = "x86_64"),
+              target_arch = "x86_64", target_arch = "asmjs"),
           any(not(target_arch = "aarch64"), not(target_os = "ios")),
-          not(target_arch = "wasm32"),
-          not(target_arch = "asmjs"),
           not(windows)))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
index 368a2f16b281e726530a25285c057e5daf80093f..ee4be6c9151194b0e7a58e32b8be797e188bd933 100644 (file)
@@ -114,8 +114,24 @@ pub fn black_box<T>(dummy: T) -> T {
     // this. LLVM's intepretation of inline assembly is that it's, well, a black
     // box. This isn't the greatest implementation since it probably deoptimizes
     // more than we want, but it's so far good enough.
+    #[cfg(not(any(
+        target_arch = "asmjs",
+        all(
+            target_arch = "wasm32",
+            target_os = "emscripten"
+        )
+    )))]
     unsafe {
         asm!("" : : "r"(&dummy));
         return dummy;
     }
+
+    // Not all platforms support inline assembly so try to do something without
+    // inline assembly which in theory still hinders at least some optimizations
+    // on those targets. This is the "best effort" scenario.
+    unsafe {
+        let ret = crate::ptr::read_volatile(&dummy);
+        crate::mem::forget(dummy);
+        ret
+    }
 }
index ca1b06fb81a78f534a8774cabec180a3af0873a0..1320e63df0635289d00b1ba756bb35182605de92 100644 (file)
@@ -520,18 +520,20 @@ macro_rules! unreachable {
     });
 }
 
-/// Indicates unfinished code.
+/// Indicates unfinished code by panicking with a message of "not yet implemented".
 ///
-/// This can be useful if you are prototyping and are just looking to have your
-/// code type-check, or if you're implementing a trait that requires multiple
-/// methods, and you're only planning on using one of them.
+/// This allows the your code to type-check, which is useful if you are prototyping or
+/// implementing a trait that requires multiple methods which you don't plan of using all of.
 ///
 /// There is no difference between `unimplemented!` and `todo!` apart from the
 /// name.
 ///
 /// # Panics
 ///
-/// This will always [panic!](macro.panic.html)
+/// This will always [panic!](macro.panic.html) because `unimplemented!` is just a
+/// shorthand for `panic!` with a fixed, specific message.
+///
+/// Like `panic!`, this macro has a second form for displaying custom values.
 ///
 /// # Examples
 ///
@@ -539,38 +541,53 @@ macro_rules! unreachable {
 ///
 /// ```
 /// trait Foo {
-///     fn bar(&self);
+///     fn bar(&self) -> u8;
 ///     fn baz(&self);
+///     fn qux(&self) -> Result<u64, ()>;
 /// }
 /// ```
 ///
-/// We want to implement `Foo` on one of our types, but we also want to work on
-/// just `bar()` first. In order for our code to compile, we need to implement
-/// `baz()`, so we can use `unimplemented!`:
+/// We want to implement `Foo` for 'MyStruct', but so far we only know how to
+/// implement the `bar()` function. `baz()` and `qux()` will still need to be defined
+/// in our implementation of `Foo`, but we can use `unimplemented!` in their definitions
+/// to allow our code to compile.
+///
+/// In the meantime, we want to have our program stop running once these
+/// unimplemented functions are reached.
 ///
 /// ```
 /// # trait Foo {
-/// #     fn bar(&self);
+/// #     fn bar(&self) -> u8;
 /// #     fn baz(&self);
+/// #     fn qux(&self) -> Result<u64, ()>;
 /// # }
 /// struct MyStruct;
 ///
 /// impl Foo for MyStruct {
-///     fn bar(&self) {
-///         // implementation goes here
+///     fn bar(&self) -> u8 {
+///         1 + 1
 ///     }
 ///
 ///     fn baz(&self) {
-///         // let's not worry about implementing baz() for now
+///         // We aren't sure how to even start writing baz yet,
+///         // so we have no logic here at all.
+///         // This will display "thread 'main' panicked at 'not yet implemented'".
 ///         unimplemented!();
 ///     }
+///
+///     fn qux(&self) -> Result<u64, ()> {
+///         let n = self.bar();
+///         // We have some logic here,
+///         // so we can use unimplemented! to display what we have so far.
+///         // This will display:
+///         // "thread 'main' panicked at 'not yet implemented: we need to divide by 2'".
+///         unimplemented!("we need to divide by {}", n);
+///     }
 /// }
 ///
 /// fn main() {
 ///     let s = MyStruct;
 ///     s.bar();
-///
-///     // we aren't even using baz() yet, so this is fine.
 /// }
 /// ```
 #[macro_export]
index 301e432c98dfc4a3af707cf9e2e87475090803c2..47e3a0d21676f6caed5ed4c23832283215947ab5 100644 (file)
@@ -1102,7 +1102,6 @@ pub fn unwrap_or_default(self) -> T {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
 impl<T: Deref> Option<T> {
     /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
     ///
@@ -1114,20 +1113,18 @@ impl<T: Deref> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inner_deref)]
-    ///
     /// let x: Option<String> = Some("hey".to_owned());
     /// assert_eq!(x.as_deref(), Some("hey"));
     ///
     /// let x: Option<String> = None;
     /// assert_eq!(x.as_deref(), None);
     /// ```
+    #[stable(feature = "option_deref", since = "1.40.0")]
     pub fn as_deref(&self) -> Option<&T::Target> {
         self.as_ref().map(|t| t.deref())
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
 impl<T: DerefMut> Option<T> {
     /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
     ///
@@ -1137,14 +1134,13 @@ impl<T: DerefMut> Option<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inner_deref)]
-    ///
     /// let mut x: Option<String> = Some("hey".to_owned());
     /// assert_eq!(x.as_deref_mut().map(|x| {
     ///     x.make_ascii_uppercase();
     ///     x
     /// }), Some("HEY".to_owned().as_mut_str()));
     /// ```
+    #[stable(feature = "option_deref", since = "1.40.0")]
     pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
         self.as_mut().map(|t| t.deref_mut())
     }
index b5462d988378be5c6f099456ffae8ccfa44d7036..4e79ea812044b41deb1c370c296965c7dde34f13 100644 (file)
@@ -63,6 +63,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
+    #[allow(unused_attributes)]
     #[allow_internal_unstable(const_fn_union)]
     pub const fn len(&self) -> usize {
         unsafe {
index ece61dde490fd5cb8a3d843448544bcd1106863a..885696e5acf49f8550c6fa85acc4eda8ec2b891a 100644 (file)
@@ -2167,6 +2167,7 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
     // SAFETY: const sound because we transmute two types with the same layout
+    #[allow(unused_attributes)]
     #[allow_internal_unstable(const_fn_union)]
     pub const fn as_bytes(&self) -> &[u8] {
         #[repr(C)]
index a7c94d057dc49624ca3119a9daec9056239b7c06..9b3609eca3e621be41054851cd692a9bf2d87ebd 100644 (file)
@@ -18,8 +18,8 @@ jobserver = "0.1"
 num_cpus = "1.0"
 scoped-tls = "1.0"
 log = { version = "0.4", features = ["release_max_level_info", "std"] }
-rustc-rayon = "0.2.0"
-rustc-rayon-core = "0.2.0"
+rustc-rayon = "0.3.0"
+rustc-rayon-core = "0.3.0"
 polonius-engine  = "0.10.0"
 rustc_apfloat = { path = "../librustc_apfloat" }
 rustc_target = { path = "../librustc_target" }
index 0c56fc7914b4cfe505a153a9c8782071c378474b..8f18e0312862fc70012c8dcf92204ce7ffffdfc8 100644 (file)
@@ -9,7 +9,6 @@
 use std::collections::hash_map::Entry;
 use std::mem;
 use crate::ty::{self, TyCtxt};
-use crate::util::common::{ProfileQueriesMsg, profq_msg};
 use parking_lot::{Mutex, Condvar};
 
 use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
@@ -75,9 +74,6 @@ struct DepGraphData {
     previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
     dep_node_debug: Lock<FxHashMap<DepNode, String>>,
-
-    // Used for testing, only populated when -Zquery-dep-graph is specified.
-    loaded_from_cache: Lock<FxHashMap<DepNodeIndex, bool>>,
 }
 
 pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
@@ -104,7 +100,6 @@ pub fn new(prev_graph: PreviousDepGraph,
                 emitting_diagnostics_cond_var: Condvar::new(),
                 previous: prev_graph,
                 colors: DepNodeColorMap::new(prev_graph_node_count),
-                loaded_from_cache: Default::default(),
             })),
         }
     }
@@ -260,10 +255,6 @@ fn with_task_impl<'a, C, A, R>(
             //  - we can get an idea of the runtime cost.
             let mut hcx = cx.get_stable_hashing_context();
 
-            if cfg!(debug_assertions) {
-                profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone()))
-            };
-
             let result = if no_tcx {
                 task(cx, arg)
             } else {
@@ -279,10 +270,6 @@ fn with_task_impl<'a, C, A, R>(
                 })
             };
 
-            if cfg!(debug_assertions) {
-                profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)
-            };
-
             let current_fingerprint = hash_result(&mut hcx, &result);
 
             let dep_node_index = finish_task_and_alloc_depnode(
@@ -858,6 +845,8 @@ pub fn is_green(&self, dep_node: &DepNode) -> bool {
     // This method will only load queries that will end up in the disk cache.
     // Other queries will not be executed.
     pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) {
+        let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion");
+
         let data = self.data.as_ref().unwrap();
         for prev_index in data.colors.values.indices() {
             match data.colors.get(prev_index) {
@@ -874,25 +863,6 @@ pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) {
             }
         }
     }
-
-    pub fn mark_loaded_from_cache(&self, dep_node_index: DepNodeIndex, state: bool) {
-        debug!("mark_loaded_from_cache({:?}, {})",
-               self.data.as_ref().unwrap().current.borrow().data[dep_node_index].node,
-               state);
-
-        self.data
-            .as_ref()
-            .unwrap()
-            .loaded_from_cache
-            .borrow_mut()
-            .insert(dep_node_index, state);
-    }
-
-    pub fn was_loaded_from_cache(&self, dep_node: &DepNode) -> Option<bool> {
-        let data = self.data.as_ref().unwrap();
-        let dep_node_index = data.current.borrow().node_to_node_index[dep_node];
-        data.loaded_from_cache.borrow().get(&dep_node_index).cloned()
-    }
 }
 
 /// A "work product" is an intermediate result that we save into the
index 968b0b9f2f2b73eab1e5b67b62fbf7ea0d4d93af..e208e25f6ea9d2d818eacec84b79cf4374dae69d 100644 (file)
@@ -466,67 +466,6 @@ fn main() {
 ```
 "##,
 
-// This shouldn't really ever trigger since the repeated value error comes first
-E0136: r##"
-A binary can only have one entry point, and by default that entry point is the
-function `main()`. If there are multiple such functions, please rename one.
-"##,
-
-E0137: r##"
-More than one function was declared with the `#[main]` attribute.
-
-Erroneous code example:
-
-```compile_fail,E0137
-#![feature(main)]
-
-#[main]
-fn foo() {}
-
-#[main]
-fn f() {} // error: multiple functions with a `#[main]` attribute
-```
-
-This error indicates that the compiler found multiple functions with the
-`#[main]` attribute. This is an error because there must be a unique entry
-point into a Rust program. Example:
-
-```
-#![feature(main)]
-
-#[main]
-fn f() {} // ok!
-```
-"##,
-
-E0138: r##"
-More than one function was declared with the `#[start]` attribute.
-
-Erroneous code example:
-
-```compile_fail,E0138
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize {}
-
-#[start]
-fn f(argc: isize, argv: *const *const u8) -> isize {}
-// error: multiple 'start' functions
-```
-
-This error indicates that the compiler found multiple functions with the
-`#[start]` attribute. This is an error because there must be a unique entry
-point into a Rust program. Example:
-
-```
-#![feature(start)]
-
-#[start]
-fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
-```
-"##,
-
 E0139: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
@@ -1580,8 +1519,51 @@ impl<'a, T> SomeTrait<'a> for T
 ```
 "##,
 
+E0495: r##"
+A lifetime cannot be determined in the given situation.
+
+Erroneous code example:
+
+```compile_fail,E0495
+fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+    match (&t,) { // error!
+        ((u,),) => u,
+    }
+}
+
+let y = Box::new((42,));
+let x = transmute_lifetime(&y);
+```
+
+In this code, you have two ways to solve this issue:
+ 1. Enforce that `'a` lives at least as long as `'b`.
+ 2. Use the same lifetime requirement for both input and output values.
+
+So for the first solution, you can do it by replacing `'a` with `'a: 'b`:
+
+```
+fn transmute_lifetime<'a: 'b, 'b, T>(t: &'a (T,)) -> &'b T {
+    match (&t,) { // ok!
+        ((u,),) => u,
+    }
+}
+```
+
+In the second you can do it by simply removing `'b` so they both use `'a`:
+
+```
+fn transmute_lifetime<'a, T>(t: &'a (T,)) -> &'a T {
+    match (&t,) { // ok!
+        ((u,),) => u,
+    }
+}
+```
+"##,
+
 E0496: r##"
-A lifetime name is shadowing another lifetime name. Erroneous code example:
+A lifetime name is shadowing another lifetime name.
+
+Erroneous code example:
 
 ```compile_fail,E0496
 struct Foo<'a> {
@@ -1613,8 +1595,11 @@ fn main() {
 "##,
 
 E0497: r##"
-A stability attribute was used outside of the standard library. Erroneous code
-example:
+#### Note: this error code is no longer emitted by the compiler.
+
+A stability attribute was used outside of the standard library.
+
+Erroneous code example:
 
 ```compile_fail
 #[stable] // error: stability attributes may not be used outside of the
@@ -1626,33 +1611,6 @@ fn foo() {}
 Also, for now, it is not possible to write deprecation messages either.
 "##,
 
-E0512: r##"
-Transmute with two differently sized types was attempted. Erroneous code
-example:
-
-```compile_fail,E0512
-fn takes_u8(_: u8) {}
-
-fn main() {
-    unsafe { takes_u8(::std::mem::transmute(0u16)); }
-    // error: cannot transmute between types of different sizes,
-    //        or dependently-sized types
-}
-```
-
-Please use types with same size or use the expected type directly. Example:
-
-```
-fn takes_u8(_: u8) {}
-
-fn main() {
-    unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok!
-    // or:
-    unsafe { takes_u8(0u8); } // ok!
-}
-```
-"##,
-
 E0517: r##"
 This error indicates that a `#[repr(..)]` attribute was placed on an
 unsupported item.
@@ -1787,6 +1745,27 @@ fn main() {
 https://doc.rust-lang.org/book/ch13-01-closures.html
 "##,
 
+E0566: r##"
+Conflicting representation hints have been used on a same item.
+
+Erroneous code example:
+
+```
+#[repr(u32, u64)] // warning!
+enum Repr { A }
+```
+
+In most cases (if not all), using just one representation hint is more than
+enough. If you want to have a representation hint depending on the current
+architecture, use `cfg_attr`. Example:
+
+```
+#[cfg_attr(linux, repr(u32))]
+#[cfg_attr(not(linux), repr(u64))]
+enum Repr { A }
+```
+"##,
+
 E0580: r##"
 The `main` function was incorrectly declared.
 
@@ -1847,84 +1826,6 @@ fn main() {
 [RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md
 "##,
 
-E0591: r##"
-Per [RFC 401][rfc401], if you have a function declaration `foo`:
-
-```
-// For the purposes of this explanation, all of these
-// different kinds of `fn` declarations are equivalent:
-struct S;
-fn foo(x: S) { /* ... */ }
-# #[cfg(for_demonstration_only)]
-extern "C" { fn foo(x: S); }
-# #[cfg(for_demonstration_only)]
-impl S { fn foo(self) { /* ... */ } }
-```
-
-the type of `foo` is **not** `fn(S)`, as one might expect.
-Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`.
-However, `typeof(foo)` can be _coerced_ to a function pointer `fn(S)`,
-so you rarely notice this:
-
-```
-# struct S;
-# fn foo(_: S) {}
-let x: fn(S) = foo; // OK, coerces
-```
-
-The reason that this matter is that the type `fn(S)` is not specific to
-any particular function: it's a function _pointer_. So calling `x()` results
-in a virtual call, whereas `foo()` is statically dispatched, because the type
-of `foo` tells us precisely what function is being called.
-
-As noted above, coercions mean that most code doesn't have to be
-concerned with this distinction. However, you can tell the difference
-when using **transmute** to convert a fn item into a fn pointer.
-
-This is sometimes done as part of an FFI:
-
-```compile_fail,E0591
-extern "C" fn foo(userdata: Box<i32>) {
-    /* ... */
-}
-
-# fn callback(_: extern "C" fn(*mut i32)) {}
-# use std::mem::transmute;
-# unsafe {
-let f: extern "C" fn(*mut i32) = transmute(foo);
-callback(f);
-# }
-```
-
-Here, transmute is being used to convert the types of the fn arguments.
-This pattern is incorrect because, because the type of `foo` is a function
-**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
-is a function pointer, which is not zero-sized.
-This pattern should be rewritten. There are a few possible ways to do this:
-
-- change the original fn declaration to match the expected signature,
-  and do the cast in the fn body (the preferred option)
-- cast the fn item fo a fn pointer before calling transmute, as shown here:
-
-    ```
-    # extern "C" fn foo(_: Box<i32>) {}
-    # use std::mem::transmute;
-    # unsafe {
-    let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_));
-    let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too
-    # }
-    ```
-
-The same applies to transmutes to `*mut fn()`, which were observed in practice.
-Note though that use of this type is generally incorrect.
-The intention is typically to describe a function pointer, but just `fn()`
-alone suffices for that. `*mut fn()` is a pointer to a fn pointer.
-(Since these values are typically just passed to C code, however, this rarely
-makes a difference in practice.)
-
-[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
-"##,
-
 E0593: r##"
 You tried to supply an `Fn`-based type with an incorrect number of arguments
 than what was expected.
@@ -1941,21 +1842,6 @@ fn main() {
 ```
 "##,
 
-E0601: r##"
-No `main` function was found in a binary crate. To fix this error, add a
-`main` function. For example:
-
-```
-fn main() {
-    // Your program will start here.
-    println!("Hello world!");
-}
-```
-
-If you don't know the basics of Rust, you can go look to the Rust Book to get
-started: https://doc.rust-lang.org/book/
-"##,
-
 E0602: r##"
 An unknown lint was used on the command line.
 
@@ -2234,6 +2120,25 @@ fn foo(){}
 rejected in your own crates.
 "##,
 
+E0736: r##"
+#[track_caller] and #[naked] cannot be applied to the same function.
+
+Erroneous code example:
+
+```compile_fail,E0736
+#![feature(track_caller)]
+
+#[naked]
+#[track_caller]
+fn foo() {}
+```
+
+This is primarily due to ABI incompatibilities between the two attributes.
+See [RFC 2091] for details on this and other limitations.
+
+[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
+"##,
+
 ;
 //  E0006, // merged with E0005
 //  E0101, // replaced with E0282
@@ -2243,7 +2148,7 @@ fn foo(){}
 //  E0272, // on_unimplemented #0
 //  E0273, // on_unimplemented #1
 //  E0274, // on_unimplemented #2
-    E0278, // requirement is not satisfied
+//  E0278, // requirement is not satisfied
     E0279, // requirement is not satisfied
     E0280, // requirement is not satisfied
 //  E0285, // overflow evaluation builtin bounds
@@ -2275,9 +2180,6 @@ fn foo(){}
     E0488, // lifetime of variable does not enclose its declaration
     E0489, // type/lifetime parameter not in scope here
     E0490, // a value of type `..` is borrowed for too long
-    E0495, // cannot infer an appropriate lifetime due to conflicting
-           // requirements
-    E0566, // conflicting representation hints
     E0623, // lifetime mismatch where both parameters are anonymous regions
     E0628, // generators cannot have explicit parameters
     E0631, // type mismatch in closure arguments
@@ -2286,14 +2188,15 @@ fn foo(){}
     E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
     E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
     E0697, // closures cannot be static
-    E0707, // multiple elided lifetimes used in arguments of `async fn`
+//  E0707, // multiple elided lifetimes used in arguments of `async fn`
     E0708, // `async` non-`move` closures with parameters are not currently
            // supported
-    E0709, // multiple different lifetimes used in arguments of `async fn`
+//  E0709, // multiple different lifetimes used in arguments of `async fn`
     E0710, // an unknown tool name found in scoped lint
     E0711, // a feature has been declared with conflicting stability attributes
 //  E0702, // replaced with a generic attribute input check
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
     E0727, // `async` generators are not yet supported
     E0728, // `await` must be in an `async` function or block
+    E0739, // invalid track_caller application/syntax
 }
index d5e956555bdfb7e4a526027c246af743a10261cf..c37fec982b1160bd80d505d3f6ad3432ac721545 100644 (file)
@@ -11,7 +11,7 @@
 use crate::ty::query::Providers;
 
 use std::fmt::{self, Display};
-use syntax::symbol::sym;
+use syntax::{attr, symbol::sym};
 use syntax_pos::Span;
 
 #[derive(Copy, Clone, PartialEq)]
@@ -103,6 +103,8 @@ fn check_attributes(&self, item: &hir::Item, target: Target) {
                 self.check_marker(attr, item, target)
             } else if attr.check_name(sym::target_feature) {
                 self.check_target_feature(attr, item, target)
+            } else if attr.check_name(sym::track_caller) {
+                self.check_track_caller(attr, &item, target)
             } else {
                 true
             };
@@ -135,6 +137,32 @@ fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bo
         }
     }
 
+    /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
+    fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
+        if target != Target::Fn {
+            struct_span_err!(
+                self.tcx.sess,
+                attr.span,
+                E0739,
+                "attribute should be applied to function"
+            )
+            .span_label(item.span, "not a function")
+            .emit();
+            false
+        } else if attr::contains_name(&item.attrs, sym::naked) {
+            struct_span_err!(
+                self.tcx.sess,
+                attr.span,
+                E0736,
+                "cannot use `#[track_caller]` with `#[naked]`",
+            )
+            .emit();
+            false
+        } else {
+            true
+        }
+    }
+
     /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
     fn check_non_exhaustive(
         &self,
index 2238a56b29d04b150139935aed91f6deaa676067..72fd054ee8a206e2abf7611d1def7371b34a0376 100644 (file)
@@ -242,6 +242,8 @@ pub fn lower_crate(
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
+    let _prof_timer = sess.prof.generic_activity("hir_lowering");
+
     LoweringContext {
         crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
         sess,
@@ -844,7 +846,7 @@ fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) {
     /// header, we convert it to an in-band lifetime.
     fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
         assert!(self.is_collecting_in_band_lifetimes);
-        let index = self.lifetimes_to_define.len();
+        let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len();
         let hir_name = ParamName::Fresh(index);
         self.lifetimes_to_define.push((span, hir_name));
         hir_name
index 1705f5692d4f9698c176921f45813021c0deaf67..16c4ab7187de4c239a87c0923945827258a9581a 100644 (file)
@@ -1222,6 +1222,8 @@ pub fn map_crate<'hir>(sess: &crate::session::Session,
                        forest: &'hir Forest,
                        definitions: &'hir Definitions)
                        -> Map<'hir> {
+    let _prof_timer = sess.prof.generic_activity("build_hir_map");
+
     // Build the reverse mapping of `node_to_hir_id`.
     let hir_to_node_id = definitions.node_to_hir_id.iter_enumerated()
         .map(|(node_id, &hir_id)| (hir_id, node_id)).collect();
index d5892794d64968e09d92daa92e7d84b1886f7dbe..e72f46682cee599d714c71c130addefb6c5c4082 100644 (file)
@@ -1053,6 +1053,13 @@ pub fn and(self, other: Self) -> Self {
             MutImmutable => MutImmutable,
         }
     }
+
+    pub fn invert(self) -> Self {
+        match self {
+            MutMutable => MutImmutable,
+            MutImmutable => MutMutable,
+        }
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)]
@@ -1548,6 +1555,19 @@ pub fn is_place_expr(&self) -> bool {
             }
         }
     }
+
+    /// If `Self.kind` is `ExprKind::DropTemps(expr)`, drill down until we get a non-`DropTemps`
+    /// `Expr`. This is used in suggestions to ignore this `ExprKind` as it is semantically
+    /// silent, only signaling the ownership system. By doing this, suggestions that check the
+    /// `ExprKind` of any given `Expr` for presentation don't have to care about `DropTemps`
+    /// beyond remembering to call this function before doing analysis on it.
+    pub fn peel_drop_temps(&self) -> &Self {
+        let mut expr = self;
+        while let ExprKind::DropTemps(inner) = &expr.kind {
+            expr = inner;
+        }
+        expr
+    }
 }
 
 impl fmt::Debug for Expr {
@@ -2669,6 +2689,11 @@ pub struct CodegenFnAttrs {
     /// probably isn't set when this is set, this is for foreign items while
     /// `#[export_name]` is for Rust-defined functions.
     pub link_name: Option<Symbol>,
+    /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
+    /// imported function has in the dynamic library. Note that this must not
+    /// be set when `link_name` is set. This is for foreign items with the
+    /// "raw-dylib" kind.
+    pub link_ordinal: Option<usize>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
     pub target_features: Vec<Symbol>,
@@ -2716,7 +2741,9 @@ pub struct CodegenFnAttrFlags: u32 {
         const USED                      = 1 << 9;
         /// #[ffi_returns_twice], indicates that an extern function can return
         /// multiple times
-        const FFI_RETURNS_TWICE = 1 << 10;
+        const FFI_RETURNS_TWICE         = 1 << 10;
+        /// #[track_caller]: allow access to the caller location
+        const TRACK_CALLER              = 1 << 11;
     }
 }
 
@@ -2728,6 +2755,7 @@ pub fn new() -> CodegenFnAttrs {
             optimize: OptimizeAttr::None,
             export_name: None,
             link_name: None,
+            link_ordinal: None,
             target_features: vec![],
             linkage: None,
             link_section: None,
index d31b527a55b6951e6e4663744a6e52b9ba98cba5..f1192c7ce10a9577858ea98883b977e91831a69e 100644 (file)
@@ -935,6 +935,7 @@ fn push_ty_ref<'tcx>(
                         .filter(|(a, b)| a == b)
                         .count();
                     let len = sub1.len() - common_default_params;
+                    let consts_offset = len - sub1.consts().count();
 
                     // Only draw `<...>` if there're lifetime/type arguments.
                     if len > 0 {
@@ -981,7 +982,8 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                     //         ^ elided type as this type argument was the same in both sides
                     let type_arguments = sub1.types().zip(sub2.types());
                     let regions_len = sub1.regions().count();
-                    for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() {
+                    let num_display_types = consts_offset - regions_len;
+                    for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
                         let i = i + regions_len;
                         if ta1 == ta2 {
                             values.0.push_normal("_");
@@ -994,6 +996,21 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                         self.push_comma(&mut values.0, &mut values.1, len, i);
                     }
 
+                    // Do the same for const arguments, if they are equal, do not highlight and
+                    // elide them from the output.
+                    let const_arguments = sub1.consts().zip(sub2.consts());
+                    for (i, (ca1, ca2)) in const_arguments.enumerate() {
+                        let i = i + consts_offset;
+                        if ca1 == ca2 {
+                            values.0.push_normal("_");
+                            values.1.push_normal("_");
+                        } else {
+                            values.0.push_highlighted(ca1.to_string());
+                            values.1.push_highlighted(ca2.to_string());
+                        }
+                        self.push_comma(&mut values.0, &mut values.1, len, i);
+                    }
+
                     // Close the type argument bracket.
                     // Only draw `<...>` if there're lifetime/type arguments.
                     if len > 0 {
index ea9e931ad838e83c71ec470ace67064e717acb08..af74d13572431a147c3235666ce7ab470b9337e7 100644 (file)
@@ -814,16 +814,16 @@ fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
     /// Executes `f` and commit the bindings.
     pub fn commit_unconditionally<R, F>(&self, f: F) -> R
     where
-        F: FnOnce() -> R,
+        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
-        debug!("commit()");
+        debug!("commit_unconditionally()");
         let snapshot = self.start_snapshot();
-        let r = f();
+        let r = f(&snapshot);
         self.commit_from(snapshot);
         r
     }
 
-    /// Executes `f` and commit the bindings if closure `f` returns `Ok(_)`.
+    /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
@@ -843,19 +843,7 @@ pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
         r
     }
 
-    /// Execute `f` in a snapshot, and commit the bindings it creates.
-    pub fn in_snapshot<T, F>(&self, f: F) -> T
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T,
-    {
-        debug!("in_snapshot()");
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        self.commit_from(snapshot);
-        r
-    }
-
-    /// Executes `f` then unroll any bindings it creates.
+    /// Execute `f` then unroll any bindings it creates.
     pub fn probe<R, F>(&self, f: F) -> R
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
index e7205dd47a6172c657913b72673d90e1c34ca56c..bd19a002fe8b7bf676e185b527bd5a034eaa574c 100644 (file)
@@ -733,12 +733,12 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
-                for upvar_ty in substs.upvar_tys(def_id, self.tcx) {
+                for upvar_ty in substs.as_generator().upvar_tys(def_id, self.tcx) {
                     upvar_ty.visit_with(self);
                 }
 
-                substs.return_ty(def_id, self.tcx).visit_with(self);
-                substs.yield_ty(def_id, self.tcx).visit_with(self);
+                substs.as_generator().return_ty(def_id, self.tcx).visit_with(self);
+                substs.as_generator().yield_ty(def_id, self.tcx).visit_with(self);
             }
             _ => {
                 ty.super_visit_with(self);
@@ -902,7 +902,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             ty::Generator(def_id, substs, movability) => {
                 let generics = self.tcx.generics_of(def_id);
                 let substs =
-                    self.tcx.mk_substs(substs.substs.iter().enumerate().map(|(index, &kind)| {
+                    self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| {
                         if index < generics.parent_count {
                             // Accommodate missing regions in the parent kinds...
                             self.fold_kind_mapping_missing_regions_to_empty(kind)
@@ -912,7 +912,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                         }
                     }));
 
-                self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability)
+                self.tcx.mk_generator(def_id, substs, movability)
             }
 
             ty::Param(..) => {
index 0c83bbc1e5394aafb079097016d09afaedb7702a..3d069425685c7761dd67a7f10e127297e238e54b 100644 (file)
@@ -14,9 +14,11 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
     /// retain the older (arguably incorrect) behavior of the
     /// compiler.
     ///
-    /// NB. The use of snapshot here is mostly an efficiency thing --
-    /// we could search *all* region constraints, but that'd be a
-    /// bigger set and the data structures are not setup for that. If
+    /// NB. Although `_snapshot` isn't used, it's passed in to prove
+    /// that we are in a snapshot, which guarantees that we can just
+    /// search the "undo log" for edges. This is mostly an efficiency
+    /// thing -- we could search *all* region constraints, but that'd be
+    /// a bigger set and the data structures are not setup for that. If
     /// we wind up keeping some form of this check long term, it would
     /// probably be better to remove the snapshot parameter and to
     /// refactor the constraint set.
index bd9899b644b5e2be6eae2d96af6528a9b34c7bc5..9c3cb3af9e79c9e61f493a065f88bbd08c8ca514 100644 (file)
@@ -35,7 +35,6 @@
 #![feature(const_transmute)]
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
-#![feature(inner_deref)]
 #![cfg_attr(windows, feature(libc))]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
 pub mod middle {
     pub mod expr_use_visitor;
     pub mod cstore;
-    pub mod dead;
     pub mod dependency_format;
     pub mod diagnostic_items;
-    pub mod entry;
     pub mod exported_symbols;
     pub mod free_region;
-    pub mod intrinsicck;
     pub mod lib_features;
     pub mod lang_items;
-    pub mod liveness;
     pub mod mem_categorization;
     pub mod privacy;
     pub mod reachable;
index 5906a6388a8bd5209ed84ebb67323ce065d37129..5ca474a8b1d91a32612e8b3554ee61e63e6e5d61 100644 (file)
@@ -368,6 +368,12 @@ pub mod parser {
         Allow,
         "possible meta-variable misuse at macro definition"
     }
+
+    declare_lint! {
+        pub INCOMPLETE_INCLUDE,
+        Deny,
+        "trailing content in included file"
+    }
 }
 
 declare_lint! {
index 5b490b701267deae304e620ddce0e8178eb2b305..b31efc24e52d1fc3d93c9db9cce52ced0bd9c720 100644 (file)
@@ -28,6 +28,7 @@
 use crate::hir;
 use crate::lint::builtin::BuiltinLintDiagnostics;
 use crate::lint::builtin::parser::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE};
+use crate::lint::builtin::parser::INCOMPLETE_INCLUDE;
 use crate::session::{Session, DiagnosticMessageId};
 use crate::ty::TyCtxt;
 use crate::ty::query::Providers;
@@ -83,6 +84,7 @@ pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
         match lint_id {
             BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT,
             BufferedEarlyLintId::MetaVariableMisuse => META_VARIABLE_MISUSE,
+            BufferedEarlyLintId::IncompleteInclude => INCOMPLETE_INCLUDE,
         }
     }
 
index 510787998ad071c969f8cab544042737ecbb4418..065959ed09fd1da00ab9385ed7ae4f1785d5ffef 100644 (file)
@@ -96,6 +96,8 @@ pub enum NativeLibraryKind {
     NativeStaticNobundle,
     /// macOS-specific
     NativeFramework,
+    /// Windows dynamic library without import library.
+    NativeRawDylib,
     /// default way to specify a dynamic library
     NativeUnknown,
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
deleted file mode 100644 (file)
index 7c75a14..0000000
+++ /dev/null
@@ -1,676 +0,0 @@
-// This implements the dead-code warning pass. It follows middle::reachable
-// closely. The idea is that all reachable symbols are live, codes called
-// from live codes are live, and everything else is dead.
-
-use crate::hir::Node;
-use crate::hir::{self, PatKind, TyKind};
-use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use crate::hir::itemlikevisit::ItemLikeVisitor;
-
-use crate::hir::def::{CtorOf, Res, DefKind};
-use crate::hir::CodegenFnAttrFlags;
-use crate::hir::def_id::{DefId, LOCAL_CRATE};
-use crate::lint;
-use crate::middle::privacy;
-use crate::ty::{self, DefIdTree, TyCtxt};
-use crate::util::nodemap::FxHashSet;
-
-use rustc_data_structures::fx::FxHashMap;
-
-use syntax::{ast, attr};
-use syntax::symbol::sym;
-use syntax_pos;
-
-// 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 {
-    match tcx.hir().find(hir_id) {
-        Some(Node::Item(..)) |
-        Some(Node::ImplItem(..)) |
-        Some(Node::ForeignItem(..)) |
-        Some(Node::TraitItem(..)) |
-        Some(Node::Variant(..)) |
-        Some(Node::AnonConst(..)) |
-        Some(Node::Pat(..)) => true,
-        _ => false
-    }
-}
-
-struct MarkSymbolVisitor<'a, 'tcx> {
-    worklist: Vec<hir::HirId>,
-    tcx: TyCtxt<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
-    live_symbols: FxHashSet<hir::HirId>,
-    repr_has_repr_c: bool,
-    in_pat: bool,
-    inherited_pub_visibility: bool,
-    ignore_variant_stack: Vec<DefId>,
-    // maps from tuple struct constructors to tuple struct items
-    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
-}
-
-impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
-    fn check_def_id(&mut self, def_id: DefId) {
-        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
-            if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) {
-                self.worklist.push(hir_id);
-            }
-            self.live_symbols.insert(hir_id);
-        }
-    }
-
-    fn insert_def_id(&mut self, def_id: DefId) {
-        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
-            debug_assert!(!should_explore(self.tcx, hir_id));
-            self.live_symbols.insert(hir_id);
-        }
-    }
-
-    fn handle_res(&mut self, res: Res) {
-        match res {
-            Res::Def(DefKind::Const, _)
-            | Res::Def(DefKind::AssocConst, _)
-            | Res::Def(DefKind::TyAlias, _) => {
-                self.check_def_id(res.def_id());
-            }
-            _ if self.in_pat => {},
-            Res::PrimTy(..) | Res::SelfCtor(..) |
-            Res::Local(..) => {}
-            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
-                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
-                let enum_id = self.tcx.parent(variant_id).unwrap();
-                self.check_def_id(enum_id);
-                if !self.ignore_variant_stack.contains(&ctor_def_id) {
-                    self.check_def_id(variant_id);
-                }
-            }
-            Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
-                self.check_def_id(enum_id);
-                if !self.ignore_variant_stack.contains(&variant_id) {
-                    self.check_def_id(variant_id);
-                }
-            }
-            Res::SelfTy(t, i) => {
-                if let Some(t) = t {
-                    self.check_def_id(t);
-                }
-                if let Some(i) = i {
-                    self.check_def_id(i);
-                }
-            }
-            Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
-            _ => {
-                self.check_def_id(res.def_id());
-            }
-        }
-    }
-
-    fn lookup_and_handle_method(&mut self, id: hir::HirId) {
-        if let Some(def_id) = self.tables.type_dependent_def_id(id) {
-            self.check_def_id(def_id);
-        } else {
-            bug!("no type-dependent def for method");
-        }
-    }
-
-    fn handle_field_access(&mut self, lhs: &hir::Expr, hir_id: hir::HirId) {
-        match self.tables.expr_ty_adjusted(lhs).kind {
-            ty::Adt(def, _) => {
-                let index = self.tcx.field_index(hir_id, self.tables);
-                self.insert_def_id(def.non_enum_variant().fields[index].did);
-            }
-            ty::Tuple(..) => {}
-            _ => span_bug!(lhs.span, "named field access on non-ADT"),
-        }
-    }
-
-    fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res, pats: &[hir::FieldPat]) {
-        let variant = match self.tables.node_type(lhs.hir_id).kind {
-            ty::Adt(adt, _) => adt.variant_of_res(res),
-            _ => span_bug!(lhs.span, "non-ADT in struct pattern")
-        };
-        for pat in pats {
-            if let PatKind::Wild = pat.pat.kind {
-                continue;
-            }
-            let index = self.tcx.field_index(pat.hir_id, self.tables);
-            self.insert_def_id(variant.fields[index].did);
-        }
-    }
-
-    fn mark_live_symbols(&mut self) {
-        let mut scanned = FxHashSet::default();
-        while let Some(id) = self.worklist.pop() {
-            if !scanned.insert(id) {
-                continue
-            }
-
-            // 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);
-
-            if let Some(node) = self.tcx.hir().find(id) {
-                self.live_symbols.insert(id);
-                self.visit_node(node);
-            }
-        }
-    }
-
-    fn visit_node(&mut self, node: Node<'tcx>) {
-        let had_repr_c = self.repr_has_repr_c;
-        self.repr_has_repr_c = false;
-        let had_inherited_pub_visibility = self.inherited_pub_visibility;
-        self.inherited_pub_visibility = false;
-        match node {
-            Node::Item(item) => {
-                match item.kind {
-                    hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                        let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                        let def = self.tcx.adt_def(def_id);
-                        self.repr_has_repr_c = def.repr.c();
-
-                        intravisit::walk_item(self, &item);
-                    }
-                    hir::ItemKind::Enum(..) => {
-                        self.inherited_pub_visibility = item.vis.node.is_pub();
-
-                        intravisit::walk_item(self, &item);
-                    }
-                    hir::ItemKind::ForeignMod(..) => {}
-                    _ => {
-                        intravisit::walk_item(self, &item);
-                    }
-                }
-            }
-            Node::TraitItem(trait_item) => {
-                intravisit::walk_trait_item(self, trait_item);
-            }
-            Node::ImplItem(impl_item) => {
-                intravisit::walk_impl_item(self, impl_item);
-            }
-            Node::ForeignItem(foreign_item) => {
-                intravisit::walk_foreign_item(self, &foreign_item);
-            }
-            _ => {}
-        }
-        self.repr_has_repr_c = had_repr_c;
-        self.inherited_pub_visibility = had_inherited_pub_visibility;
-    }
-
-    fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) {
-        if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
-            for field in fields {
-                let index = self.tcx.field_index(field.hir_id, self.tables);
-                self.insert_def_id(adt.non_enum_variant().fields[index].did);
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_tables = self.tables;
-        self.tables = self.tcx.body_tables(body);
-        let body = self.tcx.hir().body(body);
-        self.visit_body(body);
-        self.tables = old_tables;
-    }
-
-    fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
-                          _: &hir::Generics, _: hir::HirId, _: syntax_pos::Span) {
-        let has_repr_c = self.repr_has_repr_c;
-        let inherited_pub_visibility = self.inherited_pub_visibility;
-        let live_fields = def.fields().iter().filter(|f| {
-            has_repr_c || inherited_pub_visibility || f.vis.node.is_pub()
-        });
-        self.live_symbols.extend(live_fields.map(|f| f.hir_id));
-
-        intravisit::walk_struct_def(self, def);
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        match expr.kind {
-            hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
-                let res = self.tables.qpath_res(qpath, expr.hir_id);
-                self.handle_res(res);
-            }
-            hir::ExprKind::MethodCall(..) => {
-                self.lookup_and_handle_method(expr.hir_id);
-            }
-            hir::ExprKind::Field(ref lhs, ..) => {
-                self.handle_field_access(&lhs, expr.hir_id);
-            }
-            hir::ExprKind::Struct(_, ref fields, _) => {
-                if let ty::Adt(ref adt, _) = self.tables.expr_ty(expr).kind {
-                    self.mark_as_used_if_union(adt, fields);
-                }
-            }
-            _ => ()
-        }
-
-        intravisit::walk_expr(self, expr);
-    }
-
-    fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
-        // Inside the body, ignore constructions of variants
-        // necessary for the pattern to match. Those construction sites
-        // can't be reached unless the variant is constructed elsewhere.
-        let len = self.ignore_variant_stack.len();
-        self.ignore_variant_stack.extend(arm.pat.necessary_variants());
-        intravisit::walk_arm(self, arm);
-        self.ignore_variant_stack.truncate(len);
-    }
-
-    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
-        match pat.kind {
-            PatKind::Struct(ref path, ref fields, _) => {
-                let res = self.tables.qpath_res(path, pat.hir_id);
-                self.handle_field_pattern_match(pat, res, fields);
-            }
-            PatKind::Path(ref qpath) => {
-                let res = self.tables.qpath_res(qpath, pat.hir_id);
-                self.handle_res(res);
-            }
-            _ => ()
-        }
-
-        self.in_pat = true;
-        intravisit::walk_pat(self, pat);
-        self.in_pat = false;
-    }
-
-    fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) {
-        self.handle_res(path.res);
-        intravisit::walk_path(self, path);
-    }
-
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        match ty.kind {
-            TyKind::Def(item_id, _) => {
-                let item = self.tcx.hir().expect_item(item_id.id);
-                intravisit::walk_item(self, item);
-            }
-            _ => ()
-        }
-        intravisit::walk_ty(self, ty);
-    }
-
-    fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-        self.live_symbols.insert(c.hir_id);
-        intravisit::walk_anon_const(self, c);
-    }
-}
-
-fn has_allow_dead_code_or_lang_attr(
-    tcx: TyCtxt<'_>,
-    id: hir::HirId,
-    attrs: &[ast::Attribute],
-) -> bool {
-    if attr::contains_name(attrs, sym::lang) {
-        return true;
-    }
-
-    // Stable attribute for #[lang = "panic_impl"]
-    if attr::contains_name(attrs, sym::panic_handler) {
-        return true;
-    }
-
-    // (To be) stable attribute for #[lang = "oom"]
-    if attr::contains_name(attrs, sym::alloc_error_handler) {
-        return true;
-    }
-
-    let def_id = tcx.hir().local_def_id(id);
-    let cg_attrs = tcx.codegen_fn_attrs(def_id);
-
-    // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
-    // forcefully, e.g., for placing it in a specific section.
-    if cg_attrs.contains_extern_indicator() ||
-        cg_attrs.flags.contains(CodegenFnAttrFlags::USED) {
-        return true;
-    }
-
-    tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
-}
-
-// This visitor seeds items that
-//   1) We want to explicitly consider as live:
-//     * Item annotated with #[allow(dead_code)]
-//         - This is done so that if we want to suppress warnings for a
-//           group of dead functions, we only have to annotate the "root".
-//           For example, if both `f` and `g` are dead and `f` calls `g`,
-//           then annotating `f` with `#[allow(dead_code)]` will suppress
-//           warning for both `f` and `g`.
-//     * Item annotated with #[lang=".."]
-//         - This is because lang items are always callable from elsewhere.
-//   or
-//   2) We are not sure to be live or not
-//     * Implementation of a trait method
-struct LifeSeeder<'k, 'tcx> {
-    worklist: Vec<hir::HirId>,
-    krate: &'k hir::Crate,
-    tcx: TyCtxt<'tcx>,
-    // see `MarkSymbolVisitor::struct_constructors`
-    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
-}
-
-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,
-                                                               &item.attrs);
-        if allow_dead_code {
-            self.worklist.push(item.hir_id);
-        }
-        match item.kind {
-            hir::ItemKind::Enum(ref enum_def, _) => {
-                if allow_dead_code {
-                    self.worklist.extend(enum_def.variants.iter().map(|variant| 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);
-                    }
-                }
-            }
-            hir::ItemKind::Trait(.., ref trait_item_refs) => {
-                for trait_item_ref in trait_item_refs {
-                    let trait_item = self.krate.trait_item(trait_item_ref.id);
-                    match trait_item.kind {
-                        hir::TraitItemKind::Const(_, Some(_)) |
-                        hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
-                            if has_allow_dead_code_or_lang_attr(self.tcx,
-                                                                trait_item.hir_id,
-                                                                &trait_item.attrs) {
-                                self.worklist.push(trait_item.hir_id);
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            hir::ItemKind::Impl(.., ref opt_trait, _, ref impl_item_refs) => {
-                for impl_item_ref in impl_item_refs {
-                    let impl_item = self.krate.impl_item(impl_item_ref.id);
-                    if opt_trait.is_some() ||
-                            has_allow_dead_code_or_lang_attr(self.tcx,
-                                                             impl_item.hir_id,
-                                                             &impl_item.attrs) {
-                        self.worklist.push(impl_item_ref.id.hir_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);
-                }
-            }
-            _ => ()
-        }
-    }
-
-    fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
-        // ignore: we are handling this in `visit_item` above
-    }
-
-    fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
-        // ignore: we are handling this in `visit_item` above
-    }
-}
-
-fn create_and_seed_worklist<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    access_levels: &privacy::AccessLevels,
-    krate: &hir::Crate,
-) -> (Vec<hir::HirId>, FxHashMap<hir::HirId, hir::HirId>) {
-    let worklist = access_levels.map.iter().filter_map(|(&id, level)| {
-        if level >= &privacy::AccessLevel::Reachable {
-            Some(id)
-        } else {
-            None
-        }
-    }).chain(
-        // Seed entry point
-        tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().as_local_hir_id(def_id).unwrap())
-    ).collect::<Vec<_>>();
-
-    // Seed implemented trait items
-    let mut life_seeder = LifeSeeder {
-        worklist,
-        krate,
-        tcx,
-        struct_constructors: Default::default(),
-    };
-    krate.visit_all_item_likes(&mut life_seeder);
-
-    (life_seeder.worklist, life_seeder.struct_constructors)
-}
-
-fn find_live<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    access_levels: &privacy::AccessLevels,
-    krate: &hir::Crate,
-) -> FxHashSet<hir::HirId> {
-    let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
-    let mut symbol_visitor = MarkSymbolVisitor {
-        worklist,
-        tcx,
-        tables: &ty::TypeckTables::empty(None),
-        live_symbols: Default::default(),
-        repr_has_repr_c: false,
-        in_pat: false,
-        inherited_pub_visibility: false,
-        ignore_variant_stack: vec![],
-        struct_constructors,
-    };
-    symbol_visitor.mark_live_symbols();
-    symbol_visitor.live_symbols
-}
-
-struct DeadVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    live_symbols: FxHashSet<hir::HirId>,
-}
-
-impl DeadVisitor<'tcx> {
-    fn should_warn_about_item(&mut self, item: &hir::Item) -> bool {
-        let should_warn = match item.kind {
-            hir::ItemKind::Static(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Union(..) => true,
-            _ => false
-        };
-        should_warn && !self.symbol_is_live(item.hir_id)
-    }
-
-    fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool {
-        let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
-        !field.is_positional()
-            && !self.symbol_is_live(field.hir_id)
-            && !field_type.is_phantom_data()
-            && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs)
-    }
-
-    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,
-                                                 &variant.attrs)
-    }
-
-    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, &fi.attrs)
-    }
-
-    // id := HIR id of an item's definition.
-    fn symbol_is_live(
-        &mut self,
-        id: hir::HirId,
-    ) -> bool {
-        if self.live_symbols.contains(&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(item_hir_id) = self.tcx.hir().as_local_hir_id(item_did) {
-                    if self.live_symbols.contains(&item_hir_id) {
-                        return true;
-                    }
-                }
-            }
-        }
-        false
-    }
-
-    fn warn_dead_code(&mut self,
-                      id: hir::HirId,
-                      span: syntax_pos::Span,
-                      name: ast::Name,
-                      node_type: &str,
-                      participle: &str) {
-        if !name.as_str().starts_with("_") {
-            self.tcx
-                .lint_hir(lint::builtin::DEAD_CODE,
-                          id,
-                          span,
-                          &format!("{} is never {}: `{}`",
-                                   node_type, participle, name));
-        }
-    }
-}
-
-impl Visitor<'tcx> for DeadVisitor<'tcx> {
-    /// Walk nested items in place so that we don't report dead-code
-    /// on inner functions when the outer function is already getting
-    /// an error. We could do this also by checking the parents, but
-    /// this is how the code is setup and it seems harmless enough.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::All(&self.tcx.hir())
-    }
-
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        if self.should_warn_about_item(item) {
-            // For items that have a definition with a signature followed by a
-            // block, point only at the signature.
-            let span = match item.kind {
-                hir::ItemKind::Fn(..) |
-                hir::ItemKind::Mod(..) |
-                hir::ItemKind::Enum(..) |
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) |
-                hir::ItemKind::Trait(..) |
-                hir::ItemKind::Impl(..) => self.tcx.sess.source_map().def_span(item.span),
-                _ => item.span,
-            };
-            let participle = match item.kind {
-                hir::ItemKind::Struct(..) => "constructed", // Issue #52325
-                _ => "used"
-            };
-            self.warn_dead_code(
-                item.hir_id,
-                span,
-                item.ident.name,
-                item.kind.descriptive_variant(),
-                participle,
-            );
-        } else {
-            // Only continue if we didn't warn
-            intravisit::walk_item(self, item);
-        }
-    }
-
-    fn visit_variant(&mut self,
-                     variant: &'tcx hir::Variant,
-                     g: &'tcx hir::Generics,
-                     id: hir::HirId) {
-        if self.should_warn_about_variant(&variant) {
-            self.warn_dead_code(variant.id, variant.span, variant.ident.name,
-                                "variant", "constructed");
-        } else {
-            intravisit::walk_variant(self, variant, g, id);
-        }
-    }
-
-    fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
-        if self.should_warn_about_foreign_item(fi) {
-            self.warn_dead_code(fi.hir_id, fi.span, fi.ident.name,
-                                fi.kind.descriptive_variant(), "used");
-        }
-        intravisit::walk_foreign_item(self, fi);
-    }
-
-    fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
-        if self.should_warn_about_field(&field) {
-            self.warn_dead_code(field.hir_id, field.span, field.ident.name, "field", "used");
-        }
-        intravisit::walk_struct_field(self, field);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        match impl_item.kind {
-            hir::ImplItemKind::Const(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id) {
-                    self.warn_dead_code(impl_item.hir_id,
-                                        impl_item.span,
-                                        impl_item.ident.name,
-                                        "associated const",
-                                        "used");
-                }
-                self.visit_nested_body(body_id)
-            }
-            hir::ImplItemKind::Method(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id) {
-                    let span = self.tcx.sess.source_map().def_span(impl_item.span);
-                    self.warn_dead_code(impl_item.hir_id, span, impl_item.ident.name, "method",
-                        "used");
-                }
-                self.visit_nested_body(body_id)
-            }
-            hir::ImplItemKind::OpaqueTy(..) |
-            hir::ImplItemKind::TyAlias(..) => {}
-        }
-    }
-
-    // Overwrite so that we don't warn the trait item itself.
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        match trait_item.kind {
-            hir::TraitItemKind::Const(_, Some(body_id)) |
-            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
-                self.visit_nested_body(body_id)
-            }
-            hir::TraitItemKind::Const(_, None) |
-            hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
-            hir::TraitItemKind::Type(..) => {}
-        }
-    }
-}
-
-pub fn check_crate(tcx: TyCtxt<'_>) {
-    let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
-    let krate = tcx.hir().krate();
-    let live_symbols = find_live(tcx, access_levels, krate);
-    let mut visitor = DeadVisitor {
-        tcx,
-        live_symbols,
-    };
-    intravisit::walk_crate(&mut visitor, krate);
-}
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
deleted file mode 100644 (file)
index 660fe14..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-use crate::hir::map as hir_map;
-use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
-use crate::session::{config, Session};
-use crate::session::config::EntryFnType;
-use syntax::attr;
-use syntax::entry::EntryPointType;
-use syntax::symbol::sym;
-use syntax_pos::Span;
-use crate::hir::{HirId, Item, ItemKind, ImplItem, TraitItem};
-use crate::hir::itemlikevisit::ItemLikeVisitor;
-use crate::ty::TyCtxt;
-use crate::ty::query::Providers;
-
-struct EntryContext<'a, 'tcx> {
-    session: &'a Session,
-
-    map: &'a hir_map::Map<'tcx>,
-
-    /// The top-level function called `main`.
-    main_fn: Option<(HirId, Span)>,
-
-    /// The function that has attribute named `main`.
-    attr_main_fn: Option<(HirId, Span)>,
-
-    /// The function that has the attribute 'start' on it.
-    start_fn: Option<(HirId, Span)>,
-
-    /// The functions that one might think are `main` but aren't, e.g.
-    /// main functions not defined at the top level. For diagnostics.
-    non_main_fns: Vec<(HirId, Span)> ,
-}
-
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
-    fn visit_item(&mut self, item: &'tcx Item) {
-        let def_id = self.map.local_def_id(item.hir_id);
-        let def_key = self.map.def_key(def_id);
-        let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
-        find_item(item, self, at_root);
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
-        // Entry fn is never a trait item.
-    }
-
-    fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
-        // Entry fn is never a trait item.
-    }
-}
-
-fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
-    assert_eq!(cnum, LOCAL_CRATE);
-
-    let any_exe = tcx.sess.crate_types.borrow().iter().any(|ty| {
-        *ty == config::CrateType::Executable
-    });
-    if !any_exe {
-        // No need to find a main function.
-        return None;
-    }
-
-    // If the user wants no main function at all, then stop here.
-    if attr::contains_name(&tcx.hir().krate().attrs, sym::no_main) {
-        return None;
-    }
-
-    let mut ctxt = EntryContext {
-        session: tcx.sess,
-        map: tcx.hir(),
-        main_fn: None,
-        attr_main_fn: None,
-        start_fn: None,
-        non_main_fns: Vec::new(),
-    };
-
-    tcx.hir().krate().visit_all_item_likes(&mut ctxt);
-
-    configure_main(tcx, &ctxt)
-}
-
-// Beware, this is duplicated in `libsyntax/entry.rs`, so make sure to keep
-// them in sync.
-fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
-    match item.kind {
-        ItemKind::Fn(..) => {
-            if attr::contains_name(&item.attrs, sym::start) {
-                EntryPointType::Start
-            } else if attr::contains_name(&item.attrs, sym::main) {
-                EntryPointType::MainAttr
-            } else if item.ident.name == sym::main {
-                if at_root {
-                    // This is a top-level function so can be `main`.
-                    EntryPointType::MainNamed
-                } else {
-                    EntryPointType::OtherMain
-                }
-            } else {
-                EntryPointType::None
-            }
-        }
-        _ => EntryPointType::None,
-    }
-}
-
-
-fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
-    match entry_point_type(item, at_root) {
-        EntryPointType::MainNamed => {
-            if ctxt.main_fn.is_none() {
-                ctxt.main_fn = Some((item.hir_id, item.span));
-            } else {
-                span_err!(ctxt.session, item.span, E0136,
-                          "multiple `main` functions");
-            }
-        },
-        EntryPointType::OtherMain => {
-            ctxt.non_main_fns.push((item.hir_id, item.span));
-        },
-        EntryPointType::MainAttr => {
-            if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((item.hir_id, item.span));
-            } else {
-                struct_span_err!(ctxt.session, item.span, E0137,
-                                 "multiple functions with a `#[main]` attribute")
-                .span_label(item.span, "additional `#[main]` function")
-                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
-                .emit();
-            }
-        },
-        EntryPointType::Start => {
-            if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((item.hir_id, item.span));
-            } else {
-                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
-                    .span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
-                    .span_label(item.span, "multiple `start` functions")
-                    .emit();
-            }
-        }
-        EntryPointType::None => (),
-    }
-}
-
-fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
-    if let Some((hir_id, _)) = visitor.start_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start))
-    } else if let Some((hir_id, _)) = visitor.attr_main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
-    } else if let Some((hir_id, _)) = visitor.main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
-    } else {
-        no_main_err(tcx, visitor);
-        None
-    }
-}
-
-fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
-    // There is no main function.
-    let mut err = struct_err!(tcx.sess, E0601,
-        "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
-    let filename = &tcx.sess.local_crate_source_file;
-    let note = if !visitor.non_main_fns.is_empty() {
-        for &(_, span) in &visitor.non_main_fns {
-            err.span_note(span, "here is a function named `main`");
-        }
-        err.note("you have one or more functions named `main` not defined at the crate level");
-        err.help("either move the `main` function definitions or attach the `#[main]` attribute \
-                  to one of them");
-        // There were some functions named `main` though. Try to give the user a hint.
-        format!("the main function must be defined at the crate level{}",
-                 filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default())
-    } else if let Some(filename) = filename {
-        format!("consider adding a `main` function to `{}`", filename.display())
-    } else {
-        String::from("consider adding a `main` function at the crate level")
-    };
-    let sp = tcx.hir().krate().span;
-    // The file may be empty, which leads to the diagnostic machinery not emitting this
-    // note. This is a relatively simple way to detect that case and emit a span-less
-    // note instead.
-    if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) {
-        err.set_span(sp);
-        err.span_label(sp, &note);
-    } else {
-        err.note(&note);
-    }
-    if tcx.sess.teach(&err.get_code().unwrap()) {
-        err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
-                  to get started: https://doc.rust-lang.org/book/");
-    }
-    err.emit();
-}
-
-pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
-    tcx.entry_fn(LOCAL_CRATE)
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        entry_fn,
-        ..*providers
-    };
-}
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
deleted file mode 100644 (file)
index 7b5aea8..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-use crate::hir::def::{Res, DefKind};
-use crate::hir::def_id::DefId;
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::layout::{LayoutError, Pointer, SizeSkeleton, VariantIdx};
-use crate::ty::query::Providers;
-
-use rustc_target::spec::abi::Abi::RustIntrinsic;
-use rustc_index::vec::Idx;
-use syntax_pos::{Span, sym};
-use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use crate::hir;
-
-fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut ItemVisitor { tcx }.as_deep_visitor()
-    );
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        check_mod_intrinsics,
-        ..*providers
-    };
-}
-
-struct ItemVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-struct ExprVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    tables: &'tcx ty::TypeckTables<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-/// If the type is `Option<T>`, it will return `T`, otherwise
-/// the type itself. Works on most `Option`-like types.
-fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let (def, substs) = match ty.kind {
-        ty::Adt(def, substs) => (def, substs),
-        _ => return ty
-    };
-
-    if def.variants.len() == 2 && !def.repr.c() && def.repr.int.is_none() {
-        let data_idx;
-
-        let one = VariantIdx::new(1);
-        let zero = VariantIdx::new(0);
-
-        if def.variants[zero].fields.is_empty() {
-            data_idx = one;
-        } else if def.variants[one].fields.is_empty() {
-            data_idx = zero;
-        } else {
-            return ty;
-        }
-
-        if def.variants[data_idx].fields.len() == 1 {
-            return def.variants[data_idx].fields[0].ty(tcx, substs);
-        }
-    }
-
-    ty
-}
-
-impl ExprVisitor<'tcx> {
-    fn def_id_is_transmute(&self, def_id: DefId) -> bool {
-        self.tcx.fn_sig(def_id).abi() == RustIntrinsic &&
-        self.tcx.item_name(def_id) == sym::transmute
-    }
-
-    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
-        let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
-        let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
-
-        // Check for same size using the skeletons.
-        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
-            if sk_from.same_size(sk_to) {
-                return;
-            }
-
-            // Special-case transmutting from `typeof(function)` and
-            // `Option<typeof(function)>` to present a clearer error.
-            let from = unpack_option_like(self.tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) {
-                if size_to == Pointer.size(&self.tcx) {
-                    struct_span_err!(self.tcx.sess, span, E0591,
-                                     "can't transmute zero-sized type")
-                        .note(&format!("source type: {}", from))
-                        .note(&format!("target type: {}", to))
-                        .help("cast with `as` to a pointer instead")
-                        .emit();
-                    return;
-                }
-            }
-        }
-
-        // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk| {
-            match sk {
-                Ok(SizeSkeleton::Known(size)) => {
-                    format!("{} bits", size.bits())
-                }
-                Ok(SizeSkeleton::Pointer { tail, .. }) => {
-                    format!("pointer to `{}`", tail)
-                }
-                Err(LayoutError::Unknown(bad)) => {
-                    if bad == ty {
-                        "this type does not have a fixed size".to_owned()
-                    } else {
-                        format!("size can vary because of {}", bad)
-                    }
-                }
-                Err(err) => err.to_string()
-            }
-        };
-
-        let mut err = struct_span_err!(self.tcx.sess, span, E0512,
-                                       "cannot transmute between types of different sizes, \
-                                        or dependently-sized types");
-        if from == to {
-            err.note(&format!("`{}` does not have a fixed size", from));
-        } else {
-            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
-                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
-        }
-        err.emit()
-    }
-}
-
-impl Visitor<'tcx> for ItemVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
-        let body = self.tcx.hir().body(body_id);
-        let param_env = self.tcx.param_env(owner_def_id);
-        let tables = self.tcx.typeck_tables_of(owner_def_id);
-        ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
-        self.visit_body(body);
-    }
-}
-
-impl Visitor<'tcx> for ExprVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        let res = if let hir::ExprKind::Path(ref qpath) = expr.kind {
-            self.tables.qpath_res(qpath, expr.hir_id)
-        } else {
-            Res::Err
-        };
-        if let Res::Def(DefKind::Fn, did) = res {
-            if self.def_id_is_transmute(did) {
-                let typ = self.tables.node_type(expr.hir_id);
-                let sig = typ.fn_sig(self.tcx);
-                let from = sig.inputs().skip_binder()[0];
-                let to = *sig.output().skip_binder();
-                self.check_transmute(expr.span, from, to);
-            }
-        }
-
-        intravisit::walk_expr(self, expr);
-    }
-}
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
deleted file mode 100644 (file)
index a654a26..0000000
+++ /dev/null
@@ -1,1568 +0,0 @@
-//! A classic liveness analysis based on dataflow over the AST. Computes,
-//! for each local variable in a function, whether that variable is live
-//! at a given point. Program execution points are identified by their
-//! IDs.
-//!
-//! # Basic idea
-//!
-//! The basic model is that each local variable is assigned an index. We
-//! represent sets of local variables using a vector indexed by this
-//! index. The value in the vector is either 0, indicating the variable
-//! is dead, or the ID of an expression that uses the variable.
-//!
-//! We conceptually walk over the AST in reverse execution order. If we
-//! find a use of a variable, we add it to the set of live variables. If
-//! we find an assignment to a variable, we remove it from the set of live
-//! variables. When we have to merge two flows, we take the union of
-//! those two flows -- if the variable is live on both paths, we simply
-//! pick one ID. In the event of loops, we continue doing this until a
-//! fixed point is reached.
-//!
-//! ## Checking initialization
-//!
-//! At the function entry point, all variables must be dead. If this is
-//! not the case, we can report an error using the ID found in the set of
-//! live variables, which identifies a use of the variable which is not
-//! dominated by an assignment.
-//!
-//! ## Checking moves
-//!
-//! After each explicit move, the variable must be dead.
-//!
-//! ## Computing last uses
-//!
-//! Any use of the variable where the variable is dead afterwards is a
-//! last use.
-//!
-//! # Implementation details
-//!
-//! The actual implementation contains two (nested) walks over the AST.
-//! The outer walk has the job of building up the ir_maps instance for the
-//! enclosing function. On the way down the tree, it identifies those AST
-//! nodes and variable IDs that will be needed for the liveness analysis
-//! and assigns them contiguous IDs. The liveness ID for an AST node is
-//! called a `live_node` (it's a newtype'd `u32`) and the ID for a variable
-//! is called a `variable` (another newtype'd `u32`).
-//!
-//! On the way back up the tree, as we are about to exit from a function
-//! declaration we allocate a `liveness` instance. Now that we know
-//! precisely how many nodes and variables we need, we can allocate all
-//! the various arrays that we will need to precisely the right size. We then
-//! perform the actual propagation on the `liveness` instance.
-//!
-//! This propagation is encoded in the various `propagate_through_*()`
-//! methods. It effectively does a reverse walk of the AST; whenever we
-//! reach a loop node, we iterate until a fixed point is reached.
-//!
-//! ## The `RWU` struct
-//!
-//! At each live node `N`, we track three pieces of information for each
-//! variable `V` (these are encapsulated in the `RWU` struct):
-//!
-//! - `reader`: the `LiveNode` ID of some node which will read the value
-//!    that `V` holds on entry to `N`. Formally: a node `M` such
-//!    that there exists a path `P` from `N` to `M` where `P` does not
-//!    write `V`. If the `reader` is `invalid_node()`, then the current
-//!    value will never be read (the variable is dead, essentially).
-//!
-//! - `writer`: the `LiveNode` ID of some node which will write the
-//!    variable `V` and which is reachable from `N`. Formally: a node `M`
-//!    such that there exists a path `P` from `N` to `M` and `M` writes
-//!    `V`. If the `writer` is `invalid_node()`, then there is no writer
-//!    of `V` that follows `N`.
-//!
-//! - `used`: a boolean value indicating whether `V` is *used*. We
-//!   distinguish a *read* from a *use* in that a *use* is some read that
-//!   is not just used to generate a new value. For example, `x += 1` is
-//!   a read but not a use. This is used to generate better warnings.
-//!
-//! ## Special Variables
-//!
-//! We generate various special variables for various, well, special purposes.
-//! These are described in the `specials` struct:
-//!
-//! - `exit_ln`: a live node that is generated to represent every 'exit' from
-//!   the function, whether it be by explicit return, panic, or other means.
-//!
-//! - `fallthrough_ln`: a live node that represents a fallthrough
-//!
-//! - `clean_exit_var`: a synthetic variable that is only 'read' from the
-//!   fallthrough node. It is only live if the function could converge
-//!   via means other than an explicit `return` expression. That is, it is
-//!   only dead if the end of the function's block can never be reached.
-//!   It is the responsibility of typeck to ensure that there are no
-//!   `return` expressions in a function declared as diverging.
-
-use self::LiveNodeKind::*;
-use self::VarKind::*;
-
-use crate::hir;
-use crate::hir::{Expr, HirId};
-use crate::hir::def::*;
-use crate::hir::def_id::DefId;
-use crate::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use crate::hir::Node;
-use crate::hir::ptr::P;
-use crate::ty::{self, TyCtxt};
-use crate::ty::query::Providers;
-use crate::lint;
-use crate::util::nodemap::{HirIdMap, HirIdSet};
-
-use errors::Applicability;
-use rustc_data_structures::fx::FxIndexMap;
-use std::collections::VecDeque;
-use std::{fmt, u32};
-use std::io::prelude::*;
-use std::io;
-use std::rc::Rc;
-use syntax::ast;
-use syntax::symbol::sym;
-use syntax_pos::Span;
-
-#[derive(Copy, Clone, PartialEq)]
-struct Variable(u32);
-
-#[derive(Copy, Clone, PartialEq)]
-struct LiveNode(u32);
-
-impl Variable {
-    fn get(&self) -> usize { self.0 as usize }
-}
-
-impl LiveNode {
-    fn get(&self) -> usize { self.0 as usize }
-}
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-enum LiveNodeKind {
-    UpvarNode(Span),
-    ExprNode(Span),
-    VarDefNode(Span),
-    ExitNode
-}
-
-fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
-    let cm = tcx.sess.source_map();
-    match lnk {
-        UpvarNode(s) => {
-            format!("Upvar node [{}]", cm.span_to_string(s))
-        }
-        ExprNode(s) => {
-            format!("Expr node [{}]", cm.span_to_string(s))
-        }
-        VarDefNode(s) => {
-            format!("Var def node [{}]", cm.span_to_string(s))
-        }
-        ExitNode => "Exit node".to_owned(),
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
-    }
-
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::BodyId, s: Span, id: HirId) {
-        visit_fn(self, fk, fd, b, s, id);
-    }
-
-    fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
-    fn visit_expr(&mut self, ex: &'tcx Expr) { visit_expr(self, ex); }
-    fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); }
-}
-
-fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
-    );
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        check_mod_liveness,
-        ..*providers
-    };
-}
-
-impl fmt::Debug for LiveNode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "ln({})", self.get())
-    }
-}
-
-impl fmt::Debug for Variable {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "v({})", self.get())
-    }
-}
-
-// ______________________________________________________________________
-// Creating ir_maps
-//
-// This is the first pass and the one that drives the main
-// computation.  It walks up and down the IR once.  On the way down,
-// we count for each function the number of variables as well as
-// liveness nodes.  A liveness node is basically an expression or
-// capture clause that does something of interest: either it has
-// interesting control flow or it uses/defines a local variable.
-//
-// On the way back up, at each function node we create liveness sets
-// (we now know precisely how big to make our various vectors and so
-// forth) and then do the data-flow propagation to compute the set
-// of live variables at each program point.
-//
-// Finally, we run back over the IR one last time and, using the
-// computed liveness, check various safety conditions.  For example,
-// there must be no live nodes at the definition site for a variable
-// unless it has an initializer.  Similarly, each non-mutable local
-// variable must not be assigned if there is some successor
-// assignment.  And so forth.
-
-impl LiveNode {
-    fn is_valid(&self) -> bool {
-        self.0 != u32::MAX
-    }
-}
-
-fn invalid_node() -> LiveNode { LiveNode(u32::MAX) }
-
-struct CaptureInfo {
-    ln: LiveNode,
-    var_hid: HirId
-}
-
-#[derive(Copy, Clone, Debug)]
-struct LocalInfo {
-    id: HirId,
-    name: ast::Name,
-    is_shorthand: bool,
-}
-
-#[derive(Copy, Clone, Debug)]
-enum VarKind {
-    Param(HirId, ast::Name),
-    Local(LocalInfo),
-    CleanExit
-}
-
-struct IrMaps<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body_owner: DefId,
-    num_live_nodes: usize,
-    num_vars: usize,
-    live_node_map: HirIdMap<LiveNode>,
-    variable_map: HirIdMap<Variable>,
-    capture_info_map: HirIdMap<Rc<Vec<CaptureInfo>>>,
-    var_kinds: Vec<VarKind>,
-    lnks: Vec<LiveNodeKind>,
-}
-
-impl IrMaps<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> {
-        IrMaps {
-            tcx,
-            body_owner,
-            num_live_nodes: 0,
-            num_vars: 0,
-            live_node_map: HirIdMap::default(),
-            variable_map: HirIdMap::default(),
-            capture_info_map: Default::default(),
-            var_kinds: Vec::new(),
-            lnks: Vec::new(),
-        }
-    }
-
-    fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode {
-        let ln = LiveNode(self.num_live_nodes as u32);
-        self.lnks.push(lnk);
-        self.num_live_nodes += 1;
-
-        debug!("{:?} is of kind {}", ln,
-               live_node_kind_to_string(lnk, self.tcx));
-
-        ln
-    }
-
-    fn add_live_node_for_node(&mut self, hir_id: HirId, lnk: LiveNodeKind) {
-        let ln = self.add_live_node(lnk);
-        self.live_node_map.insert(hir_id, ln);
-
-        debug!("{:?} is node {:?}", ln, hir_id);
-    }
-
-    fn add_variable(&mut self, vk: VarKind) -> Variable {
-        let v = Variable(self.num_vars as u32);
-        self.var_kinds.push(vk);
-        self.num_vars += 1;
-
-        match vk {
-            Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => {
-                self.variable_map.insert(node_id, v);
-            },
-            CleanExit => {}
-        }
-
-        debug!("{:?} is {:?}", v, vk);
-
-        v
-    }
-
-    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
-        match self.variable_map.get(&hir_id) {
-            Some(&var) => var,
-            None => {
-                span_bug!(span, "no variable registered for id {:?}", hir_id);
-            }
-        }
-    }
-
-    fn variable_name(&self, var: Variable) -> String {
-        match self.var_kinds[var.get()] {
-            Local(LocalInfo { name, .. }) | Param(_, name) => {
-                name.to_string()
-            },
-            CleanExit => "<clean-exit>".to_owned()
-        }
-    }
-
-    fn variable_is_shorthand(&self, var: Variable) -> bool {
-        match self.var_kinds[var.get()] {
-            Local(LocalInfo { is_shorthand, .. }) => is_shorthand,
-            Param(..) | CleanExit => false
-        }
-    }
-
-    fn set_captures(&mut self, hir_id: HirId, cs: Vec<CaptureInfo>) {
-        self.capture_info_map.insert(hir_id, Rc::new(cs));
-    }
-
-    fn lnk(&self, ln: LiveNode) -> LiveNodeKind {
-        self.lnks[ln.get()]
-    }
-}
-
-fn visit_fn<'tcx>(
-    ir: &mut IrMaps<'tcx>,
-    fk: FnKind<'tcx>,
-    decl: &'tcx hir::FnDecl,
-    body_id: hir::BodyId,
-    sp: Span,
-    id: hir::HirId,
-) {
-    debug!("visit_fn");
-
-    // swap in a new set of IR maps for this function body:
-    let def_id = ir.tcx.hir().local_def_id(id);
-    let mut fn_maps = IrMaps::new(ir.tcx, def_id);
-
-    // Don't run unused pass for #[derive()]
-    if let FnKind::Method(..) = fk {
-        let parent = ir.tcx.hir().get_parent_item(id);
-        if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) {
-            if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) {
-                return;
-            }
-        }
-    }
-
-    debug!("creating fn_maps: {:p}", &fn_maps);
-
-    let body = ir.tcx.hir().body(body_id);
-
-    for param in &body.params {
-        let is_shorthand = match param.pat.kind {
-            crate::hir::PatKind::Struct(..) => true,
-            _ => false,
-        };
-        param.pat.each_binding(|_bm, hir_id, _x, ident| {
-            debug!("adding parameters {:?}", hir_id);
-            let var = if is_shorthand {
-                Local(LocalInfo {
-                    id: hir_id,
-                    name: ident.name,
-                    is_shorthand: true,
-                })
-            } else {
-                Param(hir_id, ident.name)
-            };
-            fn_maps.add_variable(var);
-        })
-    };
-
-    // gather up the various local variables, significant expressions,
-    // and so forth:
-    intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
-
-    // compute liveness
-    let mut lsets = Liveness::new(&mut fn_maps, body_id);
-    let entry_ln = lsets.compute(&body.value);
-
-    // check for various error conditions
-    lsets.visit_body(body);
-    lsets.warn_about_unused_args(body, entry_ln);
-}
-
-fn add_from_pat(ir: &mut IrMaps<'_>, pat: &P<hir::Pat>) {
-    // For struct patterns, take note of which fields used shorthand
-    // (`x` rather than `x: x`).
-    let mut shorthand_field_ids = HirIdSet::default();
-    let mut pats = VecDeque::new();
-    pats.push_back(pat);
-    while let Some(pat) = pats.pop_front() {
-        use crate::hir::PatKind::*;
-        match &pat.kind {
-            Binding(.., inner_pat) => {
-                pats.extend(inner_pat.iter());
-            }
-            Struct(_, fields, _) => {
-                let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
-                shorthand_field_ids.extend(ids);
-            }
-            Ref(inner_pat, _) | Box(inner_pat) => {
-                pats.push_back(inner_pat);
-            }
-            TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
-                pats.extend(inner_pats.iter());
-            }
-            Slice(pre_pats, inner_pat, post_pats) => {
-                pats.extend(pre_pats.iter());
-                pats.extend(inner_pat.iter());
-                pats.extend(post_pats.iter());
-            }
-            _ => {}
-        }
-    }
-
-    pat.each_binding(|_, hir_id, _, ident| {
-        ir.add_live_node_for_node(hir_id, VarDefNode(ident.span));
-        ir.add_variable(Local(LocalInfo {
-            id: hir_id,
-            name: ident.name,
-            is_shorthand: shorthand_field_ids.contains(&hir_id)
-        }));
-    });
-}
-
-fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local) {
-    add_from_pat(ir, &local.pat);
-    intravisit::walk_local(ir, local);
-}
-
-fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm) {
-    add_from_pat(ir, &arm.pat);
-    intravisit::walk_arm(ir, arm);
-}
-
-fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr) {
-    match expr.kind {
-      // live nodes required for uses or definitions of variables:
-      hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
-        debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
-        if let Res::Local(var_hir_id) = path.res {
-            let upvars = ir.tcx.upvars(ir.body_owner);
-            if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) {
-                ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-            }
-        }
-        intravisit::walk_expr(ir, expr);
-      }
-      hir::ExprKind::Closure(..) => {
-        // Interesting control flow (for loops can contain labeled
-        // breaks or continues)
-        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-
-        // Make a live_node for each captured variable, with the span
-        // being the location that the variable is used.  This results
-        // in better error messages than just pointing at the closure
-        // construction site.
-        let mut call_caps = Vec::new();
-        let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id);
-        if let Some(upvars) = ir.tcx.upvars(closure_def_id) {
-            let parent_upvars = ir.tcx.upvars(ir.body_owner);
-            call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| {
-                let has_parent = parent_upvars
-                    .map_or(false, |upvars| upvars.contains_key(&var_id));
-                if !has_parent {
-                    let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
-                    Some(CaptureInfo { ln: upvar_ln, var_hid: var_id })
-                } else {
-                    None
-                }
-            }));
-        }
-        ir.set_captures(expr.hir_id, call_caps);
-        let old_body_owner = ir.body_owner;
-        ir.body_owner = closure_def_id;
-        intravisit::walk_expr(ir, expr);
-        ir.body_owner = old_body_owner;
-      }
-
-      // live nodes required for interesting control flow:
-      hir::ExprKind::Match(..) |
-      hir::ExprKind::Loop(..) => {
-        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-        intravisit::walk_expr(ir, expr);
-      }
-      hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => {
-        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-        intravisit::walk_expr(ir, expr);
-      }
-
-      // otherwise, live nodes are not required:
-      hir::ExprKind::Index(..) |
-      hir::ExprKind::Field(..) |
-      hir::ExprKind::Array(..) |
-      hir::ExprKind::Call(..) |
-      hir::ExprKind::MethodCall(..) |
-      hir::ExprKind::Tup(..) |
-      hir::ExprKind::Binary(..) |
-      hir::ExprKind::AddrOf(..) |
-      hir::ExprKind::Cast(..) |
-      hir::ExprKind::DropTemps(..) |
-      hir::ExprKind::Unary(..) |
-      hir::ExprKind::Break(..) |
-      hir::ExprKind::Continue(_) |
-      hir::ExprKind::Lit(_) |
-      hir::ExprKind::Ret(..) |
-      hir::ExprKind::Block(..) |
-      hir::ExprKind::Assign(..) |
-      hir::ExprKind::AssignOp(..) |
-      hir::ExprKind::Struct(..) |
-      hir::ExprKind::Repeat(..) |
-      hir::ExprKind::InlineAsm(..) |
-      hir::ExprKind::Box(..) |
-      hir::ExprKind::Yield(..) |
-      hir::ExprKind::Type(..) |
-      hir::ExprKind::Err |
-      hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
-          intravisit::walk_expr(ir, expr);
-      }
-    }
-}
-
-// ______________________________________________________________________
-// Computing liveness sets
-//
-// Actually we compute just a bit more than just liveness, but we use
-// the same basic propagation framework in all cases.
-
-#[derive(Clone, Copy)]
-struct RWU {
-    reader: LiveNode,
-    writer: LiveNode,
-    used: bool
-}
-
-/// Conceptually, this is like a `Vec<RWU>`. But the number of `RWU`s can get
-/// very large, so it uses a more compact representation that takes advantage
-/// of the fact that when the number of `RWU`s is large, most of them have an
-/// invalid reader and an invalid writer.
-struct RWUTable {
-    /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or
-    /// an index into `unpacked_rwus`. In the common cases, this compacts the
-    /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits
-    /// in 96.
-    ///
-    /// More compact representations are possible -- e.g., use only 2 bits per
-    /// packed `RWU` and make the secondary table a HashMap that maps from
-    /// indices to `RWU`s -- but this one strikes a good balance between size
-    /// and speed.
-    packed_rwus: Vec<u32>,
-    unpacked_rwus: Vec<RWU>,
-}
-
-// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`.
-const INV_INV_FALSE: u32 = u32::MAX;
-
-// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`.
-const INV_INV_TRUE: u32 = u32::MAX - 1;
-
-impl RWUTable {
-    fn new(num_rwus: usize) -> RWUTable {
-        Self {
-            packed_rwus: vec![INV_INV_FALSE; num_rwus],
-            unpacked_rwus: vec![],
-        }
-    }
-
-    fn get(&self, idx: usize) -> RWU {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false },
-            INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true },
-            _ => self.unpacked_rwus[packed_rwu as usize],
-        }
-    }
-
-    fn get_reader(&self, idx: usize) -> LiveNode {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
-            _ => self.unpacked_rwus[packed_rwu as usize].reader,
-        }
-    }
-
-    fn get_writer(&self, idx: usize) -> LiveNode {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
-            _ => self.unpacked_rwus[packed_rwu as usize].writer,
-        }
-    }
-
-    fn get_used(&self, idx: usize) -> bool {
-        let packed_rwu = self.packed_rwus[idx];
-        match packed_rwu {
-            INV_INV_FALSE => false,
-            INV_INV_TRUE => true,
-            _ => self.unpacked_rwus[packed_rwu as usize].used,
-        }
-    }
-
-    #[inline]
-    fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) {
-        self.packed_rwus[dst_idx] = self.packed_rwus[src_idx];
-    }
-
-    fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
-        if rwu.reader == invalid_node() && rwu.writer == invalid_node() {
-            // When we overwrite an indexing entry in `self.packed_rwus` with
-            // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
-            // from `self.unpacked_rwus`; it's not worth the effort, and we
-            // can't have entries shifting around anyway.
-            self.packed_rwus[idx] = if rwu.used {
-                INV_INV_TRUE
-            } else {
-                INV_INV_FALSE
-            }
-        } else {
-            // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]`
-            // point to it.
-            self.packed_rwus[idx] = self.unpacked_rwus.len() as u32;
-            self.unpacked_rwus.push(rwu);
-        }
-    }
-
-    fn assign_inv_inv(&mut self, idx: usize) {
-        self.packed_rwus[idx] = if self.get_used(idx) {
-            INV_INV_TRUE
-        } else {
-            INV_INV_FALSE
-        };
-    }
-}
-
-#[derive(Copy, Clone)]
-struct Specials {
-    exit_ln: LiveNode,
-    fallthrough_ln: LiveNode,
-    clean_exit_var: Variable
-}
-
-const ACC_READ: u32 = 1;
-const ACC_WRITE: u32 = 2;
-const ACC_USE: u32 = 4;
-
-struct Liveness<'a, 'tcx> {
-    ir: &'a mut IrMaps<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
-    s: Specials,
-    successors: Vec<LiveNode>,
-    rwu_table: RWUTable,
-
-    // mappings from loop node ID to LiveNode
-    // ("break" label should map to loop node ID,
-    // it probably doesn't now)
-    break_ln: HirIdMap<LiveNode>,
-    cont_ln: HirIdMap<LiveNode>,
-}
-
-impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn new(ir: &'a mut IrMaps<'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
-        // Special nodes and variables:
-        // - exit_ln represents the end of the fn, either by return or panic
-        // - implicit_ret_var is a pseudo-variable that represents
-        //   an implicit return
-        let specials = Specials {
-            exit_ln: ir.add_live_node(ExitNode),
-            fallthrough_ln: ir.add_live_node(ExitNode),
-            clean_exit_var: ir.add_variable(CleanExit)
-        };
-
-        let tables = ir.tcx.body_tables(body);
-
-        let num_live_nodes = ir.num_live_nodes;
-        let num_vars = ir.num_vars;
-
-        Liveness {
-            ir,
-            tables,
-            s: specials,
-            successors: vec![invalid_node(); num_live_nodes],
-            rwu_table: RWUTable::new(num_live_nodes * num_vars),
-            break_ln: Default::default(),
-            cont_ln: Default::default(),
-        }
-    }
-
-    fn live_node(&self, hir_id: HirId, span: Span) -> LiveNode {
-        match self.ir.live_node_map.get(&hir_id) {
-          Some(&ln) => ln,
-          None => {
-            // This must be a mismatch between the ir_map construction
-            // above and the propagation code below; the two sets of
-            // code have to agree about which AST nodes are worth
-            // creating liveness nodes for.
-            span_bug!(
-                span,
-                "no live node registered for node {:?}",
-                hir_id);
-          }
-        }
-    }
-
-    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
-        self.ir.variable(hir_id, span)
-    }
-
-    fn define_bindings_in_pat(&mut self, pat: &hir::Pat, mut succ: LiveNode) -> LiveNode {
-        // In an or-pattern, only consider the first pattern; any later patterns
-        // must have the same bindings, and we also consider the first pattern
-        // to be the "authoritative" set of ids.
-        pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| {
-            let ln = self.live_node(hir_id, pat_sp);
-            let var = self.variable(hir_id, ident.span);
-            self.init_from_succ(ln, succ);
-            self.define(ln, var);
-            succ = ln;
-        });
-        succ
-    }
-
-    fn idx(&self, ln: LiveNode, var: Variable) -> usize {
-        ln.get() * self.ir.num_vars + var.get()
-    }
-
-    fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        assert!(ln.is_valid());
-        let reader = self.rwu_table.get_reader(self.idx(ln, var));
-        if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None }
-    }
-
-    // Is this variable live on entry to any of its successor nodes?
-    fn live_on_exit(&self, ln: LiveNode, var: Variable)
-                    -> Option<LiveNodeKind> {
-        let successor = self.successors[ln.get()];
-        self.live_on_entry(successor, var)
-    }
-
-    fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
-        assert!(ln.is_valid());
-        self.rwu_table.get_used(self.idx(ln, var))
-    }
-
-    fn assigned_on_entry(&self, ln: LiveNode, var: Variable)
-                         -> Option<LiveNodeKind> {
-        assert!(ln.is_valid());
-        let writer = self.rwu_table.get_writer(self.idx(ln, var));
-        if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None }
-    }
-
-    fn assigned_on_exit(&self, ln: LiveNode, var: Variable)
-                        -> Option<LiveNodeKind> {
-        let successor = self.successors[ln.get()];
-        self.assigned_on_entry(successor, var)
-    }
-
-    fn indices2<F>(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F) where
-        F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize),
-    {
-        let node_base_idx = self.idx(ln, Variable(0));
-        let succ_base_idx = self.idx(succ_ln, Variable(0));
-        for var_idx in 0..self.ir.num_vars {
-            op(self, node_base_idx + var_idx, succ_base_idx + var_idx);
-        }
-    }
-
-    fn write_vars<F>(&self,
-                     wr: &mut dyn Write,
-                     ln: LiveNode,
-                     mut test: F)
-                     -> io::Result<()> where
-        F: FnMut(usize) -> LiveNode,
-    {
-        let node_base_idx = self.idx(ln, Variable(0));
-        for var_idx in 0..self.ir.num_vars {
-            let idx = node_base_idx + var_idx;
-            if test(idx).is_valid() {
-                write!(wr, " {:?}", Variable(var_idx as u32))?;
-            }
-        }
-        Ok(())
-    }
-
-
-    #[allow(unused_must_use)]
-    fn ln_str(&self, ln: LiveNode) -> String {
-        let mut wr = Vec::new();
-        {
-            let wr = &mut wr as &mut dyn Write;
-            write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln));
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx));
-            write!(wr, "  writes");
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx));
-            write!(wr, "  precedes {:?}]", self.successors[ln.get()]);
-        }
-        String::from_utf8(wr).unwrap()
-    }
-
-    fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
-        self.successors[ln.get()] = succ_ln;
-
-        // It is not necessary to initialize the RWUs here because they are all
-        // set to INV_INV_FALSE when they are created, and the sets only grow
-        // during iterations.
-    }
-
-    fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
-        // more efficient version of init_empty() / merge_from_succ()
-        self.successors[ln.get()] = succ_ln;
-
-        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            this.rwu_table.copy_packed(idx, succ_idx);
-        });
-        debug!("init_from_succ(ln={}, succ={})",
-               self.ln_str(ln), self.ln_str(succ_ln));
-    }
-
-    fn merge_from_succ(&mut self,
-                       ln: LiveNode,
-                       succ_ln: LiveNode,
-                       first_merge: bool)
-                       -> bool {
-        if ln == succ_ln { return false; }
-
-        let mut changed = false;
-        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
-            let mut rwu = this.rwu_table.get(idx);
-            let succ_rwu = this.rwu_table.get(succ_idx);
-            if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
-                rwu.reader = succ_rwu.reader;
-                changed = true
-            }
-
-            if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
-                rwu.writer = succ_rwu.writer;
-                changed = true
-            }
-
-            if succ_rwu.used && !rwu.used {
-                rwu.used = true;
-                changed = true;
-            }
-
-            if changed {
-                this.rwu_table.assign_unpacked(idx, rwu);
-            }
-        });
-
-        debug!("merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})",
-               ln, self.ln_str(succ_ln), first_merge, changed);
-        return changed;
-    }
-
-    // Indicates that a local variable was *defined*; we know that no
-    // uses of the variable can precede the definition (resolve checks
-    // this) so we just clear out all the data.
-    fn define(&mut self, writer: LiveNode, var: Variable) {
-        let idx = self.idx(writer, var);
-        self.rwu_table.assign_inv_inv(idx);
-
-        debug!("{:?} defines {:?} (idx={}): {}", writer, var,
-               idx, self.ln_str(writer));
-    }
-
-    // Either read, write, or both depending on the acc bitset
-    fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) {
-        debug!("{:?} accesses[{:x}] {:?}: {}",
-               ln, acc, var, self.ln_str(ln));
-
-        let idx = self.idx(ln, var);
-        let mut rwu = self.rwu_table.get(idx);
-
-        if (acc & ACC_WRITE) != 0 {
-            rwu.reader = invalid_node();
-            rwu.writer = ln;
-        }
-
-        // Important: if we both read/write, must do read second
-        // or else the write will override.
-        if (acc & ACC_READ) != 0 {
-            rwu.reader = ln;
-        }
-
-        if (acc & ACC_USE) != 0 {
-            rwu.used = true;
-        }
-
-        self.rwu_table.assign_unpacked(idx, rwu);
-    }
-
-    fn compute(&mut self, body: &hir::Expr) -> LiveNode {
-        debug!("compute: using id for body, {}",
-               self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));
-
-        // the fallthrough exit is only for those cases where we do not
-        // explicitly return:
-        let s = self.s;
-        self.init_from_succ(s.fallthrough_ln, s.exit_ln);
-        self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
-
-        let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln);
-
-        // hack to skip the loop unless debug! is enabled:
-        debug!("^^ liveness computation results for body {} (entry={:?})", {
-                   for ln_idx in 0..self.ir.num_live_nodes {
-                        debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32)));
-                   }
-                   body.hir_id
-               },
-               entry_ln);
-
-        entry_ln
-    }
-
-    fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
-                               -> LiveNode {
-        if blk.targeted_by_break {
-            self.break_ln.insert(blk.hir_id, succ);
-        }
-        let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
-        blk.stmts.iter().rev().fold(succ, |succ, stmt| {
-            self.propagate_through_stmt(stmt, succ)
-        })
-    }
-
-    fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode)
-                              -> LiveNode {
-        match stmt.kind {
-            hir::StmtKind::Local(ref local) => {
-                // Note: we mark the variable as defined regardless of whether
-                // there is an initializer.  Initially I had thought to only mark
-                // the live variable as defined if it was initialized, and then we
-                // could check for uninit variables just by scanning what is live
-                // at the start of the function. But that doesn't work so well for
-                // immutable variables defined in a loop:
-                //     loop { let x; x = 5; }
-                // because the "assignment" loops back around and generates an error.
-                //
-                // So now we just check that variables defined w/o an
-                // initializer are not live at the point of their
-                // initialization, which is mildly more complex than checking
-                // once at the func header but otherwise equivalent.
-
-                let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
-                self.define_bindings_in_pat(&local.pat, succ)
-            }
-            hir::StmtKind::Item(..) => succ,
-            hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
-                self.propagate_through_expr(&expr, succ)
-            }
-        }
-    }
-
-    fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
-                               -> LiveNode {
-        exprs.iter().rev().fold(succ, |succ, expr| {
-            self.propagate_through_expr(&expr, succ)
-        })
-    }
-
-    fn propagate_through_opt_expr(&mut self,
-                                  opt_expr: Option<&Expr>,
-                                  succ: LiveNode)
-                                  -> LiveNode {
-        opt_expr.map_or(succ, |expr| self.propagate_through_expr(expr, succ))
-    }
-
-    fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
-                              -> LiveNode {
-        debug!("propagate_through_expr: {}", self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id));
-
-        match expr.kind {
-            // Interesting cases with control flow or which gen/kill
-            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
-                self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
-            }
-
-            hir::ExprKind::Field(ref e, _) => {
-                self.propagate_through_expr(&e, succ)
-            }
-
-            hir::ExprKind::Closure(..) => {
-                debug!("{} is an ExprKind::Closure",
-                       self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id));
-
-                // the construction of a closure itself is not important,
-                // but we have to consider the closed over variables.
-                let caps = self.ir.capture_info_map.get(&expr.hir_id).cloned().unwrap_or_else(||
-                    span_bug!(expr.span, "no registered caps"));
-
-                caps.iter().rev().fold(succ, |succ, cap| {
-                    self.init_from_succ(cap.ln, succ);
-                    let var = self.variable(cap.var_hid, expr.span);
-                    self.acc(cap.ln, var, ACC_READ | ACC_USE);
-                    cap.ln
-                })
-            }
-
-            // Note that labels have been resolved, so we don't need to look
-            // at the label ident
-            hir::ExprKind::Loop(ref blk, _, _) => {
-                self.propagate_through_loop(expr, &blk, succ)
-            }
-
-            hir::ExprKind::Match(ref e, ref arms, _) => {
-                //
-                //      (e)
-                //       |
-                //       v
-                //     (expr)
-                //     / | \
-                //    |  |  |
-                //    v  v  v
-                //   (..arms..)
-                //    |  |  |
-                //    v  v  v
-                //   (  succ  )
-                //
-                //
-                let ln = self.live_node(expr.hir_id, expr.span);
-                self.init_empty(ln, succ);
-                let mut first_merge = true;
-                for arm in arms {
-                    let body_succ = self.propagate_through_expr(&arm.body, succ);
-
-                    let guard_succ = self.propagate_through_opt_expr(
-                        arm.guard.as_ref().map(|hir::Guard::If(e)| &**e),
-                        body_succ
-                    );
-                    let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
-                    self.merge_from_succ(ln, arm_succ, first_merge);
-                    first_merge = false;
-                };
-                self.propagate_through_expr(&e, ln)
-            }
-
-            hir::ExprKind::Ret(ref o_e) => {
-                // ignore succ and subst exit_ln:
-                let exit_ln = self.s.exit_ln;
-                self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
-            }
-
-            hir::ExprKind::Break(label, ref opt_expr) => {
-                // Find which label this break jumps to
-                let target = match label.target_id {
-                    Ok(hir_id) => self.break_ln.get(&hir_id),
-                    Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
-                }.cloned();
-
-                // Now that we know the label we're going to,
-                // look it up in the break loop nodes table
-
-                match target {
-                    Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
-                    None => span_bug!(expr.span, "break to unknown label")
-                }
-            }
-
-            hir::ExprKind::Continue(label) => {
-                // Find which label this expr continues to
-                let sc = label.target_id.unwrap_or_else(|err|
-                    span_bug!(expr.span, "loop scope error: {}", err));
-
-                // Now that we know the label we're going to,
-                // look it up in the continue loop nodes table
-                self.cont_ln.get(&sc).cloned().unwrap_or_else(||
-                    span_bug!(expr.span, "continue to unknown label"))
-            }
-
-            hir::ExprKind::Assign(ref l, ref r) => {
-                // see comment on places in
-                // propagate_through_place_components()
-                let succ = self.write_place(&l, succ, ACC_WRITE);
-                let succ = self.propagate_through_place_components(&l, succ);
-                self.propagate_through_expr(&r, succ)
-            }
-
-            hir::ExprKind::AssignOp(_, ref l, ref r) => {
-                // an overloaded assign op is like a method call
-                if self.tables.is_method_call(expr) {
-                    let succ = self.propagate_through_expr(&l, succ);
-                    self.propagate_through_expr(&r, succ)
-                } else {
-                    // see comment on places in
-                    // propagate_through_place_components()
-                    let succ = self.write_place(&l, succ, ACC_WRITE|ACC_READ);
-                    let succ = self.propagate_through_expr(&r, succ);
-                    self.propagate_through_place_components(&l, succ)
-                }
-            }
-
-            // Uninteresting cases: just propagate in rev exec order
-
-            hir::ExprKind::Array(ref exprs) => {
-                self.propagate_through_exprs(exprs, succ)
-            }
-
-            hir::ExprKind::Struct(_, ref fields, ref with_expr) => {
-                let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
-                fields.iter().rev().fold(succ, |succ, field| {
-                    self.propagate_through_expr(&field.expr, succ)
-                })
-            }
-
-            hir::ExprKind::Call(ref f, ref args) => {
-                let m = self.ir.tcx.hir().get_module_parent(expr.hir_id);
-                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
-                    self.s.exit_ln
-                } else {
-                    succ
-                };
-                let succ = self.propagate_through_exprs(args, succ);
-                self.propagate_through_expr(&f, succ)
-            }
-
-            hir::ExprKind::MethodCall(.., ref args) => {
-                let m = self.ir.tcx.hir().get_module_parent(expr.hir_id);
-                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
-                    self.s.exit_ln
-                } else {
-                    succ
-                };
-
-                self.propagate_through_exprs(args, succ)
-            }
-
-            hir::ExprKind::Tup(ref exprs) => {
-                self.propagate_through_exprs(exprs, succ)
-            }
-
-            hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
-                let r_succ = self.propagate_through_expr(&r, succ);
-
-                let ln = self.live_node(expr.hir_id, expr.span);
-                self.init_from_succ(ln, succ);
-                self.merge_from_succ(ln, r_succ, false);
-
-                self.propagate_through_expr(&l, ln)
-            }
-
-            hir::ExprKind::Index(ref l, ref r) |
-            hir::ExprKind::Binary(_, ref l, ref r) => {
-                let r_succ = self.propagate_through_expr(&r, succ);
-                self.propagate_through_expr(&l, r_succ)
-            }
-
-            hir::ExprKind::Box(ref e) |
-            hir::ExprKind::AddrOf(_, ref e) |
-            hir::ExprKind::Cast(ref e, _) |
-            hir::ExprKind::Type(ref e, _) |
-            hir::ExprKind::DropTemps(ref e) |
-            hir::ExprKind::Unary(_, ref e) |
-            hir::ExprKind::Yield(ref e, _) |
-            hir::ExprKind::Repeat(ref e, _) => {
-                self.propagate_through_expr(&e, succ)
-            }
-
-            hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
-                let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
-                // see comment on places
-                // in propagate_through_place_components()
-                if o.is_indirect {
-                    self.propagate_through_expr(output, succ)
-                } else {
-                    let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
-                    let succ = self.write_place(output, succ, acc);
-                    self.propagate_through_place_components(output, succ)
-                }});
-
-                // Inputs are executed first. Propagate last because of rev order
-                self.propagate_through_exprs(inputs, succ)
-            }
-
-            hir::ExprKind::Lit(..) | hir::ExprKind::Err |
-            hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
-                succ
-            }
-
-            // Note that labels have been resolved, so we don't need to look
-            // at the label ident
-            hir::ExprKind::Block(ref blk, _) => {
-                self.propagate_through_block(&blk, succ)
-            }
-        }
-    }
-
-    fn propagate_through_place_components(&mut self,
-                                          expr: &Expr,
-                                          succ: LiveNode)
-                                          -> LiveNode {
-        // # Places
-        //
-        // In general, the full flow graph structure for an
-        // assignment/move/etc can be handled in one of two ways,
-        // depending on whether what is being assigned is a "tracked
-        // value" or not. A tracked value is basically a local
-        // variable or argument.
-        //
-        // The two kinds of graphs are:
-        //
-        //    Tracked place          Untracked place
-        // ----------------------++-----------------------
-        //                       ||
-        //         |             ||           |
-        //         v             ||           v
-        //     (rvalue)          ||       (rvalue)
-        //         |             ||           |
-        //         v             ||           v
-        // (write of place)     ||   (place components)
-        //         |             ||           |
-        //         v             ||           v
-        //      (succ)           ||        (succ)
-        //                       ||
-        // ----------------------++-----------------------
-        //
-        // I will cover the two cases in turn:
-        //
-        // # Tracked places
-        //
-        // A tracked place is a local variable/argument `x`.  In
-        // these cases, the link_node where the write occurs is linked
-        // to node id of `x`.  The `write_place()` routine generates
-        // the contents of this node.  There are no subcomponents to
-        // consider.
-        //
-        // # Non-tracked places
-        //
-        // These are places like `x[5]` or `x.f`.  In that case, we
-        // basically ignore the value which is written to but generate
-        // reads for the components---`x` in these two examples.  The
-        // components reads are generated by
-        // `propagate_through_place_components()` (this fn).
-        //
-        // # Illegal places
-        //
-        // It is still possible to observe assignments to non-places;
-        // these errors are detected in the later pass borrowck.  We
-        // just ignore such cases and treat them as reads.
-
-        match expr.kind {
-            hir::ExprKind::Path(_) => succ,
-            hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
-            _ => self.propagate_through_expr(expr, succ)
-        }
-    }
-
-    // see comment on propagate_through_place()
-    fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode {
-        match expr.kind {
-            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
-                self.access_path(expr.hir_id, path, succ, acc)
-            }
-
-            // We do not track other places, so just propagate through
-            // to their subcomponents.  Also, it may happen that
-            // non-places occur here, because those are detected in the
-            // later pass borrowck.
-            _ => succ
-        }
-    }
-
-    fn access_var(&mut self, hir_id: HirId, var_hid: HirId, succ: LiveNode, acc: u32, span: Span)
-                  -> LiveNode {
-        let ln = self.live_node(hir_id, span);
-        if acc != 0 {
-            self.init_from_succ(ln, succ);
-            let var = self.variable(var_hid, span);
-            self.acc(ln, var, acc);
-        }
-        ln
-    }
-
-    fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
-                   -> LiveNode {
-        match path.res {
-            Res::Local(hid) => {
-                let upvars = self.ir.tcx.upvars(self.ir.body_owner);
-                if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) {
-                    self.access_var(hir_id, hid, succ, acc, path.span)
-                } else {
-                    succ
-                }
-            }
-            _ => succ
-        }
-    }
-
-    fn propagate_through_loop(
-        &mut self,
-        expr: &Expr,
-        body: &hir::Block,
-        succ: LiveNode
-    ) -> LiveNode {
-        /*
-        We model control flow like this:
-
-              (expr) <-+
-                |      |
-                v      |
-              (body) --+
-
-        Note that a `continue` expression targeting the `loop` will have a successor of `expr`.
-        Meanwhile, a `break` expression will have a successor of `succ`.
-        */
-
-        // first iteration:
-        let mut first_merge = true;
-        let ln = self.live_node(expr.hir_id, expr.span);
-        self.init_empty(ln, succ);
-        debug!("propagate_through_loop: using id for loop body {} {}",
-               expr.hir_id, self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));
-
-        self.break_ln.insert(expr.hir_id, succ);
-
-        self.cont_ln.insert(expr.hir_id, ln);
-
-        let body_ln = self.propagate_through_block(body, ln);
-
-        // repeat until fixed point is reached:
-        while self.merge_from_succ(ln, body_ln, first_merge) {
-            first_merge = false;
-            assert_eq!(body_ln, self.propagate_through_block(body, ln));
-        }
-
-        ln
-    }
-}
-
-// _______________________________________________________________________
-// Checking for error conditions
-
-impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_local(&mut self, local: &'tcx hir::Local) {
-        self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
-            if local.init.is_some() {
-                self.warn_about_dead_assign(spans, hir_id, ln, var);
-            }
-        });
-
-        intravisit::walk_local(self, local);
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        check_expr(self, ex);
-    }
-
-    fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
-        self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {});
-        intravisit::walk_arm(self, arm);
-    }
-}
-
-fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) {
-    match expr.kind {
-        hir::ExprKind::Assign(ref l, _) => {
-            this.check_place(&l);
-        }
-
-        hir::ExprKind::AssignOp(_, ref l, _) => {
-            if !this.tables.is_method_call(expr) {
-                this.check_place(&l);
-            }
-        }
-
-        hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
-            for input in inputs {
-                this.visit_expr(input);
-            }
-
-            // Output operands must be places
-            for (o, output) in ia.outputs.iter().zip(outputs) {
-                if !o.is_indirect {
-                    this.check_place(output);
-                }
-                this.visit_expr(output);
-            }
-        }
-
-        // no correctness conditions related to liveness
-        hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) |
-        hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) |
-        hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
-        hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
-        hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | hir::ExprKind::Unary(..) |
-        hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) |
-        hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
-        hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
-        hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
-        hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {}
-    }
-
-    intravisit::walk_expr(this, expr);
-}
-
-impl<'tcx> Liveness<'_, 'tcx> {
-    fn check_place(&mut self, expr: &'tcx Expr) {
-        match expr.kind {
-            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
-                if let Res::Local(var_hid) = path.res {
-                    let upvars = self.ir.tcx.upvars(self.ir.body_owner);
-                    if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) {
-                        // Assignment to an immutable variable or argument: only legal
-                        // if there is no later assignment. If this local is actually
-                        // mutable, then check for a reassignment to flag the mutability
-                        // as being used.
-                        let ln = self.live_node(expr.hir_id, expr.span);
-                        let var = self.variable(var_hid, expr.span);
-                        self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
-                    }
-                }
-            }
-            _ => {
-                // For other kinds of places, no checks are required,
-                // and any embedded expressions are actually rvalues
-                intravisit::walk_expr(self, expr);
-            }
-        }
-    }
-
-    fn should_warn(&self, var: Variable) -> Option<String> {
-        let name = self.ir.variable_name(var);
-        if name.is_empty() || name.as_bytes()[0] == b'_' {
-            None
-        } else {
-            Some(name)
-        }
-    }
-
-    fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
-        for p in &body.params {
-            self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
-                if self.live_on_entry(ln, var).is_none() {
-                    self.report_dead_assign(hir_id, spans, var, true);
-                }
-            });
-        }
-    }
-
-    fn check_unused_vars_in_pat(
-        &self,
-        pat: &hir::Pat,
-        entry_ln: Option<LiveNode>,
-        on_used_on_entry: impl Fn(Vec<Span>, HirId, LiveNode, Variable),
-    ) {
-        // In an or-pattern, only consider the variable; any later patterns must have the same
-        // bindings, and we also consider the first pattern to be the "authoritative" set of ids.
-        // However, we should take the spans of variables with the same name from the later
-        // patterns so the suggestions to prefix with underscores will apply to those too.
-        let mut vars: FxIndexMap<String, (LiveNode, Variable, HirId, Vec<Span>)> = <_>::default();
-
-        pat.each_binding(|_, hir_id, pat_sp, ident| {
-            let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp));
-            let var = self.variable(hir_id, ident.span);
-            vars.entry(self.ir.variable_name(var))
-                .and_modify(|(.., spans)| spans.push(ident.span))
-                .or_insert_with(|| (ln, var, hir_id, vec![ident.span]));
-        });
-
-        for (_, (ln, var, id, spans)) in vars {
-            if self.used_on_entry(ln, var) {
-                on_used_on_entry(spans, id, ln, var);
-            } else {
-                self.report_unused(spans, id, ln, var);
-            }
-        }
-    }
-
-    fn report_unused(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
-        if let Some(name) = self.should_warn(var).filter(|name| name != "self") {
-            // annoying: for parameters in funcs like `fn(x: i32)
-            // {ret}`, there is only one node, so asking about
-            // assigned_on_exit() is not meaningful.
-            let is_assigned = if ln == self.s.exit_ln {
-                false
-            } else {
-                self.assigned_on_exit(ln, var).is_some()
-            };
-
-            if is_assigned {
-                self.ir.tcx.lint_hir_note(
-                    lint::builtin::UNUSED_VARIABLES,
-                    hir_id,
-                    spans,
-                    &format!("variable `{}` is assigned to, but never used", name),
-                    &format!("consider using `_{}` instead", name),
-                );
-            } else {
-                let mut err = self.ir.tcx.struct_span_lint_hir(
-                    lint::builtin::UNUSED_VARIABLES,
-                    hir_id,
-                    spans.clone(),
-                    &format!("unused variable: `{}`", name),
-                );
-
-                if self.ir.variable_is_shorthand(var) {
-                    if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
-                        // Handle `ref` and `ref mut`.
-                        let spans = spans.iter()
-                            .map(|_span| (pat.span, format!("{}: _", name)))
-                            .collect();
-
-                        err.multipart_suggestion(
-                            "try ignoring the field",
-                            spans,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                } else {
-                    err.multipart_suggestion(
-                        "consider prefixing with an underscore",
-                        spans.iter().map(|span| (*span, format!("_{}", name))).collect(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-
-                err.emit()
-            }
-        }
-    }
-
-    fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
-        if self.live_on_exit(ln, var).is_none() {
-            self.report_dead_assign(hir_id, spans, var, false);
-        }
-    }
-
-    fn report_dead_assign(&self, hir_id: HirId, spans: Vec<Span>, var: Variable, is_param: bool) {
-        if let Some(name) = self.should_warn(var) {
-            if is_param {
-                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
-                &format!("value passed to `{}` is never read", name))
-                .help("maybe it is overwritten before being read?")
-                .emit();
-            } else {
-                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
-                &format!("value assigned to `{}` is never read", name))
-                .help("maybe it is overwritten before being read?")
-                .emit();
-            }
-        }
-    }
-}
index 32f45cd9d472035ab601b8abc78a4b85396acbdd..bbf00cc23ae8835008e18b6fc596fdf440afe47a 100644 (file)
@@ -343,14 +343,19 @@ pub fn to_bits_or_ptr(
         }
     }
 
+    #[inline(always)]
+    pub fn check_raw(data: u128, size: u8, target_size: Size) {
+        assert_eq!(target_size.bytes(), size as u64);
+        assert_ne!(size, 0, "you should never look at the bits of a ZST");
+        Scalar::check_data(data, size);
+    }
+
     /// Do not call this method!  Use either `assert_bits` or `force_bits`.
     #[inline]
     pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
         match self {
             Scalar::Raw { data, size } => {
-                assert_eq!(target_size.bytes(), size as u64);
-                assert_ne!(size, 0, "you should never look at the bits of a ZST");
-                Scalar::check_data(data, size);
+                Self::check_raw(data, size, target_size);
                 Ok(data)
             }
             Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes),
index 59b4f24073398bfd2ae2f221793137b98aae414c..2b5212cb7efaa5ca5c095da678a6f079845fd998 100644 (file)
@@ -15,7 +15,7 @@
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{
-    self, AdtDef, CanonicalUserTypeAnnotations, GeneratorSubsts, Region, Ty, TyCtxt,
+    self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt,
     UserTypeAnnotationIndex,
 };
 
@@ -2189,7 +2189,7 @@ pub enum AggregateKind<'tcx> {
     Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>),
 
     Closure(DefId, SubstsRef<'tcx>),
-    Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
+    Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
index 26f718e858da8ea85b2c52bb935a280692b6ca91..e87aabf9a0566498cbe1cd615819a20a58c1a2b6 100644 (file)
@@ -197,7 +197,7 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
                 let ty = place.ty(local_decls, tcx).ty;
                 match ty.kind {
                     ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
-                    ty::Generator(_, substs, _) => substs.discr_ty(tcx),
+                    ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
                     _ => {
                         // This can only be `0`, for now, so `u8` will suffice.
                         tcx.types.u8
index ed8086b8fafec5c200d9de0388681102237f9ce0..edc7922f46eec1bb7b84978225a28dd25146b678 100644 (file)
@@ -1,5 +1,5 @@
 use crate::ty::subst::SubstsRef;
-use crate::ty::{CanonicalUserTypeAnnotation, GeneratorSubsts, Ty};
+use crate::ty::{CanonicalUserTypeAnnotation, Ty};
 use crate::mir::*;
 use syntax_pos::Span;
 
@@ -230,12 +230,6 @@ fn visit_substs(&mut self,
                 self.super_substs(substs);
             }
 
-            fn visit_generator_substs(&mut self,
-                                      substs: & $($mutability)? GeneratorSubsts<'tcx>,
-                                    _: Location) {
-                self.super_generator_substs(substs);
-            }
-
             fn visit_local_decl(&mut self,
                                 local: Local,
                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
@@ -628,7 +622,7 @@ fn super_rvalue(&mut self,
                                 generator_substs,
                                 _movability,
                             ) => {
-                                self.visit_generator_substs(generator_substs, location);
+                                self.visit_substs(generator_substs, location);
                             }
                         }
 
@@ -846,10 +840,6 @@ fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {
             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
             }
 
-            fn super_generator_substs(&mut self,
-                                      _substs: & $($mutability)? GeneratorSubsts<'tcx>) {
-            }
-
             // Convenience methods
 
             fn visit_location(&mut self, body: & $($mutability)? Body<'tcx>, location: Location) {
index 2771ce69b9e0df747c6a4cac4f33bbe17b1e1666..4618a6277edffd538c97f8613389828d2fef3d2b 100644 (file)
@@ -1316,10 +1316,6 @@ fn parse_symbol_mangling_version(
         "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing"),
-    profile_queries: bool = (false, parse_bool, [UNTRACKED],
-        "trace and profile the queries of the incremental compilation framework"),
-    profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
-        "trace and profile the queries and keys of the incremental compilation framework"),
     no_analysis: bool = (false, parse_bool, [UNTRACKED],
         "parse and expand the source, but run no analysis"),
     extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
@@ -1345,7 +1341,7 @@ fn parse_symbol_mangling_version(
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
         "set the MIR optimization level (0-3, default: 1)"),
     mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
+        "emit noalias metadata for mutable references (default: no)"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "dump MIR state to file.
         `val` is used to select which passes and functions to dump. For example:
index f22445f5d4744765c8f8c705d914edec6e929548..9d60221fa3d753a83acc72155a737a27ba5f444c 100644 (file)
@@ -11,7 +11,6 @@
 use crate::session::search_paths::{PathKind, SearchPath};
 use crate::util::nodemap::{FxHashMap, FxHashSet};
 use crate::util::common::{duration_to_secs_str, ErrorReported};
-use crate::util::common::ProfileQueriesMsg;
 
 use rustc_data_structures::base_n;
 use rustc_data_structures::sync::{
@@ -46,7 +45,7 @@
 use std::io::Write;
 use std::path::PathBuf;
 use std::time::Duration;
-use std::sync::{Arc, mpsc};
+use std::sync::Arc;
 
 mod code_stats;
 pub mod config;
@@ -125,9 +124,6 @@ pub struct Session {
     /// `-Zquery-dep-graph` is specified.
     pub cgu_reuse_tracker: CguReuseTracker,
 
-    /// Used by `-Z profile-queries` in `util::common`.
-    pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
-
     /// Used by `-Z self-profile`.
     pub prof: SelfProfilerRef,
 
@@ -509,13 +505,6 @@ pub fn time_passes(&self) -> bool {
     pub fn time_extended(&self) -> bool {
         self.opts.debugging_opts.time_passes
     }
-    pub fn profile_queries(&self) -> bool {
-        self.opts.debugging_opts.profile_queries
-            || self.opts.debugging_opts.profile_queries_and_keys
-    }
-    pub fn profile_queries_and_keys(&self) -> bool {
-        self.opts.debugging_opts.profile_queries_and_keys
-    }
     pub fn instrument_mcount(&self) -> bool {
         self.opts.debugging_opts.instrument_mcount
     }
@@ -1234,7 +1223,6 @@ fn build_session_(
         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
         cgu_reuse_tracker,
         prof: SelfProfilerRef::new(self_profiler),
-        profile_channel: Lock::new(None),
         perf_stats: PerfStats {
             symbol_hash_time: Lock::new(Duration::from_secs(0)),
             decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),
index a1c97d6c68790017ed11e70740364f402f52d42a..9eb91569ed5c4f6ded2018545d83e7814038ece9 100644 (file)
@@ -453,21 +453,17 @@ fn on_unimplemented_note(
         }
     }
 
-    fn find_similar_impl_candidates(&self,
-                                    trait_ref: ty::PolyTraitRef<'tcx>)
-                                    -> Vec<ty::TraitRef<'tcx>>
-    {
-        let simp = fast_reject::simplify_type(self.tcx,
-                                              trait_ref.skip_binder().self_ty(),
-                                              true);
+    fn find_similar_impl_candidates(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Vec<ty::TraitRef<'tcx>> {
+        let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true);
         let all_impls = self.tcx.all_impls(trait_ref.def_id());
 
         match simp {
             Some(simp) => all_impls.iter().filter_map(|&def_id| {
                 let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                let imp_simp = fast_reject::simplify_type(self.tcx,
-                                                          imp.self_ty(),
-                                                          true);
+                let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
                 if let Some(imp_simp) = imp_simp {
                     if simp != imp_simp {
                         return None
@@ -482,10 +478,11 @@ fn find_similar_impl_candidates(&self,
         }
     }
 
-    fn report_similar_impl_candidates(&self,
-                                      impl_candidates: Vec<ty::TraitRef<'tcx>>,
-                                      err: &mut DiagnosticBuilder<'_>)
-    {
+    fn report_similar_impl_candidates(
+        &self,
+        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
         if impl_candidates.is_empty() {
             return;
         }
@@ -720,10 +717,18 @@ pub fn report_selection_error(
                             // which is somewhat confusing.
                             err.help(&format!("consider adding a `where {}` bound",
                                               trait_ref.to_predicate()));
-                        } else if !have_alt_message {
-                            // Can't show anything else useful, try to find similar impls.
-                            let impl_candidates = self.find_similar_impl_candidates(trait_ref);
-                            self.report_similar_impl_candidates(impl_candidates, &mut err);
+                        } else {
+                            if !have_alt_message {
+                                // Can't show anything else useful, try to find similar impls.
+                                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                                self.report_similar_impl_candidates(impl_candidates, &mut err);
+                            }
+                            self.suggest_change_mut(
+                                &obligation,
+                                &mut err,
+                                &trait_ref,
+                                points_at_arg,
+                            );
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1081,9 +1086,11 @@ fn suggest_remove_reference(
 
                     let substs = self.tcx.mk_substs_trait(trait_type, &[]);
                     let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs);
-                    let new_obligation = Obligation::new(ObligationCause::dummy(),
-                                                         obligation.param_env,
-                                                         new_trait_ref.to_predicate());
+                    let new_obligation = Obligation::new(
+                        ObligationCause::dummy(),
+                        obligation.param_env,
+                        new_trait_ref.to_predicate(),
+                    );
 
                     if self.predicate_may_hold(&new_obligation) {
                         let sp = self.tcx.sess.source_map()
@@ -1105,6 +1112,77 @@ fn suggest_remove_reference(
         }
     }
 
+    /// Check if the trait bound is implemented for a different mutability and note it in the
+    /// final error.
+    fn suggest_change_mut(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        points_at_arg: bool,
+    ) {
+        let span = obligation.cause.span;
+        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+            let refs_number = snippet.chars()
+                .filter(|c| !c.is_whitespace())
+                .take_while(|c| *c == '&')
+                .count();
+            if let Some('\'') = snippet.chars()
+                .filter(|c| !c.is_whitespace())
+                .skip(refs_number)
+                .next()
+            { // Do not suggest removal of borrow from type arguments.
+                return;
+            }
+            let trait_ref = self.resolve_vars_if_possible(trait_ref);
+            if trait_ref.has_infer_types() {
+                // Do not ICE while trying to find if a reborrow would succeed on a trait with
+                // unresolved bindings.
+                return;
+            }
+
+            if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind {
+                let trait_type = match mutability {
+                    hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type),
+                    hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type),
+                };
+
+                let substs = self.tcx.mk_substs_trait(&trait_type, &[]);
+                let new_trait_ref = ty::TraitRef::new(trait_ref.skip_binder().def_id, substs);
+                let new_obligation = Obligation::new(
+                    ObligationCause::dummy(),
+                    obligation.param_env,
+                    new_trait_ref.to_predicate(),
+                );
+
+                if self.evaluate_obligation_no_overflow(
+                    &new_obligation,
+                ).must_apply_modulo_regions() {
+                    let sp = self.tcx.sess.source_map()
+                        .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+                    if points_at_arg &&
+                        mutability == hir::Mutability::MutImmutable &&
+                        refs_number > 0
+                    {
+                        err.span_suggestion(
+                            sp,
+                            "consider changing this borrow's mutability",
+                            "&mut ".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.note(&format!(
+                            "`{}` is implemented for `{:?}`, but not for `{:?}`",
+                            trait_ref,
+                            trait_type,
+                            trait_ref.skip_binder().self_ty(),
+                        ));
+                    }
+                }
+            }
+        }
+    }
+
     fn suggest_semicolon_removal(
         &self,
         obligation: &PredicateObligation<'tcx>,
index 7f194c2fbbc0f1b6099d3d68aa1dd1108d73b44c..d96330bf0a9b4680b88b16328cea577577d4749b 100644 (file)
@@ -610,7 +610,7 @@ pub struct VtableImplData<'tcx, N> {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct VtableGeneratorData<'tcx, N> {
     pub generator_def_id: DefId,
-    pub substs: ty::GeneratorSubsts<'tcx>,
+    pub substs: SubstsRef<'tcx>,
     /// Nested obligations. This can be non-empty if the generator
     /// signature contains associated types.
     pub nested: Vec<N>
index a7bb29c699e0e59c7a50589806ef2577adba53b9..d88bbe145d1fd7be647528ec025f91e8e2a78c60 100644 (file)
@@ -1259,7 +1259,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
-    let gen_sig = vtable.substs.poly_sig(vtable.generator_def_id, selcx.tcx());
+    let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx());
     let Normalized {
         value: gen_sig,
         obligations
@@ -1505,8 +1505,8 @@ fn assoc_ty_def(
 
     if let Some(assoc_item) = trait_def
         .ancestors(tcx, impl_def_id)
-        .defs(tcx, assoc_ty_name, ty::AssocKind::Type, trait_def_id)
-        .next() {
+        .leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
+
         assoc_item
     } else {
         // This is saying that neither the trait nor
index 17684df7e9b8eb79579abf8573c07f3c0a815de0..0d426cab9b751381f3106051b92e97ca269acdc2 100644 (file)
@@ -56,7 +56,7 @@ pub fn evaluate_obligation(
     // Helper function that canonicalizes and runs the query. If an
     // overflow results, we re-run it in the local context so we can
     // report a nice error.
-    fn evaluate_obligation_no_overflow(
+    crate fn evaluate_obligation_no_overflow(
         &self,
         obligation: &PredicateObligation<'tcx>,
     ) -> EvaluationResult {
index 1fae2a2fe8dbffc783595f05aacbf58e5f2541a7..44d611ace77d017abf94ebce568eb950cac09fa3 100644 (file)
@@ -2761,8 +2761,9 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
                 .collect(),
 
             ty::Generator(def_id, ref substs, _) => {
-                let witness = substs.witness(def_id, self.tcx());
+                let witness = substs.as_generator().witness(def_id, self.tcx());
                 substs
+                    .as_generator()
                     .upvar_tys(def_id, self.tcx())
                     .chain(iter::once(witness))
                     .collect()
@@ -2818,7 +2819,7 @@ fn collect_predicates_for_types(
                 // binder moved -\
                 let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
 
-                self.infcx.in_snapshot(|_| {
+                self.infcx.commit_unconditionally(|_| {
                     let (skol_ty, _) = self.infcx
                         .replace_bound_vars_with_placeholders(&ty);
                     let Normalized {
@@ -2931,7 +2932,7 @@ fn confirm_candidate(
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.in_snapshot(|snapshot| {
+        self.infcx.commit_unconditionally(|snapshot| {
             let result =
                 self.match_projection_obligation_against_definition_bounds(
                     obligation,
@@ -3053,19 +3054,20 @@ fn vtable_auto_impl(
             nested,
         );
 
-        let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|_| {
-            let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-            let (trait_ref, _) = self.infcx
-                .replace_bound_vars_with_placeholders(&poly_trait_ref);
-            let cause = obligation.derived_cause(ImplDerivedObligation);
-            self.impl_or_trait_obligations(
-                cause,
-                obligation.recursion_depth + 1,
-                obligation.param_env,
-                trait_def_id,
-                &trait_ref.substs,
-            )
-        });
+        let trait_obligations: Vec<PredicateObligation<'_>> =
+            self.infcx.commit_unconditionally(|_| {
+                let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+                let (trait_ref, _) = self.infcx
+                    .replace_bound_vars_with_placeholders(&poly_trait_ref);
+                let cause = obligation.derived_cause(ImplDerivedObligation);
+                self.impl_or_trait_obligations(
+                    cause,
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    trait_def_id,
+                    &trait_ref.substs,
+                )
+            });
 
         // Adds the predicates from the trait.  Note that this contains a `Self: Trait`
         // predicate as usual.  It won't have any effect since auto traits are coinductive.
@@ -3088,7 +3090,7 @@ fn confirm_impl_candidate(
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.in_snapshot(|snapshot| {
+        self.infcx.commit_unconditionally(|snapshot| {
             let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
@@ -3252,7 +3254,7 @@ fn confirm_trait_alias_candidate(
             obligation, alias_def_id
         );
 
-        self.infcx.in_snapshot(|_| {
+        self.infcx.commit_unconditionally(|_| {
             let (predicate, _) = self.infcx()
                 .replace_bound_vars_with_placeholders(&obligation.predicate);
             let trait_ref = predicate.trait_ref;
@@ -3324,8 +3326,8 @@ fn confirm_generator_candidate(
         )?);
 
         Ok(VtableGeneratorData {
-            generator_def_id: generator_def_id,
-            substs: substs.clone(),
+            generator_def_id,
+            substs,
             nested: obligations,
         })
     }
@@ -3911,9 +3913,9 @@ fn generator_trait_ref_unnormalized(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         closure_def_id: DefId,
-        substs: ty::GeneratorSubsts<'tcx>,
+        substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        let gen_sig = substs.poly_sig(closure_def_id, self.tcx());
+        let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx());
 
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an generator type and hence is
index f0389bb037ac5b827aeb4e1e5bcc8e07f1d29d5a..9c80ef7d4a23e0a612fa1b06913f091bb4cd50a5 100644 (file)
@@ -125,7 +125,7 @@ pub fn find_associated_item<'tcx>(
     let trait_def = tcx.trait_def(trait_def_id);
 
     let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
-    match ancestors.defs(tcx, item.ident, item.kind, trait_def_id).next() {
+    match ancestors.leaf_def(tcx, item.ident, item.kind) {
         Some(node_item) => {
             let substs = tcx.infer_ctxt().enter(|infcx| {
                 let param_env = param_env.with_reveal_all();
index 43f558d64430e2f94e50c67510da7ae0c4db690f..c64d6748ea97d563e47b7de484320192875c4415 100644 (file)
@@ -7,7 +7,6 @@
 use crate::ty::{self, TyCtxt, TypeFoldable};
 use crate::ty::fast_reject::{self, SimplifiedType};
 use syntax::ast::Ident;
-use crate::util::captures::Captures;
 use crate::util::nodemap::{DefIdMap, FxHashMap};
 
 /// A per-trait graph of impls in specialization order. At the moment, this
@@ -419,6 +418,35 @@ pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> {
         tcx.associated_items(self.def_id())
     }
 
+    /// Finds an associated item defined in this node.
+    ///
+    /// If this returns `None`, the item can potentially still be found in
+    /// parents of this node.
+    pub fn item(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        trait_item_name: Ident,
+        trait_item_kind: ty::AssocKind,
+        trait_def_id: DefId,
+    ) -> Option<ty::AssocItem> {
+        use crate::ty::AssocKind::*;
+
+        tcx.associated_items(self.def_id())
+            .find(move |impl_item| match (trait_item_kind, impl_item.kind) {
+                | (Const, Const)
+                | (Method, Method)
+                | (Type, Type)
+                | (Type, OpaqueTy)  // assoc. types can be made opaque in impls
+                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
+
+                | (Const, _)
+                | (Method, _)
+                | (Type, _)
+                | (OpaqueTy, _)
+                => false,
+            })
+    }
+
     pub fn def_id(&self) -> DefId {
         match *self {
             Node::Impl(did) => did,
@@ -427,6 +455,7 @@ pub fn def_id(&self) -> DefId {
     }
 }
 
+#[derive(Copy, Clone)]
 pub struct Ancestors<'tcx> {
     trait_def_id: DefId,
     specialization_graph: &'tcx Graph,
@@ -465,32 +494,18 @@ pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
 }
 
 impl<'tcx> Ancestors<'tcx> {
-    /// Search the items from the given ancestors, returning each definition
-    /// with the given name and the given kind.
-    // FIXME(#35870): avoid closures being unexported due to `impl Trait`.
-    #[inline]
-    pub fn defs(
-        self,
+    /// Finds the bottom-most (ie. most specialized) definition of an associated
+    /// item.
+    pub fn leaf_def(
+        mut self,
         tcx: TyCtxt<'tcx>,
         trait_item_name: Ident,
         trait_item_kind: ty::AssocKind,
-        trait_def_id: DefId,
-    ) -> impl Iterator<Item = NodeItem<ty::AssocItem>> + Captures<'tcx> + 'tcx {
-        self.flat_map(move |node| {
-            use crate::ty::AssocKind::*;
-            node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
-                | (Const, Const)
-                | (Method, Method)
-                | (Type, Type)
-                | (Type, OpaqueTy)
-                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
-
-                | (Const, _)
-                | (Method, _)
-                | (Type, _)
-                | (OpaqueTy, _)
-                => false,
-            }).map(move |item| NodeItem { node: node, item: item })
+    ) -> Option<NodeItem<ty::AssocItem>> {
+        let trait_def_id = self.trait_def_id;
+        self.find_map(|node| {
+            node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
+                .map(|item| NodeItem { node, item })
         })
     }
 }
index 18ec2241b2df89605db8ceca1d7a78bf9ec49d49..d8b1effe09bf41de6cff5796c3e2856f2365991d 100644 (file)
@@ -4,7 +4,6 @@
 
 use crate::hir;
 use crate::hir::def_id::DefId;
-use crate::traits::specialize::specialization_graph::NodeItem;
 use crate::ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
 use crate::ty::outlives::Component;
 use crate::ty::subst::{GenericArg, Subst, SubstsRef};
@@ -667,8 +666,8 @@ pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
         }
     }
 
-    pub fn impl_item_is_final(self, node_item: &NodeItem<hir::Defaultness>) -> bool {
-        node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
+    pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool {
+        assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id())
     }
 }
 
index 5aad6c1dc18322825a760050565cb4701c5e0355..cd52f8fa92c5a805c0ef7b953a7291e19b7fa9a5 100644 (file)
@@ -29,7 +29,7 @@
 use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals};
 use crate::ty::{self, DefIdTree, Ty, TypeAndMut};
 use crate::ty::{TyS, TyKind, List};
-use crate::ty::{AdtKind, AdtDef, GeneratorSubsts, Region, Const};
+use crate::ty::{AdtKind, AdtDef, Region, Const};
 use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
 use crate::ty::RegionKind;
 use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid};
@@ -2510,7 +2510,7 @@ pub fn mk_closure(self, closure_id: DefId, closure_substs: SubstsRef<'tcx>)
     #[inline]
     pub fn mk_generator(self,
                         id: DefId,
-                        generator_substs: GeneratorSubsts<'tcx>,
+                        generator_substs: SubstsRef<'tcx>,
                         movability: hir::GeneratorMovability)
                         -> Ty<'tcx> {
         self.mk_ty(Generator(id, generator_substs, movability))
@@ -2868,8 +2868,29 @@ fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> S
 
 impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
     type Output = Result<R, E>;
-    fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        Ok(f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?))
+    fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(mut iter: I, f: F)
+            -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // The match arms are in order of frequency. The 1, 2, and 0 cases are
+        // typically hit in ~95% of cases. We assume that if the upper and
+        // lower bounds from `size_hint` agree they are correct.
+        Ok(match iter.size_hint() {
+            (1, Some(1)) => {
+                f(&[iter.next().unwrap()?])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap()?;
+                let t1 = iter.next().unwrap()?;
+                f(&[t0, t1])
+            }
+            (0, Some(0)) => {
+                f(&[])
+            }
+            _ => {
+                f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?)
+            }
+        })
     }
 }
 
index b513ef5a96670213afccf3b7a18f388526b0da18..d3a3f51cfa47b7a8abb7aa106cbec3556d0b91bd 100644 (file)
@@ -94,7 +94,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             &ty::Generator(_, ref substs, _) => {
                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
-                self.add_substs(&substs.substs);
+                self.add_substs(substs);
             }
 
             &ty::GeneratorWitness(ref ts) => {
@@ -250,7 +250,9 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
             ConstValue::Placeholder(_) => {
                 self.add_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_CT_PLACEHOLDER);
             }
-            _ => {},
+            ConstValue::Scalar(_) => { }
+            ConstValue::Slice { data: _, start: _, end: _ } => { }
+            ConstValue::ByRef { alloc: _, offset: _ } => { }
         }
     }
 
index f6a5092d30d407b51aa43770cfc99a757dbde4c8..5192075c26e9871068aedc5d7f17fda753228b73 100644 (file)
@@ -911,13 +911,15 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
     }
 
     fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
-        if let ty::Const {
-            val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)),
-            ..
-        } = *ct {
-            debruijn >= self.outer_index
-        } else {
-            false
+        // we don't have a `visit_infer_const` callback, so we have to
+        // hook in here to catch this case (annoying...), but
+        // otherwise we do want to remember to visit the rest of the
+        // const, as it has types/regions embedded in a lot of other
+        // places.
+        match ct.val {
+            ConstValue::Infer(ty::InferConst::Canonical(debruijn, _))
+                if debruijn >= self.outer_index => true,
+            _ => ct.super_visit_with(self),
         }
     }
 }
index 34f806b15c0c6c32defa00f6855279fbab99eb36..93a8341e74628063fdda5cd8144c1d1dfdbc6b2c 100644 (file)
@@ -71,7 +71,7 @@ fn fn_sig_noadjust(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
                 ))
             }
             ty::Generator(def_id, substs, _) => {
-                let sig = substs.poly_sig(def_id, tcx);
+                let sig = substs.as_generator().poly_sig(def_id, tcx);
 
                 let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
                 let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
@@ -395,7 +395,7 @@ fn resolve_associated_item<'tcx>(
         traits::VtableGenerator(generator_data) => {
             Some(Instance {
                 def: ty::InstanceDef::Item(generator_data.generator_def_id),
-                substs: generator_data.substs.substs
+                substs: generator_data.substs
             })
         }
         traits::VtableClosure(closure_data) => {
index 6e01e1bf26a53cd2363c61a91464b36888fce6d6..ce7e1822d9ab5d6bbc09a6a79f795d0045100553 100644 (file)
@@ -1,5 +1,5 @@
 use crate::session::{self, DataTypeKind};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, subst::SubstsRef};
 
 use syntax::ast::{self, Ident, IntTy, UintTy};
 use syntax::attr;
@@ -15,7 +15,6 @@
 use crate::hir;
 use crate::ich::StableHashingContext;
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
-use crate::ty::GeneratorSubsts;
 use crate::ty::subst::Subst;
 use rustc_index::bit_set::BitSet;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -671,7 +670,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx LayoutDetails, Layou
                 tcx.intern_layout(unit)
             }
 
-            ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, &substs)?,
+            ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?,
 
             ty::Closure(def_id, ref substs) => {
                 let tys = substs.as_closure().upvar_tys(def_id, tcx);
@@ -1406,12 +1405,12 @@ fn generator_layout(
         &self,
         ty: Ty<'tcx>,
         def_id: hir::def_id::DefId,
-        substs: &GeneratorSubsts<'tcx>,
+        substs: SubstsRef<'tcx>,
     ) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
         use SavedLocalEligibility::*;
         let tcx = self.tcx;
 
-        let subst_field = |ty: Ty<'tcx>| { ty.subst(tcx, substs.substs) };
+        let subst_field = |ty: Ty<'tcx>| { ty.subst(tcx, substs) };
 
         let info = tcx.generator_layout(def_id);
         let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info);
@@ -1419,9 +1418,9 @@ fn generator_layout(
         // Build a prefix layout, including "promoting" all ineligible
         // locals as part of the prefix. We compute the layout of all of
         // these fields at once to get optimal packing.
-        let discr_index = substs.prefix_tys(def_id, tcx).count();
+        let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count();
         // FIXME(eddyb) set the correct vaidity range for the discriminant.
-        let discr_layout = self.layout_of(substs.discr_ty(tcx))?;
+        let discr_layout = self.layout_of(substs.as_generator().discr_ty(tcx))?;
         let discr = match &discr_layout.abi {
             Abi::Scalar(s) => s.clone(),
             _ => bug!(),
@@ -1430,7 +1429,7 @@ fn generator_layout(
             .map(|local| subst_field(info.field_tys[local]))
             .map(|ty| tcx.mk_maybe_uninit(ty))
             .map(|ty| self.layout_of(ty));
-        let prefix_layouts = substs.prefix_tys(def_id, tcx)
+        let prefix_layouts = substs.as_generator().prefix_tys(def_id, tcx)
             .map(|ty| self.layout_of(ty))
             .chain(iter::once(Ok(discr_layout)))
             .chain(promoted_layouts)
@@ -2153,7 +2152,7 @@ fn field(this: TyLayout<'tcx>, cx: &C, i: usize) -> C::TyLayout {
             ty::Generator(def_id, ref substs, _) => {
                 match this.variants {
                     Variants::Single { index } => {
-                        substs.state_tys(def_id, tcx)
+                        substs.as_generator().state_tys(def_id, tcx)
                             .nth(index.as_usize()).unwrap()
                             .nth(i).unwrap()
                     }
@@ -2161,7 +2160,7 @@ fn field(this: TyLayout<'tcx>, cx: &C, i: usize) -> C::TyLayout {
                         if i == discr_index {
                             return discr_layout(discr);
                         }
-                        substs.prefix_tys(def_id, tcx).nth(i).unwrap()
+                        substs.as_generator().prefix_tys(def_id, tcx).nth(i).unwrap()
                     }
                 }
             }
index 3ea767d5115984e067baf243e82c2d2bb95abb25..80e77cdfad0b6ec97f5eaa990f2e3e88bb97eaf1 100644 (file)
@@ -69,7 +69,7 @@ pub fn push_outlives_components(&self, ty0: Ty<'tcx>,
 
             ty::Generator(def_id, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.upvar_tys(def_id, *self) {
+                for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) {
                     self.compute_components(upvar_ty, out);
                 }
 
index 21c018d9ee6de5a3e2719f52ceacd8221be5beda..df39d0ccc9eed08eab509f2504669679056ad7c0 100644 (file)
@@ -8,7 +8,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::mir::interpret::ConstValue;
 use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, Const, GeneratorSubsts, Instance, Ty, TyCtxt};
+use rustc::ty::{self, Const, Instance, Ty, TyCtxt};
 use rustc::{bug, hir};
 use std::fmt::Write;
 use std::iter;
@@ -154,7 +154,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
                     self.push_type_name(sig.output(), output, debug);
                 }
             }
-            ty::Generator(def_id, GeneratorSubsts { substs }, _)
+            ty::Generator(def_id,  substs, _)
             | ty::Closure(def_id, substs) => {
                 self.push_def_path(def_id, output);
                 let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
index ad4be788dae4e49cdde02124c17b5381d8b9c7a0..07c63a92b39dd891cf128c0c94c49c913bc47673 100644 (file)
@@ -605,8 +605,8 @@ fn pretty_print_type(
             }
             ty::Str => p!(write("str")),
             ty::Generator(did, substs, movability) => {
-                let upvar_tys = substs.upvar_tys(did, self.tcx());
-                let witness = substs.witness(did, self.tcx());
+                let upvar_tys = substs.as_generator().upvar_tys(did, self.tcx());
+                let witness = substs.as_generator().witness(did, self.tcx());
                 if movability == hir::GeneratorMovability::Movable {
                     p!(write("[generator"));
                 } else {
@@ -689,7 +689,7 @@ fn pretty_print_type(
                 if self.tcx().sess.verbose() {
                     p!(write(
                         " closure_kind_ty={:?} closure_sig_ty={:?}",
-                        substs.as_closure().kind(did, self.tcx()),
+                        substs.as_closure().kind_ty(did, self.tcx()),
                         substs.as_closure().sig_ty(did, self.tcx())
                     ));
                 }
@@ -698,7 +698,9 @@ fn pretty_print_type(
             },
             ty::Array(ty, sz) => {
                 p!(write("["), print(ty), write("; "));
-                if let ConstValue::Unevaluated(..) = sz.val {
+                if self.tcx().sess.verbose() {
+                    p!(write("{:?}", sz));
+                } else if let ConstValue::Unevaluated(..) = sz.val {
                     // do not try to evalute unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
@@ -855,6 +857,11 @@ fn pretty_print_const(
     ) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
 
+        if self.tcx().sess.verbose() {
+            p!(write("Const({:?}: {:?})", ct.val, ct.ty));
+            return Ok(self);
+        }
+
         let u8 = self.tcx().types.u8;
         if let ty::FnDef(did, substs) = ct.ty.kind {
             p!(print_value_path(did, substs));
index 91082c59ba05ae7a23501902fb66c52eccd71ed4..c1c6a655d96a9132fe1e366f24b356a2582e1681 100644 (file)
@@ -73,6 +73,17 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M {
             format!("processing {:?} with query `{}`", def_id, name).into()
         }
     }
+
+    default fn cache_on_disk(_: TyCtxt<'tcx>, _: Self::Key, _: Option<&Self::Value>) -> bool {
+        false
+    }
+
+    default fn try_load_from_disk(
+        _: TyCtxt<'tcx>,
+        _: SerializedDepNodeIndex,
+    ) -> Option<Self::Value> {
+        bug!("QueryDescription::load_from_disk() called for an unsupported query.")
+    }
 }
 
 impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> {
index 97fafe341a3114ec5c82dc5f0cffce40741eb650..1bba7fdd863ea5653b64528319983a4986dfacd5 100644 (file)
@@ -1075,7 +1075,7 @@ fn encode_query_results<'a, 'tcx, Q, E>(
     let desc = &format!("encode_query_results for {}",
         ::std::any::type_name::<Q>());
 
-    time_ext(tcx.sess.time_extended(), Some(tcx.sess), desc, || {
+    time_ext(tcx.sess.time_extended(), desc, || {
         let shards = Q::query_cache(tcx).lock_shards();
         assert!(shards.iter().all(|shard| shard.active.is_empty()));
         for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) {
index 955f1447c55b67c3d61aeec068a2860accd35b65..7f05e553bc9765273d91dfd4f7157cad4873bf68 100644 (file)
@@ -9,8 +9,6 @@
 use crate::ty::query::config::{QueryConfig, QueryDescription};
 use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
 
-use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
-
 use errors::DiagnosticBuilder;
 use errors::Level;
 use errors::Diagnostic;
@@ -62,33 +60,6 @@ fn default() -> QueryCache<'tcx, M> {
     }
 }
 
-// If enabled, sends a message to the profile-queries thread.
-macro_rules! profq_msg {
-    ($tcx:expr, $msg:expr) => {
-        if cfg!(debug_assertions) {
-            if $tcx.sess.profile_queries() {
-                profq_msg($tcx.sess, $msg)
-            }
-        }
-    }
-}
-
-// If enabled, formats a key using its debug string, which can be
-// expensive to compute (in terms of time).
-macro_rules! profq_query_msg {
-    ($query:expr, $tcx:expr, $key:expr) => {{
-        let msg = if cfg!(debug_assertions) {
-            if $tcx.sess.profile_queries_and_keys() {
-                Some(format!("{:?}", $key))
-            } else { None }
-        } else { None };
-        QueryMsg {
-            query: $query,
-            msg,
-        }
-    }}
-}
-
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
 pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> {
@@ -111,7 +82,6 @@ pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<
         loop {
             let mut lock = cache.get_shard_by_value(key).lock();
             if let Some(value) = lock.results.get(key) {
-                profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
                 tcx.prof.query_cache_hit(Q::NAME);
                 let result = (value.value.clone(), value.index);
                 #[cfg(debug_assertions)]
@@ -358,13 +328,6 @@ pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key
                key,
                span);
 
-        profq_msg!(self,
-            ProfileQueriesMsg::QueryBegin(
-                span.data(),
-                profq_query_msg!(Q::NAME.as_str(), self, key),
-            )
-        );
-
         let job = match JobOwner::try_get(self, span, &key) {
             TryGetJob::NotYetStarted(job) => job,
             TryGetJob::Cycle(result) => return result,
@@ -383,7 +346,6 @@ pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key
 
         if Q::ANON {
 
-            profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
             let prof_timer = self.prof.query_provider(Q::NAME);
 
             let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
@@ -395,7 +357,6 @@ pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key
             });
 
             drop(prof_timer);
-            profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
 
             self.dep_graph.read_index(dep_node_index);
 
@@ -468,7 +429,6 @@ fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'tcx>>(
         };
 
         let result = if let Some(result) = result {
-            profq_msg!(self, ProfileQueriesMsg::CacheHit);
             result
         } else {
             // We could not load a result from the on-disk cache, so
@@ -489,10 +449,6 @@ fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'tcx>>(
             self.incremental_verify_ich::<Q>(&result, dep_node, dep_node_index);
         }
 
-        if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) {
-            self.dep_graph.mark_loaded_from_cache(dep_node_index, true);
-        }
-
         result
     }
 
@@ -546,7 +502,6 @@ fn force_query_with_job<Q: QueryDescription<'tcx>>(
                  - dep-node: {:?}",
                 key, dep_node);
 
-        profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
         let prof_timer = self.prof.query_provider(Q::NAME);
 
         let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
@@ -568,11 +523,6 @@ fn force_query_with_job<Q: QueryDescription<'tcx>>(
         });
 
         drop(prof_timer);
-        profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
-
-        if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) {
-            self.dep_graph.mark_loaded_from_cache(dep_node_index, false);
-        }
 
         if unlikely!(!diagnostics.is_empty()) {
             if dep_node.kind != crate::dep_graph::DepKind::Null {
@@ -614,19 +564,12 @@ pub(super) fn ensure_query<Q: QueryDescription<'tcx>>(self, key: Q::Key) -> () {
 
             let _ = self.get_query::<Q>(DUMMY_SP, key);
         } else {
-            profq_msg!(self, ProfileQueriesMsg::CacheHit);
             self.prof.query_cache_hit(Q::NAME);
         }
     }
 
     #[allow(dead_code)]
     fn force_query<Q: QueryDescription<'tcx>>(self, key: Q::Key, span: Span, dep_node: DepNode) {
-        profq_msg!(
-            self,
-            ProfileQueriesMsg::QueryBegin(span.data(),
-                                          profq_query_msg!(Q::NAME.as_str(), self, key))
-        );
-
         // We may be concurrently trying both execute and force a query.
         // Ensure that only one of them runs the query.
         let job = match JobOwner::try_get(self, span, &key) {
@@ -1191,37 +1134,6 @@ pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool {
         return false
     }
 
-    macro_rules! def_id {
-        () => {
-            if let Some(def_id) = dep_node.extract_def_id(tcx) {
-                def_id
-            } else {
-                // Return from the whole function.
-                return false
-            }
-        }
-    };
-
-    macro_rules! krate {
-        () => { (def_id!()).krate }
-    };
-
-    macro_rules! force_ex {
-        ($tcx:expr, $query:ident, $key:expr) => {
-            {
-                $tcx.force_query::<crate::ty::query::queries::$query<'_>>(
-                    $key,
-                    DUMMY_SP,
-                    *dep_node
-                );
-            }
-        }
-    };
-
-    macro_rules! force {
-        ($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) }
-    };
-
     rustc_dep_node_force!([dep_node, tcx]
         // These are inputs that are expected to be pre-allocated and that
         // should therefore always be red or green already.
@@ -1240,7 +1152,19 @@ macro_rules! force {
             bug!("force_from_dep_node: encountered {:?}", dep_node)
         }
 
-        DepKind::Analysis => { force!(analysis, krate!()); }
+        DepKind::Analysis => {
+            let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) {
+                def_id
+            } else {
+                // Return from the whole function.
+                return false
+            };
+            tcx.force_query::<crate::ty::query::queries::analysis<'_>>(
+                def_id.krate,
+                DUMMY_SP,
+                *dep_node
+            );
+        }
     );
 
     true
index 6b0df7fb92a4a0c0a3779fab388f99ae1b665d5f..5aa59cc309fc72cd6161d64d627d88e04115f93a 100644 (file)
@@ -1223,8 +1223,21 @@ impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
-        folder.tcx().intern_predicates(&v)
+        // This code is hot enough that it's worth specializing for a list of
+        // length 0. (No other length is common enough to be worth singling
+        // out).
+        if self.len() == 0 {
+            self
+        } else {
+            // Don't bother interning if nothing changed, which is the common
+            // case.
+            let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+            if v[..] == self[..] {
+                self
+            } else {
+                folder.tcx().intern_predicates(&v)
+            }
+        }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
index 3f09bf749edc8a6eb71b74c05c07b9bf488375c1..4af73fa389a7db87f26b353981a38697cab8020f 100644 (file)
@@ -13,7 +13,7 @@
 use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind};
 use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
-use crate::ty::layout::{Size, Integer, IntegerExt, VariantIdx};
+use crate::ty::layout::VariantIdx;
 use crate::util::captures::Captures;
 use crate::mir::interpret::{Scalar, GlobalId};
 
@@ -24,7 +24,6 @@
 use std::ops::Range;
 use rustc_target::spec::abi;
 use syntax::ast::{self, Ident};
-use syntax::attr::{SignedInt, UnsignedInt};
 use syntax::symbol::{kw, InternedString};
 
 use self::InferTy::*;
@@ -163,7 +162,7 @@ pub enum TyKind<'tcx> {
 
     /// The anonymous type of a generator. Used to represent the type of
     /// `|a| yield a`.
-    Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
+    Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability),
 
     /// A type representin the types stored inside a generator.
     /// This should only appear in GeneratorInteriors.
@@ -512,7 +511,7 @@ pub fn discriminant_for_variant(
     /// variant indices.
     #[inline]
     pub fn discriminants(
-        &'tcx self,
+        self,
         def_id: DefId,
         tcx: TyCtxt<'tcx>,
     ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'tcx> {
@@ -524,7 +523,7 @@ pub fn discriminants(
     /// Calls `f` with a reference to the name of the enumerator for the given
     /// variant `v`.
     #[inline]
-    pub fn variant_name(&self, v: VariantIdx) -> Cow<'static, str> {
+    pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> {
         match v.as_usize() {
             Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME),
             Self::RETURNED => Cow::from(Self::RETURNED_NAME),
@@ -570,7 +569,7 @@ pub fn prefix_tys(self, def_id: DefId, tcx: TyCtxt<'tcx>) -> impl Iterator<Item
 #[derive(Debug, Copy, Clone)]
 pub enum UpvarSubsts<'tcx> {
     Closure(SubstsRef<'tcx>),
-    Generator(GeneratorSubsts<'tcx>),
+    Generator(SubstsRef<'tcx>),
 }
 
 impl<'tcx> UpvarSubsts<'tcx> {
@@ -582,7 +581,7 @@ pub fn upvar_tys(
     ) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
         let upvar_kinds = match self {
             UpvarSubsts::Closure(substs) => substs.as_closure().split(def_id, tcx).upvar_kinds,
-            UpvarSubsts::Generator(substs) => substs.split(def_id, tcx).upvar_kinds,
+            UpvarSubsts::Generator(substs) => substs.as_generator().split(def_id, tcx).upvar_kinds,
         };
         upvar_kinds.iter().map(|t| {
             if let GenericArgKind::Type(ty) = t.unpack() {
@@ -1776,6 +1775,10 @@ pub fn is_phantom_data(&self) -> bool {
     #[inline]
     pub fn is_bool(&self) -> bool { self.kind == Bool }
 
+    /// Returns `true` if this type is a `str`.
+    #[inline]
+    pub fn is_str(&self) -> bool { self.kind == Str }
+
     #[inline]
     pub fn is_param(&self, index: u32) -> bool {
         match self.kind {
@@ -2109,7 +2112,8 @@ pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> {
     pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
         match self.kind {
             TyKind::Adt(adt, _) => Some(adt.variant_range()),
-            TyKind::Generator(def_id, substs, _) => Some(substs.variant_range(def_id, tcx)),
+            TyKind::Generator(def_id, substs, _) =>
+                Some(substs.as_generator().variant_range(def_id, tcx)),
             _ => None,
         }
     }
@@ -2126,7 +2130,7 @@ pub fn discriminant_for_variant(
         match self.kind {
             TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)),
             TyKind::Generator(def_id, substs, _) =>
-                Some(substs.discriminant_for_variant(def_id, tcx, variant_index)),
+                Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)),
             _ => None,
         }
     }
@@ -2149,7 +2153,7 @@ pub fn discriminant_for_variant(
                 out.extend(substs.regions())
             }
             Closure(_, ref substs ) |
-            Generator(_, GeneratorSubsts { ref substs }, _) => {
+            Generator(_, ref substs, _) => {
                 out.extend(substs.regions())
             }
             Projection(ref data) | UnnormalizedProjection(ref data) => {
@@ -2199,7 +2203,9 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
                 _ => bug!("cannot convert type `{:?}` to a closure kind", self),
             },
 
-            Infer(_) => None,
+            // "Bound" types appear in canonical queries when the
+            // closure type is not yet known
+            Bound(..) | Infer(_) => None,
 
             Error => Some(ty::ClosureKind::Fn),
 
@@ -2299,20 +2305,7 @@ pub fn try_eval_bits(
         ty: Ty<'tcx>,
     ) -> Option<u128> {
         assert_eq!(self.ty, ty);
-        // This is purely an optimization -- layout_of is a pretty expensive operation,
-        // but if we can determine the size without calling it, we don't need all that complexity
-        // (hashing, caching, etc.). As such, try to skip it.
-        let size = match ty.kind {
-            ty::Bool => Size::from_bytes(1),
-            ty::Char => Size::from_bytes(4),
-            ty::Int(ity) => {
-                Integer::from_attr(&tcx, SignedInt(ity)).size()
-            }
-            ty::Uint(uty) => {
-                Integer::from_attr(&tcx, UnsignedInt(uty)).size()
-            }
-            _ => tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size,
-        };
+        let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
         self.eval(tcx, param_env).val.try_to_bits(size)
     }
index 537192b0a2e58dccf61c50aaa0a09a033b97ac46..4081c02a33ca41f87eecb7dc6fdcf69458b73579 100644 (file)
@@ -5,7 +5,7 @@
 use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::mir::interpret::ConstValue;
-use crate::ty::sty::ClosureSubsts;
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
 
 use rustc_serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
@@ -194,6 +194,14 @@ pub fn as_closure(&'a self) -> ClosureSubsts<'a> {
         }
     }
 
+    /// Interpret these substitutions as the substitutions of a generator type.
+    /// Closure substitutions have a particular structure controlled by the
+    /// compiler that encodes information like the signature and generator kind;
+    /// see `ty::GeneratorSubsts` struct for more comments.
+    pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
+        GeneratorSubsts { substs: self }
+    }
+
     /// Creates a `InternalSubsts` that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
         Self::for_item(tcx, def_id, |param, _| {
@@ -394,14 +402,41 @@ pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsR
 
 impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
-
-        // If folding doesn't change the substs, it's faster to avoid
-        // calling `mk_substs` and instead reuse the existing substs.
-        if params[..] == self[..] {
-            self
-        } else {
-            folder.tcx().intern_substs(&params)
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // The match arms are in order of frequency. The 1, 2, and 0 cases are
+        // typically hit in 90--99.99% of cases. When folding doesn't change
+        // the substs, it's faster to reuse the existing substs rather than
+        // calling `intern_substs`.
+        match self.len() {
+            1 => {
+                let param0 = self[0].fold_with(folder);
+                if param0 == self[0] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&[param0])
+                }
+            }
+            2 => {
+                let param0 = self[0].fold_with(folder);
+                let param1 = self[1].fold_with(folder);
+                if param0 == self[0] && param1 == self[1] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&[param0, param1])
+                }
+            }
+            0 => {
+                self
+            }
+            _ => {
+                let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
+                if params[..] == self[..] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&params)
+                }
+            }
         }
     }
 
index 1895ab83674eb634384c0c53734db9fb1bfaa385..f5b1902e3cc8c5ab0085125d7c51f4c61351db96 100644 (file)
@@ -110,12 +110,10 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         ty::Adt(_, substs) | ty::Opaque(_, substs) => {
             stack.extend(substs.types().rev());
         }
-        ty::Closure(_, ref substs) => {
+        ty::Closure(_, ref substs)
+        | ty::Generator(_, ref substs, _) => {
             stack.extend(substs.types().rev());
         }
-        ty::Generator(_, ref substs, _) => {
-            stack.extend(substs.substs.types().rev());
-        }
         ty::GeneratorWitness(ts) => {
             stack.extend(ts.skip_binder().iter().cloned().rev());
         }
index 0f472126695e0720cacd8138162c6d79e3707a56..3e52a6aa50850c12901e0f9b8c5cac6e418a5374 100644 (file)
@@ -6,11 +6,8 @@
 use std::fmt::Debug;
 use std::time::{Duration, Instant};
 
-use std::sync::mpsc::{Sender};
-use syntax_pos::{SpanData};
 use syntax::symbol::{Symbol, sym};
 use rustc_macros::HashStable;
-use crate::dep_graph::{DepNode};
 use crate::session::Session;
 
 #[cfg(test)]
 
 thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
 
-/// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
-#[derive(Clone,Debug)]
-pub struct ProfQDumpParams {
-    /// A base path for the files we will dump.
-    pub path:String,
-    /// To ensure that the compiler waits for us to finish our dumps.
-    pub ack:Sender<()>,
-    /// Toggle dumping a log file with every `ProfileQueriesMsg`.
-    pub dump_profq_msg_log:bool,
-}
-
 #[allow(nonstandard_style)]
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct QueryMsg {
@@ -44,53 +30,6 @@ pub struct QueryMsg {
     pub msg: Option<String>,
 }
 
-/// A sequence of these messages induce a trace of query-based incremental compilation.
-// FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
-#[derive(Clone,Debug)]
-pub enum ProfileQueriesMsg {
-    /// Begin a timed pass.
-    TimeBegin(String),
-    /// End a timed pass.
-    TimeEnd,
-    /// Begin a task (see `dep_graph::graph::with_task`).
-    TaskBegin(DepNode),
-    /// End a task.
-    TaskEnd,
-    /// Begin a new query.
-    /// Cannot use `Span` because queries are sent to other thread.
-    QueryBegin(SpanData, QueryMsg),
-    /// Query is satisfied by using an already-known value for the given key.
-    CacheHit,
-    /// Query requires running a provider; providers may nest, permitting queries to nest.
-    ProviderBegin,
-    /// Query is satisfied by a provider terminating with a value.
-    ProviderEnd,
-    /// Dump a record of the queries to the given path.
-    Dump(ProfQDumpParams),
-    /// Halt the profiling/monitoring background thread.
-    Halt
-}
-
-/// If enabled, send a message to the profile-queries thread.
-pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) {
-    if let Some(s) = sess.profile_channel.borrow().as_ref() {
-        s.send(msg).unwrap()
-    } else {
-        // Do nothing.
-    }
-}
-
-/// Set channel for profile queries channel.
-pub fn profq_set_chan(sess: &Session, s: Sender<ProfileQueriesMsg>) -> bool {
-    let mut channel = sess.profile_channel.borrow_mut();
-    if channel.is_none() {
-        *channel = Some(s);
-        true
-    } else {
-        false
-    }
-}
-
 /// Read the current depth of `time()` calls. This is used to
 /// encourage indentation across threads.
 pub fn time_depth() -> usize {
@@ -107,10 +46,10 @@ pub fn set_time_depth(depth: usize) {
 pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where
     F: FnOnce() -> T,
 {
-    time_ext(sess.time_passes(), Some(sess), what, f)
+    time_ext(sess.time_passes(), what, f)
 }
 
-pub fn time_ext<T, F>(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> T where
+pub fn time_ext<T, F>(do_it: bool, what: &str, f: F) -> T where
     F: FnOnce() -> T,
 {
     if !do_it { return f(); }
@@ -121,19 +60,9 @@ pub fn time_ext<T, F>(do_it: bool, sess: Option<&Session>, what: &str, f: F) ->
         r
     });
 
-    if let Some(sess) = sess {
-        if cfg!(debug_assertions) {
-            profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string()))
-        }
-    }
     let start = Instant::now();
     let rv = f();
     let dur = start.elapsed();
-    if let Some(sess) = sess {
-        if cfg!(debug_assertions) {
-            profq_msg(sess, ProfileQueriesMsg::TimeEnd)
-        }
-    }
 
     print_time_passes_entry(true, what, dur);
 
index 5d43bf6ae28bf662c208365f483ac7732bf4790d..f31765cea4f122f3f4069eac19b5c09793553adc 100644 (file)
@@ -68,7 +68,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc
 
         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx,
                                                        llfn,
-                                                       "entry\0".as_ptr() as *const _);
+                                                       "entry\0".as_ptr().cast());
 
         let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
         llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
@@ -80,7 +80,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc
                                           args.as_ptr(),
                                           args.len() as c_uint,
                                           None,
-                                          "\0".as_ptr() as *const _);
+                                          "\0".as_ptr().cast());
         llvm::LLVMSetTailCall(ret, True);
         if output.is_some() {
             llvm::LLVMBuildRet(llbuilder, ret);
index 33b50401b22f149ac9f11d8464f949433848e2e2..a0bef5b78156586ee195df67e5d807d698bd5002 100644 (file)
@@ -96,10 +96,12 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     }
 
     // Currently stack probes seem somewhat incompatible with the address
-    // sanitizer. With asan we're already protected from stack overflow anyway
-    // so we don't really need stack probes regardless.
-    if let Some(Sanitizer::Address) = cx.sess().opts.debugging_opts.sanitizer {
-        return
+    // sanitizer and thread sanitizer. With asan we're already protected from
+    // stack overflow anyway so we don't really need stack probes regardless.
+    match cx.sess().opts.debugging_opts.sanitizer {
+        Some(Sanitizer::Address) |
+        Some(Sanitizer::Thread) => return,
+        _ => {},
     }
 
     // probestack doesn't play nice either with `-C profile-generate`.
index c4368d2cb8b45df859f68b601512e617ae352702..7437b1e3c8a32e2f7c31599d57a117fd86015de7 100644 (file)
@@ -116,7 +116,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
                 info!("adding bytecode {}", name);
                 let bc_encoded = data.data();
 
-                let (bc, id) = time_ext(cgcx.time_passes, None, &format!("decode {}", name), || {
+                let (bc, id) = time_ext(cgcx.time_passes, &format!("decode {}", name), || {
                     match DecodedBytecode::new(bc_encoded) {
                         Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
                         Err(e) => Err(diag_handler.fatal(&e)),
@@ -295,7 +295,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
         for (bc_decoded, name) in serialized_modules {
             let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module");
             info!("linking {:?}", name);
-            time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || {
+            time_ext(cgcx.time_passes, &format!("ll link {:?}", name), || {
                 let data = bc_decoded.data();
                 linker.add(&data).map_err(|()| {
                     let msg = format!("failed to load bc of {:?}", name);
@@ -546,7 +546,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
         llvm::LLVMRustAddAnalysisPasses(module.module_llvm.tm, pm, module.module_llvm.llmod());
 
         if config.verify_llvm_ir {
-            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
+            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
             llvm::LLVMRustAddPass(pm, pass.unwrap());
         }
 
@@ -581,16 +581,16 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
         // We always generate bitcode through ThinLTOBuffers,
         // which do not support anonymous globals
         if config.bitcode_needed() {
-            let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr() as *const _);
+            let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr().cast());
             llvm::LLVMRustAddPass(pm, pass.unwrap());
         }
 
         if config.verify_llvm_ir {
-            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
+            let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
             llvm::LLVMRustAddPass(pm, pass.unwrap());
         }
 
-        time_ext(cgcx.time_passes, None, "LTO passes", ||
+        time_ext(cgcx.time_passes, "LTO passes", ||
              llvm::LLVMRunPassManager(pm, module.module_llvm.llmod()));
 
         llvm::LLVMDisposePassManager(pm);
index 78db90b57b53d4ed968ccd1f5e21d96a775be45c..52f3a1cbb5c30b06959ddd66d120f79557fe2b4a 100644 (file)
@@ -221,8 +221,8 @@ pub fn new(cgcx: &'a CodegenContext<LlvmCodegenBackend>,
                llcx: &'a llvm::Context) -> Self {
         let data = Box::into_raw(Box::new((cgcx, handler)));
         unsafe {
-            llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
-            llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data as *mut _);
+            llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
+            llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
         }
         DiagnosticHandlers { data, llcx }
     }
@@ -427,7 +427,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
         {
             let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
             time_ext(config.time_passes,
-                        None,
                         &format!("llvm function passes [{}]", module_name.unwrap()),
                         || {
                 llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
@@ -436,7 +435,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
         {
             let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
             time_ext(config.time_passes,
-                    None,
                     &format!("llvm module passes [{}]", module_name.unwrap()),
                     || {
                 llvm::LLVMRunPassManager(mpm, llmod)
@@ -538,7 +536,7 @@ unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
             embed_bitcode(cgcx, llcx, llmod, None);
         }
 
-        time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
+        time_ext(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
             || -> Result<(), FatalError> {
             if config.emit_ir {
                 let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");
@@ -672,7 +670,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext<LlvmCodegenBackend>,
     let llglobal = llvm::LLVMAddGlobal(
         llmod,
         common::val_ty(llconst),
-        "rustc.embedded.module\0".as_ptr() as *const _,
+        "rustc.embedded.module\0".as_ptr().cast(),
     );
     llvm::LLVMSetInitializer(llglobal, llconst);
 
@@ -684,7 +682,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext<LlvmCodegenBackend>,
     } else {
         ".llvmbc\0"
     };
-    llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
+    llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
     llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
@@ -692,7 +690,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext<LlvmCodegenBackend>,
     let llglobal = llvm::LLVMAddGlobal(
         llmod,
         common::val_ty(llconst),
-        "rustc.embedded.cmdline\0".as_ptr() as *const _,
+        "rustc.embedded.cmdline\0".as_ptr().cast(),
     );
     llvm::LLVMSetInitializer(llglobal, llconst);
     let section = if  is_apple {
@@ -700,7 +698,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext<LlvmCodegenBackend>,
     } else {
         ".llvmcmd\0"
     };
-    llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _);
+    llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
     llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
 }
 
@@ -842,7 +840,7 @@ fn create_msvc_imps(
         for (imp_name, val) in globals {
             let imp = llvm::LLVMAddGlobal(llmod,
                                           i8p_ty,
-                                          imp_name.as_ptr() as *const _);
+                                          imp_name.as_ptr().cast());
             llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
             llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
         }
index cba5ee3260c16a8ed58d9cd4aad28d56500b6280..d4df5b4a804ef8345e06ba20a87b1fcd496f1f8c 100644 (file)
@@ -488,7 +488,7 @@ fn codegen_static(
                 if let Some(section) = attrs.link_section {
                     let section = llvm::LLVMMDStringInContext(
                         self.llcx,
-                        section.as_str().as_ptr() as *const _,
+                        section.as_str().as_ptr().cast(),
                         section.as_str().len() as c_uint,
                     );
                     assert!(alloc.relocations().is_empty());
@@ -500,14 +500,14 @@ fn codegen_static(
                         0..alloc.len());
                     let alloc = llvm::LLVMMDStringInContext(
                         self.llcx,
-                        bytes.as_ptr() as *const _,
+                        bytes.as_ptr().cast(),
                         bytes.len() as c_uint,
                     );
                     let data = [section, alloc];
                     let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2);
                     llvm::LLVMAddNamedMetadataOperand(
                         self.llmod,
-                        "wasm.custom_sections\0".as_ptr() as *const _,
+                        "wasm.custom_sections\0".as_ptr().cast(),
                         meta,
                     );
                 }
index 58ce97039099e7bc7dc0477a84e483d82ac6d268..18a5970fcd04432e2c45515d458de2194b8c8607 100644 (file)
@@ -211,7 +211,7 @@ pub unsafe fn create_module(
     // If skipping the PLT is enabled, we need to add some module metadata
     // to ensure intrinsic calls don't use it.
     if !sess.needs_plt() {
-        let avoid_plt = "RtLibUseGOT\0".as_ptr() as *const _;
+        let avoid_plt = "RtLibUseGOT\0".as_ptr().cast();
         llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
     }
 
index 04c9e93c7a527cf79c41c18d035706cc740ca987..9ed1c1730a697b1a44307c5d72be2454adb8a0b7 100644 (file)
@@ -37,7 +37,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>)
 
     let section_var = unsafe {
         llvm::LLVMGetNamedGlobal(cx.llmod,
-                                 c_section_var_name.as_ptr() as *const _)
+                                 c_section_var_name.as_ptr().cast())
     };
 
     section_var.unwrap_or_else(|| {
@@ -52,7 +52,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>)
                                                      llvm_type).unwrap_or_else(||{
                 bug!("symbol `{}` is already defined", section_var_name)
             });
-            llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
+            llvm::LLVMSetSection(section_var, section_name.as_ptr().cast());
             llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddr(section_var, llvm::True);
index e69f4b6aca19a9e9d45b596e44966fe5dc25858b..438a660b8a8673b5895737f732373da26868cbf3 100644 (file)
@@ -30,7 +30,7 @@
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
 use rustc::ty::layout::{self, Align, Integer, IntegerExt, LayoutOf,
                         PrimitiveExt, Size, TyLayout, VariantIdx};
-use rustc::ty::subst::GenericArgKind;
+use rustc::ty::subst::{GenericArgKind, SubstsRef};
 use rustc::session::config::{self, DebugInfo};
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path_to_c_string;
@@ -692,9 +692,10 @@ pub fn type_metadata(
                                    Some(containing_scope)).finalize(cx)
         }
         ty::Generator(def_id, substs,  _) => {
-            let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| {
-                cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
-            }).collect();
+            let upvar_tys : Vec<_> = substs
+                .as_generator().prefix_tys(def_id, cx.tcx).map(|t| {
+                    cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
+                }).collect();
             prepare_enum_metadata(cx,
                                   t,
                                   def_id,
@@ -960,9 +961,9 @@ pub fn compile_unit_metadata(
             file_metadata,
             producer.as_ptr(),
             tcx.sess.opts.optimize != config::OptLevel::No,
-            flags.as_ptr() as *const _,
+            flags.as_ptr().cast(),
             0,
-            split_name.as_ptr() as *const _,
+            split_name.as_ptr().cast(),
             kind);
 
         if tcx.sess.opts.debugging_opts.profile {
@@ -991,7 +992,7 @@ pub fn compile_unit_metadata(
         if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
             let name_metadata = llvm::LLVMMDStringInContext(
                 debug_context.llcontext,
-                rustc_producer.as_ptr() as *const _,
+                rustc_producer.as_ptr().cast(),
                 rustc_producer.as_bytes().len() as c_uint,
             );
             llvm::LLVMAddNamedMetadataOperand(
@@ -1338,7 +1339,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
                 ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
                 ty::Generator(def_id, substs, _) => {
                     let generator_layout = cx.tcx.generator_layout(*def_id);
-                    VariantInfo::Generator(*substs, generator_layout, index)
+                    VariantInfo::Generator(substs, generator_layout, index)
                 }
                 _ => bug!(),
             }
@@ -1611,7 +1612,7 @@ enum EnumDiscriminantInfo<'ll> {
 #[derive(Copy, Clone)]
 enum VariantInfo<'tcx> {
     Adt(&'tcx ty::VariantDef),
-    Generator(ty::GeneratorSubsts<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx),
+    Generator(SubstsRef<'tcx>, &'tcx GeneratorLayout<'tcx>, VariantIdx),
 }
 
 impl<'tcx> VariantInfo<'tcx> {
@@ -1619,7 +1620,7 @@ fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
         match self {
             VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
             VariantInfo::Generator(substs, _, variant_index) =>
-                f(&substs.variant_name(*variant_index)),
+                f(&substs.as_generator().variant_name(*variant_index)),
         }
     }
 
@@ -1763,9 +1764,10 @@ fn prepare_enum_metadata(
                 })
                 .collect(),
             ty::Generator(_, substs, _) => substs
+                .as_generator()
                 .variant_range(enum_def_id, cx.tcx)
                 .map(|variant_index| {
-                    let name = SmallCStr::new(&substs.variant_name(variant_index));
+                    let name = SmallCStr::new(&substs.as_generator().variant_name(variant_index));
                     unsafe {
                         Some(llvm::LLVMRustDIBuilderCreateEnumerator(
                             DIB(cx),
index e0e0cd5f739e2718474d2b2828948cf8a2157901..6e4ed42c45e9792ad2e019c8a0d50457310b34b2 100644 (file)
@@ -127,20 +127,20 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         if cx.sess().target.target.options.is_like_osx ||
            cx.sess().target.target.options.is_like_android {
             llvm::LLVMRustAddModuleFlag(cx.llmod,
-                                        "Dwarf Version\0".as_ptr() as *const _,
+                                        "Dwarf Version\0".as_ptr().cast(),
                                         2)
         }
 
         // Indicate that we want CodeView debug information on MSVC
         if cx.sess().target.target.options.is_like_msvc {
             llvm::LLVMRustAddModuleFlag(cx.llmod,
-                                        "CodeView\0".as_ptr() as *const _,
+                                        "CodeView\0".as_ptr().cast(),
                                         1)
         }
 
         // Prevent bitcode readers from deleting the debug info.
         let ptr = "Debug Info Version\0".as_ptr();
-        llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _,
+        llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(),
                                     llvm::LLVMRustDebugMetadataVersion());
     };
 }
index 2dce9b04c9e9eecff196da53b671ee368322f8fc..541d3d98b79bda83cbc591d2273b8f48a32b6a81 100644 (file)
@@ -257,7 +257,8 @@ pub fn target_feature_whitelist(sess: &Session)
         "hexagon" => HEXAGON_WHITELIST,
         "mips" | "mips64" => MIPS_WHITELIST,
         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
-        "wasm32" => WASM_WHITELIST,
+        // wasm32 on emscripten does not support these target features
+        "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
         _ => &[],
     }
 }
index 81a99bc5019b3ece4fd7bfe9873132b84dd35f15..d921bbc96adeebeedcab5dfbeab0530ede3ee620 100644 (file)
@@ -65,7 +65,7 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             if let (&ty::Generator(_, substs, _), &layout::Variants::Single { index })
                  = (&layout.ty.kind, &layout.variants)
             {
-                write!(&mut name, "::{}", substs.variant_name(index)).unwrap();
+                write!(&mut name, "::{}", substs.as_generator().variant_name(index)).unwrap();
             }
             Some(name)
         }
index 3b7ae5e33d5e716e7d869d790617fa83a1ac969c..1c5d3b1a890ee76dfcfcd60966208b55aeed3bfe 100644 (file)
@@ -323,6 +323,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
             NativeLibraryKind::NativeStatic => {}
             NativeLibraryKind::NativeStaticNobundle |
             NativeLibraryKind::NativeFramework |
+            NativeLibraryKind::NativeRawDylib |
             NativeLibraryKind::NativeUnknown => continue,
         }
         if let Some(name) = lib.name {
@@ -883,7 +884,8 @@ pub fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary
                     Some(format!("-framework {}", name))
                 },
                 // These are included, no need to print them
-                NativeLibraryKind::NativeStatic => None,
+                NativeLibraryKind::NativeStatic |
+                NativeLibraryKind::NativeRawDylib => None,
             }
         })
         .collect();
@@ -1293,7 +1295,11 @@ pub fn add_local_native_libraries(cmd: &mut dyn Linker,
             NativeLibraryKind::NativeUnknown => cmd.link_dylib(name),
             NativeLibraryKind::NativeFramework => cmd.link_framework(name),
             NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(name),
-            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path)
+            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path),
+            NativeLibraryKind::NativeRawDylib => {
+                // FIXME(#58713): Proper handling for raw dylibs.
+                bug!("raw_dylib feature not yet implemented");
+            },
         }
     }
 }
@@ -1385,7 +1391,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
                 add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
             }
-            _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => {
+            _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) &&
+                  crate_type == config::CrateType::Executable => {
+                // Link the sanitizer runtimes only if we are actually producing an executable
                 link_sanitizer_runtime::<B>(cmd, sess, codegen_results, tmpdir, cnum);
             }
             // compiler-builtins are always placed last to ensure that they're
@@ -1527,7 +1535,7 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker,
         let name = cratepath.file_name().unwrap().to_str().unwrap();
         let name = &name[3..name.len() - 5]; // chop off lib/.rlib
 
-        time_ext(sess.time_extended(), Some(sess), &format!("altering {}.rlib", name), || {
+        time_ext(sess.time_extended(), &format!("altering {}.rlib", name), || {
             let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
             archive.update_symbols();
 
@@ -1678,7 +1686,11 @@ pub fn add_upstream_native_libraries(
                 // ignore statically included native libraries here as we've
                 // already included them when we included the rust library
                 // previously
-                NativeLibraryKind::NativeStatic => {}
+                NativeLibraryKind::NativeStatic => {},
+                NativeLibraryKind::NativeRawDylib => {
+                    // FIXME(#58713): Proper handling for raw dylibs.
+                    bug!("raw_dylib feature not yet implemented");
+                },
             }
         }
     }
index caaa500766d014a1f7c755e016bbc538decfa294..481db26e1a84d09cdcf3686d528b36880c6572f1 100644 (file)
@@ -142,12 +142,15 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
         // Copy what clang does by turning on loop vectorization at O2 and
         // slp vectorization at O3. Otherwise configure other optimization aspects
         // of this pass manager builder.
+        // Turn off vectorization for emscripten, as it's not very well supported.
         self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
                              (sess.opts.optimize == config::OptLevel::Default ||
-                              sess.opts.optimize == config::OptLevel::Aggressive);
+                              sess.opts.optimize == config::OptLevel::Aggressive) &&
+                             !sess.target.target.options.is_like_emscripten;
 
         self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
-                            sess.opts.optimize == config::OptLevel::Aggressive;
+                            sess.opts.optimize == config::OptLevel::Aggressive &&
+                            !sess.target.target.options.is_like_emscripten;
 
         // Some targets (namely, NVPTX) interact badly with the MergeFunctions
         // pass. This is because MergeFunctions can generate new function calls
@@ -321,8 +324,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let (coordinator_send, coordinator_receive) = channel();
     let sess = tcx.sess;
 
-    sess.prof.generic_activity_start("codegen_and_optimize_crate");
-
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
     let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins);
@@ -1774,8 +1775,6 @@ pub fn join(
             self.backend.print_pass_timings()
         }
 
-        sess.prof.generic_activity_end("codegen_and_optimize_crate");
-
         (CodegenResults {
             crate_name: self.crate_name,
             crate_hash: self.crate_hash,
index 5787447d6230fc2aa100f72ff363a9afb7d05577..9d2f8b42c704f0d193d82e6e23c788498ac24056 100644 (file)
@@ -636,7 +636,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                         ty::Generator(def_id, substs, _) => (def_id, substs),
                         _ => bug!("generator layout without generator substs"),
                     };
-                    let state_tys = gen_substs.state_tys(def_id, tcx);
+                    let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);
 
                     generator_layout.variant_fields.iter()
                         .zip(state_tys)
index 5bcb3b4ceb3ba33f06d3bc0331e52fad0fe4e3a8..cf575c54293c76ab690f86c98783088b5c42e189 100644 (file)
@@ -225,7 +225,7 @@ fn print_type(
             ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
             ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
             ty::Closure(def_id, substs) |
-            ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+            ty::Generator(def_id, substs, _) => {
                 self.print_def_path(def_id, substs)
             }
             _ => self.pretty_print_type(ty),
index 2ad699d7c6f08808ab46a3f060940556ca5e1d95..55b148fceb2177393101b9524258e9d8da68b64c 100644 (file)
@@ -415,7 +415,7 @@ fn print_type(
             ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
             ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
             ty::Closure(def_id, substs) |
-            ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+            ty::Generator(def_id, substs, _) => {
                 self = self.print_def_path(def_id, substs)?;
             }
             ty::Foreign(def_id) => {
index e020f2f8da940e19d4a27c8b93e473eb77734702..065c8436ae06aa54fc5c19e9e727e94cf7873177 100644 (file)
@@ -20,8 +20,8 @@ graphviz = { path = "../libgraphviz" }
 cfg-if = "0.1.2"
 crossbeam-utils = { version = "0.6.5", features = ["nightly"] }
 stable_deref_trait = "1.0.0"
-rayon = { version = "0.2.0", package = "rustc-rayon" }
-rayon-core = { version = "0.2.0", package = "rustc-rayon-core" }
+rayon = { version = "0.3.0", package = "rustc-rayon" }
+rayon-core = { version = "0.3.0", package = "rustc-rayon-core" }
 rustc-hash = "1.0.1"
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 rustc_index = { path = "../librustc_index", package = "rustc_index" }
index 3f1b91256c46811c5d3e7653155395ff80c966ef..fd74d8673da4dbc482430bd764caccf5d61a0dd6 100644 (file)
@@ -298,9 +298,31 @@ pub fn tool_only_multipart_suggestion(
     /// * may contain a name of a function, variable, or type, but not whole expressions
     ///
     /// See `CodeSuggestion` for more information.
-    pub fn span_suggestion(&mut self, sp: Span, msg: &str,
-                                       suggestion: String,
-                                       applicability: Applicability) -> &mut Self {
+    pub fn span_suggestion(
+        &mut self,
+        sp: Span,
+        msg: &str,
+        suggestion: String,
+        applicability: Applicability,
+    ) -> &mut Self {
+        self.span_suggestion_with_style(
+            sp,
+            msg,
+            suggestion,
+            applicability,
+            SuggestionStyle::ShowCode,
+        );
+        self
+    }
+
+    pub fn span_suggestion_with_style(
+        &mut self,
+        sp: Span,
+        msg: &str,
+        suggestion: String,
+        applicability: Applicability,
+        style: SuggestionStyle,
+    ) -> &mut Self {
         self.suggestions.push(CodeSuggestion {
             substitutions: vec![Substitution {
                 parts: vec![SubstitutionPart {
@@ -309,16 +331,37 @@ pub fn span_suggestion(&mut self, sp: Span, msg: &str,
                 }],
             }],
             msg: msg.to_owned(),
-            style: SuggestionStyle::ShowCode,
+            style,
             applicability,
         });
         self
     }
 
+    pub fn span_suggestion_verbose(
+        &mut self,
+        sp: Span,
+        msg: &str,
+        suggestion: String,
+        applicability: Applicability,
+    ) -> &mut Self {
+        self.span_suggestion_with_style(
+            sp,
+            msg,
+            suggestion,
+            applicability,
+            SuggestionStyle::ShowAlways,
+        );
+        self
+    }
+
     /// Prints out a message with multiple suggested edits of the code.
-    pub fn span_suggestions(&mut self, sp: Span, msg: &str,
-        suggestions: impl Iterator<Item = String>, applicability: Applicability) -> &mut Self
-    {
+    pub fn span_suggestions(
+        &mut self,
+        sp: Span,
+        msg: &str,
+        suggestions: impl Iterator<Item = String>,
+        applicability: Applicability,
+    ) -> &mut Self {
         self.suggestions.push(CodeSuggestion {
             substitutions: suggestions.map(|snippet| Substitution {
                 parts: vec![SubstitutionPart {
@@ -340,17 +383,13 @@ pub fn span_suggestions(&mut self, sp: Span, msg: &str,
     pub fn span_suggestion_short(
         &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
     ) -> &mut Self {
-        self.suggestions.push(CodeSuggestion {
-            substitutions: vec![Substitution {
-                parts: vec![SubstitutionPart {
-                    snippet: suggestion,
-                    span: sp,
-                }],
-            }],
-            msg: msg.to_owned(),
-            style: SuggestionStyle::HideCodeInline,
+        self.span_suggestion_with_style(
+            sp,
+            msg,
+            suggestion,
             applicability,
-        });
+            SuggestionStyle::HideCodeInline,
+        );
         self
     }
 
@@ -363,17 +402,13 @@ pub fn span_suggestion_short(
     pub fn span_suggestion_hidden(
         &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
     ) -> &mut Self {
-        self.suggestions.push(CodeSuggestion {
-            substitutions: vec![Substitution {
-                parts: vec![SubstitutionPart {
-                    snippet: suggestion,
-                    span: sp,
-                }],
-            }],
-            msg: msg.to_owned(),
-            style: SuggestionStyle::HideCodeAlways,
+        self.span_suggestion_with_style(
+            sp,
+            msg,
+            suggestion,
             applicability,
-        });
+            SuggestionStyle::HideCodeAlways,
+        );
         self
     }
 
@@ -384,17 +419,13 @@ pub fn span_suggestion_hidden(
     pub fn tool_only_span_suggestion(
         &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
     ) -> &mut Self {
-        self.suggestions.push(CodeSuggestion {
-            substitutions: vec![Substitution {
-                parts: vec![SubstitutionPart {
-                    snippet: suggestion,
-                    span: sp,
-                }],
-            }],
-            msg: msg.to_owned(),
-            style: SuggestionStyle::CompletelyHidden,
+        self.span_suggestion_with_style(
+            sp,
+            msg,
+            suggestion,
             applicability,
-        });
+            SuggestionStyle::CompletelyHidden,
+        );
         self
     }
 
index 9aea46da68b1a340631b88c6807754463f46f697..68f933363daa1e85a87b6ca68cbdddea1bb7a1bf 100644 (file)
@@ -218,10 +218,14 @@ fn primary_span_formatted<'a>(
                sugg.msg.split_whitespace().count() < 10 &&
                // don't display multiline suggestions as labels
                !sugg.substitutions[0].parts[0].snippet.contains('\n') &&
-               // when this style is set we want the suggestion to be a message, not inline
-               sugg.style != SuggestionStyle::HideCodeAlways &&
-               // trivial suggestion for tooling's sake, never shown
-               sugg.style != SuggestionStyle::CompletelyHidden
+               ![
+                    // when this style is set we want the suggestion to be a message, not inline
+                    SuggestionStyle::HideCodeAlways,
+                    // trivial suggestion for tooling's sake, never shown
+                    SuggestionStyle::CompletelyHidden,
+                    // subtle suggestion, never shown inline
+                    SuggestionStyle::ShowAlways,
+               ].contains(&sugg.style)
             {
                 let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
                 let msg = if substitution.len() == 0 || sugg.style.hide_inline() {
index f9dc13ce97eea79c6fed0db0a275736922038518..2fae584c153621a8eb891575b8a13295419d07ab 100644 (file)
@@ -81,6 +81,8 @@ pub enum SuggestionStyle {
     /// This will *not* show the code if the suggestion is inline *and* the suggested code is
     /// empty.
     ShowCode,
+    /// Always show the suggested code independently.
+    ShowAlways,
 }
 
 impl SuggestionStyle {
index 6e03618d2b0b5f24b6d2296d5e9f60317284aaff..b12ab9e4576025c8efb7d17777df90fe7e94458b 100644 (file)
@@ -111,7 +111,7 @@ pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
 
     pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
         self.ensure_lines(line);
-        let string_len = string.len();
+        let string_len = string.chars().count();
 
         // Push the old content over to make room for new content
         for _ in 0..string_len {
index 90aefb0f32416f8bf56358ba695fb78df55ddb41..673da52c3250e62f0f27552a00952688f43f68a3 100644 (file)
@@ -101,6 +101,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     // before we fire the background thread.
 
     let time_passes = sess.time_passes();
+    let prof = sess.prof.clone();
 
     if sess.opts.incremental.is_none() {
         // No incremental compilation.
@@ -160,7 +161,9 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     }
 
     MaybeAsync::Async(std::thread::spawn(move || {
-        time_ext(time_passes, None, "background load prev dep-graph", move || {
+        time_ext(time_passes, "background load prev dep-graph", move || {
+            let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
+
             match load_data(report_incremental_info, &path) {
                 LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
                 LoadResult::Error { message } => LoadResult::Error { message },
@@ -198,6 +201,8 @@ pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> {
         return OnDiskCache::new_empty(sess.source_map());
     }
 
+    let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
+
     match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
         LoadResult::Ok{ data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
         _ => OnDiskCache::new_empty(sess.source_map())
index 6af065513ee0dccf9f6f00343ea1a491bb335bb5..f5935c9969baa04b367cb654e4d1b2b524c5a63f 100644 (file)
@@ -241,6 +241,8 @@ fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduc
 
 fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
     time(tcx.sess, "serialize query result cache", || {
+        let _timer = tcx.prof.generic_activity("incr_comp_serialize_result_cache");
+
         tcx.serialize_query_result_cache(encoder).unwrap();
     })
 }
index 780f7a7ffa9edee38e6de8ec5a4084f3b72977ed..bed5febb72ede4421f20f27f589da22fdb0ed39a 100644 (file)
@@ -11,7 +11,7 @@ doctest = false
 
 [dependencies]
 log = "0.4"
-rayon = { version = "0.2.0", package = "rustc-rayon" }
+rayon = { version = "0.3.0", package = "rustc-rayon" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
index dae8fb242d58cd69cada05ce9ed638480bcfd3d7..b26bd75c974c6b67edae5cdc985ab475cf77d484 100644 (file)
@@ -1,6 +1,5 @@
 use crate::queries::Queries;
 use crate::util;
-use crate::profile;
 pub use crate::passes::BoxedResolver;
 
 use rustc::lint;
@@ -115,17 +114,7 @@ pub fn run_compiler_in_existing_thread_pool<F, R>(config: Config, f: F) -> R
         compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry());
     });
 
-    if compiler.sess.profile_queries() {
-        profile::begin(&compiler.sess);
-    }
-
-    let r = f(&compiler);
-
-    if compiler.sess.profile_queries() {
-        profile::dump(&compiler.sess, "profile_queries".to_string())
-    }
-
-    r
+    f(&compiler)
 }
 
 pub fn run_compiler<F, R>(mut config: Config, f: F) -> R
index 2e593d441553a014c28a85bafb16e1b033e272f4..6be36e9b9001b80d608950547b3b07a7f7b865ad 100644 (file)
@@ -16,6 +16,5 @@
 mod queries;
 pub mod util;
 mod proc_macro_decls;
-mod profile;
 
 pub use interface::{run_compiler, Config};
index bf5e86017fc7b6e7d311fef436b12a7b04466c9a..a1dc5b01aba8ce2021c75927536f4214b8bb04da 100644 (file)
@@ -250,6 +250,8 @@ pub fn register_plugins<'a>(
 
     if sess.opts.incremental.is_some() {
         time(sess, "garbage-collect incremental cache directory", || {
+            let _prof_timer =
+                sess.prof.generic_activity("incr_comp_garbage_collect_session_directories");
             if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
                 warn!(
                     "Error while trying to garbage collect incremental \
@@ -780,13 +782,10 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     ty::provide(providers);
     traits::provide(providers);
     stability::provide(providers);
-    middle::intrinsicck::provide(providers);
-    middle::liveness::provide(providers);
     reachable::provide(providers);
     rustc_passes::provide(providers);
     rustc_traits::provide(providers);
     middle::region::provide(providers);
-    middle::entry::provide(providers);
     cstore::provide(providers);
     lint::provide(providers);
     rustc_lint::provide(providers);
@@ -892,7 +891,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
     time(sess, "misc checking 1", || {
         parallel!({
             entry_point = time(sess, "looking for entry point", || {
-                middle::entry::find_entry_point(tcx)
+                rustc_passes::entry::find_entry_point(tcx)
             });
 
             time(sess, "looking for plugin registrar", || {
@@ -973,7 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
                     tcx.ensure().check_private_in_public(LOCAL_CRATE);
                 });
             }, {
-                time(sess, "death checking", || middle::dead::check_crate(tcx));
+                time(sess, "death checking", || rustc_passes::dead::check_crate(tcx));
             },  {
                 time(sess, "unused lib feature checking", || {
                     stability::check_unused_or_stable_features(tcx)
diff --git a/src/librustc_interface/profile/mod.rs b/src/librustc_interface/profile/mod.rs
deleted file mode 100644 (file)
index 2e71d46..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-use log::debug;
-use rustc::dep_graph::DepNode;
-use rustc::session::Session;
-use rustc::util::common::{ProfQDumpParams, ProfileQueriesMsg, profq_msg, profq_set_chan};
-use std::sync::mpsc::{Receiver};
-use std::io::{Write};
-use std::time::{Duration, Instant};
-
-pub mod trace;
-
-/// begin a profile thread, if not already running
-pub fn begin(sess: &Session) {
-    use std::thread;
-    use std::sync::mpsc::{channel};
-    let (tx, rx) = channel();
-    if profq_set_chan(sess, tx) {
-        thread::spawn(move || profile_queries_thread(rx));
-    }
-}
-
-/// dump files with profiling information to the given base path, and
-/// wait for this dump to complete.
-///
-/// wraps the RPC (send/recv channel logic) of requesting a dump.
-pub fn dump(sess: &Session, path: String) {
-    use std::sync::mpsc::{channel};
-    let (tx, rx) = channel();
-    let params = ProfQDumpParams {
-        path,
-        ack: tx,
-        // FIXME: Add another compiler flag to toggle whether this log
-        // is written; false for now
-        dump_profq_msg_log: true,
-    };
-    profq_msg(sess, ProfileQueriesMsg::Dump(params));
-    let _ = rx.recv().unwrap();
-}
-
-// State for parsing recursive trace structure in separate thread, via messages
-#[derive(Clone, Eq, PartialEq)]
-enum ParseState {
-    // No (local) parse state; may be parsing a tree, focused on a
-    // sub-tree that could be anything.
-    Clear,
-    // Have Query information from the last message
-    HaveQuery(trace::Query, Instant),
-    // Have "time-begin" information from the last message (doit flag, and message)
-    HaveTimeBegin(String, Instant),
-    // Have "task-begin" information from the last message
-    HaveTaskBegin(DepNode, Instant),
-}
-struct StackFrame {
-    pub parse_st: ParseState,
-    pub traces:   Vec<trace::Rec>,
-}
-
-fn total_duration(traces: &[trace::Rec]) -> Duration {
-    Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum()
-}
-
-// profiling thread; retains state (in local variables) and dump traces, upon request.
-fn profile_queries_thread(r: Receiver<ProfileQueriesMsg>) {
-    use self::trace::*;
-    use std::fs::File;
-
-    let mut profq_msgs: Vec<ProfileQueriesMsg> = vec![];
-    let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] };
-    let mut stack: Vec<StackFrame> = vec![];
-    loop {
-        let msg = r.recv();
-        if let Err(_recv_err) = msg {
-            // FIXME: Perhaps do something smarter than simply quitting?
-            break
-        };
-        let msg = msg.unwrap();
-        debug!("profile_queries_thread: {:?}", msg);
-
-        // Meta-level versus _actual_ queries messages
-        match msg {
-            ProfileQueriesMsg::Halt => return,
-            ProfileQueriesMsg::Dump(params) => {
-                assert!(stack.is_empty());
-                assert!(frame.parse_st == ParseState::Clear);
-
-                // write log of all messages
-                if params.dump_profq_msg_log {
-                    let mut log_file =
-                        File::create(format!("{}.log.txt", params.path)).unwrap();
-                    for m in profq_msgs.iter() {
-                        writeln!(&mut log_file, "{:?}", m).unwrap()
-                    };
-                }
-
-                // write HTML file, and counts file
-                let html_path = format!("{}.html", params.path);
-                let mut html_file = File::create(&html_path).unwrap();
-
-                let counts_path = format!("{}.counts.txt", params.path);
-                let mut counts_file = File::create(&counts_path).unwrap();
-
-                writeln!(html_file,
-                    "<html>\n<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">",
-                    "profile_queries.css").unwrap();
-                writeln!(html_file, "<style>").unwrap();
-                trace::write_style(&mut html_file);
-                writeln!(html_file, "</style>\n</head>\n<body>").unwrap();
-                trace::write_traces(&mut html_file, &mut counts_file, &frame.traces);
-                writeln!(html_file, "</body>\n</html>").unwrap();
-
-                let ack_path = format!("{}.ack", params.path);
-                let ack_file = File::create(&ack_path).unwrap();
-                drop(ack_file);
-
-                // Tell main thread that we are done, e.g., so it can exit
-                params.ack.send(()).unwrap();
-            }
-            // Actual query message:
-            msg => {
-                // Record msg in our log
-                profq_msgs.push(msg.clone());
-                // Respond to the message, knowing that we've already handled Halt and Dump, above.
-                match (frame.parse_st.clone(), msg) {
-                    (_, ProfileQueriesMsg::Halt) | (_, ProfileQueriesMsg::Dump(_)) => {
-                        unreachable!();
-                    },
-                    // Parse State: Clear
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::QueryBegin(span, querymsg)) => {
-                        let start = Instant::now();
-                        frame.parse_st = ParseState::HaveQuery
-                            (Query { span, msg: querymsg }, start)
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::CacheHit) => {
-                        panic!("parse error: unexpected CacheHit; expected QueryBegin")
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::ProviderBegin) => {
-                        panic!("parse error: expected QueryBegin before beginning a provider")
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::ProviderEnd) => {
-                        let provider_extent = frame.traces;
-                        match stack.pop() {
-                            None =>
-                                panic!("parse error: expected a stack frame; found an empty stack"),
-                            Some(old_frame) => {
-                                match old_frame.parse_st {
-                                    ParseState::HaveQuery(q, start) => {
-                                        let duration = start.elapsed();
-                                        frame = StackFrame{
-                                            parse_st: ParseState::Clear,
-                                            traces: old_frame.traces
-                                        };
-                                        let dur_extent = total_duration(&provider_extent);
-                                        let trace = Rec {
-                                            effect: Effect::QueryBegin(q, CacheCase::Miss),
-                                            extent: Box::new(provider_extent),
-                                            start: start,
-                                            dur_self: duration - dur_extent,
-                                            dur_total: duration,
-                                        };
-                                        frame.traces.push( trace );
-                                    },
-                                    _ => panic!("internal parse error: malformed parse stack")
-                                }
-                            }
-                        }
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::TimeBegin(msg)) => {
-                        let start = Instant::now();
-                        frame.parse_st = ParseState::HaveTimeBegin(msg, start);
-                        stack.push(frame);
-                        frame = StackFrame{parse_st: ParseState::Clear, traces: vec![]};
-                    },
-                    (_, ProfileQueriesMsg::TimeBegin(_)) => {
-                        panic!("parse error; did not expect time begin here");
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::TimeEnd) => {
-                        let provider_extent = frame.traces;
-                        match stack.pop() {
-                            None =>
-                                panic!("parse error: expected a stack frame; found an empty stack"),
-                            Some(old_frame) => {
-                                match old_frame.parse_st {
-                                    ParseState::HaveTimeBegin(msg, start) => {
-                                        let duration = start.elapsed();
-                                        frame = StackFrame{
-                                            parse_st: ParseState::Clear,
-                                            traces: old_frame.traces
-                                        };
-                                        let dur_extent = total_duration(&provider_extent);
-                                        let trace = Rec {
-                                            effect: Effect::TimeBegin(msg),
-                                            extent: Box::new(provider_extent),
-                                            start: start,
-                                            dur_total: duration,
-                                            dur_self: duration - dur_extent,
-                                        };
-                                        frame.traces.push( trace );
-                                    },
-                                    _ => panic!("internal parse error: malformed parse stack")
-                                }
-                            }
-                        }
-                    },
-                    (_, ProfileQueriesMsg::TimeEnd) => {
-                        panic!("parse error")
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::TaskBegin(key)) => {
-                        let start = Instant::now();
-                        frame.parse_st = ParseState::HaveTaskBegin(key, start);
-                        stack.push(frame);
-                        frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] };
-                    },
-                    (_, ProfileQueriesMsg::TaskBegin(_)) => {
-                        panic!("parse error; did not expect time begin here");
-                    },
-                    (ParseState::Clear,
-                     ProfileQueriesMsg::TaskEnd) => {
-                        let provider_extent = frame.traces;
-                        match stack.pop() {
-                            None =>
-                                panic!("parse error: expected a stack frame; found an empty stack"),
-                            Some(old_frame) => {
-                                match old_frame.parse_st {
-                                    ParseState::HaveTaskBegin(key, start) => {
-                                        let duration = start.elapsed();
-                                        frame = StackFrame{
-                                            parse_st: ParseState::Clear,
-                                            traces: old_frame.traces
-                                        };
-                                        let dur_extent = total_duration(&provider_extent);
-                                        let trace = Rec {
-                                            effect: Effect::TaskBegin(key),
-                                            extent: Box::new(provider_extent),
-                                            start: start,
-                                            dur_total: duration,
-                                            dur_self: duration - dur_extent,
-                                        };
-                                        frame.traces.push( trace );
-                                    },
-                                    _ => panic!("internal parse error: malformed parse stack")
-                                }
-                            }
-                        }
-                    },
-                    (_, ProfileQueriesMsg::TaskEnd) => {
-                        panic!("parse error")
-                    },
-                    // Parse State: HaveQuery
-                    (ParseState::HaveQuery(q,start),
-                     ProfileQueriesMsg::CacheHit) => {
-                        let duration = start.elapsed();
-                        let trace : Rec = Rec{
-                            effect: Effect::QueryBegin(q, CacheCase::Hit),
-                            extent: Box::new(vec![]),
-                            start: start,
-                            dur_self: duration,
-                            dur_total: duration,
-                        };
-                        frame.traces.push( trace );
-                        frame.parse_st = ParseState::Clear;
-                    },
-                    (ParseState::HaveQuery(_, _),
-                     ProfileQueriesMsg::ProviderBegin) => {
-                        stack.push(frame);
-                        frame = StackFrame{ parse_st: ParseState::Clear, traces: vec![] };
-                    },
-
-                    // Parse errors:
-
-                    (ParseState::HaveQuery(q, _),
-                     ProfileQueriesMsg::ProviderEnd) => {
-                        panic!("parse error: unexpected ProviderEnd; \
-                                expected something else to follow BeginQuery for {:?}", q)
-                    },
-                    (ParseState::HaveQuery(q1, _),
-                     ProfileQueriesMsg::QueryBegin(span2, querymsg2)) => {
-                        panic!("parse error: unexpected QueryBegin; \
-                                earlier query is unfinished: {:?} and now {:?}",
-                               q1, Query{span:span2, msg: querymsg2})
-                    },
-                    (ParseState::HaveTimeBegin(_, _), _) => {
-                        unreachable!()
-                    },
-                    (ParseState::HaveTaskBegin(_, _), _) => {
-                        unreachable!()
-                    },
-                }
-            }
-        }
-    }
-}
diff --git a/src/librustc_interface/profile/trace.rs b/src/librustc_interface/profile/trace.rs
deleted file mode 100644 (file)
index 95c4ea6..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-use super::*;
-use syntax_pos::SpanData;
-use rustc_data_structures::fx::FxHashMap;
-use rustc::util::common::QueryMsg;
-use std::fs::File;
-use std::time::{Duration, Instant};
-use rustc::dep_graph::{DepNode};
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Query {
-    pub span: SpanData,
-    pub msg: QueryMsg,
-}
-pub enum Effect {
-    QueryBegin(Query, CacheCase),
-    TimeBegin(String),
-    TaskBegin(DepNode),
-}
-pub enum CacheCase {
-    Hit, Miss
-}
-/// Recursive trace structure
-pub struct Rec {
-    pub effect: Effect,
-    pub start: Instant,
-    pub dur_self: Duration,
-    pub dur_total: Duration,
-    pub extent: Box<Vec<Rec>>,
-}
-pub struct QueryMetric {
-    pub count: usize,
-    pub dur_self: Duration,
-    pub dur_total: Duration,
-}
-
-fn cons(s: &str) -> String {
-    let first = s.split(|d| d == '(' || d == '{').next();
-    assert!(first.is_some() && first != Some(""));
-    first.unwrap().to_owned()
-}
-
-pub fn cons_of_query_msg(q: &trace::Query) -> String {
-    cons(&format!("{:?}", q.msg))
-}
-
-pub fn cons_of_key(k: &DepNode) -> String {
-    cons(&format!("{:?}", k))
-}
-
-// First return value is text; second return value is a CSS class
-pub fn html_of_effect(eff: &Effect) -> (String, String) {
-    match *eff {
-        Effect::TimeBegin(ref msg) => {
-            (msg.clone(),
-             "time-begin".to_string())
-        },
-        Effect::TaskBegin(ref key) => {
-            let cons = cons_of_key(key);
-            (cons.clone(), format!("{} task-begin", cons))
-        },
-        Effect::QueryBegin(ref qmsg, ref cc) => {
-            let cons = cons_of_query_msg(qmsg);
-            (cons.clone(),
-             format!("{} {}",
-                     cons,
-                     match *cc {
-                         CacheCase::Hit => "hit",
-                         CacheCase::Miss => "miss",
-                     }))
-        }
-    }
-}
-
-// First return value is text; second return value is a CSS class
-fn html_of_duration(_start: &Instant, dur: &Duration) -> (String, String) {
-    use rustc::util::common::duration_to_secs_str;
-    (duration_to_secs_str(dur.clone()), String::new())
-}
-
-fn html_of_fraction(frac: f64) -> (String, &'static str) {
-    let css = {
-        if       frac > 0.50  { "frac-50" }
-        else if  frac > 0.40  { "frac-40" }
-        else if  frac > 0.30  { "frac-30" }
-        else if  frac > 0.20  { "frac-20" }
-        else if  frac > 0.10  { "frac-10" }
-        else if  frac > 0.05  { "frac-05" }
-        else if  frac > 0.02  { "frac-02" }
-        else if  frac > 0.01  { "frac-01" }
-        else if  frac > 0.001 { "frac-001" }
-        else                  { "frac-0" }
-    };
-    let percent = frac * 100.0;
-
-    if percent > 0.1 {
-        (format!("{:.1}%", percent), css)
-    } else {
-        ("< 0.1%".to_string(), css)
-    }
-}
-
-fn total_duration(traces: &[Rec]) -> Duration {
-    Duration::new(0, 0) + traces.iter().map(|t| t.dur_total).sum()
-}
-
-fn duration_div(nom: Duration, den: Duration) -> f64 {
-    fn to_nanos(d: Duration) -> u64 {
-        d.as_secs() * 1_000_000_000 + d.subsec_nanos() as u64
-    }
-
-    to_nanos(nom) as f64 / to_nanos(den) as f64
-}
-
-fn write_traces_rec(file: &mut File, traces: &[Rec], total: Duration, depth: usize) {
-    for t in traces {
-        let (eff_text, eff_css_classes) = html_of_effect(&t.effect);
-        let (dur_text, dur_css_classes) = html_of_duration(&t.start, &t.dur_total);
-        let fraction = duration_div(t.dur_total, total);
-        let percent = fraction * 100.0;
-        let (frc_text, frc_css_classes) = html_of_fraction(fraction);
-        writeln!(file, "<div class=\"trace depth-{} extent-{}{} {} {} {}\">",
-                 depth,
-                 t.extent.len(),
-                 /* Heuristic for 'important' CSS class: */
-                 if t.extent.len() > 5 || percent >= 1.0 { " important" } else { "" },
-                 eff_css_classes,
-                 dur_css_classes,
-                 frc_css_classes,
-        ).unwrap();
-        writeln!(file, "<div class=\"eff\">{}</div>", eff_text).unwrap();
-        writeln!(file, "<div class=\"dur\">{}</div>", dur_text).unwrap();
-        writeln!(file, "<div class=\"frc\">{}</div>", frc_text).unwrap();
-        write_traces_rec(file, &t.extent, total, depth + 1);
-        writeln!(file, "</div>").unwrap();
-    }
-}
-
-fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]) {
-    counts.reserve(traces.len());
-    for t in traces.iter() {
-        match t.effect {
-            Effect::TimeBegin(ref msg) => {
-                let qm = match counts.get(msg) {
-                    Some(_qm) => panic!("TimeBegin with non-unique, repeat message"),
-                    None => QueryMetric {
-                        count: 1,
-                        dur_self: t.dur_self,
-                        dur_total: t.dur_total,
-                    }
-                };
-                counts.insert(msg.clone(), qm);
-            },
-            Effect::TaskBegin(ref key) => {
-                let cons = cons_of_key(key);
-                let qm = match counts.get(&cons) {
-                    Some(qm) =>
-                        QueryMetric {
-                            count: qm.count + 1,
-                            dur_self: qm.dur_self + t.dur_self,
-                            dur_total: qm.dur_total + t.dur_total,
-                        },
-                    None => QueryMetric {
-                        count: 1,
-                        dur_self: t.dur_self,
-                        dur_total: t.dur_total,
-                    }
-                };
-                counts.insert(cons, qm);
-            },
-            Effect::QueryBegin(ref qmsg, ref _cc) => {
-                let qcons = cons_of_query_msg(qmsg);
-                let qm = match counts.get(&qcons) {
-                    Some(qm) =>
-                        QueryMetric {
-                            count: qm.count + 1,
-                            dur_total: qm.dur_total + t.dur_total,
-                            dur_self: qm.dur_self + t.dur_self
-                        },
-                    None => QueryMetric {
-                        count: 1,
-                        dur_total: t.dur_total,
-                        dur_self: t.dur_self,
-                    }
-                };
-                counts.insert(qcons, qm);
-            }
-        }
-        compute_counts_rec(counts, &t.extent)
-    }
-}
-
-pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap<String, QueryMetric>) {
-    use rustc::util::common::duration_to_secs_str;
-    use std::cmp::Reverse;
-
-    let mut data = counts.iter().map(|(ref cons, ref qm)|
-        (cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone())
-    ).collect::<Vec<_>>();
-
-    data.sort_by_key(|k| Reverse(k.3));
-    for (cons, count, dur_total, dur_self) in data {
-        writeln!(count_file, "{}, {}, {}, {}",
-                 cons, count,
-                 duration_to_secs_str(dur_total),
-                 duration_to_secs_str(dur_self)
-        ).unwrap();
-    }
-}
-
-pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]) {
-    let capacity = traces.iter().fold(0, |acc, t| acc + 1 + t.extent.len());
-    let mut counts = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
-    compute_counts_rec(&mut counts, traces);
-    write_counts(counts_file, &mut counts);
-
-    let total: Duration = total_duration(traces);
-    write_traces_rec(html_file, traces, total, 0)
-}
-
-pub fn write_style(html_file: &mut File) {
-    write!(html_file, "{}", "
-body {
-    font-family: sans-serif;
-    background: black;
-}
-.trace {
-    color: black;
-    display: inline-block;
-    border-style: solid;
-    border-color: red;
-    border-width: 1px;
-    border-radius: 5px;
-    padding: 0px;
-    margin: 1px;
-    font-size: 0px;
-}
-.task-begin {
-    border-width: 1px;
-    color: white;
-    border-color: #ff8;
-    font-size: 0px;
-}
-.miss {
-    border-color: red;
-    border-width: 1px;
-}
-.extent-0 {
-    padding: 2px;
-}
-.time-begin {
-    border-width: 4px;
-    font-size: 12px;
-    color: white;
-    border-color: #afa;
-}
-.important {
-    border-width: 3px;
-    font-size: 12px;
-    color: white;
-    border-color: #f77;
-}
-.hit {
-    padding: 0px;
-    border-color: blue;
-    border-width: 3px;
-}
-.eff {
-  color: #fff;
-  display: inline-block;
-}
-.frc {
-  color: #7f7;
-  display: inline-block;
-}
-.dur {
-  display: none
-}
-.frac-50 {
-  padding: 10px;
-  border-width: 10px;
-  font-size: 32px;
-}
-.frac-40 {
-  padding: 8px;
-  border-width: 8px;
-  font-size: 24px;
-}
-.frac-30 {
-  padding: 6px;
-  border-width: 6px;
-  font-size: 18px;
-}
-.frac-20 {
-  padding: 4px;
-  border-width: 6px;
-  font-size: 16px;
-}
-.frac-10 {
-  padding: 2px;
-  border-width: 6px;
-  font-size: 14px;
-}
-").unwrap();
-}
index b05bad554f406e803213e4c0fbb134411601dfa2..0c272f0c4563b01b5dbb01125bfdecf7c8c8556b 100644 (file)
@@ -202,11 +202,12 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
     stderr: &Option<Arc<Mutex<Vec<u8>>>>,
     f: F,
 ) -> R {
-    use rayon::{ThreadPool, ThreadPoolBuilder};
+    use rayon::{ThreadBuilder, ThreadPool, ThreadPoolBuilder};
 
     let gcx_ptr = &Lock::new(0);
 
     let mut config = ThreadPoolBuilder::new()
+        .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
         .release_thread_handler(jobserver::release_thread)
         .num_threads(threads)
@@ -225,20 +226,20 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
                 // the thread local rustc uses. syntax_globals and syntax_pos_globals are
                 // captured and set on the new threads. ty::tls::with_thread_locals sets up
                 // thread local callbacks from libsyntax
-                let main_handler = move |worker: &mut dyn FnMut()| {
+                let main_handler = move |thread: ThreadBuilder| {
                     syntax::GLOBALS.set(syntax_globals, || {
                         syntax_pos::GLOBALS.set(syntax_pos_globals, || {
                             if let Some(stderr) = stderr {
                                 io::set_panic(Some(box Sink(stderr.clone())));
                             }
                             ty::tls::with_thread_locals(|| {
-                                ty::tls::GCX_PTR.set(gcx_ptr, || worker())
+                                ty::tls::GCX_PTR.set(gcx_ptr, || thread.run())
                             })
                         })
                     })
                 };
 
-                ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+                config.build_scoped(main_handler, with_pool).unwrap()
             })
         })
     })
index ea2e1d9ecc53f46553207c643ec5eed7c560de96..2edc8fadf45684dae76eb1bce80429c4b97e548a 100644 (file)
@@ -1,4 +1,4 @@
 syntax::register_diagnostics! {
 ;
-    E0721, // `await` keyword
+//  E0721, // `await` keyword
 }
index 3d14a78c33f7ea74975e877b3862d3f1f417747b..aa6dfa50dddf3030267ec8325078545196ae0296 100644 (file)
@@ -631,6 +631,16 @@ fn check_type_for_ffi(&self,
                             };
                         }
 
+                        let is_non_exhaustive =
+                            def.non_enum_variant().is_field_list_non_exhaustive();
+                        if is_non_exhaustive && !def.did.is_local() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: "this struct is non-exhaustive",
+                                help: None,
+                            };
+                        }
+
                         if def.non_enum_variant().fields.is_empty() {
                             return FfiUnsafe {
                                 ty,
@@ -730,8 +740,25 @@ fn check_type_for_ffi(&self,
                             }
                         }
 
+                        if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
+                            return FfiUnsafe {
+                                ty,
+                                reason: "this enum is non-exhaustive",
+                                help: None,
+                            };
+                        }
+
                         // Check the contained variants.
                         for variant in &def.variants {
+                            let is_non_exhaustive = variant.is_field_list_non_exhaustive();
+                            if is_non_exhaustive && !variant.def_id.is_local() {
+                                return FfiUnsafe {
+                                    ty,
+                                    reason: "this enum has non-exhaustive variants",
+                                    help: None,
+                                };
+                            }
+
                             for field in &variant.fields {
                                 let field_ty = cx.normalize_erasing_regions(
                                     ParamEnv::reveal_all(),
index f989ebc6dfd8e0210c707e4523b7a550f176b64f..c28fcb1a395ff999d2637908c08b8667ea3a164d 100644 (file)
@@ -8,8 +8,8 @@ edition = "2018"
 proc-macro = true
 
 [dependencies]
-synstructure = "0.10.2"
-syn = { version = "0.15.22", features = ["full"] }
-proc-macro2 = "0.4.24"
-quote = "0.6.10"
+synstructure = "0.12.1"
+syn = { version = "1", features = ["full"] }
+proc-macro2 = "1"
+quote = "1"
 itertools = "0.8"
index a708f3191dcf84e4bb427a107542e3a0b8992b96..735cfb11b365c4876c7d8720a98183a32ea5c734 100644 (file)
@@ -15,22 +15,22 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
     };
     for attr in &field.attrs {
         if let Ok(meta) = attr.parse_meta() {
-            if &meta.name().to_string() != "stable_hasher" {
+            if !meta.path().is_ident("stable_hasher") {
                 continue;
             }
             let mut any_attr = false;
             if let Meta::List(list) = meta {
                 for nested in list.nested.iter() {
                     if let NestedMeta::Meta(meta) = nested {
-                        if &meta.name().to_string() == "ignore" {
+                        if meta.path().is_ident("ignore") {
                             attrs.ignore = true;
                             any_attr = true;
                         }
-                        if &meta.name().to_string() == "project" {
+                        if meta.path().is_ident("project") {
                             if let Meta::List(list) = meta {
                                 if let Some(nested) = list.nested.iter().next() {
                                     if let NestedMeta::Meta(meta) = nested {
-                                        attrs.project = Some(meta.name());
+                                        attrs.project = meta.path().get_ident().cloned();
                                         any_attr = true;
                                     }
                                 }
index 9a68dd0f5e3ced95e1ee9b3fd42d7b042e8fbbf5..139e1b554cf90a2597a6ec606404b8034b3ceba0 100644 (file)
@@ -495,7 +495,11 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 dep_node_force_stream.extend(quote! {
                     DepKind::#name => {
                         if let Some(key) = RecoverKey::recover($tcx, $dep_node) {
-                            force_ex!($tcx, #name, key);
+                            $tcx.force_query::<crate::ty::query::queries::#name<'_>>(
+                                key,
+                                DUMMY_SP,
+                                *$dep_node
+                            );
                         } else {
                             return false;
                         }
index 91532d84473ab173338a8b120bc7e283388afb9c..cce0900bef3dde658af98a6113cfcb74ae5402cb 100644 (file)
@@ -270,7 +270,11 @@ pub fn provide(providers: &mut Providers<'_>) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_dllimport_foreign_item: |tcx, id| {
-            tcx.native_library_kind(id) == Some(NativeLibraryKind::NativeUnknown)
+            match tcx.native_library_kind(id) {
+                Some(NativeLibraryKind::NativeUnknown) |
+                Some(NativeLibraryKind::NativeRawDylib) => true,
+                _ => false,
+            }
         },
         is_statically_included_foreign_item: |tcx, id| {
             match tcx.native_library_kind(id) {
index 34f86707ad3222606bbb5960daf50db4c8d6fc28..eed355cbc13588c6e70d15f91e25ffc7da6de3e7 100644 (file)
@@ -919,7 +919,7 @@ pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
         self.entry_unless_proc_macro(id)
             .and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx))))
             .unwrap_or_else(|| {
-                bug!("get_optimized_mir: missing MIR for `{:?}", self.local_def_id(id))
+                bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id))
             })
     }
 
index fe215d9c7999ea66c453d20689fa2da730f2fafc..24ed8fcd8dd09c11d5bba67b6d533c8c8b8a9106 100644 (file)
@@ -73,6 +73,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item) {
                         "static-nobundle" => cstore::NativeStaticNobundle,
                         "dylib" => cstore::NativeUnknown,
                         "framework" => cstore::NativeFramework,
+                        "raw-dylib" => cstore::NativeRawDylib,
                         k => {
                             struct_span_err!(self.tcx.sess, item.span(), E0458,
                                       "unknown kind: `{}`", k)
@@ -169,6 +170,14 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
                                            GateIssue::Language,
                                            "kind=\"static-nobundle\" is unstable");
         }
+        if lib.kind == cstore::NativeRawDylib &&
+           !self.tcx.features().raw_dylib {
+            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+                                           sym::raw_dylib,
+                                           span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
+                                           GateIssue::Language,
+                                           "kind=\"raw-dylib\" is unstable");
+        }
         self.libs.push(lib);
     }
 
index ef459ef0c1b702c6692317b39dbb7a5ee5fcb8c0..2f9df7bd77e847bd99e0e5850f613ca2a35dc015 100644 (file)
@@ -750,6 +750,11 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
 
+        debug!(
+            "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
+            place_desc,
+            explanation
+        );
         let err = match (place_desc, explanation) {
             (Some(_), _) if self.is_place_thread_local(root_place) => {
                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
@@ -790,6 +795,24 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
                 span,
                 &format!("`{}`", name),
             ),
+            (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::OpaqueType,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+
+            ) if borrow_spans.for_generator() => self.report_escaping_closure_capture(
+                borrow_spans.args_or_use(),
+                borrow_span,
+                region_name,
+                category,
+                span,
+                &format!("`{}`", name),
+            ),
             (
                 ref name,
                 BorrowExplanation::MustBeValidFor {
@@ -1214,6 +1237,9 @@ fn report_escaping_closure_capture(
             ConstraintCategory::Return => {
                 err.span_note(constraint_span, "closure is returned here");
             }
+            ConstraintCategory::OpaqueType => {
+                err.span_note(constraint_span, "generator is returned here");
+            }
             ConstraintCategory::CallArgument => {
                 fr_name.highlight_region_name(&mut err);
                 err.span_note(
index cfa211ad5afdb9a28f4c324eb56113c1665b2144..75d4b56fdb7c20480890b3e62c44380ef7ac0651 100644 (file)
@@ -1944,14 +1944,16 @@ fn check_access_permissions(
                     self.is_mutable(place.as_ref(), is_local_mutation_allowed),
                     self.errors_buffer.is_empty()
                 ) {
-                    // rust-lang/rust#46908: In pure NLL mode this code path should
-                    // be unreachable (and thus we signal an ICE in the else branch here).
-                    span_bug!(
-                        span,
+                    // rust-lang/rust#46908: In pure NLL mode this code path should be
+                    // unreachable, but we use `delay_span_bug` because we can hit this when
+                    // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
+                    // enabled. We don't want to ICE for that case, as other errors will have
+                    // been emitted (#52262).
+                    self.infcx.tcx.sess.delay_span_bug(span, &format!(
                         "Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
                         place,
                         kind,
-                    );
+                    ));
                 }
                 return false;
             }
index 0e22ead62d1c0b747b6976e71b77ffab2ecd65b7..b105664399a5cbb6bd1ef6ea36adc1048f73388e 100644 (file)
@@ -12,7 +12,7 @@
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::{self, GeneratorSubsts, RegionVid, Ty};
+use rustc::ty::{self, RegionVid, Ty};
 use rustc::ty::subst::SubstsRef;
 
 pub(super) fn generate_constraints<'cx, 'tcx>(
@@ -91,13 +91,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
         self.super_ty(ty);
     }
 
-    /// We sometimes have `generator_substs` within an rvalue, or within a
-    /// call. Make them live at the location where they appear.
-    fn visit_generator_substs(&mut self, substs: &GeneratorSubsts<'tcx>, location: Location) {
-        self.add_regular_live_constraint(*substs, location);
-        self.super_generator_substs(substs);
-    }
-
     fn visit_statement(
         &mut self,
         statement: &Statement<'tcx>,
index ff4243df6e9b869cd9bd648de705c68fe040ff7f..5354b45f92d0a236dfd90f1cfa5f0d69db94ed34 100644 (file)
@@ -17,6 +17,7 @@
 
 mod find_use;
 
+#[derive(Debug)]
 pub(in crate::borrow_check) enum BorrowExplanation {
     UsedLater(LaterUseKind, Span),
     UsedLaterInLoop(LaterUseKind, Span),
@@ -35,7 +36,7 @@ pub(in crate::borrow_check) enum BorrowExplanation {
     Unexplained,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 pub(in crate::borrow_check) enum LaterUseKind {
     TraitCapture,
     ClosureCapture,
index 014335711a5114bba2f1ad119645a356c9cc2d39..88ad1fb1295094a97f35d6f6d97bf4066f0930ef 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, GeneratorSubsts, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::mir::{Location, Body, Promoted};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@@ -82,18 +82,4 @@ fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
     fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
         *constant = self.renumber_regions(&*constant);
     }
-
-    fn visit_generator_substs(&mut self,
-                              substs: &mut GeneratorSubsts<'tcx>,
-                              location: Location) {
-        debug!(
-            "visit_generator_substs(substs={:?}, location={:?})",
-            substs,
-            location,
-        );
-
-        *substs = self.renumber_regions(substs);
-
-        debug!("visit_generator_substs: substs={:?}", substs);
-    }
 }
index f55889794c24db9e386ff86b9a7862702de5e877..1563a27250eb9e391d148d4a50646eeb2b5ecf8a 100644 (file)
@@ -759,13 +759,13 @@ fn field_ty(
             PlaceTy { ty, variant_index: Some(variant_index) } => match ty.kind {
                 ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs),
                 ty::Generator(def_id, substs, _) => {
-                    let mut variants = substs.state_tys(def_id, tcx);
+                    let mut variants = substs.as_generator().state_tys(def_id, tcx);
                     let mut variant = match variants.nth(variant_index.into()) {
                         Some(v) => v,
                         None => {
                             bug!("variant_index of generator out of range: {:?}/{:?}",
                                  variant_index,
-                                 substs.state_tys(def_id, tcx).count())
+                                 substs.as_generator().state_tys(def_id, tcx).count())
                         }
                     };
                     return match variant.nth(field.index()) {
@@ -791,10 +791,10 @@ fn field_ty(
                 ty::Generator(def_id, substs, _) => {
                     // Only prefix fields (upvars and current state) are
                     // accessible without a variant index.
-                    return match substs.prefix_tys(def_id, tcx).nth(field.index()) {
+                    return match substs.as_generator().prefix_tys(def_id, tcx).nth(field.index()) {
                         Some(ty) => Ok(ty),
                         None => Err(FieldAccessError::OutOfRange {
-                            field_count: substs.prefix_tys(def_id, tcx).count(),
+                            field_count: substs.as_generator().prefix_tys(def_id, tcx).count(),
                         }),
                     }
                 }
@@ -1963,10 +1963,10 @@ fn aggregate_field_ty(
                 // It doesn't make sense to look at a field beyond the prefix;
                 // these require a variant index, and are not initialized in
                 // aggregate rvalues.
-                match substs.prefix_tys(def_id, tcx).nth(field_index) {
+                match substs.as_generator().prefix_tys(def_id, tcx).nth(field_index) {
                     Some(ty) => Ok(ty),
                     None => Err(FieldAccessError::OutOfRange {
-                        field_count: substs.prefix_tys(def_id, tcx).count(),
+                        field_count: substs.as_generator().prefix_tys(def_id, tcx).count(),
                     }),
                 }
             }
@@ -2541,7 +2541,7 @@ fn prove_aggregate_predicates(
             // these extra requirements are basically like where
             // clauses on the struct.
             AggregateKind::Closure(def_id, substs)
-            | AggregateKind::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+            | AggregateKind::Generator(def_id, substs, _) => {
                 self.prove_closure_bounds(tcx, *def_id, substs, location)
             }
 
index e3efacff66a2fa50b9afafe9b1461dcfc4fb4fda..5f6951856434e8021bbf7866ec51356fb452ea73 100644 (file)
@@ -19,7 +19,7 @@
 use rustc::middle::lang_items;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{InternalSubsts, SubstsRef, Subst};
-use rustc::ty::{self, GeneratorSubsts, RegionVid, Ty, TyCtxt};
+use rustc::ty::{self, RegionVid, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_errors::DiagnosticBuilder;
@@ -90,7 +90,7 @@ pub enum DefiningTy<'tcx> {
     /// The MIR is a generator. The signature is that generators take
     /// no parameters and return the result of
     /// `ClosureSubsts::generator_return_ty`.
-    Generator(DefId, ty::GeneratorSubsts<'tcx>, hir::GeneratorMovability),
+    Generator(DefId, SubstsRef<'tcx>, hir::GeneratorMovability),
 
     /// The MIR is a fn item with the given `DefId` and substs. The signature
     /// of the function can be bound then with the `fn_sig` query.
@@ -113,7 +113,7 @@ pub fn upvar_tys(self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 't
                 substs.as_closure().upvar_tys(def_id, tcx)
             ),
             DefiningTy::Generator(def_id, substs, _) => {
-                Either::Right(Either::Left(substs.upvar_tys(def_id, tcx)))
+                Either::Right(Either::Left(substs.as_generator().upvar_tys(def_id, tcx)))
             }
             DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
                 Either::Right(Either::Right(iter::empty()))
@@ -334,7 +334,7 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                 err.note(&format!(
                     "defining type: {:?} with generator substs {:#?}",
                     def_id,
-                    &substs.substs[..]
+                    &substs[..]
                 ));
 
                 // FIXME: As above, we'd like to print out the region
@@ -470,7 +470,7 @@ fn build(self) -> UniversalRegions<'tcx> {
 
         let yield_ty = match defining_ty {
             DefiningTy::Generator(def_id, substs, _) => {
-                Some(substs.yield_ty(def_id, self.infcx.tcx))
+                Some(substs.as_generator().yield_ty(def_id, self.infcx.tcx))
             }
             _ => None,
         };
@@ -549,7 +549,7 @@ fn compute_indices(
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs)
-            | DefiningTy::Generator(_, GeneratorSubsts { ref substs }, _) => {
+            | DefiningTy::Generator(_, ref substs, _) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureSubsts are
                 // inherited from the `closure_base_def_id`.
@@ -612,7 +612,7 @@ fn compute_inputs_and_output(
 
             DefiningTy::Generator(def_id, substs, movability) => {
                 assert_eq!(self.mir_def_id, def_id);
-                let output = substs.return_ty(def_id, tcx);
+                let output = substs.as_generator().return_ty(def_id, tcx);
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
                 let inputs_and_output = self.infcx.tcx.intern_type_list(&[generator_ty, output]);
                 ty::Binder::dummy(inputs_and_output)
index b4d93a4493fd9b14b8648f75d60608ad10f7e0fb..87d95a751534d1d54750a6ec7ae3167fdd8bc239 100644 (file)
@@ -128,7 +128,6 @@ fn expr_as_rvalue(
                         expr_span,
                         scope,
                         result,
-                        expr.ty,
                     );
                 }
 
@@ -569,7 +568,6 @@ fn limit_capture_mutability(
                 upvar_span,
                 temp_lifetime,
                 temp,
-                upvar_ty,
             );
         }
 
index dbcc330eca382cc2e1d444fcb8e6856f23d3f037..18332ed68f8bd15ae65d7dba2c36fd7121bc5aef 100644 (file)
@@ -103,7 +103,6 @@ fn expr_as_temp(
                         expr_span,
                         temp_lifetime,
                         temp,
-                        expr_ty,
                         DropKind::Storage,
                     );
                 }
@@ -117,7 +116,6 @@ fn expr_as_temp(
                 expr_span,
                 temp_lifetime,
                 temp,
-                expr_ty,
                 DropKind::Value,
             );
         }
index 861de07c612e9bbaaa9b2f23616a946167161c99..2e451fc88d95c37fa29153521d63c074689ca4c5 100644 (file)
@@ -535,21 +535,18 @@ pub fn storage_live_binding(
                 kind: StatementKind::StorageLive(local_id),
             },
         );
-        let var_ty = self.local_decls[local_id].ty;
         let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
-        self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage);
+        self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         Place::from(local_id)
     }
 
     pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
         let local_id = self.var_local_id(var, for_guard);
-        let var_ty = self.local_decls[local_id].ty;
         let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
         self.schedule_drop(
             span,
             region_scope,
             local_id,
-            var_ty,
             DropKind::Value,
         );
     }
index 9c30d9509908b7e89520929a7aa26beda4cc0659..8c35342d324b7702369394766fa1eaf65f2f3b28 100644 (file)
@@ -146,7 +146,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
             let (yield_ty, return_ty) = if body.generator_kind.is_some() {
                 let gen_sig = match ty.kind {
                     ty::Generator(gen_def_id, gen_substs, ..) =>
-                        gen_substs.sig(gen_def_id, tcx),
+                        gen_substs.as_generator().sig(gen_def_id, tcx),
                     _ =>
                         span_bug!(tcx.hir().span(id),
                                   "generator w/o generator type: {:?}", ty),
@@ -829,12 +829,12 @@ fn args_and_body(&mut self,
             // Function arguments always get the first Local indices after the return place
             let local = Local::new(index + 1);
             let place = Place::from(local);
-            let &ArgInfo(ty, opt_ty_info, arg_opt, ref self_binding) = arg_info;
+            let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info;
 
             // Make sure we drop (parts of) the argument even when not matched on.
             self.schedule_drop(
                 arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
-                argument_scope, local, ty, DropKind::Value,
+                argument_scope, local, DropKind::Value,
             );
 
             if let Some(arg) = arg_opt {
index a26ec72584bda72b86ef4d814094e81ca40ce6e4..a749b4263ea64abe73a5e4a5981519ec35995648 100644 (file)
@@ -85,7 +85,6 @@
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
 use crate::hair::{Expr, ExprRef, LintLevel};
 use rustc::middle::region;
-use rustc::ty::Ty;
 use rustc::hir;
 use rustc::mir::*;
 use syntax_pos::{DUMMY_SP, Span};
@@ -173,11 +172,11 @@ struct BreakableScope<'tcx> {
     region_scope: region::Scope,
     /// Where the body of the loop begins. `None` if block
     continue_block: Option<BasicBlock>,
-    /// Block to branch into when the loop or block terminates (either by being `break`-en out
-    /// from, or by having its condition to become false)
+    /// Block to branch into when the loop or block terminates (either by being
+    /// `break`-en out from, or by having its condition to become false)
     break_block: BasicBlock,
-    /// The destination of the loop/block expression itself (i.e., where to put the result of a
-    /// `break` expression)
+    /// The destination of the loop/block expression itself (i.e., where to put
+    /// the result of a `break` expression)
     break_destination: Place<'tcx>,
 }
 
@@ -728,10 +727,9 @@ pub fn schedule_drop_storage_and_value(
         span: Span,
         region_scope: region::Scope,
         local: Local,
-        place_ty: Ty<'tcx>,
     ) {
-        self.schedule_drop(span, region_scope, local, place_ty, DropKind::Storage);
-        self.schedule_drop(span, region_scope, local, place_ty, DropKind::Value);
+        self.schedule_drop(span, region_scope, local, DropKind::Storage);
+        self.schedule_drop(span, region_scope, local, DropKind::Value);
     }
 
     /// Indicates that `place` should be dropped on exit from
@@ -744,12 +742,13 @@ pub fn schedule_drop(
         span: Span,
         region_scope: region::Scope,
         local: Local,
-        place_ty: Ty<'tcx>,
         drop_kind: DropKind,
     ) {
-        let needs_drop = self.hir.needs_drop(place_ty);
-        match drop_kind {
-            DropKind::Value => if !needs_drop { return },
+        let needs_drop = match drop_kind {
+            DropKind::Value => {
+                if !self.hir.needs_drop(self.local_decls[local].ty) { return }
+                true
+            },
             DropKind::Storage => {
                 if local.index() <= self.arg_count {
                     span_bug!(
@@ -758,8 +757,9 @@ pub fn schedule_drop(
                         self.arg_count,
                     )
                 }
+                false
             }
-        }
+        };
 
         for scope in self.scopes.iter_mut() {
             let this_scope = scope.region_scope == region_scope;
index 0f66b13fdc51af33d7404e3113583334aec274d9..c1695ba66d0d536e54142f907043c66ddbe975e3 100644 (file)
@@ -109,15 +109,13 @@ fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
         assert_eq!(1, self.body.arg_count);
     }
 
-    fn statement_effect(&self,
-                        sets: &mut GenKillSet<Local>,
-                        loc: Location) {
-        self.check_for_move(sets, loc);
+    fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
+        // If we borrow or assign to a place then it needs storage for that
+        // statement.
         self.check_for_borrow(sets, loc);
 
         let stmt = &self.body[loc.block].statements[loc.statement_index];
         match stmt.kind {
-            StatementKind::StorageLive(l) => sets.gen(l),
             StatementKind::StorageDead(l) => sets.kill(l),
             StatementKind::Assign(box(ref place, _))
             | StatementKind::SetDiscriminant { box ref place, .. } => {
@@ -136,11 +134,35 @@ fn statement_effect(&self,
         }
     }
 
-    fn terminator_effect(&self,
-                         sets: &mut GenKillSet<Local>,
-                         loc: Location) {
+    fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
+        // If we move from a place then only stops needing storage *after*
+        // that statement.
         self.check_for_move(sets, loc);
+    }
+
+    fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
         self.check_for_borrow(sets, loc);
+
+        if let TerminatorKind::Call {
+            destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
+            ..
+        } = self.body[loc.block].terminator().kind {
+            sets.gen(local);
+        }
+    }
+
+    fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
+        // For call terminators the destination requires storage for the call
+        // and after the call returns successfully, but not after a panic.
+        // Since `propagate_call_unwind` doesn't exist, we have to kill the
+        // destination here, and then gen it again in `propagate_call_return`.
+        if let TerminatorKind::Call {
+            destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)),
+            ..
+        } = self.body[loc.block].terminator().kind {
+            sets.kill(local);
+        }
+        self.check_for_move(sets, loc);
     }
 
     fn propagate_call_return(
index fb1311de9a70659bf14855cfc9fa9f1bc302e176..77853ff1fe80aa2681de8a1df8056101400e1f20 100644 (file)
@@ -953,7 +953,7 @@ fn mutable() {
 "##,
 
 E0388: r##"
-E0388 was removed and is no longer issued.
+#### Note: this error code is no longer emitted by the compiler.
 "##,
 
 E0389: r##"
index d3bc61a4dde560b69cc62125108ed2ded5c4f963..3ea58052877244bb2923f73ed4a77c0a6967f01f 100644 (file)
@@ -434,6 +434,13 @@ enum Constructor<'tcx> {
 }
 
 impl<'tcx> Constructor<'tcx> {
+    fn is_slice(&self) -> bool {
+        match self {
+            Slice { .. } => true,
+            _ => false,
+        }
+    }
+
     fn variant_index_for_adt<'a>(
         &self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
@@ -827,6 +834,80 @@ struct IntRange<'tcx> {
 }
 
 impl<'tcx> IntRange<'tcx> {
+    #[inline]
+    fn is_integral(ty: Ty<'_>) -> bool {
+        match ty.kind {
+            ty::Char | ty::Int(_) | ty::Uint(_) => true,
+            _ => false,
+        }
+    }
+
+    #[inline]
+    fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
+        match ty.kind {
+            ty::Char => Some((Size::from_bytes(4), 0)),
+            ty::Int(ity) => {
+                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                Some((size, 1u128 << (size.bits() as u128 - 1)))
+            }
+            ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    fn from_const(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &Const<'tcx>,
+    ) -> Option<IntRange<'tcx>> {
+        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
+            let ty = value.ty;
+            let val = if let ConstValue::Scalar(Scalar::Raw { data, size }) = value.val {
+                // For this specific pattern we can skip a lot of effort and go
+                // straight to the result, after doing a bit of checking. (We
+                // could remove this branch and just use the next branch, which
+                // is more general but much slower.)
+                Scalar::<()>::check_raw(data, size, target_size);
+                data
+            } else if let Some(val) = value.try_eval_bits(tcx, param_env, ty) {
+                // This is a more general form of the previous branch.
+                val
+            } else {
+                return None
+            };
+            let val = val ^ bias;
+            Some(IntRange { range: val..=val, ty })
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn from_range(
+        tcx: TyCtxt<'tcx>,
+        lo: u128,
+        hi: u128,
+        ty: Ty<'tcx>,
+        end: &RangeEnd,
+    ) -> Option<IntRange<'tcx>> {
+        if Self::is_integral(ty) {
+            // Perform a shift if the underlying types are signed,
+            // which makes the interval arithmetic simpler.
+            let bias = IntRange::signed_bias(tcx, ty);
+            let (lo, hi) = (lo ^ bias, hi ^ bias);
+            // Make sure the interval is well-formed.
+            if lo > hi || lo == hi && *end == RangeEnd::Excluded {
+                None
+            } else {
+                let offset = (*end == RangeEnd::Excluded) as u128;
+                Some(IntRange { range: lo..=(hi - offset), ty })
+            }
+        } else {
+            None
+        }
+    }
+
     fn from_ctor(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -834,37 +915,9 @@ fn from_ctor(
     ) -> Option<IntRange<'tcx>> {
         // Floating-point ranges are permitted and we don't want
         // to consider them when constructing integer ranges.
-        fn is_integral(ty: Ty<'_>) -> bool {
-            match ty.kind {
-                ty::Char | ty::Int(_) | ty::Uint(_) => true,
-                _ => false,
-            }
-        }
-
         match ctor {
-            ConstantRange(lo, hi, ty, end) if is_integral(ty) => {
-                // Perform a shift if the underlying types are signed,
-                // which makes the interval arithmetic simpler.
-                let bias = IntRange::signed_bias(tcx, ty);
-                let (lo, hi) = (lo ^ bias, hi ^ bias);
-                // Make sure the interval is well-formed.
-                if lo > hi || lo == hi && *end == RangeEnd::Excluded {
-                    None
-                } else {
-                    let offset = (*end == RangeEnd::Excluded) as u128;
-                    Some(IntRange { range: lo..=(hi - offset), ty })
-                }
-            }
-            ConstantValue(val) if is_integral(val.ty) => {
-                let ty = val.ty;
-                if let Some(val) = val.try_eval_bits(tcx, param_env, ty) {
-                    let bias = IntRange::signed_bias(tcx, ty);
-                    let val = val ^ bias;
-                    Some(IntRange { range: val..=val, ty })
-                } else {
-                    None
-                }
-            }
+            ConstantRange(lo, hi, ty, end) => Self::from_range(tcx, *lo, *hi, ty, end),
+            ConstantValue(val) => Self::from_const(tcx, param_env, val),
             _ => None,
         }
     }
@@ -874,22 +927,26 @@ fn from_pat(
         param_env: ty::ParamEnv<'tcx>,
         mut pat: &Pat<'tcx>,
     ) -> Option<IntRange<'tcx>> {
-        let range = loop {
+        loop {
             match pat.kind {
-                box PatKind::Constant { value } => break ConstantValue(value),
-                box PatKind::Range(PatRange { lo, hi, end }) => break ConstantRange(
-                    lo.eval_bits(tcx, param_env, lo.ty),
-                    hi.eval_bits(tcx, param_env, hi.ty),
-                    lo.ty,
-                    end,
-                ),
+                box PatKind::Constant { value } => {
+                    return Self::from_const(tcx, param_env, value);
+                }
+                box PatKind::Range(PatRange { lo, hi, end }) => {
+                    return Self::from_range(
+                        tcx,
+                        lo.eval_bits(tcx, param_env, lo.ty),
+                        hi.eval_bits(tcx, param_env, hi.ty),
+                        &lo.ty,
+                        &end,
+                    );
+                }
                 box PatKind::AscribeUserType { ref subpattern, .. } => {
                     pat = subpattern;
                 },
                 _ => return None,
             }
-        };
-        Self::from_ctor(tcx, param_env, &range)
+        }
     }
 
     // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -1298,9 +1355,11 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
         }
     }).collect();
     let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
-    let matrix = Matrix(m.iter().flat_map(|r| {
-        specialize(cx, &r, &ctor, &wild_patterns)
-    }).collect());
+    let matrix = Matrix(
+        m.iter()
+            .filter_map(|r| specialize(cx, &r, &ctor, &wild_patterns))
+            .collect()
+    );
     match specialize(cx, v, &ctor, &wild_patterns) {
         Some(v) => match is_useful(cx, &matrix, &v, witness) {
             UsefulWithWitness(witnesses) => UsefulWithWitness(
@@ -1618,36 +1677,6 @@ fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
     split_ctors
 }
 
-/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
-fn constructor_intersects_pattern<'p, 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ctor: &Constructor<'tcx>,
-    pat: &'p Pat<'tcx>,
-) -> Option<SmallVec<[&'p Pat<'tcx>; 2]>> {
-    if should_treat_range_exhaustively(tcx, ctor) {
-        match (IntRange::from_ctor(tcx, param_env, ctor), IntRange::from_pat(tcx, param_env, pat)) {
-            (Some(ctor), Some(pat)) => {
-                ctor.intersection(&pat).map(|_| {
-                    let (pat_lo, pat_hi) = pat.range.into_inner();
-                    let (ctor_lo, ctor_hi) = ctor.range.into_inner();
-                    assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
-                    smallvec![]
-                })
-            }
-            _ => None,
-        }
-    } else {
-        // Fallback for non-ranges and ranges that involve floating-point numbers, which are not
-        // conveniently handled by `IntRange`. For these cases, the constructor may not be a range
-        // so intersection actually devolves into being covered by the pattern.
-        match constructor_covered_by_range(tcx, param_env, ctor, pat) {
-            Ok(true) => Some(smallvec![]),
-            Ok(false) | Err(ErrorReported) => None,
-        }
-    }
-}
-
 fn constructor_covered_by_range<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -1766,90 +1795,104 @@ fn specialize<'p, 'a: 'p, 'tcx>(
             Some(smallvec![subpattern])
         }
 
-        PatKind::Constant { value } => {
-            match *constructor {
-                Slice(..) => {
-                    // we extract an `Option` for the pointer because slices of zero elements don't
-                    // necessarily point to memory, they are usually just integers. The only time
-                    // they should be pointing to memory is when they are subslices of nonzero
-                    // slices
-                    let (alloc, offset, n, ty) = match value.ty.kind {
-                        ty::Array(t, n) => {
-                            match value.val {
-                                ConstValue::ByRef { offset, alloc, .. } => (
-                                    alloc,
-                                    offset,
-                                    n.eval_usize(cx.tcx, cx.param_env),
-                                    t,
-                                ),
-                                _ => span_bug!(
-                                    pat.span,
-                                    "array pattern is {:?}", value,
-                                ),
-                            }
-                        },
-                        ty::Slice(t) => {
-                            match value.val {
-                                ConstValue::Slice { data, start, end } => (
-                                    data,
-                                    Size::from_bytes(start as u64),
-                                    (end - start) as u64,
-                                    t,
-                                ),
-                                ConstValue::ByRef { .. } => {
-                                    // FIXME(oli-obk): implement `deref` for `ConstValue`
-                                    return None;
-                                },
-                                _ => span_bug!(
-                                    pat.span,
-                                    "slice pattern constant must be scalar pair but is {:?}",
-                                    value,
-                                ),
-                            }
+        PatKind::Constant { value } if constructor.is_slice() => {
+            // We extract an `Option` for the pointer because slices of zero
+            // elements don't necessarily point to memory, they are usually
+            // just integers. The only time they should be pointing to memory
+            // is when they are subslices of nonzero slices.
+            let (alloc, offset, n, ty) = match value.ty.kind {
+                ty::Array(t, n) => {
+                    match value.val {
+                        ConstValue::ByRef { offset, alloc, .. } => (
+                            alloc,
+                            offset,
+                            n.eval_usize(cx.tcx, cx.param_env),
+                            t,
+                        ),
+                        _ => span_bug!(
+                            pat.span,
+                            "array pattern is {:?}", value,
+                        ),
+                    }
+                },
+                ty::Slice(t) => {
+                    match value.val {
+                        ConstValue::Slice { data, start, end } => (
+                            data,
+                            Size::from_bytes(start as u64),
+                            (end - start) as u64,
+                            t,
+                        ),
+                        ConstValue::ByRef { .. } => {
+                            // FIXME(oli-obk): implement `deref` for `ConstValue`
+                            return None;
                         },
                         _ => span_bug!(
                             pat.span,
-                            "unexpected const-val {:?} with ctor {:?}",
+                            "slice pattern constant must be scalar pair but is {:?}",
                             value,
-                            constructor,
                         ),
-                    };
-                    if wild_patterns.len() as u64 == n {
-                        // convert a constant slice/array pattern to a list of patterns.
-                        let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
-                        let ptr = Pointer::new(AllocId(0), offset);
-                        (0..n).map(|i| {
-                            let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
-                            let scalar = alloc.read_scalar(
-                                &cx.tcx, ptr, layout.size,
-                            ).ok()?;
-                            let scalar = scalar.not_undef().ok()?;
-                            let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
-                            let pattern = Pat {
-                                ty,
-                                span: pat.span,
-                                kind: box PatKind::Constant { value },
-                            };
-                            Some(&*cx.pattern_arena.alloc(pattern))
-                        }).collect()
-                    } else {
-                        None
                     }
-                }
-                _ => {
-                    // If the constructor is a:
-                    //      Single value: add a row if the constructor equals the pattern.
-                    //      Range: add a row if the constructor contains the pattern.
-                    constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat)
-                }
+                },
+                _ => span_bug!(
+                    pat.span,
+                    "unexpected const-val {:?} with ctor {:?}",
+                    value,
+                    constructor,
+                ),
+            };
+            if wild_patterns.len() as u64 == n {
+                // convert a constant slice/array pattern to a list of patterns.
+                let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
+                let ptr = Pointer::new(AllocId(0), offset);
+                (0..n).map(|i| {
+                    let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
+                    let scalar = alloc.read_scalar(
+                        &cx.tcx, ptr, layout.size,
+                    ).ok()?;
+                    let scalar = scalar.not_undef().ok()?;
+                    let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
+                    let pattern = Pat {
+                        ty,
+                        span: pat.span,
+                        kind: box PatKind::Constant { value },
+                    };
+                    Some(&*cx.pattern_arena.alloc(pattern))
+                }).collect()
+            } else {
+                None
             }
         }
 
+        PatKind::Constant { .. } |
         PatKind::Range { .. } => {
             // If the constructor is a:
-            //      Single value: add a row if the pattern contains the constructor.
-            //      Range: add a row if the constructor intersects the pattern.
-            constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat)
+            // - Single value: add a row if the pattern contains the constructor.
+            // - Range: add a row if the constructor intersects the pattern.
+            if should_treat_range_exhaustively(cx.tcx, constructor) {
+                match (IntRange::from_ctor(cx.tcx, cx.param_env, constructor),
+                       IntRange::from_pat(cx.tcx, cx.param_env, pat)) {
+                    (Some(ctor), Some(pat)) => {
+                        ctor.intersection(&pat).map(|_| {
+                            let (pat_lo, pat_hi) = pat.range.into_inner();
+                            let (ctor_lo, ctor_hi) = ctor.range.into_inner();
+                            assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
+                            smallvec![]
+                        })
+                    }
+                    _ => None,
+                }
+            } else {
+                // Fallback for non-ranges and ranges that involve
+                // floating-point numbers, which are not conveniently handled
+                // by `IntRange`. For these cases, the constructor may not be a
+                // range so intersection actually devolves into being covered
+                // by the pattern.
+                match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) {
+                    Ok(true) => Some(smallvec![]),
+                    Ok(false) | Err(ErrorReported) => None,
+                }
+            }
         }
 
         PatKind::Array { ref prefix, ref slice, ref suffix } |
index dc3b7694c35c9b3800f588fab44a00d8da7ec210..f9200f8c1c04239c87ba03610dee0027ff50f31f 100644 (file)
@@ -68,8 +68,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
             | ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs })
             | ty::Closure(def_id, substs)
-            | ty::Generator(def_id, ty::GeneratorSubsts { substs }, _)
-            => self.print_def_path(def_id, substs),
+            | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
 
             ty::GeneratorWitness(_) => {
index 861e5ebef877deb024ed8654ff39c56d4b706b5e..4bdd71f9602ac2b25c336960eda4c49568ed049f 100644 (file)
@@ -664,14 +664,18 @@ pub fn read_discriminant(
                     bits_discr
                 };
                 // Make sure we catch invalid discriminants
-                let index = match &rval.layout.ty.kind {
+                let index = match rval.layout.ty.kind {
                     ty::Adt(adt, _) => adt
                         .discriminants(self.tcx.tcx)
                         .find(|(_, var)| var.val == real_discr),
-                    ty::Generator(def_id, substs, _) => substs
-                        .discriminants(*def_id, self.tcx.tcx)
-                        .find(|(_, var)| var.val == real_discr),
+                    ty::Generator(def_id, substs, _) => {
+                        let substs = substs.as_generator();
+                        substs
+                            .discriminants(def_id, self.tcx.tcx)
+                            .find(|(_, var)| var.val == real_discr)
+                    }
                     _ => bug!("tagged layout for non-adt non-generator"),
+
                 }.ok_or_else(
                     || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag()))
                 )?;
index 1166ca9bf24443b30c8a550aad2f0708b8ca7021..3ba989529f18f1263b943da1e2f6d310d4c7d4a5 100644 (file)
@@ -594,6 +594,13 @@ pub(super) fn eval_static_to_mplace(
             StaticKind::Promoted(promoted, promoted_substs) => {
                 let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs);
                 let instance = ty::Instance::new(place_static.def_id, substs);
+
+                // Even after getting `substs` from the frame, this instance may still be
+                // polymorphic because `ConstProp` will try to promote polymorphic MIR.
+                if instance.needs_subst() {
+                    throw_inval!(TooGeneric);
+                }
+
                 self.const_eval_raw(GlobalId {
                     instance,
                     promoted: Some(promoted),
index 3ac837dd330fd0ffe22adec26fcfadeca21613c0..3f0a2674305d49407fb0da04cbba6b4d75fe3658 100644 (file)
@@ -285,7 +285,11 @@ pub fn collect_crate_mono_items(
     tcx: TyCtxt<'_>,
     mode: MonoItemCollectionMode,
 ) -> (FxHashSet<MonoItem<'_>>, InliningMap<'_>) {
+    let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");
+
     let roots = time(tcx.sess, "collecting roots", || {
+        let _prof_timer = tcx.prof
+            .generic_activity("monomorphization_collector_root_collections");
         collect_roots(tcx, mode)
     });
 
@@ -295,6 +299,9 @@ pub fn collect_crate_mono_items(
     let mut inlining_map = MTLock::new(InliningMap::new());
 
     {
+        let _prof_timer = tcx.prof
+            .generic_activity("monomorphization_collector_graph_walk");
+
         let visited: MTRef<'_, _> = &mut visited;
         let inlining_map: MTRef<'_, _> = &mut inlining_map;
 
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
deleted file mode 100644 (file)
index e634262..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::mir::mono::MonoItem;
-use rustc::session::config::OptLevel;
-use rustc::ty::{self, TyCtxt, Instance};
-use rustc::ty::subst::InternalSubsts;
-use rustc::ty::print::obsolete::DefPathBasedNames;
-use syntax::attr::InlineAttr;
-use std::fmt;
-use rustc::mir::mono::Linkage;
-use syntax_pos::symbol::InternedString;
-use syntax::source_map::Span;
-
-/// Describes how a monomorphization will be instantiated in object files.
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
-pub enum InstantiationMode {
-    /// There will be exactly one instance of the given MonoItem. It will have
-    /// external linkage so that it can be linked to from other codegen units.
-    GloballyShared {
-        /// In some compilation scenarios we may decide to take functions that
-        /// are typically `LocalCopy` and instead move them to `GloballyShared`
-        /// to avoid codegenning them a bunch of times. In this situation,
-        /// however, our local copy may conflict with other crates also
-        /// inlining the same function.
-        ///
-        /// This flag indicates that this situation is occurring, and informs
-        /// symbol name calculation that some extra mangling is needed to
-        /// avoid conflicts. Note that this may eventually go away entirely if
-        /// ThinLTO enables us to *always* have a globally shared instance of a
-        /// function within one crate's compilation.
-        may_conflict: bool,
-    },
-
-    /// Each codegen unit containing a reference to the given MonoItem will
-    /// have its own private copy of the function (with internal linkage).
-    LocalCopy,
-}
-
-pub trait MonoItemExt<'tcx>: fmt::Debug {
-    fn as_mono_item(&self) -> &MonoItem<'tcx>;
-
-    fn is_generic_fn(&self) -> bool {
-        match *self.as_mono_item() {
-            MonoItem::Fn(ref instance) => {
-                instance.substs.non_erasable_generics().next().is_some()
-            }
-            MonoItem::Static(..) |
-            MonoItem::GlobalAsm(..) => false,
-        }
-    }
-
-    fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
-        match *self.as_mono_item() {
-            MonoItem::Fn(instance) => tcx.symbol_name(instance),
-            MonoItem::Static(def_id) => {
-                tcx.symbol_name(Instance::mono(tcx, def_id))
-            }
-            MonoItem::GlobalAsm(hir_id) => {
-                let def_id = tcx.hir().local_def_id(hir_id);
-                ty::SymbolName {
-                    name: InternedString::intern(&format!("global_asm_{:?}", def_id))
-                }
-            }
-        }
-    }
-    fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
-        let inline_in_all_cgus =
-            tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
-                tcx.sess.opts.optimize != OptLevel::No
-            }) && !tcx.sess.opts.cg.link_dead_code;
-
-        match *self.as_mono_item() {
-            MonoItem::Fn(ref instance) => {
-                let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
-                // If this function isn't inlined or otherwise has explicit
-                // linkage, then we'll be creating a globally shared version.
-                if self.explicit_linkage(tcx).is_some() ||
-                    !instance.def.requires_local(tcx) ||
-                    Some(instance.def_id()) == entry_def_id
-                {
-                    return InstantiationMode::GloballyShared  { may_conflict: false }
-                }
-
-                // At this point we don't have explicit linkage and we're an
-                // inlined function. If we're inlining into all CGUs then we'll
-                // be creating a local copy per CGU
-                if inline_in_all_cgus {
-                    return InstantiationMode::LocalCopy
-                }
-
-                // Finally, if this is `#[inline(always)]` we're sure to respect
-                // that with an inline copy per CGU, but otherwise we'll be
-                // creating one copy of this `#[inline]` function which may
-                // conflict with upstream crates as it could be an exported
-                // symbol.
-                match tcx.codegen_fn_attrs(instance.def_id()).inline {
-                    InlineAttr::Always => InstantiationMode::LocalCopy,
-                    _ => {
-                        InstantiationMode::GloballyShared  { may_conflict: true }
-                    }
-                }
-            }
-            MonoItem::Static(..) |
-            MonoItem::GlobalAsm(..) => {
-                InstantiationMode::GloballyShared { may_conflict: false }
-            }
-        }
-    }
-
-    fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option<Linkage> {
-        let def_id = match *self.as_mono_item() {
-            MonoItem::Fn(ref instance) => instance.def_id(),
-            MonoItem::Static(def_id) => def_id,
-            MonoItem::GlobalAsm(..) => return None,
-        };
-
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
-        codegen_fn_attrs.linkage
-    }
-
-    /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
-    /// predicates.
-    ///
-    /// In order to codegen an item, all of its predicates must hold, because
-    /// otherwise the item does not make sense. Type-checking ensures that
-    /// the predicates of every item that is *used by* a valid item *do*
-    /// hold, so we can rely on that.
-    ///
-    /// However, we codegen collector roots (reachable items) and functions
-    /// in vtables when they are seen, even if they are not used, and so they
-    /// might not be instantiable. For example, a programmer can define this
-    /// public function:
-    ///
-    ///     pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
-    ///         <&mut () as Clone>::clone(&s);
-    ///     }
-    ///
-    /// That function can't be codegened, because the method `<&mut () as Clone>::clone`
-    /// does not exist. Luckily for us, that function can't ever be used,
-    /// because that would require for `&'a mut (): Clone` to hold, so we
-    /// can just not emit any code, or even a linker reference for it.
-    ///
-    /// Similarly, if a vtable method has such a signature, and therefore can't
-    /// be used, we can just not emit it and have a placeholder (a null pointer,
-    /// which will never be accessed) in its place.
-    fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool {
-        debug!("is_instantiable({:?})", self);
-        let (def_id, substs) = match *self.as_mono_item() {
-            MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
-            MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()),
-            // global asm never has predicates
-            MonoItem::GlobalAsm(..) => return true
-        };
-
-        tcx.substitute_normalize_and_test_predicates((def_id, &substs))
-    }
-
-    fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {
-        return match *self.as_mono_item() {
-            MonoItem::Fn(instance) => {
-                to_string_internal(tcx, "fn ", instance, debug)
-            },
-            MonoItem::Static(def_id) => {
-                let instance = Instance::new(def_id, tcx.intern_substs(&[]));
-                to_string_internal(tcx, "static ", instance, debug)
-            },
-            MonoItem::GlobalAsm(..) => {
-                "global_asm".to_string()
-            }
-        };
-
-        fn to_string_internal<'a, 'tcx>(
-            tcx: TyCtxt<'tcx>,
-            prefix: &str,
-            instance: Instance<'tcx>,
-            debug: bool,
-        ) -> String {
-            let mut result = String::with_capacity(32);
-            result.push_str(prefix);
-            let printer = DefPathBasedNames::new(tcx, false, false);
-            printer.push_instance_as_string(instance, &mut result, debug);
-            result
-        }
-    }
-
-    fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
-        match *self.as_mono_item() {
-            MonoItem::Fn(Instance { def, .. }) => {
-                tcx.hir().as_local_hir_id(def.def_id())
-            }
-            MonoItem::Static(def_id) => {
-                tcx.hir().as_local_hir_id(def_id)
-            }
-            MonoItem::GlobalAsm(hir_id) => {
-                Some(hir_id)
-            }
-        }.map(|hir_id| tcx.hir().span(hir_id))
-    }
-}
-
-impl MonoItemExt<'tcx> for MonoItem<'tcx> {
-    fn as_mono_item(&self) -> &MonoItem<'tcx> {
-        self
-    }
-}
index c193911247e2bea5bb4219c1461214ab7476bf5d..6d9dae7214cc2a77581817ee3b84ad66b4ebe1e5 100644 (file)
@@ -134,10 +134,15 @@ pub fn partition<'tcx, I>(
 where
     I: Iterator<Item = MonoItem<'tcx>>,
 {
+    let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
+
     // In the first step, we place all regular monomorphizations into their
     // respective 'home' codegen unit. Regular monomorphizations are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = place_root_mono_items(tcx, mono_items);
+    let mut initial_partitioning = {
+        let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
+        place_root_mono_items(tcx, mono_items)
+    };
 
     initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
 
@@ -146,8 +151,8 @@ pub fn partition<'tcx, I>(
     // If the partitioning should produce a fixed count of codegen units, merge
     // until that count is reached.
     if let PartitioningStrategy::FixedUnitCount(count) = strategy {
+        let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
         merge_codegen_units(tcx, &mut initial_partitioning, count);
-
         debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
     }
 
@@ -155,8 +160,11 @@ pub fn partition<'tcx, I>(
     // monomorphizations have to go into each codegen unit. These additional
     // monomorphizations can be drop-glue, functions from external crates, and
     // local functions the definition of which is marked with `#[inline]`.
-    let mut post_inlining = place_inlined_mono_items(initial_partitioning,
-                                                            inlining_map);
+    let mut post_inlining = {
+        let _prof_timer =
+            tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
+        place_inlined_mono_items(initial_partitioning, inlining_map)
+    };
 
     post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
 
@@ -165,6 +173,8 @@ pub fn partition<'tcx, I>(
     // Next we try to make as many symbols "internal" as possible, so LLVM has
     // more freedom to optimize.
     if !tcx.sess.opts.cg.link_dead_code {
+        let _prof_timer =
+            tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
         internalize_symbols(tcx, &mut post_inlining, inlining_map);
     }
 
@@ -494,6 +504,9 @@ fn merge_codegen_units<'tcx>(
         for (k, v) in smallest.items_mut().drain() {
             second_smallest.items_mut().insert(k, v);
         }
+        debug!("CodegenUnit {} merged in to CodegenUnit {}",
+               smallest.name(),
+               second_smallest.name());
     }
 
     let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
@@ -774,7 +787,7 @@ fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
     if cfg!(debug_assertions) {
         debug!("{}", label);
         for cgu in cgus {
-            debug!("CodegenUnit {}:", cgu.name());
+            debug!("CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate());
 
             for (mono_item, linkage) in cgu.items() {
                 let symbol_name = mono_item.symbol_name(tcx).name.as_str();
@@ -782,10 +795,11 @@ fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
                 let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..])
                                                    .unwrap_or("<no hash>");
 
-                debug!(" - {} [{:?}] [{}]",
+                debug!(" - {} [{:?}] [{}] estimated size {}",
                        mono_item.to_string(tcx, true),
                        linkage,
-                       symbol_hash);
+                       symbol_hash,
+                       mono_item.size_estimate(tcx));
             }
 
             debug!("");
index d089eafbb0798138acd0a854cc4ac56221d7f697..78008e2fcd361c69004d9c619b425a30ff999f14 100644 (file)
@@ -169,7 +169,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     // Check if this is a generator, if so, return the drop glue for it
     if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty {
         let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap();
-        return body.subst(tcx, substs.substs);
+        return body.subst(tcx, substs);
     }
 
     let substs = if let Some(ty) = ty {
index 21ca339eb968bdfb6f644a14011725a021daee75..38a04ce8f38158f68bdeaca16caca4e9b08f2304 100644 (file)
@@ -39,12 +39,6 @@ fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
         *substs = self.tcx.erase_regions(substs);
     }
-
-    fn visit_statement(&mut self,
-                       statement: &mut Statement<'tcx>,
-                       location: Location) {
-        self.super_statement(statement, location);
-    }
 }
 
 pub struct EraseRegions;
index bfc5eb5a94ef88ea37410dc1a6e3f9ffb96c4b5e..865fa012c2995e3a07b904272b3725b0d6caa854 100644 (file)
@@ -508,10 +508,7 @@ fn locals_live_across_suspend_points(
             storage_liveness_map.insert(block, storage_liveness.clone());
 
             requires_storage_cursor.seek(loc);
-            let mut storage_required = requires_storage_cursor.get().clone();
-
-            // Mark locals without storage statements as always requiring storage
-            storage_required.union(&ignored.0);
+            let storage_required = requires_storage_cursor.get().clone();
 
             // Locals live are live at this point only if they are used across
             // suspension points (the `liveness` variable)
@@ -1126,6 +1123,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
         // Get the interior types and substs which typeck computed
         let (upvars, interior, discr_ty, movable) = match gen_ty.kind {
             ty::Generator(_, substs, movability) => {
+                let substs = substs.as_generator();
                 (substs.upvar_tys(def_id, tcx).collect(),
                  substs.witness(def_id, tcx),
                  substs.discr_ty(tcx),
index bdbf040276d22eee0df4adcab73e994f1da244fd..f7ba6f1ec6993994d8595ab43d4d44721db210f8 100644 (file)
@@ -798,7 +798,7 @@ fn open_drop(&mut self) -> BasicBlock {
             // It effetively only contains upvars until the generator transformation runs.
             // See librustc_body/transform/generator.rs for more details.
             ty::Generator(def_id, substs, _) => {
-                let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect();
+                let tys : Vec<_> = substs.as_generator().upvar_tys(def_id, self.tcx()).collect();
                 self.open_drop_for_tuple(&tys)
             }
             ty::Tuple(..) => {
index 596ec6c19bcbfd0b5e419173ca1d6541a47270df..9d29a230314437f8e6b887d91c901551ebffdd78 100644 (file)
@@ -15,3 +15,5 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
+rustc_target = { path = "../librustc_target" }
+rustc_index = { path = "../librustc_index" }
diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs
new file mode 100644 (file)
index 0000000..f2aef2c
--- /dev/null
@@ -0,0 +1,676 @@
+// This implements the dead-code warning pass. It follows middle::reachable
+// closely. The idea is that all reachable symbols are live, codes called
+// from live codes are live, and everything else is dead.
+
+use rustc::hir::Node;
+use rustc::hir::{self, PatKind, TyKind};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+
+use rustc::hir::def::{CtorOf, Res, DefKind};
+use rustc::hir::CodegenFnAttrFlags;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
+use rustc::lint;
+use rustc::middle::privacy;
+use rustc::ty::{self, DefIdTree, TyCtxt};
+use rustc::util::nodemap::FxHashSet;
+
+use rustc_data_structures::fx::FxHashMap;
+
+use syntax::{ast, attr};
+use syntax::symbol::sym;
+use syntax_pos;
+
+// 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 {
+    match tcx.hir().find(hir_id) {
+        Some(Node::Item(..)) |
+        Some(Node::ImplItem(..)) |
+        Some(Node::ForeignItem(..)) |
+        Some(Node::TraitItem(..)) |
+        Some(Node::Variant(..)) |
+        Some(Node::AnonConst(..)) |
+        Some(Node::Pat(..)) => true,
+        _ => false
+    }
+}
+
+struct MarkSymbolVisitor<'a, 'tcx> {
+    worklist: Vec<hir::HirId>,
+    tcx: TyCtxt<'tcx>,
+    tables: &'a ty::TypeckTables<'tcx>,
+    live_symbols: FxHashSet<hir::HirId>,
+    repr_has_repr_c: bool,
+    in_pat: bool,
+    inherited_pub_visibility: bool,
+    ignore_variant_stack: Vec<DefId>,
+    // maps from tuple struct constructors to tuple struct items
+    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+}
+
+impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
+    fn check_def_id(&mut self, def_id: DefId) {
+        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
+            if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) {
+                self.worklist.push(hir_id);
+            }
+            self.live_symbols.insert(hir_id);
+        }
+    }
+
+    fn insert_def_id(&mut self, def_id: DefId) {
+        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
+            debug_assert!(!should_explore(self.tcx, hir_id));
+            self.live_symbols.insert(hir_id);
+        }
+    }
+
+    fn handle_res(&mut self, res: Res) {
+        match res {
+            Res::Def(DefKind::Const, _)
+            | Res::Def(DefKind::AssocConst, _)
+            | Res::Def(DefKind::TyAlias, _) => {
+                self.check_def_id(res.def_id());
+            }
+            _ if self.in_pat => {},
+            Res::PrimTy(..) | Res::SelfCtor(..) |
+            Res::Local(..) => {}
+            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
+                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id).unwrap();
+                self.check_def_id(enum_id);
+                if !self.ignore_variant_stack.contains(&ctor_def_id) {
+                    self.check_def_id(variant_id);
+                }
+            }
+            Res::Def(DefKind::Variant, variant_id) => {
+                let enum_id = self.tcx.parent(variant_id).unwrap();
+                self.check_def_id(enum_id);
+                if !self.ignore_variant_stack.contains(&variant_id) {
+                    self.check_def_id(variant_id);
+                }
+            }
+            Res::SelfTy(t, i) => {
+                if let Some(t) = t {
+                    self.check_def_id(t);
+                }
+                if let Some(i) = i {
+                    self.check_def_id(i);
+                }
+            }
+            Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
+            _ => {
+                self.check_def_id(res.def_id());
+            }
+        }
+    }
+
+    fn lookup_and_handle_method(&mut self, id: hir::HirId) {
+        if let Some(def_id) = self.tables.type_dependent_def_id(id) {
+            self.check_def_id(def_id);
+        } else {
+            bug!("no type-dependent def for method");
+        }
+    }
+
+    fn handle_field_access(&mut self, lhs: &hir::Expr, hir_id: hir::HirId) {
+        match self.tables.expr_ty_adjusted(lhs).kind {
+            ty::Adt(def, _) => {
+                let index = self.tcx.field_index(hir_id, self.tables);
+                self.insert_def_id(def.non_enum_variant().fields[index].did);
+            }
+            ty::Tuple(..) => {}
+            _ => span_bug!(lhs.span, "named field access on non-ADT"),
+        }
+    }
+
+    fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, res: Res, pats: &[hir::FieldPat]) {
+        let variant = match self.tables.node_type(lhs.hir_id).kind {
+            ty::Adt(adt, _) => adt.variant_of_res(res),
+            _ => span_bug!(lhs.span, "non-ADT in struct pattern")
+        };
+        for pat in pats {
+            if let PatKind::Wild = pat.pat.kind {
+                continue;
+            }
+            let index = self.tcx.field_index(pat.hir_id, self.tables);
+            self.insert_def_id(variant.fields[index].did);
+        }
+    }
+
+    fn mark_live_symbols(&mut self) {
+        let mut scanned = FxHashSet::default();
+        while let Some(id) = self.worklist.pop() {
+            if !scanned.insert(id) {
+                continue
+            }
+
+            // 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);
+
+            if let Some(node) = self.tcx.hir().find(id) {
+                self.live_symbols.insert(id);
+                self.visit_node(node);
+            }
+        }
+    }
+
+    fn visit_node(&mut self, node: Node<'tcx>) {
+        let had_repr_c = self.repr_has_repr_c;
+        self.repr_has_repr_c = false;
+        let had_inherited_pub_visibility = self.inherited_pub_visibility;
+        self.inherited_pub_visibility = false;
+        match node {
+            Node::Item(item) => {
+                match item.kind {
+                    hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
+                        let def_id = self.tcx.hir().local_def_id(item.hir_id);
+                        let def = self.tcx.adt_def(def_id);
+                        self.repr_has_repr_c = def.repr.c();
+
+                        intravisit::walk_item(self, &item);
+                    }
+                    hir::ItemKind::Enum(..) => {
+                        self.inherited_pub_visibility = item.vis.node.is_pub();
+
+                        intravisit::walk_item(self, &item);
+                    }
+                    hir::ItemKind::ForeignMod(..) => {}
+                    _ => {
+                        intravisit::walk_item(self, &item);
+                    }
+                }
+            }
+            Node::TraitItem(trait_item) => {
+                intravisit::walk_trait_item(self, trait_item);
+            }
+            Node::ImplItem(impl_item) => {
+                intravisit::walk_impl_item(self, impl_item);
+            }
+            Node::ForeignItem(foreign_item) => {
+                intravisit::walk_foreign_item(self, &foreign_item);
+            }
+            _ => {}
+        }
+        self.repr_has_repr_c = had_repr_c;
+        self.inherited_pub_visibility = had_inherited_pub_visibility;
+    }
+
+    fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) {
+        if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
+            for field in fields {
+                let index = self.tcx.field_index(field.hir_id, self.tables);
+                self.insert_def_id(adt.non_enum_variant().fields[index].did);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let old_tables = self.tables;
+        self.tables = self.tcx.body_tables(body);
+        let body = self.tcx.hir().body(body);
+        self.visit_body(body);
+        self.tables = old_tables;
+    }
+
+    fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
+                          _: &hir::Generics, _: hir::HirId, _: syntax_pos::Span) {
+        let has_repr_c = self.repr_has_repr_c;
+        let inherited_pub_visibility = self.inherited_pub_visibility;
+        let live_fields = def.fields().iter().filter(|f| {
+            has_repr_c || inherited_pub_visibility || f.vis.node.is_pub()
+        });
+        self.live_symbols.extend(live_fields.map(|f| f.hir_id));
+
+        intravisit::walk_struct_def(self, def);
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+        match expr.kind {
+            hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
+                let res = self.tables.qpath_res(qpath, expr.hir_id);
+                self.handle_res(res);
+            }
+            hir::ExprKind::MethodCall(..) => {
+                self.lookup_and_handle_method(expr.hir_id);
+            }
+            hir::ExprKind::Field(ref lhs, ..) => {
+                self.handle_field_access(&lhs, expr.hir_id);
+            }
+            hir::ExprKind::Struct(_, ref fields, _) => {
+                if let ty::Adt(ref adt, _) = self.tables.expr_ty(expr).kind {
+                    self.mark_as_used_if_union(adt, fields);
+                }
+            }
+            _ => ()
+        }
+
+        intravisit::walk_expr(self, expr);
+    }
+
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
+        // Inside the body, ignore constructions of variants
+        // necessary for the pattern to match. Those construction sites
+        // can't be reached unless the variant is constructed elsewhere.
+        let len = self.ignore_variant_stack.len();
+        self.ignore_variant_stack.extend(arm.pat.necessary_variants());
+        intravisit::walk_arm(self, arm);
+        self.ignore_variant_stack.truncate(len);
+    }
+
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
+        match pat.kind {
+            PatKind::Struct(ref path, ref fields, _) => {
+                let res = self.tables.qpath_res(path, pat.hir_id);
+                self.handle_field_pattern_match(pat, res, fields);
+            }
+            PatKind::Path(ref qpath) => {
+                let res = self.tables.qpath_res(qpath, pat.hir_id);
+                self.handle_res(res);
+            }
+            _ => ()
+        }
+
+        self.in_pat = true;
+        intravisit::walk_pat(self, pat);
+        self.in_pat = false;
+    }
+
+    fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) {
+        self.handle_res(path.res);
+        intravisit::walk_path(self, path);
+    }
+
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+        match ty.kind {
+            TyKind::Def(item_id, _) => {
+                let item = self.tcx.hir().expect_item(item_id.id);
+                intravisit::walk_item(self, item);
+            }
+            _ => ()
+        }
+        intravisit::walk_ty(self, ty);
+    }
+
+    fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+        self.live_symbols.insert(c.hir_id);
+        intravisit::walk_anon_const(self, c);
+    }
+}
+
+fn has_allow_dead_code_or_lang_attr(
+    tcx: TyCtxt<'_>,
+    id: hir::HirId,
+    attrs: &[ast::Attribute],
+) -> bool {
+    if attr::contains_name(attrs, sym::lang) {
+        return true;
+    }
+
+    // Stable attribute for #[lang = "panic_impl"]
+    if attr::contains_name(attrs, sym::panic_handler) {
+        return true;
+    }
+
+    // (To be) stable attribute for #[lang = "oom"]
+    if attr::contains_name(attrs, sym::alloc_error_handler) {
+        return true;
+    }
+
+    let def_id = tcx.hir().local_def_id(id);
+    let cg_attrs = tcx.codegen_fn_attrs(def_id);
+
+    // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
+    // forcefully, e.g., for placing it in a specific section.
+    if cg_attrs.contains_extern_indicator() ||
+        cg_attrs.flags.contains(CodegenFnAttrFlags::USED) {
+        return true;
+    }
+
+    tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
+}
+
+// This visitor seeds items that
+//   1) We want to explicitly consider as live:
+//     * Item annotated with #[allow(dead_code)]
+//         - This is done so that if we want to suppress warnings for a
+//           group of dead functions, we only have to annotate the "root".
+//           For example, if both `f` and `g` are dead and `f` calls `g`,
+//           then annotating `f` with `#[allow(dead_code)]` will suppress
+//           warning for both `f` and `g`.
+//     * Item annotated with #[lang=".."]
+//         - This is because lang items are always callable from elsewhere.
+//   or
+//   2) We are not sure to be live or not
+//     * Implementation of a trait method
+struct LifeSeeder<'k, 'tcx> {
+    worklist: Vec<hir::HirId>,
+    krate: &'k hir::Crate,
+    tcx: TyCtxt<'tcx>,
+    // see `MarkSymbolVisitor::struct_constructors`
+    struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+}
+
+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,
+                                                               &item.attrs);
+        if allow_dead_code {
+            self.worklist.push(item.hir_id);
+        }
+        match item.kind {
+            hir::ItemKind::Enum(ref enum_def, _) => {
+                if allow_dead_code {
+                    self.worklist.extend(enum_def.variants.iter().map(|variant| 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);
+                    }
+                }
+            }
+            hir::ItemKind::Trait(.., ref trait_item_refs) => {
+                for trait_item_ref in trait_item_refs {
+                    let trait_item = self.krate.trait_item(trait_item_ref.id);
+                    match trait_item.kind {
+                        hir::TraitItemKind::Const(_, Some(_)) |
+                        hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
+                            if has_allow_dead_code_or_lang_attr(self.tcx,
+                                                                trait_item.hir_id,
+                                                                &trait_item.attrs) {
+                                self.worklist.push(trait_item.hir_id);
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            hir::ItemKind::Impl(.., ref opt_trait, _, ref impl_item_refs) => {
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.krate.impl_item(impl_item_ref.id);
+                    if opt_trait.is_some() ||
+                            has_allow_dead_code_or_lang_attr(self.tcx,
+                                                             impl_item.hir_id,
+                                                             &impl_item.attrs) {
+                        self.worklist.push(impl_item_ref.id.hir_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);
+                }
+            }
+            _ => ()
+        }
+    }
+
+    fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
+        // ignore: we are handling this in `visit_item` above
+    }
+
+    fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
+        // ignore: we are handling this in `visit_item` above
+    }
+}
+
+fn create_and_seed_worklist<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    access_levels: &privacy::AccessLevels,
+    krate: &hir::Crate,
+) -> (Vec<hir::HirId>, FxHashMap<hir::HirId, hir::HirId>) {
+    let worklist = access_levels.map.iter().filter_map(|(&id, level)| {
+        if level >= &privacy::AccessLevel::Reachable {
+            Some(id)
+        } else {
+            None
+        }
+    }).chain(
+        // Seed entry point
+        tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().as_local_hir_id(def_id).unwrap())
+    ).collect::<Vec<_>>();
+
+    // Seed implemented trait items
+    let mut life_seeder = LifeSeeder {
+        worklist,
+        krate,
+        tcx,
+        struct_constructors: Default::default(),
+    };
+    krate.visit_all_item_likes(&mut life_seeder);
+
+    (life_seeder.worklist, life_seeder.struct_constructors)
+}
+
+fn find_live<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    access_levels: &privacy::AccessLevels,
+    krate: &hir::Crate,
+) -> FxHashSet<hir::HirId> {
+    let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
+    let mut symbol_visitor = MarkSymbolVisitor {
+        worklist,
+        tcx,
+        tables: &ty::TypeckTables::empty(None),
+        live_symbols: Default::default(),
+        repr_has_repr_c: false,
+        in_pat: false,
+        inherited_pub_visibility: false,
+        ignore_variant_stack: vec![],
+        struct_constructors,
+    };
+    symbol_visitor.mark_live_symbols();
+    symbol_visitor.live_symbols
+}
+
+struct DeadVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    live_symbols: FxHashSet<hir::HirId>,
+}
+
+impl DeadVisitor<'tcx> {
+    fn should_warn_about_item(&mut self, item: &hir::Item) -> bool {
+        let should_warn = match item.kind {
+            hir::ItemKind::Static(..)
+            | hir::ItemKind::Const(..)
+            | hir::ItemKind::Fn(..)
+            | hir::ItemKind::TyAlias(..)
+            | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::Union(..) => true,
+            _ => false
+        };
+        should_warn && !self.symbol_is_live(item.hir_id)
+    }
+
+    fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool {
+        let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
+        !field.is_positional()
+            && !self.symbol_is_live(field.hir_id)
+            && !field_type.is_phantom_data()
+            && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs)
+    }
+
+    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,
+                                                 &variant.attrs)
+    }
+
+    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, &fi.attrs)
+    }
+
+    // id := HIR id of an item's definition.
+    fn symbol_is_live(
+        &mut self,
+        id: hir::HirId,
+    ) -> bool {
+        if self.live_symbols.contains(&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(item_hir_id) = self.tcx.hir().as_local_hir_id(item_did) {
+                    if self.live_symbols.contains(&item_hir_id) {
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    fn warn_dead_code(&mut self,
+                      id: hir::HirId,
+                      span: syntax_pos::Span,
+                      name: ast::Name,
+                      node_type: &str,
+                      participle: &str) {
+        if !name.as_str().starts_with("_") {
+            self.tcx
+                .lint_hir(lint::builtin::DEAD_CODE,
+                          id,
+                          span,
+                          &format!("{} is never {}: `{}`",
+                                   node_type, participle, name));
+        }
+    }
+}
+
+impl Visitor<'tcx> for DeadVisitor<'tcx> {
+    /// Walk nested items in place so that we don't report dead-code
+    /// on inner functions when the outer function is already getting
+    /// an error. We could do this also by checking the parents, but
+    /// this is how the code is setup and it seems harmless enough.
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.hir())
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        if self.should_warn_about_item(item) {
+            // For items that have a definition with a signature followed by a
+            // block, point only at the signature.
+            let span = match item.kind {
+                hir::ItemKind::Fn(..) |
+                hir::ItemKind::Mod(..) |
+                hir::ItemKind::Enum(..) |
+                hir::ItemKind::Struct(..) |
+                hir::ItemKind::Union(..) |
+                hir::ItemKind::Trait(..) |
+                hir::ItemKind::Impl(..) => self.tcx.sess.source_map().def_span(item.span),
+                _ => item.span,
+            };
+            let participle = match item.kind {
+                hir::ItemKind::Struct(..) => "constructed", // Issue #52325
+                _ => "used"
+            };
+            self.warn_dead_code(
+                item.hir_id,
+                span,
+                item.ident.name,
+                item.kind.descriptive_variant(),
+                participle,
+            );
+        } else {
+            // Only continue if we didn't warn
+            intravisit::walk_item(self, item);
+        }
+    }
+
+    fn visit_variant(&mut self,
+                     variant: &'tcx hir::Variant,
+                     g: &'tcx hir::Generics,
+                     id: hir::HirId) {
+        if self.should_warn_about_variant(&variant) {
+            self.warn_dead_code(variant.id, variant.span, variant.ident.name,
+                                "variant", "constructed");
+        } else {
+            intravisit::walk_variant(self, variant, g, id);
+        }
+    }
+
+    fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
+        if self.should_warn_about_foreign_item(fi) {
+            self.warn_dead_code(fi.hir_id, fi.span, fi.ident.name,
+                                fi.kind.descriptive_variant(), "used");
+        }
+        intravisit::walk_foreign_item(self, fi);
+    }
+
+    fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
+        if self.should_warn_about_field(&field) {
+            self.warn_dead_code(field.hir_id, field.span, field.ident.name, "field", "used");
+        }
+        intravisit::walk_struct_field(self, field);
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+        match impl_item.kind {
+            hir::ImplItemKind::Const(_, body_id) => {
+                if !self.symbol_is_live(impl_item.hir_id) {
+                    self.warn_dead_code(impl_item.hir_id,
+                                        impl_item.span,
+                                        impl_item.ident.name,
+                                        "associated const",
+                                        "used");
+                }
+                self.visit_nested_body(body_id)
+            }
+            hir::ImplItemKind::Method(_, body_id) => {
+                if !self.symbol_is_live(impl_item.hir_id) {
+                    let span = self.tcx.sess.source_map().def_span(impl_item.span);
+                    self.warn_dead_code(impl_item.hir_id, span, impl_item.ident.name, "method",
+                        "used");
+                }
+                self.visit_nested_body(body_id)
+            }
+            hir::ImplItemKind::OpaqueTy(..) |
+            hir::ImplItemKind::TyAlias(..) => {}
+        }
+    }
+
+    // Overwrite so that we don't warn the trait item itself.
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+        match trait_item.kind {
+            hir::TraitItemKind::Const(_, Some(body_id)) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+                self.visit_nested_body(body_id)
+            }
+            hir::TraitItemKind::Const(_, None) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+            hir::TraitItemKind::Type(..) => {}
+        }
+    }
+}
+
+pub fn check_crate(tcx: TyCtxt<'_>) {
+    let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
+    let krate = tcx.hir().krate();
+    let live_symbols = find_live(tcx, access_levels, krate);
+    let mut visitor = DeadVisitor {
+        tcx,
+        live_symbols,
+    };
+    intravisit::walk_crate(&mut visitor, krate);
+}
diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs
new file mode 100644 (file)
index 0000000..bf68807
--- /dev/null
@@ -0,0 +1,202 @@
+use rustc::hir::map as hir_map;
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
+use rustc::session::{config, Session};
+use rustc::session::config::EntryFnType;
+use syntax::attr;
+use syntax::entry::EntryPointType;
+use syntax::symbol::sym;
+use syntax_pos::Span;
+use rustc::hir::{HirId, Item, ItemKind, ImplItem, TraitItem};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::TyCtxt;
+use rustc::ty::query::Providers;
+
+struct EntryContext<'a, 'tcx> {
+    session: &'a Session,
+
+    map: &'a hir_map::Map<'tcx>,
+
+    /// The top-level function called `main`.
+    main_fn: Option<(HirId, Span)>,
+
+    /// The function that has attribute named `main`.
+    attr_main_fn: Option<(HirId, Span)>,
+
+    /// The function that has the attribute 'start' on it.
+    start_fn: Option<(HirId, Span)>,
+
+    /// The functions that one might think are `main` but aren't, e.g.
+    /// main functions not defined at the top level. For diagnostics.
+    non_main_fns: Vec<(HirId, Span)> ,
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx Item) {
+        let def_id = self.map.local_def_id(item.hir_id);
+        let def_key = self.map.def_key(def_id);
+        let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+        find_item(item, self, at_root);
+    }
+
+    fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
+        // Entry fn is never a trait item.
+    }
+
+    fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
+        // Entry fn is never a trait item.
+    }
+}
+
+fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    let any_exe = tcx.sess.crate_types.borrow().iter().any(|ty| {
+        *ty == config::CrateType::Executable
+    });
+    if !any_exe {
+        // No need to find a main function.
+        return None;
+    }
+
+    // If the user wants no main function at all, then stop here.
+    if attr::contains_name(&tcx.hir().krate().attrs, sym::no_main) {
+        return None;
+    }
+
+    let mut ctxt = EntryContext {
+        session: tcx.sess,
+        map: tcx.hir(),
+        main_fn: None,
+        attr_main_fn: None,
+        start_fn: None,
+        non_main_fns: Vec::new(),
+    };
+
+    tcx.hir().krate().visit_all_item_likes(&mut ctxt);
+
+    configure_main(tcx, &ctxt)
+}
+
+// Beware, this is duplicated in `libsyntax/entry.rs`, so make sure to keep
+// them in sync.
+fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
+    match item.kind {
+        ItemKind::Fn(..) => {
+            if attr::contains_name(&item.attrs, sym::start) {
+                EntryPointType::Start
+            } else if attr::contains_name(&item.attrs, sym::main) {
+                EntryPointType::MainAttr
+            } else if item.ident.name == sym::main {
+                if at_root {
+                    // This is a top-level function so can be `main`.
+                    EntryPointType::MainNamed
+                } else {
+                    EntryPointType::OtherMain
+                }
+            } else {
+                EntryPointType::None
+            }
+        }
+        _ => EntryPointType::None,
+    }
+}
+
+
+fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
+    match entry_point_type(item, at_root) {
+        EntryPointType::MainNamed => {
+            if ctxt.main_fn.is_none() {
+                ctxt.main_fn = Some((item.hir_id, item.span));
+            } else {
+                span_err!(ctxt.session, item.span, E0136,
+                          "multiple `main` functions");
+            }
+        },
+        EntryPointType::OtherMain => {
+            ctxt.non_main_fns.push((item.hir_id, item.span));
+        },
+        EntryPointType::MainAttr => {
+            if ctxt.attr_main_fn.is_none() {
+                ctxt.attr_main_fn = Some((item.hir_id, item.span));
+            } else {
+                struct_span_err!(ctxt.session, item.span, E0137,
+                                 "multiple functions with a `#[main]` attribute")
+                .span_label(item.span, "additional `#[main]` function")
+                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
+                .emit();
+            }
+        },
+        EntryPointType::Start => {
+            if ctxt.start_fn.is_none() {
+                ctxt.start_fn = Some((item.hir_id, item.span));
+            } else {
+                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
+                    .span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
+                    .span_label(item.span, "multiple `start` functions")
+                    .emit();
+            }
+        }
+        EntryPointType::None => (),
+    }
+}
+
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
+    if let Some((hir_id, _)) = visitor.start_fn {
+        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start))
+    } else if let Some((hir_id, _)) = visitor.attr_main_fn {
+        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
+    } else if let Some((hir_id, _)) = visitor.main_fn {
+        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
+    } else {
+        no_main_err(tcx, visitor);
+        None
+    }
+}
+
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+    // There is no main function.
+    let mut err = struct_err!(tcx.sess, E0601,
+        "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
+    let filename = &tcx.sess.local_crate_source_file;
+    let note = if !visitor.non_main_fns.is_empty() {
+        for &(_, span) in &visitor.non_main_fns {
+            err.span_note(span, "here is a function named `main`");
+        }
+        err.note("you have one or more functions named `main` not defined at the crate level");
+        err.help("either move the `main` function definitions or attach the `#[main]` attribute \
+                  to one of them");
+        // There were some functions named `main` though. Try to give the user a hint.
+        format!("the main function must be defined at the crate level{}",
+                 filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default())
+    } else if let Some(filename) = filename {
+        format!("consider adding a `main` function to `{}`", filename.display())
+    } else {
+        String::from("consider adding a `main` function at the crate level")
+    };
+    let sp = tcx.hir().krate().span;
+    // The file may be empty, which leads to the diagnostic machinery not emitting this
+    // note. This is a relatively simple way to detect that case and emit a span-less
+    // note instead.
+    if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) {
+        err.set_span(sp);
+        err.span_label(sp, &note);
+    } else {
+        err.note(&note);
+    }
+    if tcx.sess.teach(&err.get_code().unwrap()) {
+        err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
+                  to get started: https://doc.rust-lang.org/book/");
+    }
+    err.emit();
+}
+
+pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
+    tcx.entry_fn(LOCAL_CRATE)
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        entry_fn,
+        ..*providers
+    };
+}
index af07c790e2a8799a35e82878719ab7d1af97d0f4..e460e9813b3ee01c547eb5d093f12acdc23ebe86 100644 (file)
@@ -1,12 +1,15 @@
 syntax::register_diagnostics! {
-/*
 E0014: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 Constants can only be initialized by a constant value or, in a future
 version of Rust, a call to a const function. This error indicates the use
 of a path (like a::b, or x) denoting something other than one of these
-allowed items. Erroneous code xample:
+allowed items.
 
-```compile_fail
+Erroneous code example:
+
+```
 const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
 ```
 
 const FOO2: i32 = { 0 }; // but brackets are useless here
 ```
 "##,
-*/
 
 E0130: r##"
 You declared a pattern as an argument in a foreign function declaration.
+
 Erroneous code example:
 
 ```compile_fail
@@ -53,6 +56,81 @@ struct SomeStruct {
 ```
 "##,
 
+// This shouldn't really ever trigger since the repeated value error comes first
+E0136: r##"
+A binary can only have one entry point, and by default that entry point is the
+function `main()`. If there are multiple such functions, please rename one.
+
+Erroneous code example:
+
+```compile_fail,E0136
+fn main() {
+    // ...
+}
+
+// ...
+
+fn main() { // error!
+    // ...
+}
+```
+"##,
+
+E0137: r##"
+More than one function was declared with the `#[main]` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0137
+#![feature(main)]
+
+#[main]
+fn foo() {}
+
+#[main]
+fn f() {} // error: multiple functions with a `#[main]` attribute
+```
+
+This error indicates that the compiler found multiple functions with the
+`#[main]` attribute. This is an error because there must be a unique entry
+point into a Rust program. Example:
+
+```
+#![feature(main)]
+
+#[main]
+fn f() {} // ok!
+```
+"##,
+
+E0138: r##"
+More than one function was declared with the `#[start]` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0138
+#![feature(start)]
+
+#[start]
+fn foo(argc: isize, argv: *const *const u8) -> isize {}
+
+#[start]
+fn f(argc: isize, argv: *const *const u8) -> isize {}
+// error: multiple 'start' functions
+```
+
+This error indicates that the compiler found multiple functions with the
+`#[start]` attribute. This is an error because there must be a unique entry
+point into a Rust program. Example:
+
+```
+#![feature(start)]
+
+#[start]
+fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
+```
+"##,
+
 E0197: r##"
 Inherent implementations (one that do not implement a trait but provide
 methods associated with a type) are always safe because they are not
@@ -198,20 +276,86 @@ fn foo() {}
 ```
 "##,
 
+E0512: r##"
+Transmute with two differently sized types was attempted. Erroneous code
+example:
 
-E0590: r##"
-`break` or `continue` must include a label when used in the condition of a
-`while` loop.
+```compile_fail,E0512
+fn takes_u8(_: u8) {}
 
-Example of erroneous code:
+fn main() {
+    unsafe { takes_u8(::std::mem::transmute(0u16)); }
+    // error: cannot transmute between types of different sizes,
+    //        or dependently-sized types
+}
+```
+
+Please use types with same size or use the expected type directly. Example:
 
-```compile_fail
-while break {}
 ```
+fn takes_u8(_: u8) {}
 
-To fix this, add a label specifying which loop is being broken out of:
+fn main() {
+    unsafe { takes_u8(::std::mem::transmute(0i8)); } // ok!
+    // or:
+    unsafe { takes_u8(0u8); } // ok!
+}
 ```
-'foo: while break 'foo {}
+"##,
+
+E0561: r##"
+A non-ident or non-wildcard pattern has been used as a parameter of a function
+pointer type.
+
+Erroneous code example:
+
+```compile_fail,E0561
+type A1 = fn(mut param: u8); // error!
+type A2 = fn(&param: u32); // error!
+```
+
+When using an alias over a function type, you cannot e.g. denote a parameter as
+being mutable.
+
+To fix the issue, remove patterns (`_` is allowed though). Example:
+
+```
+type A1 = fn(param: u8); // ok!
+type A2 = fn(_: u32); // ok!
+```
+
+You can also omit the parameter name:
+
+```
+type A3 = fn(i16); // ok!
+```
+"##,
+
+E0567: r##"
+Generics have been used on an auto trait.
+
+Erroneous code example:
+
+```compile_fail,E0567
+#![feature(optin_builtin_traits)]
+
+auto trait Generic<T> {} // error!
+
+fn main() {}
+```
+
+Since an auto trait is implemented on all existing types, the
+compiler would not be able to infer the types of the trait's generic
+parameters.
+
+To fix this issue, just remove the generics:
+
+```
+#![feature(optin_builtin_traits)]
+
+auto trait Generic {} // ok!
+
+fn main() {}
 ```
 "##,
 
@@ -249,6 +393,115 @@ fn foo() {}
 ```
 "##,
 
+E0590: r##"
+`break` or `continue` must include a label when used in the condition of a
+`while` loop.
+
+Example of erroneous code:
+
+```compile_fail
+while break {}
+```
+
+To fix this, add a label specifying which loop is being broken out of:
+```
+'foo: while break 'foo {}
+```
+"##,
+
+E0591: r##"
+Per [RFC 401][rfc401], if you have a function declaration `foo`:
+
+```
+// For the purposes of this explanation, all of these
+// different kinds of `fn` declarations are equivalent:
+struct S;
+fn foo(x: S) { /* ... */ }
+# #[cfg(for_demonstration_only)]
+extern "C" { fn foo(x: S); }
+# #[cfg(for_demonstration_only)]
+impl S { fn foo(self) { /* ... */ } }
+```
+
+the type of `foo` is **not** `fn(S)`, as one might expect.
+Rather, it is a unique, zero-sized marker type written here as `typeof(foo)`.
+However, `typeof(foo)` can be _coerced_ to a function pointer `fn(S)`,
+so you rarely notice this:
+
+```
+# struct S;
+# fn foo(_: S) {}
+let x: fn(S) = foo; // OK, coerces
+```
+
+The reason that this matter is that the type `fn(S)` is not specific to
+any particular function: it's a function _pointer_. So calling `x()` results
+in a virtual call, whereas `foo()` is statically dispatched, because the type
+of `foo` tells us precisely what function is being called.
+
+As noted above, coercions mean that most code doesn't have to be
+concerned with this distinction. However, you can tell the difference
+when using **transmute** to convert a fn item into a fn pointer.
+
+This is sometimes done as part of an FFI:
+
+```compile_fail,E0591
+extern "C" fn foo(userdata: Box<i32>) {
+    /* ... */
+}
+
+# fn callback(_: extern "C" fn(*mut i32)) {}
+# use std::mem::transmute;
+# unsafe {
+let f: extern "C" fn(*mut i32) = transmute(foo);
+callback(f);
+# }
+```
+
+Here, transmute is being used to convert the types of the fn arguments.
+This pattern is incorrect because, because the type of `foo` is a function
+**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
+is a function pointer, which is not zero-sized.
+This pattern should be rewritten. There are a few possible ways to do this:
+
+- change the original fn declaration to match the expected signature,
+  and do the cast in the fn body (the preferred option)
+- cast the fn item fo a fn pointer before calling transmute, as shown here:
+
+    ```
+    # extern "C" fn foo(_: Box<i32>) {}
+    # use std::mem::transmute;
+    # unsafe {
+    let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_));
+    let f: extern "C" fn(*mut i32) = transmute(foo as usize); // works too
+    # }
+    ```
+
+The same applies to transmutes to `*mut fn()`, which were observed in practice.
+Note though that use of this type is generally incorrect.
+The intention is typically to describe a function pointer, but just `fn()`
+alone suffices for that. `*mut fn()` is a pointer to a fn pointer.
+(Since these values are typically just passed to C code, however, this rarely
+makes a difference in practice.)
+
+[rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+"##,
+
+E0601: r##"
+No `main` function was found in a binary crate. To fix this error, add a
+`main` function. For example:
+
+```
+fn main() {
+    // Your program will start here.
+    println!("Hello world!");
+}
+```
+
+If you don't know the basics of Rust, you can go look to the Rust Book to get
+started: https://doc.rust-lang.org/book/
+"##,
+
 E0642: r##"
 Trait methods currently cannot take patterns as arguments.
 
@@ -319,11 +572,10 @@ async fn foo() {}
 
 Switch to the Rust 2018 edition to use `async fn`.
 "##,
+
 ;
     E0226, // only a single explicit lifetime bound is permitted
     E0472, // asm! is unsupported on this target
-    E0561, // patterns aren't allowed in function pointer types
-    E0567, // auto traits can not have generic parameters
     E0568, // auto traits can not have super traits
     E0666, // nested `impl Trait` is illegal
     E0667, // `impl Trait` in projections
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
new file mode 100644 (file)
index 0000000..91a7e9f
--- /dev/null
@@ -0,0 +1,170 @@
+use rustc::hir::def::{Res, DefKind};
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{LayoutError, Pointer, SizeSkeleton, VariantIdx};
+use rustc::ty::query::Providers;
+
+use rustc_target::spec::abi::Abi::RustIntrinsic;
+use rustc_index::vec::Idx;
+use syntax_pos::{Span, sym};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::hir;
+
+fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
+    tcx.hir().visit_item_likes_in_module(
+        module_def_id,
+        &mut ItemVisitor { tcx }.as_deep_visitor()
+    );
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        check_mod_intrinsics,
+        ..*providers
+    };
+}
+
+struct ItemVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+struct ExprVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    tables: &'tcx ty::TypeckTables<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    let (def, substs) = match ty.kind {
+        ty::Adt(def, substs) => (def, substs),
+        _ => return ty
+    };
+
+    if def.variants.len() == 2 && !def.repr.c() && def.repr.int.is_none() {
+        let data_idx;
+
+        let one = VariantIdx::new(1);
+        let zero = VariantIdx::new(0);
+
+        if def.variants[zero].fields.is_empty() {
+            data_idx = one;
+        } else if def.variants[one].fields.is_empty() {
+            data_idx = zero;
+        } else {
+            return ty;
+        }
+
+        if def.variants[data_idx].fields.len() == 1 {
+            return def.variants[data_idx].fields[0].ty(tcx, substs);
+        }
+    }
+
+    ty
+}
+
+impl ExprVisitor<'tcx> {
+    fn def_id_is_transmute(&self, def_id: DefId) -> bool {
+        self.tcx.fn_sig(def_id).abi() == RustIntrinsic &&
+        self.tcx.item_name(def_id) == sym::transmute
+    }
+
+    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
+        let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
+        let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
+
+        // Check for same size using the skeletons.
+        if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+            if sk_from.same_size(sk_to) {
+                return;
+            }
+
+            // Special-case transmutting from `typeof(function)` and
+            // `Option<typeof(function)>` to present a clearer error.
+            let from = unpack_option_like(self.tcx, from);
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) {
+                if size_to == Pointer.size(&self.tcx) {
+                    struct_span_err!(self.tcx.sess, span, E0591,
+                                     "can't transmute zero-sized type")
+                        .note(&format!("source type: {}", from))
+                        .note(&format!("target type: {}", to))
+                        .help("cast with `as` to a pointer instead")
+                        .emit();
+                    return;
+                }
+            }
+        }
+
+        // Try to display a sensible error with as much information as possible.
+        let skeleton_string = |ty: Ty<'tcx>, sk| {
+            match sk {
+                Ok(SizeSkeleton::Known(size)) => {
+                    format!("{} bits", size.bits())
+                }
+                Ok(SizeSkeleton::Pointer { tail, .. }) => {
+                    format!("pointer to `{}`", tail)
+                }
+                Err(LayoutError::Unknown(bad)) => {
+                    if bad == ty {
+                        "this type does not have a fixed size".to_owned()
+                    } else {
+                        format!("size can vary because of {}", bad)
+                    }
+                }
+                Err(err) => err.to_string()
+            }
+        };
+
+        let mut err = struct_span_err!(self.tcx.sess, span, E0512,
+                                       "cannot transmute between types of different sizes, \
+                                        or dependently-sized types");
+        if from == to {
+            err.note(&format!("`{}` does not have a fixed size", from));
+        } else {
+            err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+                .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+        }
+        err.emit()
+    }
+}
+
+impl Visitor<'tcx> for ItemVisitor<'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
+        let body = self.tcx.hir().body(body_id);
+        let param_env = self.tcx.param_env(owner_def_id);
+        let tables = self.tcx.typeck_tables_of(owner_def_id);
+        ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
+        self.visit_body(body);
+    }
+}
+
+impl Visitor<'tcx> for ExprVisitor<'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+        let res = if let hir::ExprKind::Path(ref qpath) = expr.kind {
+            self.tables.qpath_res(qpath, expr.hir_id)
+        } else {
+            Res::Err
+        };
+        if let Res::Def(DefKind::Fn, did) = res {
+            if self.def_id_is_transmute(did) {
+                let typ = self.tables.node_type(expr.hir_id);
+                let sig = typ.fn_sig(self.tcx);
+                let from = sig.inputs().skip_binder()[0];
+                let to = *sig.output().skip_binder();
+                self.check_transmute(expr.span, from, to);
+            }
+        }
+
+        intravisit::walk_expr(self, expr);
+    }
+}
index 6c7958fb365dd1ddac040a0b202583642a59a1e4..db59d8e101f77df07c0655f3e7bc5c761196cd7a 100644 (file)
 
 #[macro_use]
 extern crate rustc;
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate syntax;
 
 use rustc::ty::query::Providers;
 
 pub mod hir_stats;
 pub mod layout_test;
 pub mod loops;
+pub mod dead;
+pub mod entry;
+mod liveness;
+mod intrinsicck;
 
 pub fn provide(providers: &mut Providers<'_>) {
+    entry::provide(providers);
     loops::provide(providers);
+    liveness::provide(providers);
+    intrinsicck::provide(providers);
 }
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
new file mode 100644 (file)
index 0000000..fb06808
--- /dev/null
@@ -0,0 +1,1568 @@
+//! A classic liveness analysis based on dataflow over the AST. Computes,
+//! for each local variable in a function, whether that variable is live
+//! at a given point. Program execution points are identified by their
+//! IDs.
+//!
+//! # Basic idea
+//!
+//! The basic model is that each local variable is assigned an index. We
+//! represent sets of local variables using a vector indexed by this
+//! index. The value in the vector is either 0, indicating the variable
+//! is dead, or the ID of an expression that uses the variable.
+//!
+//! We conceptually walk over the AST in reverse execution order. If we
+//! find a use of a variable, we add it to the set of live variables. If
+//! we find an assignment to a variable, we remove it from the set of live
+//! variables. When we have to merge two flows, we take the union of
+//! those two flows -- if the variable is live on both paths, we simply
+//! pick one ID. In the event of loops, we continue doing this until a
+//! fixed point is reached.
+//!
+//! ## Checking initialization
+//!
+//! At the function entry point, all variables must be dead. If this is
+//! not the case, we can report an error using the ID found in the set of
+//! live variables, which identifies a use of the variable which is not
+//! dominated by an assignment.
+//!
+//! ## Checking moves
+//!
+//! After each explicit move, the variable must be dead.
+//!
+//! ## Computing last uses
+//!
+//! Any use of the variable where the variable is dead afterwards is a
+//! last use.
+//!
+//! # Implementation details
+//!
+//! The actual implementation contains two (nested) walks over the AST.
+//! The outer walk has the job of building up the ir_maps instance for the
+//! enclosing function. On the way down the tree, it identifies those AST
+//! nodes and variable IDs that will be needed for the liveness analysis
+//! and assigns them contiguous IDs. The liveness ID for an AST node is
+//! called a `live_node` (it's a newtype'd `u32`) and the ID for a variable
+//! is called a `variable` (another newtype'd `u32`).
+//!
+//! On the way back up the tree, as we are about to exit from a function
+//! declaration we allocate a `liveness` instance. Now that we know
+//! precisely how many nodes and variables we need, we can allocate all
+//! the various arrays that we will need to precisely the right size. We then
+//! perform the actual propagation on the `liveness` instance.
+//!
+//! This propagation is encoded in the various `propagate_through_*()`
+//! methods. It effectively does a reverse walk of the AST; whenever we
+//! reach a loop node, we iterate until a fixed point is reached.
+//!
+//! ## The `RWU` struct
+//!
+//! At each live node `N`, we track three pieces of information for each
+//! variable `V` (these are encapsulated in the `RWU` struct):
+//!
+//! - `reader`: the `LiveNode` ID of some node which will read the value
+//!    that `V` holds on entry to `N`. Formally: a node `M` such
+//!    that there exists a path `P` from `N` to `M` where `P` does not
+//!    write `V`. If the `reader` is `invalid_node()`, then the current
+//!    value will never be read (the variable is dead, essentially).
+//!
+//! - `writer`: the `LiveNode` ID of some node which will write the
+//!    variable `V` and which is reachable from `N`. Formally: a node `M`
+//!    such that there exists a path `P` from `N` to `M` and `M` writes
+//!    `V`. If the `writer` is `invalid_node()`, then there is no writer
+//!    of `V` that follows `N`.
+//!
+//! - `used`: a boolean value indicating whether `V` is *used*. We
+//!   distinguish a *read* from a *use* in that a *use* is some read that
+//!   is not just used to generate a new value. For example, `x += 1` is
+//!   a read but not a use. This is used to generate better warnings.
+//!
+//! ## Special Variables
+//!
+//! We generate various special variables for various, well, special purposes.
+//! These are described in the `specials` struct:
+//!
+//! - `exit_ln`: a live node that is generated to represent every 'exit' from
+//!   the function, whether it be by explicit return, panic, or other means.
+//!
+//! - `fallthrough_ln`: a live node that represents a fallthrough
+//!
+//! - `clean_exit_var`: a synthetic variable that is only 'read' from the
+//!   fallthrough node. It is only live if the function could converge
+//!   via means other than an explicit `return` expression. That is, it is
+//!   only dead if the end of the function's block can never be reached.
+//!   It is the responsibility of typeck to ensure that there are no
+//!   `return` expressions in a function declared as diverging.
+
+use self::LiveNodeKind::*;
+use self::VarKind::*;
+
+use rustc::hir;
+use rustc::hir::{Expr, HirId};
+use rustc::hir::def::*;
+use rustc::hir::def_id::DefId;
+use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
+use rustc::hir::Node;
+use rustc::hir::ptr::P;
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::query::Providers;
+use rustc::lint;
+use rustc::util::nodemap::{HirIdMap, HirIdSet};
+
+use errors::Applicability;
+use rustc_data_structures::fx::FxIndexMap;
+use std::collections::VecDeque;
+use std::{fmt, u32};
+use std::io::prelude::*;
+use std::io;
+use std::rc::Rc;
+use syntax::ast;
+use syntax::symbol::sym;
+use syntax_pos::Span;
+
+#[derive(Copy, Clone, PartialEq)]
+struct Variable(u32);
+
+#[derive(Copy, Clone, PartialEq)]
+struct LiveNode(u32);
+
+impl Variable {
+    fn get(&self) -> usize { self.0 as usize }
+}
+
+impl LiveNode {
+    fn get(&self) -> usize { self.0 as usize }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+enum LiveNodeKind {
+    UpvarNode(Span),
+    ExprNode(Span),
+    VarDefNode(Span),
+    ExitNode
+}
+
+fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
+    let cm = tcx.sess.source_map();
+    match lnk {
+        UpvarNode(s) => {
+            format!("Upvar node [{}]", cm.span_to_string(s))
+        }
+        ExprNode(s) => {
+            format!("Expr node [{}]", cm.span_to_string(s))
+        }
+        VarDefNode(s) => {
+            format!("Var def node [{}]", cm.span_to_string(s))
+        }
+        ExitNode => "Exit node".to_owned(),
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
+    }
+
+    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
+                b: hir::BodyId, s: Span, id: HirId) {
+        visit_fn(self, fk, fd, b, s, id);
+    }
+
+    fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
+    fn visit_expr(&mut self, ex: &'tcx Expr) { visit_expr(self, ex); }
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); }
+}
+
+fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
+    tcx.hir().visit_item_likes_in_module(
+        module_def_id,
+        &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
+    );
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        check_mod_liveness,
+        ..*providers
+    };
+}
+
+impl fmt::Debug for LiveNode {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ln({})", self.get())
+    }
+}
+
+impl fmt::Debug for Variable {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "v({})", self.get())
+    }
+}
+
+// ______________________________________________________________________
+// Creating ir_maps
+//
+// This is the first pass and the one that drives the main
+// computation.  It walks up and down the IR once.  On the way down,
+// we count for each function the number of variables as well as
+// liveness nodes.  A liveness node is basically an expression or
+// capture clause that does something of interest: either it has
+// interesting control flow or it uses/defines a local variable.
+//
+// On the way back up, at each function node we create liveness sets
+// (we now know precisely how big to make our various vectors and so
+// forth) and then do the data-flow propagation to compute the set
+// of live variables at each program point.
+//
+// Finally, we run back over the IR one last time and, using the
+// computed liveness, check various safety conditions.  For example,
+// there must be no live nodes at the definition site for a variable
+// unless it has an initializer.  Similarly, each non-mutable local
+// variable must not be assigned if there is some successor
+// assignment.  And so forth.
+
+impl LiveNode {
+    fn is_valid(&self) -> bool {
+        self.0 != u32::MAX
+    }
+}
+
+fn invalid_node() -> LiveNode { LiveNode(u32::MAX) }
+
+struct CaptureInfo {
+    ln: LiveNode,
+    var_hid: HirId
+}
+
+#[derive(Copy, Clone, Debug)]
+struct LocalInfo {
+    id: HirId,
+    name: ast::Name,
+    is_shorthand: bool,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum VarKind {
+    Param(HirId, ast::Name),
+    Local(LocalInfo),
+    CleanExit
+}
+
+struct IrMaps<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body_owner: DefId,
+    num_live_nodes: usize,
+    num_vars: usize,
+    live_node_map: HirIdMap<LiveNode>,
+    variable_map: HirIdMap<Variable>,
+    capture_info_map: HirIdMap<Rc<Vec<CaptureInfo>>>,
+    var_kinds: Vec<VarKind>,
+    lnks: Vec<LiveNodeKind>,
+}
+
+impl IrMaps<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> {
+        IrMaps {
+            tcx,
+            body_owner,
+            num_live_nodes: 0,
+            num_vars: 0,
+            live_node_map: HirIdMap::default(),
+            variable_map: HirIdMap::default(),
+            capture_info_map: Default::default(),
+            var_kinds: Vec::new(),
+            lnks: Vec::new(),
+        }
+    }
+
+    fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode {
+        let ln = LiveNode(self.num_live_nodes as u32);
+        self.lnks.push(lnk);
+        self.num_live_nodes += 1;
+
+        debug!("{:?} is of kind {}", ln,
+               live_node_kind_to_string(lnk, self.tcx));
+
+        ln
+    }
+
+    fn add_live_node_for_node(&mut self, hir_id: HirId, lnk: LiveNodeKind) {
+        let ln = self.add_live_node(lnk);
+        self.live_node_map.insert(hir_id, ln);
+
+        debug!("{:?} is node {:?}", ln, hir_id);
+    }
+
+    fn add_variable(&mut self, vk: VarKind) -> Variable {
+        let v = Variable(self.num_vars as u32);
+        self.var_kinds.push(vk);
+        self.num_vars += 1;
+
+        match vk {
+            Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => {
+                self.variable_map.insert(node_id, v);
+            },
+            CleanExit => {}
+        }
+
+        debug!("{:?} is {:?}", v, vk);
+
+        v
+    }
+
+    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
+        match self.variable_map.get(&hir_id) {
+            Some(&var) => var,
+            None => {
+                span_bug!(span, "no variable registered for id {:?}", hir_id);
+            }
+        }
+    }
+
+    fn variable_name(&self, var: Variable) -> String {
+        match self.var_kinds[var.get()] {
+            Local(LocalInfo { name, .. }) | Param(_, name) => {
+                name.to_string()
+            },
+            CleanExit => "<clean-exit>".to_owned()
+        }
+    }
+
+    fn variable_is_shorthand(&self, var: Variable) -> bool {
+        match self.var_kinds[var.get()] {
+            Local(LocalInfo { is_shorthand, .. }) => is_shorthand,
+            Param(..) | CleanExit => false
+        }
+    }
+
+    fn set_captures(&mut self, hir_id: HirId, cs: Vec<CaptureInfo>) {
+        self.capture_info_map.insert(hir_id, Rc::new(cs));
+    }
+
+    fn lnk(&self, ln: LiveNode) -> LiveNodeKind {
+        self.lnks[ln.get()]
+    }
+}
+
+fn visit_fn<'tcx>(
+    ir: &mut IrMaps<'tcx>,
+    fk: FnKind<'tcx>,
+    decl: &'tcx hir::FnDecl,
+    body_id: hir::BodyId,
+    sp: Span,
+    id: hir::HirId,
+) {
+    debug!("visit_fn");
+
+    // swap in a new set of IR maps for this function body:
+    let def_id = ir.tcx.hir().local_def_id(id);
+    let mut fn_maps = IrMaps::new(ir.tcx, def_id);
+
+    // Don't run unused pass for #[derive()]
+    if let FnKind::Method(..) = fk {
+        let parent = ir.tcx.hir().get_parent_item(id);
+        if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) {
+            if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) {
+                return;
+            }
+        }
+    }
+
+    debug!("creating fn_maps: {:p}", &fn_maps);
+
+    let body = ir.tcx.hir().body(body_id);
+
+    for param in &body.params {
+        let is_shorthand = match param.pat.kind {
+            rustc::hir::PatKind::Struct(..) => true,
+            _ => false,
+        };
+        param.pat.each_binding(|_bm, hir_id, _x, ident| {
+            debug!("adding parameters {:?}", hir_id);
+            let var = if is_shorthand {
+                Local(LocalInfo {
+                    id: hir_id,
+                    name: ident.name,
+                    is_shorthand: true,
+                })
+            } else {
+                Param(hir_id, ident.name)
+            };
+            fn_maps.add_variable(var);
+        })
+    };
+
+    // gather up the various local variables, significant expressions,
+    // and so forth:
+    intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
+
+    // compute liveness
+    let mut lsets = Liveness::new(&mut fn_maps, body_id);
+    let entry_ln = lsets.compute(&body.value);
+
+    // check for various error conditions
+    lsets.visit_body(body);
+    lsets.warn_about_unused_args(body, entry_ln);
+}
+
+fn add_from_pat(ir: &mut IrMaps<'_>, pat: &P<hir::Pat>) {
+    // For struct patterns, take note of which fields used shorthand
+    // (`x` rather than `x: x`).
+    let mut shorthand_field_ids = HirIdSet::default();
+    let mut pats = VecDeque::new();
+    pats.push_back(pat);
+    while let Some(pat) = pats.pop_front() {
+        use rustc::hir::PatKind::*;
+        match &pat.kind {
+            Binding(.., inner_pat) => {
+                pats.extend(inner_pat.iter());
+            }
+            Struct(_, fields, _) => {
+                let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
+                shorthand_field_ids.extend(ids);
+            }
+            Ref(inner_pat, _) | Box(inner_pat) => {
+                pats.push_back(inner_pat);
+            }
+            TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
+                pats.extend(inner_pats.iter());
+            }
+            Slice(pre_pats, inner_pat, post_pats) => {
+                pats.extend(pre_pats.iter());
+                pats.extend(inner_pat.iter());
+                pats.extend(post_pats.iter());
+            }
+            _ => {}
+        }
+    }
+
+    pat.each_binding(|_, hir_id, _, ident| {
+        ir.add_live_node_for_node(hir_id, VarDefNode(ident.span));
+        ir.add_variable(Local(LocalInfo {
+            id: hir_id,
+            name: ident.name,
+            is_shorthand: shorthand_field_ids.contains(&hir_id)
+        }));
+    });
+}
+
+fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local) {
+    add_from_pat(ir, &local.pat);
+    intravisit::walk_local(ir, local);
+}
+
+fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm) {
+    add_from_pat(ir, &arm.pat);
+    intravisit::walk_arm(ir, arm);
+}
+
+fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr) {
+    match expr.kind {
+      // live nodes required for uses or definitions of variables:
+      hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
+        debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
+        if let Res::Local(var_hir_id) = path.res {
+            let upvars = ir.tcx.upvars(ir.body_owner);
+            if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) {
+                ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+            }
+        }
+        intravisit::walk_expr(ir, expr);
+      }
+      hir::ExprKind::Closure(..) => {
+        // Interesting control flow (for loops can contain labeled
+        // breaks or continues)
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+
+        // Make a live_node for each captured variable, with the span
+        // being the location that the variable is used.  This results
+        // in better error messages than just pointing at the closure
+        // construction site.
+        let mut call_caps = Vec::new();
+        let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id);
+        if let Some(upvars) = ir.tcx.upvars(closure_def_id) {
+            let parent_upvars = ir.tcx.upvars(ir.body_owner);
+            call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| {
+                let has_parent = parent_upvars
+                    .map_or(false, |upvars| upvars.contains_key(&var_id));
+                if !has_parent {
+                    let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
+                    Some(CaptureInfo { ln: upvar_ln, var_hid: var_id })
+                } else {
+                    None
+                }
+            }));
+        }
+        ir.set_captures(expr.hir_id, call_caps);
+        let old_body_owner = ir.body_owner;
+        ir.body_owner = closure_def_id;
+        intravisit::walk_expr(ir, expr);
+        ir.body_owner = old_body_owner;
+      }
+
+      // live nodes required for interesting control flow:
+      hir::ExprKind::Match(..) |
+      hir::ExprKind::Loop(..) => {
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+        intravisit::walk_expr(ir, expr);
+      }
+      hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => {
+        ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+        intravisit::walk_expr(ir, expr);
+      }
+
+      // otherwise, live nodes are not required:
+      hir::ExprKind::Index(..) |
+      hir::ExprKind::Field(..) |
+      hir::ExprKind::Array(..) |
+      hir::ExprKind::Call(..) |
+      hir::ExprKind::MethodCall(..) |
+      hir::ExprKind::Tup(..) |
+      hir::ExprKind::Binary(..) |
+      hir::ExprKind::AddrOf(..) |
+      hir::ExprKind::Cast(..) |
+      hir::ExprKind::DropTemps(..) |
+      hir::ExprKind::Unary(..) |
+      hir::ExprKind::Break(..) |
+      hir::ExprKind::Continue(_) |
+      hir::ExprKind::Lit(_) |
+      hir::ExprKind::Ret(..) |
+      hir::ExprKind::Block(..) |
+      hir::ExprKind::Assign(..) |
+      hir::ExprKind::AssignOp(..) |
+      hir::ExprKind::Struct(..) |
+      hir::ExprKind::Repeat(..) |
+      hir::ExprKind::InlineAsm(..) |
+      hir::ExprKind::Box(..) |
+      hir::ExprKind::Yield(..) |
+      hir::ExprKind::Type(..) |
+      hir::ExprKind::Err |
+      hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
+          intravisit::walk_expr(ir, expr);
+      }
+    }
+}
+
+// ______________________________________________________________________
+// Computing liveness sets
+//
+// Actually we compute just a bit more than just liveness, but we use
+// the same basic propagation framework in all cases.
+
+#[derive(Clone, Copy)]
+struct RWU {
+    reader: LiveNode,
+    writer: LiveNode,
+    used: bool
+}
+
+/// Conceptually, this is like a `Vec<RWU>`. But the number of `RWU`s can get
+/// very large, so it uses a more compact representation that takes advantage
+/// of the fact that when the number of `RWU`s is large, most of them have an
+/// invalid reader and an invalid writer.
+struct RWUTable {
+    /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or
+    /// an index into `unpacked_rwus`. In the common cases, this compacts the
+    /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits
+    /// in 96.
+    ///
+    /// More compact representations are possible -- e.g., use only 2 bits per
+    /// packed `RWU` and make the secondary table a HashMap that maps from
+    /// indices to `RWU`s -- but this one strikes a good balance between size
+    /// and speed.
+    packed_rwus: Vec<u32>,
+    unpacked_rwus: Vec<RWU>,
+}
+
+// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`.
+const INV_INV_FALSE: u32 = u32::MAX;
+
+// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`.
+const INV_INV_TRUE: u32 = u32::MAX - 1;
+
+impl RWUTable {
+    fn new(num_rwus: usize) -> RWUTable {
+        Self {
+            packed_rwus: vec![INV_INV_FALSE; num_rwus],
+            unpacked_rwus: vec![],
+        }
+    }
+
+    fn get(&self, idx: usize) -> RWU {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false },
+            INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true },
+            _ => self.unpacked_rwus[packed_rwu as usize],
+        }
+    }
+
+    fn get_reader(&self, idx: usize) -> LiveNode {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
+            _ => self.unpacked_rwus[packed_rwu as usize].reader,
+        }
+    }
+
+    fn get_writer(&self, idx: usize) -> LiveNode {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE | INV_INV_TRUE => invalid_node(),
+            _ => self.unpacked_rwus[packed_rwu as usize].writer,
+        }
+    }
+
+    fn get_used(&self, idx: usize) -> bool {
+        let packed_rwu = self.packed_rwus[idx];
+        match packed_rwu {
+            INV_INV_FALSE => false,
+            INV_INV_TRUE => true,
+            _ => self.unpacked_rwus[packed_rwu as usize].used,
+        }
+    }
+
+    #[inline]
+    fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) {
+        self.packed_rwus[dst_idx] = self.packed_rwus[src_idx];
+    }
+
+    fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
+        if rwu.reader == invalid_node() && rwu.writer == invalid_node() {
+            // When we overwrite an indexing entry in `self.packed_rwus` with
+            // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
+            // from `self.unpacked_rwus`; it's not worth the effort, and we
+            // can't have entries shifting around anyway.
+            self.packed_rwus[idx] = if rwu.used {
+                INV_INV_TRUE
+            } else {
+                INV_INV_FALSE
+            }
+        } else {
+            // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]`
+            // point to it.
+            self.packed_rwus[idx] = self.unpacked_rwus.len() as u32;
+            self.unpacked_rwus.push(rwu);
+        }
+    }
+
+    fn assign_inv_inv(&mut self, idx: usize) {
+        self.packed_rwus[idx] = if self.get_used(idx) {
+            INV_INV_TRUE
+        } else {
+            INV_INV_FALSE
+        };
+    }
+}
+
+#[derive(Copy, Clone)]
+struct Specials {
+    exit_ln: LiveNode,
+    fallthrough_ln: LiveNode,
+    clean_exit_var: Variable
+}
+
+const ACC_READ: u32 = 1;
+const ACC_WRITE: u32 = 2;
+const ACC_USE: u32 = 4;
+
+struct Liveness<'a, 'tcx> {
+    ir: &'a mut IrMaps<'tcx>,
+    tables: &'a ty::TypeckTables<'tcx>,
+    s: Specials,
+    successors: Vec<LiveNode>,
+    rwu_table: RWUTable,
+
+    // mappings from loop node ID to LiveNode
+    // ("break" label should map to loop node ID,
+    // it probably doesn't now)
+    break_ln: HirIdMap<LiveNode>,
+    cont_ln: HirIdMap<LiveNode>,
+}
+
+impl<'a, 'tcx> Liveness<'a, 'tcx> {
+    fn new(ir: &'a mut IrMaps<'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
+        // Special nodes and variables:
+        // - exit_ln represents the end of the fn, either by return or panic
+        // - implicit_ret_var is a pseudo-variable that represents
+        //   an implicit return
+        let specials = Specials {
+            exit_ln: ir.add_live_node(ExitNode),
+            fallthrough_ln: ir.add_live_node(ExitNode),
+            clean_exit_var: ir.add_variable(CleanExit)
+        };
+
+        let tables = ir.tcx.body_tables(body);
+
+        let num_live_nodes = ir.num_live_nodes;
+        let num_vars = ir.num_vars;
+
+        Liveness {
+            ir,
+            tables,
+            s: specials,
+            successors: vec![invalid_node(); num_live_nodes],
+            rwu_table: RWUTable::new(num_live_nodes * num_vars),
+            break_ln: Default::default(),
+            cont_ln: Default::default(),
+        }
+    }
+
+    fn live_node(&self, hir_id: HirId, span: Span) -> LiveNode {
+        match self.ir.live_node_map.get(&hir_id) {
+          Some(&ln) => ln,
+          None => {
+            // This must be a mismatch between the ir_map construction
+            // above and the propagation code below; the two sets of
+            // code have to agree about which AST nodes are worth
+            // creating liveness nodes for.
+            span_bug!(
+                span,
+                "no live node registered for node {:?}",
+                hir_id);
+          }
+        }
+    }
+
+    fn variable(&self, hir_id: HirId, span: Span) -> Variable {
+        self.ir.variable(hir_id, span)
+    }
+
+    fn define_bindings_in_pat(&mut self, pat: &hir::Pat, mut succ: LiveNode) -> LiveNode {
+        // In an or-pattern, only consider the first pattern; any later patterns
+        // must have the same bindings, and we also consider the first pattern
+        // to be the "authoritative" set of ids.
+        pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| {
+            let ln = self.live_node(hir_id, pat_sp);
+            let var = self.variable(hir_id, ident.span);
+            self.init_from_succ(ln, succ);
+            self.define(ln, var);
+            succ = ln;
+        });
+        succ
+    }
+
+    fn idx(&self, ln: LiveNode, var: Variable) -> usize {
+        ln.get() * self.ir.num_vars + var.get()
+    }
+
+    fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
+        assert!(ln.is_valid());
+        let reader = self.rwu_table.get_reader(self.idx(ln, var));
+        if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None }
+    }
+
+    // Is this variable live on entry to any of its successor nodes?
+    fn live_on_exit(&self, ln: LiveNode, var: Variable)
+                    -> Option<LiveNodeKind> {
+        let successor = self.successors[ln.get()];
+        self.live_on_entry(successor, var)
+    }
+
+    fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
+        assert!(ln.is_valid());
+        self.rwu_table.get_used(self.idx(ln, var))
+    }
+
+    fn assigned_on_entry(&self, ln: LiveNode, var: Variable)
+                         -> Option<LiveNodeKind> {
+        assert!(ln.is_valid());
+        let writer = self.rwu_table.get_writer(self.idx(ln, var));
+        if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None }
+    }
+
+    fn assigned_on_exit(&self, ln: LiveNode, var: Variable)
+                        -> Option<LiveNodeKind> {
+        let successor = self.successors[ln.get()];
+        self.assigned_on_entry(successor, var)
+    }
+
+    fn indices2<F>(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F) where
+        F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize),
+    {
+        let node_base_idx = self.idx(ln, Variable(0));
+        let succ_base_idx = self.idx(succ_ln, Variable(0));
+        for var_idx in 0..self.ir.num_vars {
+            op(self, node_base_idx + var_idx, succ_base_idx + var_idx);
+        }
+    }
+
+    fn write_vars<F>(&self,
+                     wr: &mut dyn Write,
+                     ln: LiveNode,
+                     mut test: F)
+                     -> io::Result<()> where
+        F: FnMut(usize) -> LiveNode,
+    {
+        let node_base_idx = self.idx(ln, Variable(0));
+        for var_idx in 0..self.ir.num_vars {
+            let idx = node_base_idx + var_idx;
+            if test(idx).is_valid() {
+                write!(wr, " {:?}", Variable(var_idx as u32))?;
+            }
+        }
+        Ok(())
+    }
+
+
+    #[allow(unused_must_use)]
+    fn ln_str(&self, ln: LiveNode) -> String {
+        let mut wr = Vec::new();
+        {
+            let wr = &mut wr as &mut dyn Write;
+            write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln));
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx));
+            write!(wr, "  writes");
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx));
+            write!(wr, "  precedes {:?}]", self.successors[ln.get()]);
+        }
+        String::from_utf8(wr).unwrap()
+    }
+
+    fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
+        self.successors[ln.get()] = succ_ln;
+
+        // It is not necessary to initialize the RWUs here because they are all
+        // set to INV_INV_FALSE when they are created, and the sets only grow
+        // during iterations.
+    }
+
+    fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
+        // more efficient version of init_empty() / merge_from_succ()
+        self.successors[ln.get()] = succ_ln;
+
+        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
+            this.rwu_table.copy_packed(idx, succ_idx);
+        });
+        debug!("init_from_succ(ln={}, succ={})",
+               self.ln_str(ln), self.ln_str(succ_ln));
+    }
+
+    fn merge_from_succ(&mut self,
+                       ln: LiveNode,
+                       succ_ln: LiveNode,
+                       first_merge: bool)
+                       -> bool {
+        if ln == succ_ln { return false; }
+
+        let mut changed = false;
+        self.indices2(ln, succ_ln, |this, idx, succ_idx| {
+            let mut rwu = this.rwu_table.get(idx);
+            let succ_rwu = this.rwu_table.get(succ_idx);
+            if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
+                rwu.reader = succ_rwu.reader;
+                changed = true
+            }
+
+            if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
+                rwu.writer = succ_rwu.writer;
+                changed = true
+            }
+
+            if succ_rwu.used && !rwu.used {
+                rwu.used = true;
+                changed = true;
+            }
+
+            if changed {
+                this.rwu_table.assign_unpacked(idx, rwu);
+            }
+        });
+
+        debug!("merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})",
+               ln, self.ln_str(succ_ln), first_merge, changed);
+        return changed;
+    }
+
+    // Indicates that a local variable was *defined*; we know that no
+    // uses of the variable can precede the definition (resolve checks
+    // this) so we just clear out all the data.
+    fn define(&mut self, writer: LiveNode, var: Variable) {
+        let idx = self.idx(writer, var);
+        self.rwu_table.assign_inv_inv(idx);
+
+        debug!("{:?} defines {:?} (idx={}): {}", writer, var,
+               idx, self.ln_str(writer));
+    }
+
+    // Either read, write, or both depending on the acc bitset
+    fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) {
+        debug!("{:?} accesses[{:x}] {:?}: {}",
+               ln, acc, var, self.ln_str(ln));
+
+        let idx = self.idx(ln, var);
+        let mut rwu = self.rwu_table.get(idx);
+
+        if (acc & ACC_WRITE) != 0 {
+            rwu.reader = invalid_node();
+            rwu.writer = ln;
+        }
+
+        // Important: if we both read/write, must do read second
+        // or else the write will override.
+        if (acc & ACC_READ) != 0 {
+            rwu.reader = ln;
+        }
+
+        if (acc & ACC_USE) != 0 {
+            rwu.used = true;
+        }
+
+        self.rwu_table.assign_unpacked(idx, rwu);
+    }
+
+    fn compute(&mut self, body: &hir::Expr) -> LiveNode {
+        debug!("compute: using id for body, {}",
+               self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));
+
+        // the fallthrough exit is only for those cases where we do not
+        // explicitly return:
+        let s = self.s;
+        self.init_from_succ(s.fallthrough_ln, s.exit_ln);
+        self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ);
+
+        let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln);
+
+        // hack to skip the loop unless debug! is enabled:
+        debug!("^^ liveness computation results for body {} (entry={:?})", {
+                   for ln_idx in 0..self.ir.num_live_nodes {
+                        debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32)));
+                   }
+                   body.hir_id
+               },
+               entry_ln);
+
+        entry_ln
+    }
+
+    fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
+                               -> LiveNode {
+        if blk.targeted_by_break {
+            self.break_ln.insert(blk.hir_id, succ);
+        }
+        let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
+        blk.stmts.iter().rev().fold(succ, |succ, stmt| {
+            self.propagate_through_stmt(stmt, succ)
+        })
+    }
+
+    fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode)
+                              -> LiveNode {
+        match stmt.kind {
+            hir::StmtKind::Local(ref local) => {
+                // Note: we mark the variable as defined regardless of whether
+                // there is an initializer.  Initially I had thought to only mark
+                // the live variable as defined if it was initialized, and then we
+                // could check for uninit variables just by scanning what is live
+                // at the start of the function. But that doesn't work so well for
+                // immutable variables defined in a loop:
+                //     loop { let x; x = 5; }
+                // because the "assignment" loops back around and generates an error.
+                //
+                // So now we just check that variables defined w/o an
+                // initializer are not live at the point of their
+                // initialization, which is mildly more complex than checking
+                // once at the func header but otherwise equivalent.
+
+                let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
+                self.define_bindings_in_pat(&local.pat, succ)
+            }
+            hir::StmtKind::Item(..) => succ,
+            hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
+                self.propagate_through_expr(&expr, succ)
+            }
+        }
+    }
+
+    fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
+                               -> LiveNode {
+        exprs.iter().rev().fold(succ, |succ, expr| {
+            self.propagate_through_expr(&expr, succ)
+        })
+    }
+
+    fn propagate_through_opt_expr(&mut self,
+                                  opt_expr: Option<&Expr>,
+                                  succ: LiveNode)
+                                  -> LiveNode {
+        opt_expr.map_or(succ, |expr| self.propagate_through_expr(expr, succ))
+    }
+
+    fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
+                              -> LiveNode {
+        debug!("propagate_through_expr: {}", self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id));
+
+        match expr.kind {
+            // Interesting cases with control flow or which gen/kill
+            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
+                self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
+            }
+
+            hir::ExprKind::Field(ref e, _) => {
+                self.propagate_through_expr(&e, succ)
+            }
+
+            hir::ExprKind::Closure(..) => {
+                debug!("{} is an ExprKind::Closure",
+                       self.ir.tcx.hir().hir_to_pretty_string(expr.hir_id));
+
+                // the construction of a closure itself is not important,
+                // but we have to consider the closed over variables.
+                let caps = self.ir.capture_info_map.get(&expr.hir_id).cloned().unwrap_or_else(||
+                    span_bug!(expr.span, "no registered caps"));
+
+                caps.iter().rev().fold(succ, |succ, cap| {
+                    self.init_from_succ(cap.ln, succ);
+                    let var = self.variable(cap.var_hid, expr.span);
+                    self.acc(cap.ln, var, ACC_READ | ACC_USE);
+                    cap.ln
+                })
+            }
+
+            // Note that labels have been resolved, so we don't need to look
+            // at the label ident
+            hir::ExprKind::Loop(ref blk, _, _) => {
+                self.propagate_through_loop(expr, &blk, succ)
+            }
+
+            hir::ExprKind::Match(ref e, ref arms, _) => {
+                //
+                //      (e)
+                //       |
+                //       v
+                //     (expr)
+                //     / | \
+                //    |  |  |
+                //    v  v  v
+                //   (..arms..)
+                //    |  |  |
+                //    v  v  v
+                //   (  succ  )
+                //
+                //
+                let ln = self.live_node(expr.hir_id, expr.span);
+                self.init_empty(ln, succ);
+                let mut first_merge = true;
+                for arm in arms {
+                    let body_succ = self.propagate_through_expr(&arm.body, succ);
+
+                    let guard_succ = self.propagate_through_opt_expr(
+                        arm.guard.as_ref().map(|hir::Guard::If(e)| &**e),
+                        body_succ
+                    );
+                    let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
+                    self.merge_from_succ(ln, arm_succ, first_merge);
+                    first_merge = false;
+                };
+                self.propagate_through_expr(&e, ln)
+            }
+
+            hir::ExprKind::Ret(ref o_e) => {
+                // ignore succ and subst exit_ln:
+                let exit_ln = self.s.exit_ln;
+                self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
+            }
+
+            hir::ExprKind::Break(label, ref opt_expr) => {
+                // Find which label this break jumps to
+                let target = match label.target_id {
+                    Ok(hir_id) => self.break_ln.get(&hir_id),
+                    Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+                }.cloned();
+
+                // Now that we know the label we're going to,
+                // look it up in the break loop nodes table
+
+                match target {
+                    Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
+                    None => span_bug!(expr.span, "break to unknown label")
+                }
+            }
+
+            hir::ExprKind::Continue(label) => {
+                // Find which label this expr continues to
+                let sc = label.target_id.unwrap_or_else(|err|
+                    span_bug!(expr.span, "loop scope error: {}", err));
+
+                // Now that we know the label we're going to,
+                // look it up in the continue loop nodes table
+                self.cont_ln.get(&sc).cloned().unwrap_or_else(||
+                    span_bug!(expr.span, "continue to unknown label"))
+            }
+
+            hir::ExprKind::Assign(ref l, ref r) => {
+                // see comment on places in
+                // propagate_through_place_components()
+                let succ = self.write_place(&l, succ, ACC_WRITE);
+                let succ = self.propagate_through_place_components(&l, succ);
+                self.propagate_through_expr(&r, succ)
+            }
+
+            hir::ExprKind::AssignOp(_, ref l, ref r) => {
+                // an overloaded assign op is like a method call
+                if self.tables.is_method_call(expr) {
+                    let succ = self.propagate_through_expr(&l, succ);
+                    self.propagate_through_expr(&r, succ)
+                } else {
+                    // see comment on places in
+                    // propagate_through_place_components()
+                    let succ = self.write_place(&l, succ, ACC_WRITE|ACC_READ);
+                    let succ = self.propagate_through_expr(&r, succ);
+                    self.propagate_through_place_components(&l, succ)
+                }
+            }
+
+            // Uninteresting cases: just propagate in rev exec order
+
+            hir::ExprKind::Array(ref exprs) => {
+                self.propagate_through_exprs(exprs, succ)
+            }
+
+            hir::ExprKind::Struct(_, ref fields, ref with_expr) => {
+                let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
+                fields.iter().rev().fold(succ, |succ, field| {
+                    self.propagate_through_expr(&field.expr, succ)
+                })
+            }
+
+            hir::ExprKind::Call(ref f, ref args) => {
+                let m = self.ir.tcx.hir().get_module_parent(expr.hir_id);
+                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
+                    self.s.exit_ln
+                } else {
+                    succ
+                };
+                let succ = self.propagate_through_exprs(args, succ);
+                self.propagate_through_expr(&f, succ)
+            }
+
+            hir::ExprKind::MethodCall(.., ref args) => {
+                let m = self.ir.tcx.hir().get_module_parent(expr.hir_id);
+                let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
+                    self.s.exit_ln
+                } else {
+                    succ
+                };
+
+                self.propagate_through_exprs(args, succ)
+            }
+
+            hir::ExprKind::Tup(ref exprs) => {
+                self.propagate_through_exprs(exprs, succ)
+            }
+
+            hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
+                let r_succ = self.propagate_through_expr(&r, succ);
+
+                let ln = self.live_node(expr.hir_id, expr.span);
+                self.init_from_succ(ln, succ);
+                self.merge_from_succ(ln, r_succ, false);
+
+                self.propagate_through_expr(&l, ln)
+            }
+
+            hir::ExprKind::Index(ref l, ref r) |
+            hir::ExprKind::Binary(_, ref l, ref r) => {
+                let r_succ = self.propagate_through_expr(&r, succ);
+                self.propagate_through_expr(&l, r_succ)
+            }
+
+            hir::ExprKind::Box(ref e) |
+            hir::ExprKind::AddrOf(_, ref e) |
+            hir::ExprKind::Cast(ref e, _) |
+            hir::ExprKind::Type(ref e, _) |
+            hir::ExprKind::DropTemps(ref e) |
+            hir::ExprKind::Unary(_, ref e) |
+            hir::ExprKind::Yield(ref e, _) |
+            hir::ExprKind::Repeat(ref e, _) => {
+                self.propagate_through_expr(&e, succ)
+            }
+
+            hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
+                let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
+                // see comment on places
+                // in propagate_through_place_components()
+                if o.is_indirect {
+                    self.propagate_through_expr(output, succ)
+                } else {
+                    let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
+                    let succ = self.write_place(output, succ, acc);
+                    self.propagate_through_place_components(output, succ)
+                }});
+
+                // Inputs are executed first. Propagate last because of rev order
+                self.propagate_through_exprs(inputs, succ)
+            }
+
+            hir::ExprKind::Lit(..) | hir::ExprKind::Err |
+            hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
+                succ
+            }
+
+            // Note that labels have been resolved, so we don't need to look
+            // at the label ident
+            hir::ExprKind::Block(ref blk, _) => {
+                self.propagate_through_block(&blk, succ)
+            }
+        }
+    }
+
+    fn propagate_through_place_components(&mut self,
+                                          expr: &Expr,
+                                          succ: LiveNode)
+                                          -> LiveNode {
+        // # Places
+        //
+        // In general, the full flow graph structure for an
+        // assignment/move/etc can be handled in one of two ways,
+        // depending on whether what is being assigned is a "tracked
+        // value" or not. A tracked value is basically a local
+        // variable or argument.
+        //
+        // The two kinds of graphs are:
+        //
+        //    Tracked place          Untracked place
+        // ----------------------++-----------------------
+        //                       ||
+        //         |             ||           |
+        //         v             ||           v
+        //     (rvalue)          ||       (rvalue)
+        //         |             ||           |
+        //         v             ||           v
+        // (write of place)     ||   (place components)
+        //         |             ||           |
+        //         v             ||           v
+        //      (succ)           ||        (succ)
+        //                       ||
+        // ----------------------++-----------------------
+        //
+        // I will cover the two cases in turn:
+        //
+        // # Tracked places
+        //
+        // A tracked place is a local variable/argument `x`.  In
+        // these cases, the link_node where the write occurs is linked
+        // to node id of `x`.  The `write_place()` routine generates
+        // the contents of this node.  There are no subcomponents to
+        // consider.
+        //
+        // # Non-tracked places
+        //
+        // These are places like `x[5]` or `x.f`.  In that case, we
+        // basically ignore the value which is written to but generate
+        // reads for the components---`x` in these two examples.  The
+        // components reads are generated by
+        // `propagate_through_place_components()` (this fn).
+        //
+        // # Illegal places
+        //
+        // It is still possible to observe assignments to non-places;
+        // these errors are detected in the later pass borrowck.  We
+        // just ignore such cases and treat them as reads.
+
+        match expr.kind {
+            hir::ExprKind::Path(_) => succ,
+            hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
+            _ => self.propagate_through_expr(expr, succ)
+        }
+    }
+
+    // see comment on propagate_through_place()
+    fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode {
+        match expr.kind {
+            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
+                self.access_path(expr.hir_id, path, succ, acc)
+            }
+
+            // We do not track other places, so just propagate through
+            // to their subcomponents.  Also, it may happen that
+            // non-places occur here, because those are detected in the
+            // later pass borrowck.
+            _ => succ
+        }
+    }
+
+    fn access_var(&mut self, hir_id: HirId, var_hid: HirId, succ: LiveNode, acc: u32, span: Span)
+                  -> LiveNode {
+        let ln = self.live_node(hir_id, span);
+        if acc != 0 {
+            self.init_from_succ(ln, succ);
+            let var = self.variable(var_hid, span);
+            self.acc(ln, var, acc);
+        }
+        ln
+    }
+
+    fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
+                   -> LiveNode {
+        match path.res {
+            Res::Local(hid) => {
+                let upvars = self.ir.tcx.upvars(self.ir.body_owner);
+                if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) {
+                    self.access_var(hir_id, hid, succ, acc, path.span)
+                } else {
+                    succ
+                }
+            }
+            _ => succ
+        }
+    }
+
+    fn propagate_through_loop(
+        &mut self,
+        expr: &Expr,
+        body: &hir::Block,
+        succ: LiveNode
+    ) -> LiveNode {
+        /*
+        We model control flow like this:
+
+              (expr) <-+
+                |      |
+                v      |
+              (body) --+
+
+        Note that a `continue` expression targeting the `loop` will have a successor of `expr`.
+        Meanwhile, a `break` expression will have a successor of `succ`.
+        */
+
+        // first iteration:
+        let mut first_merge = true;
+        let ln = self.live_node(expr.hir_id, expr.span);
+        self.init_empty(ln, succ);
+        debug!("propagate_through_loop: using id for loop body {} {}",
+               expr.hir_id, self.ir.tcx.hir().hir_to_pretty_string(body.hir_id));
+
+        self.break_ln.insert(expr.hir_id, succ);
+
+        self.cont_ln.insert(expr.hir_id, ln);
+
+        let body_ln = self.propagate_through_block(body, ln);
+
+        // repeat until fixed point is reached:
+        while self.merge_from_succ(ln, body_ln, first_merge) {
+            first_merge = false;
+            assert_eq!(body_ln, self.propagate_through_block(body, ln));
+        }
+
+        ln
+    }
+}
+
+// _______________________________________________________________________
+// Checking for error conditions
+
+impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_local(&mut self, local: &'tcx hir::Local) {
+        self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
+            if local.init.is_some() {
+                self.warn_about_dead_assign(spans, hir_id, ln, var);
+            }
+        });
+
+        intravisit::walk_local(self, local);
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
+        check_expr(self, ex);
+    }
+
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
+        self.check_unused_vars_in_pat(&arm.pat, None, |_, _, _, _| {});
+        intravisit::walk_arm(self, arm);
+    }
+}
+
+fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr) {
+    match expr.kind {
+        hir::ExprKind::Assign(ref l, _) => {
+            this.check_place(&l);
+        }
+
+        hir::ExprKind::AssignOp(_, ref l, _) => {
+            if !this.tables.is_method_call(expr) {
+                this.check_place(&l);
+            }
+        }
+
+        hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
+            for input in inputs {
+                this.visit_expr(input);
+            }
+
+            // Output operands must be places
+            for (o, output) in ia.outputs.iter().zip(outputs) {
+                if !o.is_indirect {
+                    this.check_place(output);
+                }
+                this.visit_expr(output);
+            }
+        }
+
+        // no correctness conditions related to liveness
+        hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) |
+        hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) |
+        hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
+        hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
+        hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | hir::ExprKind::Unary(..) |
+        hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) |
+        hir::ExprKind::Lit(_) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
+        hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
+        hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
+        hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {}
+    }
+
+    intravisit::walk_expr(this, expr);
+}
+
+impl<'tcx> Liveness<'_, 'tcx> {
+    fn check_place(&mut self, expr: &'tcx Expr) {
+        match expr.kind {
+            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
+                if let Res::Local(var_hid) = path.res {
+                    let upvars = self.ir.tcx.upvars(self.ir.body_owner);
+                    if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) {
+                        // Assignment to an immutable variable or argument: only legal
+                        // if there is no later assignment. If this local is actually
+                        // mutable, then check for a reassignment to flag the mutability
+                        // as being used.
+                        let ln = self.live_node(expr.hir_id, expr.span);
+                        let var = self.variable(var_hid, expr.span);
+                        self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var);
+                    }
+                }
+            }
+            _ => {
+                // For other kinds of places, no checks are required,
+                // and any embedded expressions are actually rvalues
+                intravisit::walk_expr(self, expr);
+            }
+        }
+    }
+
+    fn should_warn(&self, var: Variable) -> Option<String> {
+        let name = self.ir.variable_name(var);
+        if name.is_empty() || name.as_bytes()[0] == b'_' {
+            None
+        } else {
+            Some(name)
+        }
+    }
+
+    fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
+        for p in &body.params {
+            self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| {
+                if self.live_on_entry(ln, var).is_none() {
+                    self.report_dead_assign(hir_id, spans, var, true);
+                }
+            });
+        }
+    }
+
+    fn check_unused_vars_in_pat(
+        &self,
+        pat: &hir::Pat,
+        entry_ln: Option<LiveNode>,
+        on_used_on_entry: impl Fn(Vec<Span>, HirId, LiveNode, Variable),
+    ) {
+        // In an or-pattern, only consider the variable; any later patterns must have the same
+        // bindings, and we also consider the first pattern to be the "authoritative" set of ids.
+        // However, we should take the spans of variables with the same name from the later
+        // patterns so the suggestions to prefix with underscores will apply to those too.
+        let mut vars: FxIndexMap<String, (LiveNode, Variable, HirId, Vec<Span>)> = <_>::default();
+
+        pat.each_binding(|_, hir_id, pat_sp, ident| {
+            let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp));
+            let var = self.variable(hir_id, ident.span);
+            vars.entry(self.ir.variable_name(var))
+                .and_modify(|(.., spans)| spans.push(ident.span))
+                .or_insert_with(|| (ln, var, hir_id, vec![ident.span]));
+        });
+
+        for (_, (ln, var, id, spans)) in vars {
+            if self.used_on_entry(ln, var) {
+                on_used_on_entry(spans, id, ln, var);
+            } else {
+                self.report_unused(spans, id, ln, var);
+            }
+        }
+    }
+
+    fn report_unused(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
+        if let Some(name) = self.should_warn(var).filter(|name| name != "self") {
+            // annoying: for parameters in funcs like `fn(x: i32)
+            // {ret}`, there is only one node, so asking about
+            // assigned_on_exit() is not meaningful.
+            let is_assigned = if ln == self.s.exit_ln {
+                false
+            } else {
+                self.assigned_on_exit(ln, var).is_some()
+            };
+
+            if is_assigned {
+                self.ir.tcx.lint_hir_note(
+                    lint::builtin::UNUSED_VARIABLES,
+                    hir_id,
+                    spans,
+                    &format!("variable `{}` is assigned to, but never used", name),
+                    &format!("consider using `_{}` instead", name),
+                );
+            } else {
+                let mut err = self.ir.tcx.struct_span_lint_hir(
+                    lint::builtin::UNUSED_VARIABLES,
+                    hir_id,
+                    spans.clone(),
+                    &format!("unused variable: `{}`", name),
+                );
+
+                if self.ir.variable_is_shorthand(var) {
+                    if let Node::Binding(pat) = self.ir.tcx.hir().get(hir_id) {
+                        // Handle `ref` and `ref mut`.
+                        let spans = spans.iter()
+                            .map(|_span| (pat.span, format!("{}: _", name)))
+                            .collect();
+
+                        err.multipart_suggestion(
+                            "try ignoring the field",
+                            spans,
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                } else {
+                    err.multipart_suggestion(
+                        "consider prefixing with an underscore",
+                        spans.iter().map(|span| (*span, format!("_{}", name))).collect(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+
+                err.emit()
+            }
+        }
+    }
+
+    fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
+        if self.live_on_exit(ln, var).is_none() {
+            self.report_dead_assign(hir_id, spans, var, false);
+        }
+    }
+
+    fn report_dead_assign(&self, hir_id: HirId, spans: Vec<Span>, var: Variable, is_param: bool) {
+        if let Some(name) = self.should_warn(var) {
+            if is_param {
+                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
+                &format!("value passed to `{}` is never read", name))
+                .help("maybe it is overwritten before being read?")
+                .emit();
+            } else {
+                self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, spans,
+                &format!("value assigned to `{}` is never read", name))
+                .help("maybe it is overwritten before being read?")
+                .emit();
+            }
+        }
+    }
+}
index 67066466f1d222d0d0af63a786a193a46f45f137..03afb547d3a226a54faa166b91bf8673bb20b2ad 100644 (file)
@@ -1,8 +1,9 @@
 syntax::register_diagnostics! {
 
 E0445: r##"
-A private trait was used on a public type parameter bound. Erroneous code
-examples:
+A private trait was used on a public type parameter bound.
+
+Erroneous code examples:
 
 ```compile_fail,E0445
 #![deny(private_in_public)]
@@ -32,7 +33,9 @@ pub fn foo<T: Foo> (t: T) {} // ok!
 "##,
 
 E0446: r##"
-A private type was used in a public type signature. Erroneous code example:
+A private type was used in a public type signature.
+
+Erroneous code example:
 
 ```compile_fail,E0446
 #![deny(private_in_public)]
@@ -65,7 +68,9 @@ pub fn bar() -> Bar { // ok!
 E0447: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
-The `pub` keyword was used inside a function. Erroneous code example:
+The `pub` keyword was used inside a function.
+
+Erroneous code example:
 
 ```
 fn foo() {
@@ -79,7 +84,11 @@ fn foo() {
 "##,
 
 E0448: r##"
-The `pub` keyword was used inside a public enum. Erroneous code example:
+#### Note: this error code is no longer emitted by the compiler.
+
+The `pub` keyword was used inside a public enum.
+
+Erroneous code example:
 
 ```compile_fail
 pub enum Foo {
@@ -106,7 +115,9 @@ pub enum Foo {
 "##,
 
 E0451: r##"
-A struct constructor with private fields was invoked. Erroneous code example:
+A struct constructor with private fields was invoked.
+
+Erroneous code example:
 
 ```compile_fail,E0451
 mod Bar {
index 7f819486f5bd3af609c66464df97703cc721966b..d713315decbe95bb3d689ce0249ed6e049a0c039 100644 (file)
@@ -20,7 +20,7 @@
 
 use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
 use crate::{path_names_to_string, KNOWN_TOOLS};
-use crate::{BindingError, CrateLint, LegacyScope, Module, ModuleOrUniformRoot};
+use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
 use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
 
 type Res = def::Res<ast::NodeId>;
@@ -102,7 +102,7 @@ impl<'a> Resolver<'a> {
         &self, span: Span, resolution_error: ResolutionError<'_>
     ) -> DiagnosticBuilder<'_> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
+            ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
                 let mut err = struct_span_err!(self.session,
                     span,
                     E0401,
@@ -148,22 +148,24 @@ impl<'a> Resolver<'a> {
                     }
                 }
 
-                // Try to retrieve the span of the function signature and generate a new message
-                // with a local type or const parameter.
-                let sugg_msg = &format!("try using a local generic parameter instead");
-                if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
-                    // Suggest the modification to the user
-                    err.span_suggestion(
-                        sugg_span,
-                        sugg_msg,
-                        new_snippet,
-                        Applicability::MachineApplicable,
-                    );
-                } else if let Some(sp) = cm.generate_fn_name_span(span) {
-                    err.span_label(sp,
-                        format!("try adding a local generic parameter in this method instead"));
-                } else {
-                    err.help(&format!("try using a local generic parameter instead"));
+                if has_generic_params == HasGenericParams::Yes {
+                    // Try to retrieve the span of the function signature and generate a new
+                    // message with a local type or const parameter.
+                    let sugg_msg = &format!("try using a local generic parameter instead");
+                    if let Some((sugg_span, snippet)) = cm.generate_local_type_param_snippet(span) {
+                        // Suggest the modification to the user
+                        err.span_suggestion(
+                            sugg_span,
+                            sugg_msg,
+                            snippet,
+                            Applicability::MachineApplicable,
+                        );
+                    } else if let Some(sp) = cm.generate_fn_name_span(span) {
+                        err.span_label(sp,
+                            format!("try adding a local generic parameter in this method instead"));
+                    } else {
+                        err.help(&format!("try using a local generic parameter instead"));
+                    }
                 }
 
                 err
@@ -527,7 +529,7 @@ fn lookup_import_candidates_from_module<FilterFn>(&mut self,
                         in_module_is_extern)) = worklist.pop() {
             // We have to visit module children in deterministic order to avoid
             // instabilities in reported imports (#43552).
-            in_module.for_each_child_stable(self, |this, ident, ns, name_binding| {
+            in_module.for_each_child(self, |this, ident, ns, name_binding| {
                 // avoid imports entirely
                 if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
                 // avoid non-importable candidates as well
index 93c96b9f75ba20c6de1d283dd063c20d732b1d26..bb9f895c5f39b67aa0d89c2ab990da75c05b8fd6 100644 (file)
@@ -5,7 +5,6 @@
 //! If you wonder why there's no `early.rs`, that's because it's split into three files -
 //! `build_reduced_graph.rs`, `macros.rs` and `resolve_imports.rs`.
 
-use GenericParameters::*;
 use RibKind::*;
 
 use crate::{path_names_to_string, BindingError, CrateLint, LexicalScopeBinding};
@@ -46,16 +45,6 @@ struct BindingInfo {
     binding_mode: BindingMode,
 }
 
-#[derive(Copy, Clone)]
-enum GenericParameters<'a, 'b> {
-    NoGenericParams,
-    HasGenericParams(// Type parameters.
-                      &'b Generics,
-
-                      // The kind of the rib used for type parameters.
-                      RibKind<'a>),
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum PatternSource {
     Match,
@@ -85,6 +74,10 @@ enum PatBoundCtx {
     Or,
 }
 
+/// Does this the item (from the item rib scope) allow generic parameters?
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+crate enum HasGenericParams { Yes, No }
+
 /// The rib kind restricts certain accesses,
 /// e.g. to a `Res::Local` of an outer item.
 #[derive(Copy, Clone, Debug)]
@@ -103,7 +96,7 @@ enum PatBoundCtx {
     FnItemRibKind,
 
     /// We passed through an item scope. Disallow upvars.
-    ItemRibKind,
+    ItemRibKind(HasGenericParams),
 
     /// We're in a constant item. Can't refer to dynamic stuff.
     ConstantItemRibKind,
@@ -134,7 +127,7 @@ impl RibKind<'_> {
             | ModuleRibKind(_)
             | MacroDefinition(_) => false,
             AssocItemRibKind
-            | ItemRibKind
+            | ItemRibKind(_)
             | ForwardTyParamBanRibKind
             | TyParamAsConstParamTy => true,
         }
@@ -406,17 +399,21 @@ fn visit_poly_trait_ref(&mut self,
         visit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_foreign_item(&mut self, foreign_item: &'tcx ForeignItem) {
-        let generic_params = match foreign_item.kind {
+        match foreign_item.kind {
             ForeignItemKind::Fn(_, ref generics) => {
-                HasGenericParams(generics, ItemRibKind)
+                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
+                    visit::walk_foreign_item(this, foreign_item);
+                });
             }
-            ForeignItemKind::Static(..) => NoGenericParams,
-            ForeignItemKind::Ty => NoGenericParams,
-            ForeignItemKind::Macro(..) => NoGenericParams,
-        };
-        self.with_generic_param_rib(generic_params, |this| {
-            visit::walk_foreign_item(this, foreign_item);
-        });
+            ForeignItemKind::Static(..) => {
+                self.with_item_rib(HasGenericParams::No, |this| {
+                    visit::walk_foreign_item(this, foreign_item);
+                });
+            }
+            ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {
+                visit::walk_foreign_item(self, foreign_item);
+            }
+        }
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) {
         debug!("(resolving function) entering function");
@@ -660,7 +657,7 @@ fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
     fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
-            this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+            this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                 let item_def_id = this.r.definitions.local_def_id(item.id);
                 this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
                     visit::walk_item(this, item);
@@ -719,10 +716,8 @@ fn resolve_item(&mut self, item: &Item) {
             ItemKind::TyAlias(_, ref generics) |
             ItemKind::OpaqueTy(_, ref generics) |
             ItemKind::Fn(_, _, ref generics, _) => {
-                self.with_generic_param_rib(
-                    HasGenericParams(generics, ItemRibKind),
-                    |this| visit::walk_item(this, item)
-                );
+                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes),
+                                            |this| visit::walk_item(this, item));
             }
 
             ItemKind::Enum(_, ref generics) |
@@ -740,7 +735,7 @@ fn resolve_item(&mut self, item: &Item) {
 
             ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                     let local_def_id = this.r.definitions.local_def_id(item.id);
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
@@ -748,35 +743,32 @@ fn resolve_item(&mut self, item: &Item) {
 
                         for trait_item in trait_items {
                             this.with_trait_items(trait_items, |this| {
-                                let generic_params = HasGenericParams(
-                                    &trait_item.generics,
-                                    AssocItemRibKind,
-                                );
-                                this.with_generic_param_rib(generic_params, |this| {
-                                    match trait_item.kind {
-                                        TraitItemKind::Const(ref ty, ref default) => {
-                                            this.visit_ty(ty);
-
-                                            // Only impose the restrictions of
-                                            // ConstRibKind for an actual constant
-                                            // expression in a provided default.
-                                            if let Some(ref expr) = *default{
-                                                this.with_constant_rib(|this| {
-                                                    this.visit_expr(expr);
-                                                });
+                                this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind,
+                                    |this| {
+                                        match trait_item.kind {
+                                            TraitItemKind::Const(ref ty, ref default) => {
+                                                this.visit_ty(ty);
+
+                                                // Only impose the restrictions of
+                                                // ConstRibKind for an actual constant
+                                                // expression in a provided default.
+                                                if let Some(ref expr) = *default{
+                                                    this.with_constant_rib(|this| {
+                                                        this.visit_expr(expr);
+                                                    });
+                                                }
                                             }
-                                        }
-                                        TraitItemKind::Method(_, _) => {
-                                            visit::walk_trait_item(this, trait_item)
-                                        }
-                                        TraitItemKind::Type(..) => {
-                                            visit::walk_trait_item(this, trait_item)
-                                        }
-                                        TraitItemKind::Macro(_) => {
-                                            panic!("unexpanded macro in resolve!")
-                                        }
-                                    };
-                                });
+                                            TraitItemKind::Method(_, _) => {
+                                                visit::walk_trait_item(this, trait_item)
+                                            }
+                                            TraitItemKind::Type(..) => {
+                                                visit::walk_trait_item(this, trait_item)
+                                            }
+                                            TraitItemKind::Macro(_) => {
+                                                panic!("unexpanded macro in resolve!")
+                                            }
+                                        };
+                                    });
                             });
                         }
                     });
@@ -785,7 +777,7 @@ fn resolve_item(&mut self, item: &Item) {
 
             ItemKind::TraitAlias(ref generics, ref bounds) => {
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                     let local_def_id = this.r.definitions.local_def_id(item.id);
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
@@ -803,7 +795,7 @@ fn resolve_item(&mut self, item: &Item) {
             ItemKind::Static(ref ty, _, ref expr) |
             ItemKind::Const(ref ty, ref expr) => {
                 debug!("resolve_item ItemKind::Const");
-                self.with_item_rib(|this| {
+                self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
                     this.with_constant_rib(|this| {
                         this.visit_expr(expr);
@@ -824,91 +816,75 @@ fn resolve_item(&mut self, item: &Item) {
         }
     }
 
-    fn with_generic_param_rib<'c, F>(&'c mut self, generic_params: GenericParameters<'a, 'c>, f: F)
+    fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
         where F: FnOnce(&mut Self)
     {
         debug!("with_generic_param_rib");
-        match generic_params {
-            HasGenericParams(generics, rib_kind) => {
-                let mut function_type_rib = Rib::new(rib_kind);
-                let mut function_value_rib = Rib::new(rib_kind);
-                let mut seen_bindings = FxHashMap::default();
-                // We also can't shadow bindings from the parent item
-                if let AssocItemRibKind = rib_kind {
-                    let mut add_bindings_for_ns = |ns| {
-                        let parent_rib = self.ribs[ns].iter()
-                            .rfind(|rib| if let ItemRibKind = rib.kind { true } else { false })
-                            .expect("associated item outside of an item");
-                        seen_bindings.extend(
-                            parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)),
-                        );
-                    };
-                    add_bindings_for_ns(ValueNS);
-                    add_bindings_for_ns(TypeNS);
-                }
-                for param in &generics.params {
-                    match param.kind {
-                        GenericParamKind::Lifetime { .. } => {}
-                        GenericParamKind::Type { .. } => {
-                            let ident = param.ident.modern();
-                            debug!("with_generic_param_rib: {}", param.id);
-
-                            if seen_bindings.contains_key(&ident) {
-                                let span = seen_bindings.get(&ident).unwrap();
-                                let err = ResolutionError::NameAlreadyUsedInParameterList(
-                                    ident.name,
-                                    *span,
-                                );
-                                self.r.report_error(param.ident.span, err);
-                            }
-                            seen_bindings.entry(ident).or_insert(param.ident.span);
-
-                            // Plain insert (no renaming).
-                            let res = Res::Def(
-                                DefKind::TyParam,
-                                self.r.definitions.local_def_id(param.id),
-                            );
-                            function_type_rib.bindings.insert(ident, res);
-                            self.r.record_partial_res(param.id, PartialRes::new(res));
-                        }
-                        GenericParamKind::Const { .. } => {
-                            let ident = param.ident.modern();
-                            debug!("with_generic_param_rib: {}", param.id);
-
-                            if seen_bindings.contains_key(&ident) {
-                                let span = seen_bindings.get(&ident).unwrap();
-                                let err = ResolutionError::NameAlreadyUsedInParameterList(
-                                    ident.name,
-                                    *span,
-                                );
-                                self.r.report_error(param.ident.span, err);
-                            }
-                            seen_bindings.entry(ident).or_insert(param.ident.span);
-
-                            let res = Res::Def(
-                                DefKind::ConstParam,
-                                self.r.definitions.local_def_id(param.id),
-                            );
-                            function_value_rib.bindings.insert(ident, res);
-                            self.r.record_partial_res(param.id, PartialRes::new(res));
-                        }
-                    }
-                }
-                self.ribs[ValueNS].push(function_value_rib);
-                self.ribs[TypeNS].push(function_type_rib);
+        let mut function_type_rib = Rib::new(kind);
+        let mut function_value_rib = Rib::new(kind);
+        let mut seen_bindings = FxHashMap::default();
+
+        // We also can't shadow bindings from the parent item
+        if let AssocItemRibKind = kind {
+            let mut add_bindings_for_ns = |ns| {
+                let parent_rib = self.ribs[ns].iter()
+                    .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false })
+                    .expect("associated item outside of an item");
+                seen_bindings.extend(
+                    parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span)),
+                );
+            };
+            add_bindings_for_ns(ValueNS);
+            add_bindings_for_ns(TypeNS);
+        }
+
+        for param in &generics.params {
+            if let GenericParamKind::Lifetime { .. } = param.kind {
+                continue;
             }
 
-            NoGenericParams => {
-                // Nothing to do.
+            let def_kind = match param.kind {
+                GenericParamKind::Type { .. } => DefKind::TyParam,
+                GenericParamKind::Const { .. } => DefKind::ConstParam,
+                _ => unreachable!(),
+            };
+
+            let ident = param.ident.modern();
+            debug!("with_generic_param_rib: {}", param.id);
+
+            if seen_bindings.contains_key(&ident) {
+                let span = seen_bindings.get(&ident).unwrap();
+                let err = ResolutionError::NameAlreadyUsedInParameterList(
+                    ident.name,
+                    *span,
+                );
+                self.r.report_error(param.ident.span, err);
+            }
+            seen_bindings.entry(ident).or_insert(param.ident.span);
+
+            // Plain insert (no renaming).
+            let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id));
+
+            match param.kind {
+                GenericParamKind::Type { .. } => {
+                    function_type_rib.bindings.insert(ident, res);
+                    self.r.record_partial_res(param.id, PartialRes::new(res));
+                }
+                GenericParamKind::Const { .. } => {
+                    function_value_rib.bindings.insert(ident, res);
+                    self.r.record_partial_res(param.id, PartialRes::new(res));
+                }
+                _ => unreachable!(),
             }
         }
 
+        self.ribs[ValueNS].push(function_value_rib);
+        self.ribs[TypeNS].push(function_type_rib);
+
         f(self);
 
-        if let HasGenericParams(..) = generic_params {
-            self.ribs[TypeNS].pop();
-            self.ribs[ValueNS].pop();
-        }
+        self.ribs[TypeNS].pop();
+        self.ribs[ValueNS].pop();
     }
 
     fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
@@ -917,8 +893,9 @@ fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
         self.label_ribs.pop();
     }
 
-    fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
-        self.with_rib(ValueNS, ItemRibKind, |this| this.with_rib(TypeNS, ItemRibKind, f))
+    fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
+        let kind = ItemRibKind(has_generic_params);
+        self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
     fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
@@ -1023,7 +1000,7 @@ fn resolve_implementation(&mut self,
                               impl_items: &[ImplItem]) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
+        self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
             // Dummy self type for better errors if `Self` is used in the trait path.
             this.with_self_rib(Res::SelfTy(None, None), |this| {
                 // Resolve the trait reference, if necessary.
@@ -1044,9 +1021,9 @@ fn resolve_implementation(&mut self,
                                 debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
                                 for impl_item in impl_items {
                                     // We also need a new scope for the impl item type parameters.
-                                    let generic_params = HasGenericParams(&impl_item.generics,
-                                                                          AssocItemRibKind);
-                                    this.with_generic_param_rib(generic_params, |this| {
+                                    this.with_generic_param_rib(&impl_item.generics,
+                                                                AssocItemRibKind,
+                                                                |this| {
                                         use crate::ResolutionError::*;
                                         match impl_item.kind {
                                             ImplItemKind::Const(..) => {
index d3bf82b66ad1cf163a9310ecf28db381196ddd01..1016989ca6e38d5f73f81e9093fb74b4392aef3b 100644 (file)
@@ -728,7 +728,7 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
             // abort if the module is already found
             if result.is_some() { break; }
 
-            in_module.for_each_child_stable(self.r, |_, ident, _, name_binding| {
+            in_module.for_each_child(self.r, |_, ident, _, name_binding| {
                 // abort if the module is already found or if name_binding is private external
                 if result.is_some() || !name_binding.vis.is_visible_locally() {
                     return
@@ -760,7 +760,7 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
     fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
             let mut variants = Vec::new();
-            enum_module.for_each_child_stable(self.r, |_, ident, _, name_binding| {
+            enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
                 if let Res::Def(DefKind::Variant, _) = name_binding.res() {
                     let mut segms = enum_import_suggestion.path.segments.clone();
                     segms.push(ast::PathSegment::from_ident(ident));
index e7292b52ab3e88c512dbafab43797192f40a5cd8..9211ee5f1453464be42a55e68e9f6b52015cc283 100644 (file)
@@ -9,7 +9,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 
-#![feature(inner_deref)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(mem_take)]
 use std::collections::BTreeSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::fx::FxIndexMap;
 
 use diagnostics::{Suggestion, ImportSuggestion};
 use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
-use late::{PathSource, Rib, RibKind::*};
+use late::{HasGenericParams, PathSource, Rib, RibKind::*};
 use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
 use macros::{LegacyBinding, LegacyScope};
 
@@ -178,7 +178,7 @@ fn cmp(&self, other: &BindingError) -> cmp::Ordering {
 
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer function.
-    GenericParamsFromOuterFunction(Res),
+    GenericParamsFromOuterFunction(Res, HasGenericParams),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
     NameAlreadyUsedInParameterList(Name, Span),
@@ -431,7 +431,7 @@ pub fn name(&self) -> Option<Name> {
     }
 }
 
-type Resolutions<'a> = RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
+type Resolutions<'a> = RefCell<FxIndexMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
 
 /// One node in the tree of modules.
 pub struct ModuleData<'a> {
@@ -496,17 +496,6 @@ fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
         }
     }
 
-    fn for_each_child_stable<R, F>(&'a self, resolver: &mut R, mut f: F)
-        where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
-    {
-        let resolutions = resolver.as_mut().resolutions(self).borrow();
-        let mut resolutions = resolutions.iter().collect::<Vec<_>>();
-        resolutions.sort_by_cached_key(|&(&(ident, ns), _)| (ident.as_str(), ns));
-        for &(&(ident, ns), &resolution) in resolutions.iter() {
-            resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
-        }
-    }
-
     fn res(&self) -> Option<Res> {
         match self.kind {
             ModuleKind::Def(kind, def_id, _) => Some(Res::Def(kind, def_id)),
@@ -1266,6 +1255,9 @@ fn has_derives(&self, expn_id: ExpnId, markers: SpecialDerives) -> bool {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
+        let _prof_timer =
+            self.session.prof.generic_activity("resolve_crate");
+
         ImportResolver { r: self }.finalize_imports();
         self.finalize_macro_resolutions();
 
@@ -2167,7 +2159,7 @@ fn validate_res_from_ribs(
                         ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
                             // Nothing to do. Continue.
                         }
-                        ItemRibKind | FnItemRibKind | AssocItemRibKind => {
+                        ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
@@ -2195,22 +2187,23 @@ fn validate_res_from_ribs(
             }
             Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
                 for rib in ribs {
-                    match rib.kind {
+                    let has_generic_params = match rib.kind {
                         NormalRibKind | AssocItemRibKind |
                         ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
                         ConstantItemRibKind | TyParamAsConstParamTy => {
                             // Nothing to do. Continue.
+                            continue;
                         }
-                        ItemRibKind | FnItemRibKind => {
-                            // This was an attempt to use a type parameter outside its scope.
-                            if record_used {
-                                self.report_error(
-                                    span, ResolutionError::GenericParamsFromOuterFunction(res)
-                                );
-                            }
-                            return Res::Err;
-                        }
+                        // This was an attempt to use a type parameter outside its scope.
+                        ItemRibKind(has_generic_params) => has_generic_params,
+                        FnItemRibKind => HasGenericParams::Yes,
+                    };
+
+                    if record_used {
+                        self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
+                            res, has_generic_params));
                     }
+                    return Res::Err;
                 }
             }
             Res::Def(DefKind::ConstParam, _) => {
@@ -2222,15 +2215,18 @@ fn validate_res_from_ribs(
                     ribs.next();
                 }
                 for rib in ribs {
-                    if let ItemRibKind | FnItemRibKind = rib.kind {
-                        // This was an attempt to use a const parameter outside its scope.
-                        if record_used {
-                            self.report_error(
-                                span, ResolutionError::GenericParamsFromOuterFunction(res)
-                            );
-                        }
-                        return Res::Err;
+                    let has_generic_params = match rib.kind {
+                        ItemRibKind(has_generic_params) => has_generic_params,
+                        FnItemRibKind => HasGenericParams::Yes,
+                        _ => continue,
+                    };
+
+                    // This was an attempt to use a const parameter outside its scope.
+                    if record_used {
+                        self.report_error(span, ResolutionError::GenericParamsFromOuterFunction(
+                            res, has_generic_params));
                     }
+                    return Res::Err;
                 }
             }
             _ => {}
index e3c898610cde0c8be1575cef14ab6c76d2c09441..70b508d4786975d9b68d329482a68bb5d1201bf1 100644 (file)
@@ -1,6 +1,5 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(nll)]
-#![feature(inner_deref)]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_target/abi/call/asmjs.rs b/src/librustc_target/abi/call/asmjs.rs
new file mode 100644 (file)
index 0000000..92c8637
--- /dev/null
@@ -0,0 +1,47 @@
+use crate::abi::call::{FnType, ArgType, Uniform};
+use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+
+// Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
+
+// See the https://github.com/kripken/emscripten-fastcomp-clang repository.
+// The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
+
+fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if ret.layout.is_aggregate() {
+        if let Some(unit) = ret.layout.homogeneous_aggregate(cx).unit() {
+            let size = ret.layout.size;
+            if unit.size == size {
+                ret.cast_to(Uniform {
+                    unit,
+                    total: size
+                });
+                return;
+            }
+        }
+
+        ret.make_indirect();
+    }
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
+    if arg.layout.is_aggregate() {
+        arg.make_indirect_byval();
+    }
+}
+
+pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(cx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(arg);
+    }
+}
index 17bad189bcfdad0d72d204b7272d9364d965b74e..bc21113527ecfa83b7602319689a882517713c5d 100644 (file)
@@ -5,6 +5,7 @@
 mod aarch64;
 mod amdgpu;
 mod arm;
+mod asmjs;
 mod hexagon;
 mod mips;
 mod mips64;
@@ -21,7 +22,6 @@
 mod x86_64;
 mod x86_win64;
 mod wasm32;
-mod wasm32_bindgen_compat;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum PassMode {
@@ -557,6 +557,14 @@ pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(),
             "powerpc" => powerpc::compute_abi_info(cx, self),
             "powerpc64" => powerpc64::compute_abi_info(cx, self),
             "s390x" => s390x::compute_abi_info(cx, self),
+            "asmjs" => asmjs::compute_abi_info(cx, self),
+            "wasm32" => {
+                if cx.target_spec().llvm_target.contains("emscripten") {
+                    asmjs::compute_abi_info(cx, self)
+                } else {
+                    wasm32::compute_abi_info(self)
+                }
+            }
             "msp430" => msp430::compute_abi_info(self),
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
@@ -565,9 +573,6 @@ pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(),
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" => riscv::compute_abi_info(self, 32),
             "riscv64" => riscv::compute_abi_info(self, 64),
-            "wasm32" if cx.target_spec().target_os != "emscripten"
-                => wasm32_bindgen_compat::compute_abi_info(self),
-            "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
         }
 
index 27799edab91954dbbd842c9bfca90211ab560dc8..1fdcbb8e39bdff0397f0aaa6a3599d6dcc301f3c 100644 (file)
@@ -1,60 +1,20 @@
-use crate::abi::call::{FnType, ArgType, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
+use crate::abi::call::{FnType, ArgType};
 
-fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgType<'a, Ty>) -> bool
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
-    if val.layout.is_aggregate() {
-        if let Some(unit) = val.layout.homogeneous_aggregate(cx).unit() {
-            let size = val.layout.size;
-            if unit.size == size {
-                val.cast_to(Uniform {
-                    unit,
-                    total: size
-                });
-                return true;
-            }
-        }
-    }
-    false
-}
-
-
-fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>)
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
+fn classify_ret_ty<Ty>(ret: &mut ArgType<'_, Ty>) {
     ret.extend_integer_width_to(32);
-    if ret.layout.is_aggregate() {
-        if !unwrap_trivial_aggregate(cx, ret) {
-            ret.make_indirect();
-        }
-    }
 }
 
-fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>)
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
+fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
     arg.extend_integer_width_to(32);
-    if arg.layout.is_aggregate() {
-        if !unwrap_trivial_aggregate(cx, arg) {
-            arg.make_indirect_byval();
-        }
-    }
 }
 
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>)
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
+pub fn compute_abi_info<Ty>(fty: &mut FnType<'_, Ty>) {
     if !fty.ret.is_ignore() {
-        classify_ret_ty(cx, &mut fty.ret);
+        classify_ret_ty(&mut fty.ret);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        classify_arg_ty(cx, arg);
+        classify_arg_ty(arg);
     }
 }
diff --git a/src/librustc_target/abi/call/wasm32_bindgen_compat.rs b/src/librustc_target/abi/call/wasm32_bindgen_compat.rs
deleted file mode 100644 (file)
index 2645e30..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// This is not and has never been a correct C ABI for WebAssembly, but
-// for a long time this was the C ABI that Rust used. wasm-bindgen
-// depends on ABI details for this ABI and is incompatible with the
-// correct C ABI, so this ABI is being kept around until wasm-bindgen
-// can be fixed to work with the correct ABI. See #63649 for further
-// discussion.
-
-use crate::abi::call::{FnType, ArgType};
-
-fn classify_ret_ty<Ty>(ret: &mut ArgType<'_, Ty>) {
-    ret.extend_integer_width_to(32);
-}
-
-fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
-    arg.extend_integer_width_to(32);
-}
-
-pub fn compute_abi_info<Ty>(fty: &mut FnType<'_, Ty>) {
-    if !fty.ret.is_ignore() {
-        classify_ret_ty(&mut fty.ret);
-    }
-
-    for arg in &mut fty.args {
-        if arg.is_ignore() { continue; }
-        classify_arg_ty(arg);
-    }
-}
index e8f9c1f3d61dea198a3eb9cef22b5ecf8098f7e7..6dc140cf160eadb6e727d5f2abf99831ea5153fb 100644 (file)
@@ -1,10 +1,40 @@
-use super::{LinkerFlavor, Target, wasm32_unknown_emscripten};
+use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Result<Target, String> {
-    let mut target = wasm32_unknown_emscripten::target()?;
-    target.options.post_link_args
-        .entry(LinkerFlavor::Em)
-        .or_default()
-        .extend(vec!["-s".to_string(), "WASM=0".to_string()]);
-    Ok(target)
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Em,
+                vec!["-s".to_string(),
+                     "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
+                     "-s".to_string(),
+                     "ABORTING_MALLOC=0".to_string(),
+                     "-s".to_string(),
+                     "WASM=0".to_string()]);
+
+    let opts = TargetOptions {
+        dynamic_linking: false,
+        executables: true,
+        exe_suffix: ".js".to_string(),
+        linker_is_gnu: true,
+        allow_asm: false,
+        obj_is_bitcode: true,
+        is_like_emscripten: true,
+        max_atomic_width: Some(32),
+        post_link_args: args,
+        target_family: Some("unix".to_string()),
+        codegen_backend: "emscripten".to_string(),
+        .. Default::default()
+    };
+    Ok(Target {
+        llvm_target: "asmjs-unknown-emscripten".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_os: "emscripten".to_string(),
+        target_env: String::new(),
+        target_vendor: "unknown".to_string(),
+        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
+        arch: "asmjs".to_string(),
+        linker_flavor: LinkerFlavor::Em,
+        options: opts,
+    })
 }
index cf1a84dec97bccf625742399a4d9c5e0bd2f8b4e..25add0cc6a4be2cede092124a1ed10954cbdf989 100644 (file)
@@ -462,6 +462,7 @@ fn $module() {
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-unknown-unknown", wasm32_unknown_unknown),
     ("wasm32-wasi", wasm32_wasi),
+    ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
     ("thumbv7m-none-eabi", thumbv7m_none_eabi),
diff --git a/src/librustc_target/spec/wasm32_experimental_emscripten.rs b/src/librustc_target/spec/wasm32_experimental_emscripten.rs
new file mode 100644 (file)
index 0000000..b802bee
--- /dev/null
@@ -0,0 +1,44 @@
+use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
+
+pub fn target() -> Result<Target, String> {
+    let mut post_link_args = LinkArgs::new();
+    post_link_args.insert(LinkerFlavor::Em,
+                          vec!["-s".to_string(),
+                               "WASM=1".to_string(),
+                               "-s".to_string(),
+                               "ASSERTIONS=1".to_string(),
+                               "-s".to_string(),
+                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
+                               "-g3".to_string()]);
+
+    let opts = TargetOptions {
+        dynamic_linking: false,
+        executables: true,
+        // Today emcc emits two files - a .js file to bootstrap and
+        // possibly interpret the wasm, and a .wasm file
+        exe_suffix: ".js".to_string(),
+        linker_is_gnu: true,
+        link_env: vec![("EMCC_WASM_BACKEND".to_string(), "1".to_string())],
+        allow_asm: false,
+        obj_is_bitcode: true,
+        is_like_emscripten: true,
+        max_atomic_width: Some(32),
+        post_link_args,
+        limit_rdylib_exports: false,
+        target_family: Some("unix".to_string()),
+        .. Default::default()
+    };
+    Ok(Target {
+        llvm_target: "wasm32-unknown-unknown".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_os: "emscripten".to_string(),
+        target_env: String::new(),
+        target_vendor: "unknown".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        arch: "wasm32".to_string(),
+        linker_flavor: LinkerFlavor::Em,
+        options: opts,
+    })
+}
index 6a2c8c495372f2d3483283aa7c6dd9065f975e41..e0df36884bf5629f6325948002fbf61ea6224cf7 100644 (file)
@@ -1,46 +1,45 @@
-use super::wasm32_base;
-use super::{LinkArgs, LinkerFlavor, Target, TargetOptions, PanicStrategy};
+use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Result<Target, String> {
+    // FIXME(nikic) BINARYEN_TRAP_MODE=clamp is needed to avoid trapping in our
+    // -Zsaturating-float-casts implementation. This can be dropped if/when
+    // we have native fpto[su]i.sat intrinsics, or the implementation otherwise
+    // stops relying on non-trapping fpto[su]i.
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(LinkerFlavor::Em,
                           vec!["-s".to_string(),
-                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
-                               "-s".to_string(),
-                               "ASSERTIONS=1".to_string(),
+                               "BINARYEN=1".to_string(),
                                "-s".to_string(),
-                               "DISABLE_EXCEPTION_CATCHING=1".to_string(),
+                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
                                "-s".to_string(),
-                               "ABORTING_MALLOC=0".to_string(),
-                               // FIXME(tlively): Enable this linker option once libc type errors
-                               // are resolved. See https://github.com/rust-lang/libc/pull/1478.
-                               // "-Wl,--fatal-warnings".to_string(),
-                               ]);
+                               "BINARYEN_TRAP_MODE='clamp'".to_string()]);
 
     let opts = TargetOptions {
-        // emcc emits two files - a .js file to instantiate the wasm and supply platform
-        // functionality, and a .wasm file.
+        dynamic_linking: false,
+        executables: true,
+        // Today emcc emits two files - a .js file to bootstrap and
+        // possibly interpret the wasm, and a .wasm file
         exe_suffix: ".js".to_string(),
-        linker: None,
         linker_is_gnu: true,
+        allow_asm: false,
+        obj_is_bitcode: true,
         is_like_emscripten: true,
-        // FIXME(tlively): Emscripten supports unwinding, but we would have to pass
-        // -enable-emscripten-cxx-exceptions to LLVM at codegen time and merge
-        // https://reviews.llvm.org/rG5c3cdef84b82464756bb571c13c31cf7773860c3to use it.
-        panic_strategy: PanicStrategy::Abort,
+        max_atomic_width: Some(32),
         post_link_args,
+        limit_rdylib_exports: false,
         target_family: Some("unix".to_string()),
-        .. wasm32_base::options()
+        codegen_backend: "emscripten".to_string(),
+        .. Default::default()
     };
     Ok(Target {
-        llvm_target: "wasm32-unknown-emscripten".to_string(),
+        llvm_target: "asmjs-unknown-emscripten".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
         target_os: "emscripten".to_string(),
         target_env: String::new(),
         target_vendor: "unknown".to_string(),
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Em,
         options: opts,
index 7db1a7413c7be27351560ea7a5555cdeda478388..88e62db9a10d8aacbda75a3a4f60af3c1ab0a41f 100644 (file)
@@ -223,7 +223,7 @@ fn dtorck_constraint_for_ty<'tcx>(
             // *do* incorporate the upvars here.
 
             let constraint = DtorckConstraint {
-                outlives: substs.upvar_tys(def_id, tcx).map(|t| t.into()).collect(),
+                outlives: substs.as_generator().upvar_tys(def_id, tcx).map(|t| t.into()).collect(),
                 dtorck_types: vec![],
                 overflows: vec![],
             };
index 30a1814d0f83ef697d6a1fdc26ed779718ac3765..dc7eeead30cbeb639657770cf614293a75913618 100644 (file)
@@ -17,10 +17,12 @@ fn evaluate_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonical_goal: CanonicalPredicateGoal<'tcx>,
 ) -> Result<EvaluationResult, OverflowError> {
+    debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
     tcx.infer_ctxt().enter_with_canonical(
         DUMMY_SP,
         &canonical_goal,
         |ref infcx, goal, _canonical_inference_vars| {
+            debug!("evaluate_obligation: goal={:#?}", goal);
             let ParamEnvAnd {
                 param_env,
                 value: predicate,
index 91ca6415bdcb94b84e0d9307ebbbb0ce6aef6f51..cc5348623fabda0dfdf0eda61c36b30fafc7e935 100644 (file)
@@ -73,7 +73,9 @@
 }
 
 crate fn generator(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> {
-    tcx.mk_generator(def_id, ty::GeneratorSubsts {
-        substs: InternalSubsts::bound_vars_for_item(tcx, def_id),
-    }, hir::GeneratorMovability::Movable)
+    tcx.mk_generator(
+        def_id,
+        InternalSubsts::bound_vars_for_item(tcx, def_id),
+        hir::GeneratorMovability::Movable
+    )
 }
index 03f0860c6605589637bcc7ba68bbd77621bc2a94..8b97bf643e9bb9a2ab9f4da7f87dafa5b37572af 100644 (file)
@@ -113,21 +113,21 @@ fn check_closure(
             }
         });
         if let Some(GeneratorTypes { yield_ty, interior, movability }) = generator_types {
-            let substs = ty::GeneratorSubsts { substs };
+            let generator_substs = substs.as_generator();
             self.demand_eqtype(
                 expr.span,
                 yield_ty,
-                substs.yield_ty(expr_def_id, self.tcx),
+                generator_substs.yield_ty(expr_def_id, self.tcx),
             );
             self.demand_eqtype(
                 expr.span,
                 liberated_sig.output(),
-                substs.return_ty(expr_def_id, self.tcx),
+                generator_substs.return_ty(expr_def_id, self.tcx),
             );
             self.demand_eqtype(
                 expr.span,
                 interior,
-                substs.witness(expr_def_id, self.tcx),
+                generator_substs.witness(expr_def_id, self.tcx),
             );
             return self.tcx.mk_generator(expr_def_id, substs, movability);
         }
index 2ea0afb1793562d47582a6e71143dc9d8c8e2fd5..d92ea7fd49a7294fa5d87175bf524ac020399c5b 100644 (file)
@@ -115,6 +115,7 @@ pub fn demand_coerce_diag(&self,
             Err(e) => e
         };
 
+        let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
@@ -349,7 +350,14 @@ pub fn check_ref(
 
         // If the span is from a macro, then it's hard to extract the text
         // and make a good suggestion, so don't bother.
-        let is_macro = sp.from_expansion();
+        let is_desugaring = match sp.desugaring_kind() {
+            Some(k) => sp.is_desugaring(k),
+            None => false
+        };
+        let is_macro = sp.from_expansion() && !is_desugaring;
+
+        // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
+        let expr = expr.peel_drop_temps();
 
         match (&expr.kind, &expected.kind, &checked_ty.kind) {
             (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) {
index 7a6fe9560fbfff4a6ed5fb4d182090df8ec73133..ad46a443b8ffa9e886969f8409266a13d30b4d7a 100644 (file)
@@ -87,10 +87,8 @@ fn check_expr_meets_expectation_or_error(
         }
 
         if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
-            let expr = match &expr.kind {
-                ExprKind::DropTemps(expr) => expr,
-                _ => expr,
-            };
+            let expr = expr.peel_drop_temps();
+            self.suggest_ref_or_into(&mut err, expr, expected_ty, ty);
             extend_err(&mut err);
             // Error possibly reported in `check_assign` so avoid emitting error again.
             err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
index 2be311127214d2b6c3b6fd804e4b15c63d079bd5..434ead50e0423817e0e7bf1b8eadcc99587d6620 100644 (file)
@@ -58,7 +58,7 @@ pub enum MethodError<'tcx> {
 
     // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
     // forgotten to import a trait.
-    IllegalSizedBound(Vec<DefId>),
+    IllegalSizedBound(Vec<DefId>, bool),
 
     // Found a match, but the return type is wrong
     BadReturnType,
@@ -213,33 +213,49 @@ pub fn lookup_method(
             segment,
         );
 
+        let mut needs_mut = false;
+        if let ty::Ref(region, t_type, mutability) = self_ty.kind {
+            let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut {
+                ty: t_type,
+                mutbl: mutability.invert(),
+            });
+            match self.lookup_probe(
+                span,
+                segment.ident,
+                trait_type,
+                call_expr,
+                ProbeScope::TraitsInScope
+            ) {
+                Ok(ref new_pick) if *new_pick != pick => {
+                    needs_mut = true;
+                }
+                _ => {}
+            }
+        }
+
         if result.illegal_sized_bound {
             // We probe again, taking all traits into account (not only those in scope).
-            let candidates =
-                match self.lookup_probe(span,
-                                        segment.ident,
-                                        self_ty,
-                                        call_expr,
-                                        ProbeScope::AllTraits) {
-
-                    // If we find a different result the caller probably forgot to import a trait.
-                    Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
-                    Err(Ambiguity(ref sources)) => {
-                        sources.iter()
-                               .filter_map(|source| {
-                                   match *source {
-                                       // Note: this cannot come from an inherent impl,
-                                       // because the first probing succeeded.
-                                       ImplSource(def) => self.tcx.trait_id_of_impl(def),
-                                       TraitSource(_) => None,
-                                   }
-                               })
-                               .collect()
+            let candidates = match self.lookup_probe(
+                span,
+                segment.ident,
+                self_ty,
+                call_expr,
+                ProbeScope::AllTraits,
+            ) {
+                // If we find a different result the caller probably forgot to import a trait.
+                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
+                Err(Ambiguity(ref sources)) => sources.iter().filter_map(|source| {
+                    match *source {
+                        // Note: this cannot come from an inherent impl,
+                        // because the first probing succeeded.
+                        ImplSource(def) => self.tcx.trait_id_of_impl(def),
+                        TraitSource(_) => None,
                     }
-                    _ => Vec::new(),
-                };
+                }).collect(),
+                _ => Vec::new(),
+            };
 
-            return Err(IllegalSizedBound(candidates));
+            return Err(IllegalSizedBound(candidates, needs_mut));
         }
 
         Ok(result.callee)
index 2b34c24b266d0d29d4e927dcc50c0b28f667c8c1..ebeb9ba25c6cb523a504d2da243b2cf373a0aa87 100644 (file)
@@ -461,16 +461,36 @@ macro_rules! report_function {
                     err.span_label(span, "this is an associated function, not a method");
                 }
                 if static_sources.len() == 1 {
+                    let ty_str = if let Some(CandidateSource::ImplSource(
+                        impl_did,
+                    )) = static_sources.get(0) {
+                        // When the "method" is resolved through dereferencing, we really want the
+                        // original type that has the associated function for accurate suggestions.
+                        // (#61411)
+                        let ty = self.impl_self_ty(span, *impl_did).ty;
+                        match (&ty.peel_refs().kind, &actual.peel_refs().kind) {
+                            (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
+                                // Use `actual` as it will have more `substs` filled in.
+                                self.ty_to_value_string(actual.peel_refs())
+                            }
+                            _ => self.ty_to_value_string(ty.peel_refs()),
+                        }
+                    } else {
+                        self.ty_to_value_string(actual.peel_refs())
+                    };
                     if let SelfSource::MethodCall(expr) = source {
-                        err.span_suggestion(expr.span.to(span),
-                                            "use associated function syntax instead",
-                                            format!("{}::{}",
-                                                    self.ty_to_string(actual),
-                                                    item_name),
-                                            Applicability::MachineApplicable);
+                        err.span_suggestion(
+                            expr.span.to(span),
+                            "use associated function syntax instead",
+                            format!("{}::{}", ty_str, item_name),
+                            Applicability::MachineApplicable,
+                        );
                     } else {
-                        err.help(&format!("try with `{}::{}`",
-                                          self.ty_to_string(actual), item_name));
+                        err.help(&format!(
+                            "try with `{}::{}`",
+                            ty_str,
+                            item_name,
+                        ));
                     }
 
                     report_candidates(span, &mut err, static_sources);
@@ -518,7 +538,27 @@ macro_rules! report_function {
                     }
                 }
 
-                if let Some(lev_candidate) = lev_candidate {
+                let mut fallback_span = true;
+                let msg = "remove this method call";
+                if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
+                    if let SelfSource::MethodCall(expr) = source {
+                        let call_expr = self.tcx.hir().expect_expr(
+                            self.tcx.hir().get_parent_node(expr.hir_id),
+                        );
+                        if let Some(span) = call_expr.span.trim_start(expr.span) {
+                            err.span_suggestion(
+                                span,
+                                msg,
+                                String::new(),
+                                Applicability::MachineApplicable,
+                            );
+                            fallback_span = false;
+                        }
+                    }
+                    if fallback_span {
+                        err.span_label(span, msg);
+                    }
+                } else if let Some(lev_candidate) = lev_candidate {
                     let def_kind = lev_candidate.def_kind();
                     err.span_suggestion(
                         span,
@@ -553,22 +593,33 @@ macro_rules! report_function {
                 err.emit();
             }
 
-            MethodError::IllegalSizedBound(candidates) => {
+            MethodError::IllegalSizedBound(candidates, needs_mut) => {
                 let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
                 let mut err = self.sess().struct_span_err(span, &msg);
                 if !candidates.is_empty() {
-                    let help = format!("{an}other candidate{s} {were} found in the following \
-                                        trait{s}, perhaps add a `use` for {one_of_them}:",
-                                    an = if candidates.len() == 1 {"an" } else { "" },
-                                    s = pluralise!(candidates.len()),
-                                    were = if candidates.len() == 1 { "was" } else { "were" },
-                                    one_of_them = if candidates.len() == 1 {
-                                        "it"
-                                    } else {
-                                        "one_of_them"
-                                    });
+                    let help = format!(
+                        "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
+                         add a `use` for {one_of_them}:",
+                        an = if candidates.len() == 1 {"an" } else { "" },
+                        s = pluralise!(candidates.len()),
+                        were = if candidates.len() == 1 { "was" } else { "were" },
+                        one_of_them = if candidates.len() == 1 {
+                            "it"
+                        } else {
+                            "one_of_them"
+                        },
+                    );
                     self.suggest_use_candidates(&mut err, help, candidates);
                 }
+                if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind {
+                    if needs_mut {
+                        let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut {
+                            ty: t_type,
+                            mutbl: mutability.invert(),
+                        });
+                        err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
+                    }
+                }
                 err.emit();
             }
 
@@ -579,6 +630,14 @@ macro_rules! report_function {
         None
     }
 
+    /// Print out the type for use in value namespace.
+    fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
+        match ty.kind {
+            ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)),
+            _ => self.ty_to_string(ty),
+        }
+    }
+
     fn suggest_use_candidates(&self,
                               err: &mut DiagnosticBuilder<'_>,
                               mut msg: String,
index 7380bf7536de587f76ddd6cebbb51cedd2b832cd..7475b9cc3b327b9b4940f2edc0b9587756aa12e9 100644 (file)
@@ -1713,8 +1713,6 @@ fn check_specialization_validity<'tcx>(
     impl_id: DefId,
     impl_item: &hir::ImplItem,
 ) {
-    let ancestors = trait_def.ancestors(tcx, impl_id);
-
     let kind = match impl_item.kind {
         hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
         hir::ImplItemKind::Method(..) => ty::AssocKind::Method,
@@ -1722,15 +1720,53 @@ fn check_specialization_validity<'tcx>(
         hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
     };
 
-    let parent = ancestors.defs(tcx, trait_item.ident, kind, trait_def.def_id).nth(1)
-        .map(|node_item| node_item.map(|parent| parent.defaultness));
+    let mut ancestor_impls = trait_def.ancestors(tcx, impl_id)
+        .skip(1)
+        .filter_map(|parent| {
+            if parent.is_from_trait() {
+                None
+            } else {
+                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            }
+        })
+        .peekable();
 
-    if let Some(parent) = parent {
-        if tcx.impl_item_is_final(&parent) {
-            report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
-        }
+    if ancestor_impls.peek().is_none() {
+        // No parent, nothing to specialize.
+        return;
     }
 
+    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
+        match parent_item {
+            // Parent impl exists, and contains the parent item we're trying to specialize, but
+            // doesn't mark it `default`.
+            Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
+                Some(Err(parent_impl.def_id()))
+            }
+
+            // Parent impl contains item and makes it specializable.
+            Some(_) => {
+                Some(Ok(()))
+            }
+
+            // Parent impl doesn't mention the item. This means it's inherited from the
+            // grandparent. In that case, if parent is a `default impl`, inherited items use the
+            // "defaultness" from the grandparent, else they are final.
+            None => if tcx.impl_is_default(parent_impl.def_id()) {
+                None
+            } else {
+                Some(Err(parent_impl.def_id()))
+            }
+        }
+    });
+
+    // If `opt_result` is `None`, we have only encoutered `default impl`s that don't contain the
+    // item. This is allowed, the item isn't actually getting specialized here.
+    let result = opt_result.unwrap_or(Ok(()));
+
+    if let Err(parent_impl) = result {
+        report_forbidden_specialization(tcx, impl_item, parent_impl);
+    }
 }
 
 fn check_impl_items_against_trait<'tcx>(
@@ -1846,8 +1882,7 @@ fn check_impl_items_against_trait<'tcx>(
     let associated_type_overridden = overridden_associated_type.is_some();
     for trait_item in tcx.associated_items(impl_trait_ref.def_id) {
         let is_implemented = trait_def.ancestors(tcx, impl_id)
-            .defs(tcx, trait_item.ident, trait_item.kind, impl_trait_ref.def_id)
-            .next()
+            .leaf_def(tcx, trait_item.ident, trait_item.kind)
             .map(|node_item| !node_item.node.is_from_trait())
             .unwrap_or(false);
 
@@ -4181,20 +4216,21 @@ pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl, bool
     pub fn suggest_mismatched_types_on_tail(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
-        expression: &'tcx hir::Expr,
+        expr: &'tcx hir::Expr,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         cause_span: Span,
         blk_id: hir::HirId,
     ) -> bool {
-        self.suggest_missing_semicolon(err, expression, expected, cause_span);
+        let expr = expr.peel_drop_temps();
+        self.suggest_missing_semicolon(err, expr, expected, cause_span);
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
             pointing_at_return_type = self.suggest_missing_return_type(
                 err, &fn_decl, expected, found, can_suggest);
         }
-        self.suggest_ref_or_into(err, expression, expected, found);
-        self.suggest_boxing_when_appropriate(err, expression, expected, found);
+        self.suggest_ref_or_into(err, expr, expected, found);
+        self.suggest_boxing_when_appropriate(err, expr, expected, found);
         pointing_at_return_type
     }
 
index e736a55a5f51cead6cbbfd6c23ce733c387cdfec..fa283904fe47467e83357e6cc7d46c4db2060fbd 100644 (file)
@@ -172,6 +172,18 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) {
         _ => None
     };
     check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);
+
+    // Prohibits applying `#[track_caller]` to trait decls
+    for attr in &trait_item.attrs {
+        if attr.check_name(sym::track_caller) {
+            struct_span_err!(
+                tcx.sess,
+                attr.span,
+                E0738,
+                "`#[track_caller]` is not supported in trait declarations."
+            ).emit();
+        }
+    }
 }
 
 pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -182,6 +194,30 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
         hir::ImplItemKind::Method(ref sig, _) => Some(sig),
         _ => None
     };
+
+    // Prohibits applying `#[track_caller]` to trait impls
+    if method_sig.is_some() {
+        let track_caller_attr = impl_item.attrs.iter()
+            .find(|a| a.check_name(sym::track_caller));
+        if let Some(tc_attr) = track_caller_attr {
+            let parent_hir_id = tcx.hir().get_parent_item(hir_id);
+            let containing_item = tcx.hir().expect_item(parent_hir_id);
+            let containing_impl_is_for_trait = match &containing_item.kind {
+                hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(),
+                _ => bug!("parent of an ImplItem must be an Impl"),
+            };
+
+            if containing_impl_is_for_trait {
+                struct_span_err!(
+                    tcx.sess,
+                    tc_attr.span,
+                    E0738,
+                    "`#[track_caller]` is not supported in traits yet."
+                ).emit();
+            }
+        }
+    }
+
     check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
 }
 
index d973106058eafc37b5bc2ffe5ef615bf59780294..7f34aa354c9e858c288ae82fff7ae59b4544aa5e 100644 (file)
@@ -2560,6 +2560,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
 
     let mut inline_span = None;
+    let mut link_ordinal_span = None;
     for attr in attrs.iter() {
         if attr.check_name(sym::cold) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
@@ -2593,6 +2594,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
         } else if attr.check_name(sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
+        } else if attr.check_name(sym::track_caller) {
+            if tcx.fn_sig(id).abi() != abi::Abi::Rust {
+                struct_span_err!(
+                    tcx.sess,
+                    attr.span,
+                    E0737,
+                    "rust ABI is required to use `#[track_caller]`"
+                ).emit();
+            }
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
         } else if attr.check_name(sym::export_name) {
             if let Some(s) = attr.value_str() {
                 if s.as_str().contains("\0") {
@@ -2641,6 +2652,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             }
         } else if attr.check_name(sym::link_name) {
             codegen_fn_attrs.link_name = attr.value_str();
+        } else if attr.check_name(sym::link_ordinal) {
+            link_ordinal_span = Some(attr.span);
+            if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+                codegen_fn_attrs.link_ordinal = ordinal;
+            }
         }
     }
 
@@ -2718,6 +2734,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     // purpose functions as they wouldn't have the right target features
     // enabled. For that reason we also forbid #[inline(always)] as it can't be
     // respected.
+
     if codegen_fn_attrs.target_features.len() > 0 {
         if codegen_fn_attrs.inline == InlineAttr::Always {
             if let Some(span) = inline_span {
@@ -2742,6 +2759,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         codegen_fn_attrs.export_name = Some(name);
         codegen_fn_attrs.link_name = Some(name);
     }
+    check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
 
     // Internal symbols to the standard library all have no_mangle semantics in
     // that they have defined symbol names present in the function name. This
@@ -2752,3 +2770,48 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 
     codegen_fn_attrs
 }
+
+fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
+    use syntax::ast::{Lit, LitIntType, LitKind};
+    let meta_item_list = attr.meta_item_list();
+    let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
+    let sole_meta_list = match meta_item_list {
+        Some([item]) => item.literal(),
+        _ => None,
+    };
+    if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list {
+        if *ordinal <= std::usize::MAX as u128 {
+            Some(*ordinal as usize)
+        } else {
+            let msg = format!(
+                "ordinal value in `link_ordinal` is too large: `{}`",
+                &ordinal
+            );
+            tcx.sess.struct_span_err(attr.span, &msg)
+                .note("the value may not exceed `std::usize::MAX`")
+                .emit();
+            None
+        }
+    } else {
+        tcx.sess.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
+            .note("an unsuffixed integer value, e.g., `1`, is expected")
+            .emit();
+        None
+    }
+}
+
+fn check_link_name_xor_ordinal(
+    tcx: TyCtxt<'_>,
+    codegen_fn_attrs: &CodegenFnAttrs,
+    inline_span: Option<Span>,
+) {
+    if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
+        return;
+    }
+    let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
+    if let Some(span) = inline_span {
+        tcx.sess.span_err(span, msg);
+    } else {
+        tcx.sess.err(msg);
+    }
+}
index 3a07171b12fb80160016eb7a83463f41d141aa5f..ef08e8d4f0b7ab341d428a998b7061f653ebe29e 100644 (file)
@@ -1873,13 +1873,14 @@ struct Foo<'a> {
 differs from the behavior for `&T`, which is always `Copy`).
 "##,
 
-/*
 E0205: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 An attempt to implement the `Copy` trait for an enum failed because one of the
 variants does not implement `Copy`. To fix this, you must implement `Copy` for
 the mentioned variant. Note that this may not be possible, as in the example of
 
-```compile_fail,E0205
+```compile_fail,E0204
 enum Foo {
     Bar(Vec<u32>),
     Baz,
@@ -1892,7 +1893,7 @@ impl Copy for Foo { }
 
 Here's another example that will fail:
 
-```compile_fail,E0205
+```compile_fail,E0204
 #[derive(Copy)]
 enum Foo<'a> {
     Bar(&'a mut bool),
@@ -1903,7 +1904,6 @@ enum Foo<'a> {
 This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
 differs from the behavior for `&T`, which is always `Copy`).
 "##,
-*/
 
 E0206: r##"
 You can only implement `Copy` for a struct or enum. Both of the following
@@ -2126,8 +2126,9 @@ impl<P1, ..., Pm> ForeignTrait<T1, ..., Tn> for T0 { ... }
 [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
 "##,
 
-/*
 E0211: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 You used a function or type which doesn't fit the requirements for where it was
 used. Erroneous code examples:
 
@@ -2174,7 +2175,7 @@ fn x(self: Rc<Foo>) {}
 }
 ```
 
-The second case example is a bit particular : the main function must always
+The second case example is a bit particular: the main function must always
 have this definition:
 
 ```compile_fail
@@ -2206,7 +2207,6 @@ fn x(self: Box<Foo>) {} // ok!
 }
 ```
 "##,
-     */
 
 E0220: r##"
 You used an associated type which isn't defined in the trait.
@@ -2727,14 +2727,9 @@ impl<T, U> CoerceUnsized<MyType<U>> for MyType<T>
 [`CoerceUnsized`]: https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html
 "##,
 
-/*
-// Associated consts can now be accessed through generic type parameters, and
-// this error is no longer emitted.
-//
-// FIXME: consider whether to leave it in the error index, or remove it entirely
-//        as associated consts is not stabilized yet.
-
 E0329: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 An attempt was made to access an associated constant through either a generic
 type parameter or `Self`. This is not supported yet. An example causing this
 error is shown below:
@@ -2765,12 +2760,15 @@ trait Foo {
 
 struct MyStruct;
 
+impl Foo for MyStruct {
+    const BAR: f64 = 0f64;
+}
+
 fn get_bar_good() -> f64 {
     <MyStruct as Foo>::BAR
 }
 ```
 "##,
-*/
 
 E0366: r##"
 An attempt was made to implement `Drop` on a concrete specialization of a
@@ -4907,6 +4905,75 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
 The `Box<...>` ensures that the result is of known size,
 and the pin is required to keep it in the same place in memory.
 "##,
+
+E0737: r##"
+#[track_caller] requires functions to have the "Rust" ABI for implicitly
+receiving caller location. See [RFC 2091] for details on this and other
+restrictions.
+
+Erroneous code example:
+
+```compile_fail,E0737
+#![feature(track_caller)]
+
+#[track_caller]
+extern "C" fn foo() {}
+```
+
+[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
+"##,
+
+E0738: r##"
+#[track_caller] cannot be used in traits yet.  This is due to limitations in the
+compiler which are likely to be temporary. See [RFC 2091] for details on this
+and other restrictions.
+
+Erroneous example with a trait method implementation:
+
+```compile_fail,E0738
+#![feature(track_caller)]
+
+trait Foo {
+    fn bar(&self);
+}
+
+impl Foo for u64 {
+    #[track_caller]
+    fn bar(&self) {}
+}
+```
+
+Erroneous example with a blanket trait method implementation:
+
+```compile_fail,E0738
+#![feature(track_caller)]
+
+trait Foo {
+    #[track_caller]
+    fn bar(&self) {}
+    fn baz(&self);
+}
+```
+
+Erroneous example with a trait method declaration:
+
+```compile_fail,E0738
+#![feature(track_caller)]
+
+trait Foo {
+    fn bar(&self) {}
+
+    #[track_caller]
+    fn baz(&self);
+}
+```
+
+Note that while the compiler may be able to support the attribute in traits in
+the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
+
+[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
+"##,
+
 ;
 //  E0035, merged into E0087/E0089
 //  E0036, merged into E0087/E0089
@@ -4973,7 +5040,7 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
            // between structures with the same definition
 //  E0558, // replaced with a generic attribute input check
 //  E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
-    E0564, // only named lifetimes are allowed in `impl Trait`,
+//  E0564, // only named lifetimes are allowed in `impl Trait`,
            // but `{}` was found in the type `{}`
     E0587, // type has conflicting packed and align representation hints
     E0588, // packed type cannot transitively contain a `[repr(align)]` type
@@ -4986,7 +5053,7 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
     E0634, // type has conflicting packed representaton hints
     E0640, // infer outlives requirements
     E0641, // cannot cast to/from a pointer with an unknown kind
-    E0645, // trait aliases not finished
+//  E0645, // trait aliases not finished
     E0719, // duplicate values for associated type binding
     E0722, // Malformed `#[optimize]` attribute
     E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
index 26a8f79b8d8315df83321766d6f8b72b3cadc161..e2e8c09bb5840be06a1a4cca793bcc44fbf0352b 100644 (file)
@@ -67,7 +67,6 @@
 #![feature(nll)]
 #![feature(slice_patterns)]
 #![feature(never_type)]
-#![feature(inner_deref)]
 #![feature(mem_take)]
 
 #![recursion_limit="256"]
index 0eb8b73016d1048493b682d6b33f86cee31ed05f..e3de7fe20493e8353dbb0f729ab2390a58d47f37 100644 (file)
@@ -11,5 +11,5 @@ path = "lib.rs"
 [dependencies]
 pulldown-cmark = { version = "0.5.3", default-features = false }
 minifier = "0.0.33"
-rayon = { version = "0.2.0", package = "rustc-rayon" }
+rayon = { version = "0.3.0", package = "rustc-rayon" }
 tempfile = "3"
index 7de2583b9f6c6e383174eebe9d57fbc3cf74ca52..da3b52afadffb50a6252d2e43e9cef0fac1dbe0a 100644 (file)
@@ -360,7 +360,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                     ("target_arch", Some(arch)) => match &*arch.as_str() {
                         "aarch64" => "AArch64",
                         "arm" => "ARM",
-                        "asmjs" => "JavaScript",
+                        "asmjs" => "asm.js",
                         "mips" => "MIPS",
                         "mips64" => "MIPS-64",
                         "msp430" => "MSP430",
index 8f35ca01f79df2c8349109e9fa2ad95aca54374c..212a09ee6e6341e643b33bcdac095f69eb165686 100644 (file)
@@ -198,7 +198,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
             Item {
                 source: Span::empty(),
                 name: Some(kw.clone()),
-                attrs: attrs,
+                attrs,
                 visibility: Public,
                 stability: get_stability(cx, def_id),
                 deprecation: get_deprecation(cx, def_id),
@@ -1570,7 +1570,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
                     did: cx.tcx.hir().local_def_id(self.hir_id),
                     bounds: self.bounds.clean(cx),
                     default: default.clean(cx),
-                    synthetic: synthetic,
+                    synthetic,
                 })
             }
             hir::GenericParamKind::Const { ref ty } => {
@@ -2213,7 +2213,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
         let is_spotlight = attrs.has_doc_flag(sym::spotlight);
         Item {
             name: Some(self.name.clean(cx)),
-            attrs: attrs,
+            attrs,
             source: self.whence.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id),
             visibility: self.vis.clean(cx),
@@ -2844,7 +2844,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
                 } else {
                     Some(l.clean(cx))
                 };
-                BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
+                BorrowedRef {lifetime, mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)}
             }
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
@@ -3102,9 +3102,9 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
                 let path = external_path(cx, cx.tcx.item_name(did),
                                          None, false, vec![], InternalSubsts::empty());
                 ResolvedPath {
-                    path: path,
+                    path,
                     param_names: None,
-                    did: did,
+                    did,
                     is_generic: false,
                 }
             }
@@ -4274,7 +4274,7 @@ fn resolve_type(cx: &DocContext<'_>,
         _ => false,
     };
     let did = register_res(&*cx, path.res);
-    ResolvedPath { path: path, param_names: None, did: did, is_generic: is_generic }
+    ResolvedPath { path, param_names: None, did, is_generic }
 }
 
 pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
index 539bf5dfe28e629fff59367218888c7853f6ad0e..c23890e2a05ee590074da9b937af2baaee8f939b 100644 (file)
@@ -14,7 +14,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(const_fn)]
 #![feature(drain_filter)]
-#![feature(inner_deref)]
 #![feature(never_type)]
 #![feature(mem_take)]
 #![feature(unicode_internals)]
@@ -487,8 +486,8 @@ fn rust_input<R, F>(options: config::Options, f: F) -> R
         krate.version = crate_version;
 
         f(Output {
-            krate: krate,
-            renderinfo: renderinfo,
+            krate,
+            renderinfo,
             renderopts,
         })
     });
index ee4b367b5c5b93040c781dd7c71d18b68e5e509d..5309af6f4c342eb9e99f67b4135506ff750bd18f 100644 (file)
@@ -23,7 +23,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of
 compiler_builtins = { version = "0.1.16" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
-hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.6.1", default-features = false, features = ['rustc-dep-of-std'] }
 
 [dependencies.backtrace_rs]
 package = "backtrace"
index ff50051ef504043d673d3f3bdec1466093fa0850..fcca112563d2da04ae415174cc2d888b8b4404b7 100644 (file)
@@ -2030,6 +2030,31 @@ pub fn and_modify<F>(self, f: F) -> Self
             Vacant(entry) => Vacant(entry),
         }
     }
+
+    /// Sets the value of the entry, and returns an OccupiedEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(entry_insert)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<&str, String> = HashMap::new();
+    /// let entry = map.entry("poneyland").insert("hoho".to_string());
+    ///
+    /// assert_eq!(entry.key(), &"poneyland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "entry_insert", issue = "65225")]
+    pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V> {
+        match self {
+            Occupied(mut entry) => {
+                entry.insert(value);
+                entry
+            },
+            Vacant(entry) => entry.insert_entry(value),
+        }
+    }
 }
 
 impl<'a, K, V: Default> Entry<'a, K, V> {
@@ -2347,6 +2372,28 @@ pub fn into_key(self) -> K {
     pub fn insert(self, value: V) -> &'a mut V {
         self.base.insert(value)
     }
+
+    /// Sets the value of the entry with the VacantEntry's key,
+    /// and returns an OccupiedEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    /// use std::collections::hash_map::Entry;
+    ///
+    /// let mut map: HashMap<&str, u32> = HashMap::new();
+    ///
+    /// if let Entry::Vacant(o) = map.entry("poneyland") {
+    ///     o.insert(37);
+    /// }
+    /// assert_eq!(map["poneyland"], 37);
+    /// ```
+    #[inline]
+    fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> {
+        let base = self.base.insert_entry(value);
+        OccupiedEntry { base }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 8933f027a065f8c0b727d085c4f976bfb565a354..fc26dcb321148c1765cf00c5987d5c621b066ca1 100644 (file)
@@ -3112,8 +3112,10 @@ fn c<T: Clone>(t: &T) -> T { t.clone() }
 
         #[cfg(windows)]
         let invalid_options = 87; // ERROR_INVALID_PARAMETER
-        #[cfg(unix)]
+        #[cfg(all(unix, not(target_os = "vxworks")))]
         let invalid_options = "Invalid argument";
+        #[cfg(target_os = "vxworks")]
+        let invalid_options = "invalid argument";
 
         // Test various combinations of creation modes and access modes.
         //
index a5e7cd992f2272d226ef606c489b02f34183fac0..46bbd8855dedabdf098e2b7b90139ae12befe940 100644 (file)
@@ -185,7 +185,6 @@ pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A)
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(udp_peer_addr)]
     /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
     ///
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
@@ -199,14 +198,13 @@ pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A)
     /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected
     ///
     /// ```no_run
-    /// #![feature(udp_peer_addr)]
     /// use std::net::UdpSocket;
     ///
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// assert_eq!(socket.peer_addr().unwrap_err().kind(),
     ///            ::std::io::ErrorKind::NotConnected);
     /// ```
-    #[unstable(feature = "udp_peer_addr", issue = "59127")]
+    #[stable(feature = "udp_peer_addr", since = "1.40.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         self.0.peer_addr()
     }
index 28fb40244043e5aa46e534b9b3a1131060d9b66a..638ce1679b8e98dc0c4db2f37b0462f9516d4a8c 100644 (file)
 use crate::mem;
 use crate::ptr;
 use crate::raw;
+use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::stdio::panic_output;
 use crate::sys_common::rwlock::RWLock;
-use crate::sys_common::{thread_info, util, backtrace};
+use crate::sys_common::{thread_info, util};
+use crate::sys_common::backtrace::{self, RustBacktrace};
 use crate::thread;
 
 #[cfg(not(test))]
@@ -158,16 +160,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
 fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
-    let log_backtrace = if cfg!(feature = "backtrace") {
-        let panics = update_panic_count(0);
-
-        if panics >= 2 {
-            Some(backtrace_rs::PrintFmt::Full)
-        } else {
-            backtrace::log_enabled()
-        }
+    let backtrace_env = if update_panic_count(0) >= 2 {
+        RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
     } else {
-        None
+        backtrace::rust_backtrace_env()
     };
 
     // The current implementation always returns `Some`.
@@ -187,16 +183,16 @@ fn default_hook(info: &PanicInfo<'_>) {
         let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
                          name, msg, location);
 
-        if cfg!(feature = "backtrace") {
-            use crate::sync::atomic::{AtomicBool, Ordering};
-
-            static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
+        static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
 
-            if let Some(format) = log_backtrace {
-                let _ = backtrace::print(err, format);
-            } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
-                let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
-                                       environment variable to display a backtrace.");
+        match backtrace_env {
+            RustBacktrace::Print(format) => drop(backtrace::print(err, format)),
+            RustBacktrace::Disabled => {}
+            RustBacktrace::RuntimeDisabled => {
+                if FIRST_PANIC.swap(false, Ordering::SeqCst) {
+                    let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
+                                           environment variable to display a backtrace.");
+                }
             }
         }
     };
index cf45eb0daba3988b5626730c3988ca8a732dcd80..63e35d5ed919a294fa1c191479b008650b363aac 100644 (file)
@@ -44,12 +44,9 @@ fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindS
         sys::args::init(argc, argv);
 
         // Let's run some code!
-        #[cfg(feature = "backtrace")]
         let exit_code = panic::catch_unwind(|| {
             sys_common::backtrace::__rust_begin_short_backtrace(move || main())
         });
-        #[cfg(not(feature = "backtrace"))]
-        let exit_code = panic::catch_unwind(move || main());
 
         sys_common::cleanup();
         exit_code.unwrap_or(101) as isize
index d7e733b7fa032bc834fae05f15f8b9de0e5ec041..952ba40ee87a9d786a2762d1d6546f26a150edc4 100644 (file)
@@ -10,8 +10,7 @@
 // fallback implementation to use as well.
 //
 // Due to rust-lang/rust#18804, make sure this is not generic!
-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit", target_os = "redox",
-          target_os = "emscripten"))]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit", target_os = "redox"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
     use crate::mem;
     use crate::sys_common::thread_local::register_dtor_fallback;
index 718f422ed11e635b7fdc5d47b51ee9b11691e79d..19b123f2b6131aab14c9ee14b2f0a7ec780d2c72 100644 (file)
@@ -25,7 +25,7 @@ pub unsafe fn read(&self) {
         let r = libc::pthread_rwlock_rdlock(self.inner.get());
         if r == libc::EAGAIN {
             panic!("rwlock maximum reader count exceeded");
-        } else if r == libc::EDEADLK || *self.write_locked.get() {
+        } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
             if r == 0 {
                 self.raw_unlock();
             }
index 01711d415d86c28f6655d2f49956bc4685a65eb2..9c406ec39cc45a3afebe9154db865346318337a2 100644 (file)
@@ -7,6 +7,7 @@
 use crate::borrow::Cow;
 use crate::io::prelude::*;
 use crate::path::{self, Path, PathBuf};
+use crate::sync::atomic::{self, Ordering};
 use crate::sys::mutex::Mutex;
 
 use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
@@ -115,8 +116,10 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
     Ok(())
 }
 
-/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
-#[inline(never)]
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
+/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// it's fine to optimize away.
+#[cfg_attr(feature = "backtrace", inline(never))]
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
 where
     F: FnOnce() -> T,
@@ -126,42 +129,49 @@ pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
     f()
 }
 
+pub enum RustBacktrace {
+    Print(PrintFmt),
+    Disabled,
+    RuntimeDisabled,
+}
+
 // For now logging is turned off by default, and this function checks to see
 // whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> Option<PrintFmt> {
-    use crate::sync::atomic::{self, Ordering};
+pub fn rust_backtrace_env() -> RustBacktrace {
+    // If the `backtrace` feature of this crate isn't enabled quickly return
+    // `None` so this can be constant propagated all over the place to turn
+    // optimize away callers.
+    if !cfg!(feature = "backtrace") {
+        return RustBacktrace::Disabled;
+    }
 
     // Setting environment variables for Fuchsia components isn't a standard
     // or easily supported workflow. For now, always display backtraces.
     if cfg!(target_os = "fuchsia") {
-        return Some(PrintFmt::Full);
+        return RustBacktrace::Print(PrintFmt::Full);
     }
 
     static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
     match ENABLED.load(Ordering::SeqCst) {
         0 => {}
-        1 => return None,
-        2 => return Some(PrintFmt::Short),
-        _ => return Some(PrintFmt::Full),
+        1 => return RustBacktrace::RuntimeDisabled,
+        2 => return RustBacktrace::Print(PrintFmt::Short),
+        _ => return RustBacktrace::Print(PrintFmt::Full),
     }
 
-    let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
-        if &x == "0" {
-            None
-        } else if &x == "full" {
-            Some(PrintFmt::Full)
-        } else {
-            Some(PrintFmt::Short)
-        }
-    });
-    ENABLED.store(
-        match val {
-            Some(v) => v as isize,
-            None => 1,
-        },
-        Ordering::SeqCst,
-    );
-    val
+    let (format, cache) = env::var_os("RUST_BACKTRACE")
+        .map(|x| {
+            if &x == "0" {
+                (RustBacktrace::RuntimeDisabled, 1)
+            } else if &x == "full" {
+                (RustBacktrace::Print(PrintFmt::Full), 3)
+            } else {
+                (RustBacktrace::Print(PrintFmt::Short), 2)
+            }
+        })
+        .unwrap_or((RustBacktrace::RuntimeDisabled, 1));
+    ENABLED.store(cache, Ordering::SeqCst);
+    format
 }
 
 /// Prints the filename of the backtrace frame.
index 764041d2f4239f668c9efafc3a99bac075dcca83..0ffa6ace2e4d2ea73ce1824b2149152c2bd90b70 100644 (file)
@@ -465,12 +465,9 @@ pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>>
             }
 
             thread_info::set(imp::guard::current(), their_thread);
-            #[cfg(feature = "backtrace")]
             let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
                 crate::sys_common::backtrace::__rust_begin_short_backtrace(f)
             }));
-            #[cfg(not(feature = "backtrace"))]
-            let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
             *their_packet.get() = Some(try_result);
         };
 
index 3bf2b8be1fe8e32d68a43f7301a0dcae418773be..e1ae01b602a8db8d97e1620837b79af23a485d04 100644 (file)
 use crate::cmp;
 use crate::error::Error;
 use crate::fmt;
-use crate::ops::{Add, Sub, AddAssign, SubAssign};
+use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::time;
-use crate::sys_common::FromInner;
 use crate::sys_common::mutex::Mutex;
+use crate::sys_common::FromInner;
 
 #[stable(feature = "time", since = "1.3.0")]
 pub use core::time::Duration;
@@ -216,17 +216,17 @@ pub fn now() -> Instant {
         // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
         //   Firefox bug
         //
-        // It simply seems that this it just happens so that a lot in the wild
-        // we're seeing panics across various platforms where consecutive calls
+        // It seems that this just happens a lot in the wild.
+        // We're seeing panics across various platforms where consecutive calls
         // to `Instant::now`, such as via the `elapsed` function, are panicking
         // as they're going backwards. Placed here is a last-ditch effort to try
         // to fix things up. We keep a global "latest now" instance which is
         // returned instead of what the OS says if the OS goes backwards.
         //
-        // To hopefully mitigate the impact of this though a few platforms are
+        // To hopefully mitigate the impact of this, a few platforms are
         // whitelisted as "these at least haven't gone backwards yet".
         if time::Instant::actually_monotonic() {
-            return Instant(os_now)
+            return Instant(os_now);
         }
 
         static LOCK: Mutex = Mutex::new();
@@ -353,8 +353,7 @@ impl Add<Duration> for Instant {
     ///
     /// [`checked_add`]: ../../std/time/struct.Instant.html#method.checked_add
     fn add(self, other: Duration) -> Instant {
-        self.checked_add(other)
-            .expect("overflow when adding duration to instant")
+        self.checked_add(other).expect("overflow when adding duration to instant")
     }
 }
 
@@ -370,8 +369,7 @@ impl Sub<Duration> for Instant {
     type Output = Instant;
 
     fn sub(self, other: Duration) -> Instant {
-        self.checked_sub(other)
-            .expect("overflow when subtracting duration from instant")
+        self.checked_sub(other).expect("overflow when subtracting duration from instant")
     }
 }
 
@@ -464,8 +462,7 @@ pub fn now() -> SystemTime {
     /// println!("{:?}", difference);
     /// ```
     #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration_since(&self, earlier: SystemTime)
-                          -> Result<Duration, SystemTimeError> {
+    pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
         self.0.sub_time(&earlier.0).map_err(SystemTimeError)
     }
 
@@ -532,8 +529,7 @@ impl Add<Duration> for SystemTime {
     ///
     /// [`checked_add`]: ../../std/time/struct.SystemTime.html#method.checked_add
     fn add(self, dur: Duration) -> SystemTime {
-        self.checked_add(dur)
-            .expect("overflow when adding duration to instant")
+        self.checked_add(dur).expect("overflow when adding duration to instant")
     }
 }
 
@@ -549,8 +545,7 @@ impl Sub<Duration> for SystemTime {
     type Output = SystemTime;
 
     fn sub(self, dur: Duration) -> SystemTime {
-        self.checked_sub(dur)
-            .expect("overflow when subtracting duration from instant")
+        self.checked_sub(dur).expect("overflow when subtracting duration from instant")
     }
 }
 
@@ -626,7 +621,9 @@ pub fn duration(&self) -> Duration {
 
 #[stable(feature = "time2", since = "1.8.0")]
 impl Error for SystemTimeError {
-    fn description(&self) -> &str { "other time was not earlier than self" }
+    fn description(&self) -> &str {
+        "other time was not earlier than self"
+    }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
@@ -644,17 +641,16 @@ fn from_inner(time: time::SystemTime) -> SystemTime {
 
 #[cfg(test)]
 mod tests {
-    use super::{Instant, SystemTime, Duration, UNIX_EPOCH};
+    use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
 
     macro_rules! assert_almost_eq {
-        ($a:expr, $b:expr) => ({
+        ($a:expr, $b:expr) => {{
             let (a, b) = ($a, $b);
             if a != b {
-                let (a, b) = if a > b {(a, b)} else {(b, a)};
-                assert!(a - Duration::new(0, 1000) <= b,
-                        "{:?} is not almost equal to {:?}", a, b);
+                let (a, b) = if a > b { (a, b) } else { (b, a) };
+                assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b);
             }
-        })
+        }};
     }
 
     #[test]
@@ -729,7 +725,7 @@ fn instant_checked_duration_since_nopanic() {
     fn instant_saturating_duration_since_nopanic() {
         let a = Instant::now();
         let ret = (a - Duration::new(1, 0)).saturating_duration_since(a);
-        assert_eq!(ret, Duration::new(0,0));
+        assert_eq!(ret, Duration::new(0, 0));
     }
 
     #[test]
@@ -755,15 +751,14 @@ fn system_time_math() {
 
         let second = Duration::new(1, 0);
         assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
-        assert_almost_eq!(a.duration_since(a + second).unwrap_err()
-                           .duration(), second);
+        assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);
 
         assert_almost_eq!(a - second + second, a);
         assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
 
         let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
-        let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
-            + Duration::new(0, 500_000_000);
+        let one_second_from_epoch2 =
+            UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000);
         assert_eq!(one_second_from_epoch, one_second_from_epoch2);
 
         // checked_add_duration will not panic on overflow
index 36c1da2929975a3ec15ac7f4efbd58a7d0a16a99..5cc953b9066282400bd11c5493f90c1bf4a0873b 100644 (file)
@@ -11,6 +11,7 @@
 pub enum BufferedEarlyLintId {
     IllFormedAttributeInput,
     MetaVariableMisuse,
+    IncompleteInclude,
 }
 
 /// Stores buffered lint info which can later be passed to `librustc`.
index c0963026945b0f9039bb669f5c6ebd59c518b00a..fc3f095856a800a68916338ddb8891dca9f12a2b 100644 (file)
@@ -163,6 +163,25 @@ fn the_banished() {} // ok!
 ```
 "##,
 
+E0551: r##"
+An invalid meta-item was used inside an attribute.
+
+Erroneous code example:
+
+```compile_fail,E0551
+#[deprecated(note)] // error!
+fn i_am_deprecated() {}
+```
+
+Meta items are the key-value pairs inside of an attribute. To fix this issue,
+you need to give a value to the `note` key. Example:
+
+```
+#[deprecated(note = "because")] // ok!
+fn i_am_deprecated() {}
+```
+"##,
+
 E0552: r##"
 A unrecognized representation attribute was used.
 
@@ -473,7 +492,6 @@ pub(in crate::foo) struct Bar {
     // rustc_deprecated attribute must be paired with either stable or unstable
     // attribute
     E0549,
-    E0551, // incorrect meta item
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
     E0584, // file for module `..` found at both .. and ..
index 47ee41f0adc1690b0d0de4e1437ba1906b61c1a1..94f0995566f5289fa6f66229528281ac0a1c0e8c 100644 (file)
@@ -519,6 +519,15 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows the use of or-patterns (e.g., `0 | 1`).
     (active, or_patterns, "1.38.0", Some(54883), None),
 
+    /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
+    (active, const_extern_fn, "1.40.0", Some(64926), None),
+
+    // Allows the use of raw-dylibs (RFC 2627).
+    (active, raw_dylib, "1.40.0", Some(58713), None),
+
+    /// Enable accurate caller location reporting during panic (RFC 2091).
+    (active, track_caller, "1.40.0", Some(47809), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -533,4 +542,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     sym::const_generics,
     sym::or_patterns,
     sym::let_chains,
+    sym::raw_dylib,
+    sym::track_caller,
 ];
index 80a80ff0a0d47b100ad4d97c994751be84adb420..ae23cc5cb933c24f631dd48415bc6a1580ff52d6 100644 (file)
@@ -276,6 +276,10 @@ macro_rules! experimental {
         "the `link_args` attribute is experimental and not portable across platforms, \
         it is recommended to use `#[link(name = \"foo\")] instead",
     ),
+    gated!(
+        link_ordinal, Whitelisted, template!(List: "ordinal"), raw_dylib,
+        experimental!(link_ordinal)
+    ),
 
     // Plugins:
     (
@@ -320,6 +324,7 @@ macro_rules! experimental {
     ),
 
     gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)),
+    gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)),
 
     // ==========================================================================
     // Internal attributes: Stability, deprecation, and unsafe:
index d7fc74955bbbde1c421c5c1e86226f594df07b97..9e40b1a26ac1a6d0ae34a52f2522c68a673b0ec9 100644 (file)
@@ -821,6 +821,7 @@ macro_rules! gate_all {
     gate_all!(async_closure, "async closures are unstable");
     gate_all!(yields, generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
+    gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
 
     visit::walk_crate(&mut visitor, krate);
 }
index 4ad0bd06d99aeb68129a470a8b7e13a7c03806a1..f376c19a66ccd5e294669421ed8f576bb7253bf9 100644 (file)
@@ -17,6 +17,7 @@
 use log::{debug, trace};
 use std::mem;
 
+const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments";
 /// Creates a placeholder argument.
 crate fn dummy_arg(ident: Ident) -> Param {
     let pat = P(Pat {
@@ -543,35 +544,154 @@ pub fn maybe_annotate_with_ascription(
     }
 
     /// Produces an error if comparison operators are chained (RFC #558).
-    /// We only need to check the LHS, not the RHS, because all comparison ops
-    /// have same precedence and are left-associative.
-    crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> {
-        debug_assert!(outer_op.is_comparison(),
-                      "check_no_chained_comparison: {:?} is not comparison",
-                      outer_op);
+    /// We only need to check the LHS, not the RHS, because all comparison ops have same
+    /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
+    ///
+    /// This can also be hit if someone incorrectly writes `foo<bar>()` when they should have used
+    /// the turbofish (`foo::<bar>()`) syntax. We attempt some heuristic recovery if that is the
+    /// case.
+    ///
+    /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left
+    /// associative we can infer that we have:
+    ///
+    ///           outer_op
+    ///           /   \
+    ///     inner_op   r2
+    ///        /  \
+    ///     l1    r1
+    crate fn check_no_chained_comparison(
+        &mut self,
+        lhs: &Expr,
+        outer_op: &AssocOp,
+    ) -> PResult<'a, Option<P<Expr>>> {
+        debug_assert!(
+            outer_op.is_comparison(),
+            "check_no_chained_comparison: {:?} is not comparison",
+            outer_op,
+        );
+
+        let mk_err_expr = |this: &Self, span| {
+            Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new())))
+        };
+
         match lhs.kind {
             ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
                 // Respan to include both operators.
-                let op_span = op.span.to(self.token.span);
+                let op_span = op.span.to(self.prev_span);
                 let mut err = self.struct_span_err(
                     op_span,
                     "chained comparison operators require parentheses",
                 );
+
+                let suggest = |err: &mut DiagnosticBuilder<'_>| {
+                    err.span_suggestion_verbose(
+                        op_span.shrink_to_lo(),
+                        TURBOFISH,
+                        "::".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                };
+
                 if op.node == BinOpKind::Lt &&
                     *outer_op == AssocOp::Less ||  // Include `<` to provide this recommendation
                     *outer_op == AssocOp::Greater  // even in a case like the following:
                 {                                  //     Foo<Bar<Baz<Qux, ()>>>
-                    err.help(
-                        "use `::<...>` instead of `<...>` if you meant to specify type arguments");
-                    err.help("or use `(...)` if you meant to specify fn arguments");
-                    // These cases cause too many knock-down errors, bail out (#61329).
-                    return Err(err);
+                    if *outer_op == AssocOp::Less {
+                        let snapshot = self.clone();
+                        self.bump();
+                        // So far we have parsed `foo<bar<`, consume the rest of the type args.
+                        let modifiers = [
+                            (token::Lt, 1),
+                            (token::Gt, -1),
+                            (token::BinOp(token::Shr), -2),
+                        ];
+                        self.consume_tts(1, &modifiers[..]);
+
+                        if !&[
+                            token::OpenDelim(token::Paren),
+                            token::ModSep,
+                        ].contains(&self.token.kind) {
+                            // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
+                            // parser and bail out.
+                            mem::replace(self, snapshot.clone());
+                        }
+                    }
+                    return if token::ModSep == self.token.kind {
+                        // We have some certainty that this was a bad turbofish at this point.
+                        // `foo< bar >::`
+                        suggest(&mut err);
+
+                        let snapshot = self.clone();
+                        self.bump(); // `::`
+
+                        // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
+                        match self.parse_expr() {
+                            Ok(_) => {
+                                // 99% certain that the suggestion is correct, continue parsing.
+                                err.emit();
+                                // FIXME: actually check that the two expressions in the binop are
+                                // paths and resynthesize new fn call expression instead of using
+                                // `ExprKind::Err` placeholder.
+                                mk_err_expr(self, lhs.span.to(self.prev_span))
+                            }
+                            Err(mut expr_err) => {
+                                expr_err.cancel();
+                                // Not entirely sure now, but we bubble the error up with the
+                                // suggestion.
+                                mem::replace(self, snapshot);
+                                Err(err)
+                            }
+                        }
+                    } else if token::OpenDelim(token::Paren) == self.token.kind {
+                        // We have high certainty that this was a bad turbofish at this point.
+                        // `foo< bar >(`
+                        suggest(&mut err);
+                        // Consume the fn call arguments.
+                        match self.consume_fn_args() {
+                            Err(()) => Err(err),
+                            Ok(()) => {
+                                err.emit();
+                                // FIXME: actually check that the two expressions in the binop are
+                                // paths and resynthesize new fn call expression instead of using
+                                // `ExprKind::Err` placeholder.
+                                mk_err_expr(self, lhs.span.to(self.prev_span))
+                            }
+                        }
+                    } else {
+                        // All we know is that this is `foo < bar >` and *nothing* else. Try to
+                        // be helpful, but don't attempt to recover.
+                        err.help(TURBOFISH);
+                        err.help("or use `(...)` if you meant to specify fn arguments");
+                        // These cases cause too many knock-down errors, bail out (#61329).
+                        Err(err)
+                    };
                 }
                 err.emit();
             }
             _ => {}
         }
-        Ok(())
+        Ok(None)
+    }
+
+    fn consume_fn_args(&mut self) -> Result<(), ()> {
+        let snapshot = self.clone();
+        self.bump(); // `(`
+
+        // Consume the fn call arguments.
+        let modifiers = [
+            (token::OpenDelim(token::Paren), 1),
+            (token::CloseDelim(token::Paren), -1),
+        ];
+        self.consume_tts(1, &modifiers[..]);
+
+        if self.token.kind == token::Eof {
+            // Not entirely sure that what we consumed were fn arguments, rollback.
+            mem::replace(self, snapshot);
+            Err(())
+        } else {
+            // 99% certain that the suggestion is correct, continue parsing.
+            Ok(())
+        }
     }
 
     crate fn maybe_report_ambiguous_plus(
@@ -1364,6 +1484,23 @@ fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question:
         err
     }
 
+    fn consume_tts(
+        &mut self,
+        mut acc: i64, // `i64` because malformed code can have more closing delims than opening.
+        // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`.
+        modifier: &[(token::TokenKind, i64)],
+    ) {
+        while acc > 0 {
+            if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) {
+                acc += *val;
+            }
+            if self.token.kind == token::Eof {
+                break;
+            }
+            self.bump();
+        }
+    }
+
     /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors.
     ///
     /// This is necessary because at this point we don't know whether we parsed a function with
index fa4c10431228ade0ce645b5c270031a585f64592..1518da23b096f329e786525a7a052f9c057c5850 100644 (file)
@@ -57,6 +57,8 @@ pub struct GatedSpans {
     pub yields: Lock<Vec<Span>>,
     /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`.
     pub or_patterns: Lock<Vec<Span>>,
+    /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`.
+    pub const_extern_fn: Lock<Vec<Span>>,
 }
 
 /// Info about a parsing session.
index d4a6e9f6c6bc8f4fa1d9ccd10a024a4151c5d9df..4a457f5a43caa651dd34e0bab0ccf7ffc8dc4b38 100644 (file)
@@ -11,7 +11,7 @@
 mod generics;
 
 use crate::ast::{
-    self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident,
+    self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
     IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
     VisibilityKind, Unsafety,
 };
@@ -56,6 +56,17 @@ struct Restrictions: u8 {
     Ignore,
 }
 
+/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
+struct ParamCfg {
+    /// Is `self` is allowed as the first parameter?
+    is_self_allowed: bool,
+    /// Is `...` allowed as the tail of the parameter list?
+    allow_c_variadic: bool,
+    /// `is_name_required` decides if, per-parameter,
+    /// the parameter must have a pattern or just a type.
+    is_name_required: fn(&token::Token) -> bool,
+}
+
 /// Like `maybe_whole_expr`, but for things other than expressions.
 #[macro_export]
 macro_rules! maybe_whole {
@@ -1094,26 +1105,18 @@ fn with_res<T>(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) ->
         res
     }
 
-    fn parse_fn_params(
-        &mut self,
-        named_params: bool,
-        allow_c_variadic: bool,
-    ) -> PResult<'a, Vec<Param>> {
+    /// Parses the parameter list of a function, including the `(` and `)` delimiters.
+    fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
         let sp = self.token.span;
-        let do_not_enforce_named_params_for_c_variadic = |token: &token::Token| {
-            match token.kind {
-                token::DotDotDot => false,
-                _ => named_params,
-            }
-        };
+        let is_trait_item = cfg.is_self_allowed;
         let mut c_variadic = false;
+        // Parse the arguments, starting out with `self` being possibly allowed...
         let (params, _) = self.parse_paren_comma_seq(|p| {
-            match p.parse_param_general(
-                false,
-                false,
-                allow_c_variadic,
-                do_not_enforce_named_params_for_c_variadic,
-            ) {
+            let param = p.parse_param_general(&cfg, is_trait_item);
+            // ...now that we've parsed the first argument, `self` is no longer allowed.
+            cfg.is_self_allowed = false;
+
+            match param {
                 Ok(param) => Ok(
                     if let TyKind::CVarArgs = param.ty.kind {
                         c_variadic = true;
@@ -1144,7 +1147,10 @@ fn parse_fn_params(
             }
         })?;
 
-        let params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
+        let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
+
+        // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
+        self.deduplicate_recovered_params_names(&mut params);
 
         if c_variadic && params.len() <= 1 {
             self.span_err(
@@ -1156,79 +1162,53 @@ fn parse_fn_params(
         Ok(params)
     }
 
-    /// Parses the parameter list and result type of a function that may have a `self` parameter.
-    fn parse_fn_decl_with_self(
-        &mut self,
-        is_name_required: impl Copy + Fn(&token::Token) -> bool,
-    ) -> PResult<'a, P<FnDecl>> {
-        // Parse the arguments, starting out with `self` being allowed...
-        let mut is_self_allowed = true;
-        let (mut inputs, _): (Vec<_>, _) = self.parse_paren_comma_seq(|p| {
-            let res = p.parse_param_general(is_self_allowed, true, false, is_name_required);
-            // ...but now that we've parsed the first argument, `self` is no longer allowed.
-            is_self_allowed = false;
-            res
-        })?;
-
-        // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
-        self.deduplicate_recovered_params_names(&mut inputs);
-
-        Ok(P(FnDecl {
-            inputs,
-            output: self.parse_ret_ty(true)?,
-        }))
-    }
-
     /// Skips unexpected attributes and doc comments in this position and emits an appropriate
     /// error.
     /// This version of parse param doesn't necessarily require identifier names.
-    fn parse_param_general(
-        &mut self,
-        is_self_allowed: bool,
-        is_trait_item: bool,
-        allow_c_variadic: bool,
-        is_name_required: impl Fn(&token::Token) -> bool,
-    ) -> PResult<'a, Param> {
+    fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
 
         // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
         if let Some(mut param) = self.parse_self_param()? {
             param.attrs = attrs.into();
-            return if is_self_allowed {
+            return if cfg.is_self_allowed {
                 Ok(param)
             } else {
                 self.recover_bad_self_param(param, is_trait_item)
             };
         }
 
-        let is_name_required = is_name_required(&self.token);
+        let is_name_required = match self.token.kind {
+            token::DotDotDot => false,
+            _ => (cfg.is_name_required)(&self.token),
+        };
         let (pat, ty) = if is_name_required || self.is_named_param() {
             debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
 
             let pat = self.parse_fn_param_pat()?;
             if let Err(mut err) = self.expect(&token::Colon) {
-                if let Some(ident) = self.parameter_without_type(
+                return if let Some(ident) = self.parameter_without_type(
                     &mut err,
                     pat,
                     is_name_required,
-                    is_self_allowed,
+                    cfg.is_self_allowed,
                     is_trait_item,
                 ) {
                     err.emit();
-                    return Ok(dummy_arg(ident));
+                    Ok(dummy_arg(ident))
                 } else {
-                    return Err(err);
-                }
+                    Err(err)
+                };
             }
 
             self.eat_incorrect_doc_comment_for_param_type();
-            (pat, self.parse_ty_common(true, true, allow_c_variadic)?)
+            (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
         } else {
             debug!("parse_param_general ident_to_pat");
             let parser_snapshot_before_ty = self.clone();
             self.eat_incorrect_doc_comment_for_param_type();
-            let mut ty = self.parse_ty_common(true, true, allow_c_variadic);
+            let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
             if ty.is_ok() && self.token != token::Comma &&
                self.token != token::CloseDelim(token::Paren) {
                 // This wasn't actually a type, but a pattern looking like a type,
@@ -1487,6 +1467,15 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
         Ok(())
     }
 
+    /// Parses `extern` followed by an optional ABI string, or nothing.
+    fn parse_extern_abi(&mut self) -> PResult<'a, Abi> {
+        if self.eat_keyword(kw::Extern) {
+            Ok(self.parse_opt_abi()?.unwrap_or(Abi::C))
+        } else {
+            Ok(Abi::Rust)
+        }
+    }
+
     /// Parses a string as an ABI spec on an extern type or module. Consumes
     /// the `extern` keyword, if one is found.
     fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> {
index 23674ad589dc570716e65b9225355c265b36672b..b459782d237c7c6ecbeadc84db10eef5e203fc1a 100644 (file)
@@ -238,7 +238,9 @@ pub(super) fn parse_assoc_expr_with(
 
             self.bump();
             if op.is_comparison() {
-                self.check_no_chained_comparison(&lhs, &op)?;
+                if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
+                    return Ok(expr);
+                }
             }
             // Special cases:
             if op == AssocOp::As {
index c00a5807d52c5d56a125715f45eace6b4adc33b8..3c60c88e2aa5887b2001a173ca7b5356f894cfca 100644 (file)
@@ -1,10 +1,10 @@
-use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
+use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
 
 use crate::maybe_whole;
 use crate::ptr::P;
 use crate::ast::{
     self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle,
-    Item, ItemKind, ImplItem, TraitItem, TraitItemKind,
+    Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind,
     UseTree, UseTreeKind, PathSegment,
     IsAuto, Constness, IsAsync, Unsafety, Defaultness,
     Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
@@ -98,7 +98,7 @@ fn parse_item_implementation(
 
         let lo = self.token.span;
 
-        let visibility = self.parse_visibility(false)?;
+        let vis = self.parse_visibility(false)?;
 
         if self.eat_keyword(kw::Use) {
             // USE ITEM
@@ -106,15 +106,14 @@ fn parse_item_implementation(
             self.expect(&token::Semi)?;
 
             let span = lo.to(self.prev_span);
-            let item =
-                self.mk_item(span, Ident::invalid(), item_, visibility, attrs);
+            let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs);
             return Ok(Some(item));
         }
 
         if self.eat_keyword(kw::Extern) {
             let extern_sp = self.prev_span;
             if self.eat_keyword(kw::Crate) {
-                return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?));
+                return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
             }
 
             let opt_abi = self.parse_opt_abi()?;
@@ -128,10 +127,10 @@ fn parse_item_implementation(
                     constness: respan(fn_span, Constness::NotConst),
                     abi: opt_abi.unwrap_or(Abi::C),
                 };
-                return self.parse_item_fn(lo, visibility, attrs, header);
+                return self.parse_item_fn(lo, vis, attrs, header);
             } else if self.check(&token::OpenDelim(token::Brace)) {
                 return Ok(Some(
-                    self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?,
+                    self.parse_item_foreign_mod(lo, opt_abi, vis, attrs, extern_sp)?,
                 ));
             }
 
@@ -142,26 +141,31 @@ fn parse_item_implementation(
             self.bump();
             // STATIC ITEM
             let m = self.parse_mutability();
-            let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_const(Some(m))?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.eat_keyword(kw::Const) {
             let const_span = self.prev_span;
-            if self.check_keyword(kw::Fn)
-                || (self.check_keyword(kw::Unsafe)
-                    && self.is_keyword_ahead(1, &[kw::Fn])) {
+            if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) {
                 // CONST FUNCTION ITEM
                 let unsafety = self.parse_unsafety();
-                self.bump();
+
+                if self.check_keyword(kw::Extern) {
+                    self.sess.gated_spans.const_extern_fn.borrow_mut().push(
+                        lo.to(self.token.span)
+                    );
+                }
+                let abi = self.parse_extern_abi()?;
+                self.bump(); // `fn`
+
                 let header = FnHeader {
                     unsafety,
                     asyncness: respan(const_span, IsAsync::NotAsync),
                     constness: respan(const_span, Constness::Const),
-                    abi: Abi::Rust,
+                    abi,
                 };
-                return self.parse_item_fn(lo, visibility, attrs, header);
+                return self.parse_item_fn(lo, vis, attrs, header);
             }
 
             // CONST ITEM
@@ -177,10 +181,9 @@ fn parse_item_implementation(
                     )
                     .emit();
             }
-            let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+
+            let info = self.parse_item_const(None)?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
         // Parses `async unsafe? fn`.
@@ -205,40 +208,33 @@ fn parse_item_implementation(
                     constness: respan(fn_span, Constness::NotConst),
                     abi: Abi::Rust,
                 };
-                return self.parse_item_fn(lo, visibility, attrs, header);
+                return self.parse_item_fn(lo, vis, attrs, header);
             }
         }
+
         if self.check_keyword(kw::Unsafe) &&
             self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
         {
             // UNSAFE TRAIT ITEM
             self.bump(); // `unsafe`
-            let is_auto = if self.eat_keyword(kw::Trait) {
-                IsAuto::No
-            } else {
-                self.expect_keyword(kw::Auto)?;
-                self.expect_keyword(kw::Trait)?;
-                IsAuto::Yes
-            };
-            let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Unsafe)?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_trait(Unsafety::Unsafe)?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.check_keyword(kw::Impl) ||
            self.check_keyword(kw::Unsafe) &&
                 self.is_keyword_ahead(1, &[kw::Impl]) ||
            self.check_keyword(kw::Default) &&
-                self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) {
+                self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe])
+        {
             // IMPL ITEM
             let defaultness = self.parse_defaultness();
             let unsafety = self.parse_unsafety();
             self.expect_keyword(kw::Impl)?;
-            let (ident, item_, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_impl(unsafety, defaultness)?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.check_keyword(kw::Fn) {
             // FUNCTION ITEM
             self.bump();
@@ -249,19 +245,17 @@ fn parse_item_implementation(
                 constness: respan(fn_span, Constness::NotConst),
                 abi: Abi::Rust,
             };
-            return self.parse_item_fn(lo, visibility, attrs, header);
+            return self.parse_item_fn(lo, vis, attrs, header);
         }
+
         if self.check_keyword(kw::Unsafe)
-            && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
+            && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace))
+        {
             // UNSAFE FUNCTION ITEM
             self.bump(); // `unsafe`
             // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic.
             self.check(&token::OpenDelim(token::Brace));
-            let abi = if self.eat_keyword(kw::Extern) {
-                self.parse_opt_abi()?.unwrap_or(Abi::C)
-            } else {
-                Abi::Rust
-            };
+            let abi = self.parse_extern_abi()?;
             self.expect_keyword(kw::Fn)?;
             let fn_span = self.prev_span;
             let header = FnHeader {
@@ -270,15 +264,15 @@ fn parse_item_implementation(
                 constness: respan(fn_span, Constness::NotConst),
                 abi,
             };
-            return self.parse_item_fn(lo, visibility, attrs, header);
+            return self.parse_item_fn(lo, vis, attrs, header);
         }
+
         if self.eat_keyword(kw::Mod) {
             // MODULE ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_mod(&attrs[..])?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if let Some(type_) = self.eat_type() {
             let (ident, alias, generics) = type_?;
             // TYPE ITEM
@@ -287,54 +281,44 @@ fn parse_item_implementation(
                 AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics),
             };
             let span = lo.to(self.prev_span);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            return Ok(Some(self.mk_item(span, ident, item_, vis, attrs)));
         }
+
         if self.eat_keyword(kw::Enum) {
             // ENUM ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_enum()?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_enum()?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.check_keyword(kw::Trait)
             || (self.check_keyword(kw::Auto)
                 && self.is_keyword_ahead(1, &[kw::Trait]))
         {
-            let is_auto = if self.eat_keyword(kw::Trait) {
-                IsAuto::No
-            } else {
-                self.expect_keyword(kw::Auto)?;
-                self.expect_keyword(kw::Trait)?;
-                IsAuto::Yes
-            };
             // TRAIT ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_trait(is_auto, Unsafety::Normal)?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_trait(Unsafety::Normal)?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.eat_keyword(kw::Struct) {
             // STRUCT ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_struct()?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_struct()?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
+
         if self.is_union_item() {
             // UNION ITEM
             self.bump();
-            let (ident, item_, extra_attrs) = self.parse_item_union()?;
-            let span = lo.to(self.prev_span);
-            let attrs = maybe_append(attrs, extra_attrs);
-            return Ok(Some(self.mk_item(span, ident, item_, visibility, attrs)));
+            let info = self.parse_item_union()?;
+            return self.mk_item_with_info(attrs, lo, vis, info);
         }
-        if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? {
+
+        if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? {
             return Ok(Some(macro_def));
         }
 
         // Verify whether we have encountered a struct or method definition where the user forgot to
         // add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
-        if visibility.node.is_pub() &&
+        if vis.node.is_pub() &&
             self.check_ident() &&
             self.look_ahead(1, |t| *t != token::Not)
         {
@@ -425,7 +409,20 @@ fn parse_item_implementation(
                 return Err(err);
             }
         }
-        self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
+        self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
+    }
+
+    fn mk_item_with_info(
+        &self,
+        attrs: Vec<Attribute>,
+        lo: Span,
+        vis: Visibility,
+        info: ItemInfo,
+    ) -> PResult<'a, Option<P<Item>>> {
+        let (ident, item, extra_attrs) = info;
+        let span = lo.to(self.prev_span);
+        let attrs = maybe_append(attrs, extra_attrs);
+        Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
     }
 
     fn recover_first_param(&mut self) -> &'static str {
@@ -724,16 +721,7 @@ fn parse_impl_item_(&mut self,
             };
             (name, kind, generics)
         } else if self.is_const_item() {
-            // This parses the grammar:
-            //     ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
-            self.expect_keyword(kw::Const)?;
-            let name = self.parse_ident()?;
-            self.expect(&token::Colon)?;
-            let typ = self.parse_ty()?;
-            self.expect(&token::Eq)?;
-            let expr = self.parse_expr()?;
-            self.expect(&token::Semi)?;
-            (name, ast::ImplItemKind::Const(typ, expr), Generics::default())
+            self.parse_impl_const()?
         } else {
             let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?;
             attrs.extend(inner_attrs);
@@ -782,12 +770,25 @@ fn is_const_item(&self) -> bool {
             !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
     }
 
+    /// This parses the grammar:
+    ///     ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
+    fn parse_impl_const(&mut self) -> PResult<'a, (Ident, ImplItemKind, Generics)> {
+        self.expect_keyword(kw::Const)?;
+        let name = self.parse_ident()?;
+        self.expect(&token::Colon)?;
+        let typ = self.parse_ty()?;
+        self.expect(&token::Eq)?;
+        let expr = self.parse_expr()?;
+        self.expect(&token::Semi)?;
+        Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
+    }
+
     /// Parses a method or a macro invocation in a trait impl.
     fn parse_impl_method(
         &mut self,
         vis: &Visibility,
         at_end: &mut bool
-    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ast::ImplItemKind)> {
+    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
         // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
         if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
             // method macro
@@ -804,14 +805,15 @@ fn parse_impl_method(
     /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
     fn parse_method_sig(
         &mut self,
-        is_name_required: impl Copy + Fn(&token::Token) -> bool,
+        is_name_required: fn(&token::Token) -> bool,
     ) -> PResult<'a, (Ident, MethodSig, Generics)> {
         let header = self.parse_fn_front_matter()?;
-        let (ident, mut generics) = self.parse_fn_header()?;
-        let decl = self.parse_fn_decl_with_self(is_name_required)?;
-        let sig = MethodSig { header, decl };
-        generics.where_clause = self.parse_where_clause()?;
-        Ok((ident, sig, generics))
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: true,
+            allow_c_variadic: false,
+            is_name_required,
+        })?;
+        Ok((ident, MethodSig { header, decl }, generics))
     }
 
     /// Parses all the "front matter" for a `fn` declaration, up to
@@ -834,11 +836,7 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         let (constness, unsafety, abi) = if is_const_fn {
             (respan(const_span, Constness::Const), unsafety, Abi::Rust)
         } else {
-            let abi = if self.eat_keyword(kw::Extern) {
-                self.parse_opt_abi()?.unwrap_or(Abi::C)
-            } else {
-                Abi::Rust
-            };
+            let abi = self.parse_extern_abi()?;
             (respan(self.prev_span, Constness::NotConst), unsafety, abi)
         };
         if !self.eat_keyword(kw::Fn) {
@@ -850,8 +848,16 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         Ok(FnHeader { constness, unsafety, asyncness, abi })
     }
 
-    /// Parses `trait Foo { ... }` or `trait Foo = Bar;`.
-    fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
+    /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
+    fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
+        // Parse optional `auto` prefix.
+        let is_auto = if self.eat_keyword(kw::Auto) {
+            IsAuto::Yes
+        } else {
+            IsAuto::No
+        };
+
+        self.expect_keyword(kw::Trait)?;
         let ident = self.parse_ident()?;
         let mut tps = self.parse_generics()?;
 
@@ -936,30 +942,20 @@ pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem>
         Ok(item)
     }
 
-    fn parse_trait_item_(&mut self,
-                         at_end: &mut bool,
-                         mut attrs: Vec<Attribute>) -> PResult<'a, TraitItem> {
+    fn parse_trait_item_(
+        &mut self,
+        at_end: &mut bool,
+        mut attrs: Vec<Attribute>,
+    ) -> PResult<'a, TraitItem> {
         let lo = self.token.span;
         self.eat_bad_pub();
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_trait_item_assoc_ty()?
         } else if self.is_const_item() {
-            self.expect_keyword(kw::Const)?;
-            let ident = self.parse_ident()?;
-            self.expect(&token::Colon)?;
-            let ty = self.parse_ty()?;
-            let default = if self.eat(&token::Eq) {
-                let expr = self.parse_expr()?;
-                self.expect(&token::Semi)?;
-                Some(expr)
-            } else {
-                self.expect(&token::Semi)?;
-                None
-            };
-            (ident, TraitItemKind::Const(ty, default), Generics::default())
+            self.parse_trait_item_const()?
         } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
             // trait item macro.
-            (Ident::invalid(), ast::TraitItemKind::Macro(mac), Generics::default())
+            (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
         } else {
             // This is somewhat dubious; We don't want to allow
             // argument names to be left off if there is a definition...
@@ -967,7 +963,7 @@ fn parse_trait_item_(&mut self,
             // We don't allow argument names to be left off in edition 2018.
             let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
             let body = self.parse_trait_method_body(at_end, &mut attrs)?;
-            (ident, ast::TraitItemKind::Method(sig, body), generics)
+            (ident, TraitItemKind::Method(sig, body), generics)
         };
 
         Ok(TraitItem {
@@ -981,6 +977,20 @@ fn parse_trait_item_(&mut self,
         })
     }
 
+    fn parse_trait_item_const(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+        self.expect_keyword(kw::Const)?;
+        let ident = self.parse_ident()?;
+        self.expect(&token::Colon)?;
+        let ty = self.parse_ty()?;
+        let default = if self.eat(&token::Eq) {
+            Some(self.parse_expr()?)
+        } else {
+            None
+        };
+        self.expect(&token::Semi)?;
+        Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
+    }
+
     /// Parse the "body" of a method in a trait item definition.
     /// This can either be `;` when there's no body,
     /// or e.g. a block when the method is a provided one.
@@ -1021,8 +1031,7 @@ fn parse_trait_method_body(
     /// Parses the following grammar:
     ///
     ///     TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
-    fn parse_trait_item_assoc_ty(&mut self)
-        -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+    fn parse_trait_item_assoc_ty(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
@@ -1068,21 +1077,13 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
                 );
             }
 
-            if self.eat(&token::BinOp(token::Star)) {
-                UseTreeKind::Glob
-            } else {
-                UseTreeKind::Nested(self.parse_use_tree_list()?)
-            }
+            self.parse_use_tree_glob_or_nested()?
         } else {
             // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
             prefix = self.parse_path(PathStyle::Mod)?;
 
             if self.eat(&token::ModSep) {
-                if self.eat(&token::BinOp(token::Star)) {
-                    UseTreeKind::Glob
-                } else {
-                    UseTreeKind::Nested(self.parse_use_tree_list()?)
-                }
+                self.parse_use_tree_glob_or_nested()?
             } else {
                 UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID)
             }
@@ -1091,6 +1092,15 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> {
         Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) })
     }
 
+    /// Parses `*` or `{...}`.
+    fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
+        Ok(if self.eat(&token::BinOp(token::Star)) {
+            UseTreeKind::Glob
+        } else {
+            UseTreeKind::Nested(self.parse_use_tree_list()?)
+        })
+    }
+
     /// Parses a `UseTreeKind::Nested(list)`.
     ///
     /// ```
@@ -1192,38 +1202,34 @@ fn parse_item_fn(
         attrs: Vec<Attribute>,
         header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
-        let allow_c_variadic = header.abi == Abi::C && header.unsafety == Unsafety::Unsafe;
-        let (ident, decl, generics) = self.parse_fn_sig(allow_c_variadic)?;
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: false,
+            allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
+            is_name_required: |_| true,
+        })?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-        let span = lo.to(self.prev_span);
         let kind = ItemKind::Fn(decl, header, generics, body);
-        let attrs = maybe_append(attrs, Some(inner_attrs));
-        Ok(Some(self.mk_item(span, ident, kind, vis, attrs)))
+        self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
     }
 
     /// Parse the "signature", including the identifier, parameters, and generics of a function.
-    fn parse_fn_sig(
-        &mut self,
-        allow_c_variadic: bool,
-    ) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
-        let (ident, mut generics) = self.parse_fn_header()?;
-        let decl = self.parse_fn_decl(allow_c_variadic)?;
+    fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
+        let ident = self.parse_ident()?;
+        let mut generics = self.parse_generics()?;
+        let decl = self.parse_fn_decl(cfg, true)?;
         generics.where_clause = self.parse_where_clause()?;
         Ok((ident, decl, generics))
     }
 
-    /// Parses the name and optional generic types of a function header.
-    fn parse_fn_header(&mut self) -> PResult<'a, (Ident, Generics)> {
-        let id = self.parse_ident()?;
-        let generics = self.parse_generics()?;
-        Ok((id, generics))
-    }
-
     /// Parses the parameter list and result type of a function declaration.
-    fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P<FnDecl>> {
+    pub(super) fn parse_fn_decl(
+        &mut self,
+        cfg: ParamCfg,
+        ret_allow_plus: bool,
+    ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
-            inputs: self.parse_fn_params(true, allow_c_variadic)?,
-            output: self.parse_ret_ty(true)?,
+            inputs: self.parse_fn_params(cfg)?,
+            output: self.parse_ret_ty(ret_allow_plus)?,
         }))
     }
 
@@ -1278,14 +1284,30 @@ fn parse_item_foreign_mod(
         // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
         if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) {
             if self.token.is_keyword(kw::Const) {
-                self.diagnostic()
-                    .struct_span_err(self.token.span, "extern items cannot be `const`")
-                    .span_suggestion(
+                let mut err = self
+                    .struct_span_err(self.token.span, "extern items cannot be `const`");
+
+
+                // The user wrote 'const fn'
+                if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) {
+                    err.emit();
+                    // Consume `const`
+                    self.bump();
+                    // Consume `unsafe` if present, since `extern` blocks
+                    // don't allow it. This will leave behind a plain 'fn'
+                    self.eat_keyword(kw::Unsafe);
+                    // Treat 'const fn` as a plain `fn` for error recovery purposes.
+                    // We've already emitted an error, so compilation is guaranteed
+                    // to fail
+                    return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?);
+                }
+                err.span_suggestion(
                         self.token.span,
                         "try using a static value",
                         "static".to_owned(),
                         Applicability::MachineApplicable
-                    ).emit();
+                );
+                err.emit();
             }
             self.bump(); // `static` or `const`
             return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?);
@@ -1331,7 +1353,11 @@ fn parse_item_foreign_fn(
         extern_sp: Span,
     ) -> PResult<'a, ForeignItem> {
         self.expect_keyword(kw::Fn)?;
-        let (ident, decl, generics) = self.parse_fn_sig(true)?;
+        let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg {
+            is_self_allowed: false,
+            allow_c_variadic: true,
+            is_name_required: |_| true,
+        })?;
         let span = lo.to(self.token.span);
         self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
         Ok(ast::ForeignItem {
index 7eb2a73a11a82c28664129ec9e465ef1a5cb13ee..48f9e30161031948dcadbce9e40bd106e8a3aaea 100644 (file)
@@ -4,7 +4,7 @@
 use crate::ptr::P;
 use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
 use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
-use crate::mut_visit::{noop_visit_pat, MutVisitor};
+use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor};
 use crate::parse::token::{self};
 use crate::print::pprust;
 use crate::source_map::{respan, Span, Spanned};
@@ -481,6 +481,10 @@ fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> {
     fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
         struct AddMut(bool);
         impl MutVisitor for AddMut {
+            fn visit_mac(&mut self, mac: &mut Mac) {
+                noop_visit_mac(mac, self);
+            }
+
             fn visit_pat(&mut self, pat: &mut P<Pat>) {
                 if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..)
                     = pat.kind
index 41ee2a1599d74028ab9a9d092792e591fb56eb7f..018b5951e6e2e797a923a9a80738e37255692ad0 100644 (file)
@@ -4,13 +4,11 @@
 use crate::ptr::P;
 use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
 use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
-use crate::ast::{Mutability, AnonConst, FnDecl, Mac};
+use crate::ast::{Mutability, AnonConst, Mac};
 use crate::parse::token::{self, Token};
 use crate::source_map::Span;
 use crate::symbol::{kw};
 
-use rustc_target::spec::abi::Abi;
-
 use errors::{Applicability, pluralise};
 
 /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
@@ -281,19 +279,14 @@ fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a,
         */
 
         let unsafety = self.parse_unsafety();
-        let abi = if self.eat_keyword(kw::Extern) {
-            self.parse_opt_abi()?.unwrap_or(Abi::C)
-        } else {
-            Abi::Rust
-        };
-
+        let abi = self.parse_extern_abi()?;
         self.expect_keyword(kw::Fn)?;
-        let inputs = self.parse_fn_params(false, true)?;
-        let ret_ty = self.parse_ret_ty(false)?;
-        let decl = P(FnDecl {
-            inputs,
-            output: ret_ty,
-        });
+        let cfg = super::ParamCfg {
+            is_self_allowed: false,
+            allow_c_variadic: true,
+            is_name_required: |_| false,
+        };
+        let decl = self.parse_fn_decl(cfg, false)?;
         Ok(TyKind::BareFn(P(BareFnTy {
             abi,
             unsafety,
index 26cae2a8e7c42fb2d598bf5e6e03b8d1b1d7d740..bef12ed4fadafc22d88d48a3670b3020651b1107 100644 (file)
@@ -249,20 +249,47 @@ pub fn is_empty(&self) -> bool {
             0 => TokenStream::empty(),
             1 => streams.pop().unwrap(),
             _ => {
-                // rust-lang/rust#57735: pre-allocate vector to avoid
-                // quadratic blow-up due to on-the-fly reallocations.
-                let tree_count = streams.iter()
-                    .map(|ts| match &ts.0 { None => 0, Some(s) => s.len() })
+                // We are going to extend the first stream in `streams` with
+                // the elements from the subsequent streams. This requires
+                // using `make_mut()` on the first stream, and in practice this
+                // doesn't cause cloning 99.9% of the time.
+                //
+                // One very common use case is when `streams` has two elements,
+                // where the first stream has any number of elements within
+                // (often 1, but sometimes many more) and the second stream has
+                // a single element within.
+
+                // Determine how much the first stream will be extended.
+                // Needed to avoid quadratic blow up from on-the-fly
+                // reallocations (#57735).
+                let num_appends = streams.iter()
+                    .skip(1)
+                    .map(|ts| ts.len())
                     .sum();
-                let mut vec = Vec::with_capacity(tree_count);
 
-                for stream in streams {
-                    match stream.0 {
-                        None => {},
-                        Some(stream2) => vec.extend(stream2.iter().cloned()),
+                // Get the first stream. If it's `None`, create an empty
+                // stream.
+                let mut iter = streams.drain();
+                let mut first_stream_lrc = match iter.next().unwrap().0 {
+                    Some(first_stream_lrc) => first_stream_lrc,
+                    None => Lrc::new(vec![]),
+                };
+
+                // Append the elements to the first stream, after reserving
+                // space for them.
+                let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc);
+                first_vec_mut.reserve(num_appends);
+                for stream in iter {
+                    if let Some(stream) = stream.0 {
+                        first_vec_mut.extend(stream.iter().cloned());
                     }
                 }
-                TokenStream::new(vec)
+
+                // Create the final `TokenStream`.
+                match first_vec_mut.len() {
+                    0 => TokenStream(None),
+                    _ => TokenStream(Some(first_stream_lrc)),
+                }
             }
         }
     }
@@ -363,25 +390,6 @@ pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
                     .collect())
         }))
     }
-
-    fn first_tree_and_joint(&self) -> Option<TreeAndJoint> {
-        self.0.as_ref().map(|stream| {
-            stream.first().unwrap().clone()
-        })
-    }
-
-    fn last_tree_if_joint(&self) -> Option<TokenTree> {
-        match self.0 {
-            None => None,
-            Some(ref stream) => {
-                if let (tree, Joint) = stream.last().unwrap() {
-                    Some(tree.clone())
-                } else {
-                    None
-                }
-            }
-        }
-    }
 }
 
 // 99.5%+ of the time we have 1 or 2 elements in this vector.
@@ -394,18 +402,49 @@ pub fn new() -> TokenStreamBuilder {
     }
 
     pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
-        let stream = stream.into();
-        let last_tree_if_joint = self.0.last().and_then(TokenStream::last_tree_if_joint);
-        if let Some(TokenTree::Token(last_token)) = last_tree_if_joint {
-            if let Some((TokenTree::Token(token), is_joint)) = stream.first_tree_and_joint() {
-                if let Some(glued_tok) = last_token.glue(&token) {
-                    let last_stream = self.0.pop().unwrap();
-                    self.push_all_but_last_tree(&last_stream);
-                    let glued_tt = TokenTree::Token(glued_tok);
-                    let glued_tokenstream = TokenStream::new(vec![(glued_tt, is_joint)]);
-                    self.0.push(glued_tokenstream);
-                    self.push_all_but_first_tree(&stream);
-                    return
+        let mut stream = stream.into();
+
+        // If `self` is not empty and the last tree within the last stream is a
+        // token tree marked with `Joint`...
+        if let Some(TokenStream(Some(ref mut last_stream_lrc))) = self.0.last_mut() {
+            if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() {
+
+                // ...and `stream` is not empty and the first tree within it is
+                // a token tree...
+                if let TokenStream(Some(ref mut stream_lrc)) = stream {
+                    if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
+
+                        // ...and the two tokens can be glued together...
+                        if let Some(glued_tok) = last_token.glue(&token) {
+
+                            // ...then do so, by overwriting the last token
+                            // tree in `self` and removing the first token tree
+                            // from `stream`. This requires using `make_mut()`
+                            // on the last stream in `self` and on `stream`,
+                            // and in practice this doesn't cause cloning 99.9%
+                            // of the time.
+
+                            // Overwrite the last token tree with the merged
+                            // token.
+                            let last_vec_mut = Lrc::make_mut(last_stream_lrc);
+                            *last_vec_mut.last_mut().unwrap() =
+                                (TokenTree::Token(glued_tok), *is_joint);
+
+                            // Remove the first token tree from `stream`. (This
+                            // is almost always the only tree in `stream`.)
+                            let stream_vec_mut = Lrc::make_mut(stream_lrc);
+                            stream_vec_mut.remove(0);
+
+                            // Don't push `stream` if it's empty -- that could
+                            // block subsequent token gluing, by getting
+                            // between two token trees that should be glued
+                            // together.
+                            if !stream.is_empty() {
+                                self.0.push(stream);
+                            }
+                            return;
+                        }
+                    }
                 }
             }
         }
@@ -415,26 +454,6 @@ pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
     pub fn build(self) -> TokenStream {
         TokenStream::from_streams(self.0)
     }
-
-    fn push_all_but_last_tree(&mut self, stream: &TokenStream) {
-        if let Some(ref streams) = stream.0 {
-            let len = streams.len();
-            match len {
-                1 => {}
-                _ => self.0.push(TokenStream(Some(Lrc::new(streams[0 .. len - 1].to_vec())))),
-            }
-        }
-    }
-
-    fn push_all_but_first_tree(&mut self, stream: &TokenStream) {
-        if let Some(ref streams) = stream.0 {
-            let len = streams.len();
-            match len {
-                1 => {}
-                _ => self.0.push(TokenStream(Some(Lrc::new(streams[1 .. len].to_vec())))),
-            }
-        }
-    }
 }
 
 #[derive(Clone)]
index 9dc9d66b86f1d31f8f11e429f404d6da397b2b35..f74507dcc21f678dca92fe0eb07324b1075ad405 100644 (file)
@@ -5,6 +5,7 @@
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax::tokenstream::TokenStream;
+use syntax::early_buffered_lints::BufferedEarlyLintId;
 
 use smallvec::SmallVec;
 use syntax_pos::{self, Pos, Span};
@@ -83,7 +84,16 @@ struct ExpandResult<'a> {
     }
     impl<'a> base::MacResult for ExpandResult<'a> {
         fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
-            Some(panictry!(self.p.parse_expr()))
+            let r = panictry!(self.p.parse_expr());
+            if self.p.token != token::Eof {
+                self.p.sess.buffer_lint(
+                    BufferedEarlyLintId::IncompleteInclude,
+                    self.p.token.span,
+                    ast::CRATE_NODE_ID,
+                    "include macro expected single expression in source",
+                );
+            }
+            Some(r)
         }
 
         fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
index 82c47e6dbb75879ec01f1537ccc26dcefcc994c8..2b005c3fc421a192c8031c84933aa9a13282a306 100644 (file)
         console,
         const_compare_raw_pointers,
         const_constructor,
+        const_extern_fn,
         const_fn,
         const_fn_union,
         const_generics,
         link_cfg,
         link_llvm_intrinsics,
         link_name,
+        link_ordinal,
         link_section,
         LintPass,
         lint_reasons,
         RangeInclusive,
         RangeTo,
         RangeToInclusive,
+        raw_dylib,
         raw_identifiers,
         Ready,
         reason,
         tool_attributes,
         tool_lints,
         trace_macros,
+        track_caller,
         trait_alias,
         transmute,
         transparent,
index e8f3434b958d35cc236095cd9b8dacd5e75a6537..8b76080fc68c61718d6e3e69c59a07e9691d8df2 100644 (file)
@@ -1478,9 +1478,9 @@ pub fn run_test(
 ) {
     let TestDescAndFn { desc, testfn } = test;
 
-    // FIXME: Re-enable emscripten once it can catch panics again
-    let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No
-        && (cfg!(target_arch = "wasm32") || cfg!(target_os = "emscripten"));
+    let ignore_because_no_process_support = cfg!(target_arch = "wasm32")
+        && !cfg!(target_os = "emscripten")
+        && desc.should_panic != ShouldPanic::No;
 
     if force_ignore || desc.ignore || ignore_because_no_process_support {
         monitor_ch.send((desc, TrIgnored, None, Vec::new())).unwrap();
index c3727b3013fc8921e01d05ec837b33412d047214..b95fb5df710d35873be882a3900c6b8c4dd97ac7 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::test::{
     filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy,
-    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts,
+    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailedMsg,
     TrIgnored, TrOk,
 };
 use std::sync::mpsc::channel;
@@ -90,9 +90,7 @@ fn f() {}
     assert!(res == TrIgnored);
 }
 
-// FIXME: Re-enable emscripten once it can catch panics again
 #[test]
-#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic() {
     fn f() {
         panic!();
@@ -112,9 +110,7 @@ fn f() {
     assert!(res == TrOk);
 }
 
-// FIXME: Re-enable emscripten once it can catch panics again
 #[test]
-#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_good_message() {
     fn f() {
         panic!("an error message");
@@ -134,11 +130,8 @@ fn f() {
     assert!(res == TrOk);
 }
 
-// FIXME: Re-enable emscripten once it can catch panics again
 #[test]
-#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_bad_message() {
-    use crate::tests::TrFailedMsg;
     fn f() {
         panic!("an error message");
     }
@@ -159,9 +152,7 @@ fn f() {
     assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
 }
 
-// FIXME: Re-enable emscripten once it can catch panics again
 #[test]
-#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_but_succeeds() {
     fn f() {}
     let desc = TestDescAndFn {
index 7fa61d15f77c4af42e3ef9eeb331f3916e9295ab..2acf95de97ee8fcf4ecd83829ac3f92b274cb8a2 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes
 // ignore-tidy-linelength
 
index 49e40d5f243f16c80e9e5990037108c9105f3dbe..307c4e2c1e273b061c987bc20c538996e42c4c68 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 786f2c8422b788ab02ff750c295f9cb6a0925015..a935d8865226777371e97ea07c52039f46ddaead 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index ee61814678ce4a7d119e2b950eef9e1f4eb72a3e..e44373926b76aa45cb952d54f11808fe367fe62d 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten default visibility is hidden
 // compile-flags: -O
 // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
 // definitions
index 88b8692b0ac540b1c8d411cd76f2cae9f1757dbc..86c1365fdb7118977c0db1d29cfe9a9a9afdf026 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten default visibility is hidden
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 47b38d29417424a5c8b206b715a9f7976868dca9..ad497b25a9ec52e8330b41bf4d3c616002428e65 100644 (file)
@@ -1,5 +1,7 @@
 // compile-flags: -O
 
+// ignore-asmjs
+
 #![feature(asm)]
 #![crate_type = "lib"]
 
index c82ae476b1b2c2a9cc3c10c26177895201e44d6f..05888c0e733ad10bbcb52a7a40a238d9e29c319c 100644 (file)
@@ -1,5 +1,4 @@
 // ignore-msvc
-// ignore-emscripten compiled with panic=abort by default
 
 // compile-flags: -O -C no-prepopulate-passes
 
index afefb9c9f71a53eb2a6fb6a5ceeb56f7a01cd38b..5521c3c849f5363a661ec24f58235e503cfae22f 100644 (file)
@@ -1,7 +1,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 // ignore-aarch64
-// ignore-emscripten
+// ignore-asmjs
 // ignore-mips64
 // ignore-powerpc
 // ignore-powerpc64
@@ -9,6 +9,7 @@
 // ignore-s390x
 // ignore-sparc
 // ignore-sparc64
+// ignore-wasm
 // ignore-x86
 // ignore-x86_64
 // See repr-transparent.rs
index 0a687078cd8eb3c7c05063fe368c447ab6b600b6..acb993d51fb8c928aa9138d1cc3c14f8e4ac95f9 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 9d47339d163cc362f45e59a1be1ff06801e87b6f..58667af7e50edcb0dcd7eff217adcea710616ac7 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 770b2a730377b6be40f1e4f505d2aa8497beacb1..affbe17d3341f22f870846c0caf3e8ac52300470 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 33c8605066686f028d971a22de2e1e63562cee45..43472d9dece8ea98f278cb887f1f197262b3b61d 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index f7a8986242d17e80608cc43e9cc2d6b4c61e6697..471d49b7841eceea455f324229930bdb2917ed12 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index a4070317a62bb8cf4f4f5dfcaa07c0b3ef0d85f7..bd8ba8b6cd774a286cc0ea39e7c5274c0921b232 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 0800a498cb718f74661e7ba22d3a57df5f05bd2d..8ad9e9004c2cd77b578f399f5c3c3141ca613ae1 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index adc44ffd811758a49eacb72ee52974097b5ddaac..ecffca960dab4d4d2646cdaf9898a81e86d01c48 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 9c236f196362ec6276509d829e18c2b8bf5a7ae7..79e6ed54690bf9628eafd64dbc119d3861802222 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index a922161affab600411039669e036f796b35eeb89..db92a94fca84b32c6cb59e783b11b7d1df470e89 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 9624acb383fbd17f42bd34c1fd36aab833bd98e7..90d9ec3cedd6f5a7d1ffb419721cc48bdb0a5e49 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 7b9b1aec6c855615d245690bd8ded9def8e278f6..2761392e6a92357be53c3a39e4466d7a8136b4a0 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-emscripten
 // min-llvm-version 7.0
 
 // compile-flags: -C no-prepopulate-passes
index 6639e5d652b04be215b89d43e2c65e4926cdadd6..1dd2c2ccb83db98c6f70bb6c77efecf4bfbf6088 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 5e82ea023d8e094070734651abdf6938a1e4ca11..09f31bdd6bbdfa56de0fa80e88c061b91f0103b9 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 8ca2ca86076492709a79d971b7b2fa26c871768c..dc87651c2aa1f058d81fcef013132b7ada2d0120 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-emscripten
+
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
index 237d15a5c68cf4239f1e990aebcde51523a637bc..adee796d2475a19302082318c19a93dfef86bf48 100644 (file)
 // CHECK-LABEL: @sadd_i8x2
 #[no_mangle]
 pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x4
 #[no_mangle]
 pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x8
 #[no_mangle]
 pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x16
 #[no_mangle]
 pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x32
 #[no_mangle]
 pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x64
 #[no_mangle]
 pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x2
 #[no_mangle]
 pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x4
 #[no_mangle]
 pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x8
 #[no_mangle]
 pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x16
 #[no_mangle]
 pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x32
 #[no_mangle]
 pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x2
 #[no_mangle]
 pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x4
 #[no_mangle]
 pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x8
 #[no_mangle]
 pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x16
 #[no_mangle]
 pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x2
 #[no_mangle]
 pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x4
 #[no_mangle]
 pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x8
 #[no_mangle]
 pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i128x2
 #[no_mangle]
 pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i128x4
 #[no_mangle]
 pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
@@ -261,140 +261,140 @@ pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
 // CHECK-LABEL: @uadd_u8x2
 #[no_mangle]
 pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x4
 #[no_mangle]
 pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x8
 #[no_mangle]
 pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x16
 #[no_mangle]
 pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x32
 #[no_mangle]
 pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x64
 #[no_mangle]
 pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x2
 #[no_mangle]
 pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x4
 #[no_mangle]
 pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x8
 #[no_mangle]
 pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x16
 #[no_mangle]
 pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x32
 #[no_mangle]
 pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x2
 #[no_mangle]
 pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x4
 #[no_mangle]
 pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x8
 #[no_mangle]
 pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x16
 #[no_mangle]
 pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x2
 #[no_mangle]
 pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x4
 #[no_mangle]
 pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x8
 #[no_mangle]
 pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u128x2
 #[no_mangle]
 pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u128x4
 #[no_mangle]
 pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
     simd_saturating_add(x, y)
 }
 
@@ -405,140 +405,140 @@ pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
 // CHECK-LABEL: @ssub_i8x2
 #[no_mangle]
 pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x4
 #[no_mangle]
 pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x8
 #[no_mangle]
 pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x16
 #[no_mangle]
 pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x32
 #[no_mangle]
 pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x64
 #[no_mangle]
 pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x2
 #[no_mangle]
 pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x4
 #[no_mangle]
 pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x8
 #[no_mangle]
 pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x16
 #[no_mangle]
 pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x32
 #[no_mangle]
 pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x2
 #[no_mangle]
 pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x4
 #[no_mangle]
 pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x8
 #[no_mangle]
 pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x16
 #[no_mangle]
 pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x2
 #[no_mangle]
 pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x4
 #[no_mangle]
 pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x8
 #[no_mangle]
 pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i128x2
 #[no_mangle]
 pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i128x4
 #[no_mangle]
 pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
@@ -547,139 +547,139 @@ pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
 // CHECK-LABEL: @usub_u8x2
 #[no_mangle]
 pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x4
 #[no_mangle]
 pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x8
 #[no_mangle]
 pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x16
 #[no_mangle]
 pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x32
 #[no_mangle]
 pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x64
 #[no_mangle]
 pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x2
 #[no_mangle]
 pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x4
 #[no_mangle]
 pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x8
 #[no_mangle]
 pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x16
 #[no_mangle]
 pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x32
 #[no_mangle]
 pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x2
 #[no_mangle]
 pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x4
 #[no_mangle]
 pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x8
 #[no_mangle]
 pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x16
 #[no_mangle]
 pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x2
 #[no_mangle]
 pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x4
 #[no_mangle]
 pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x8
 #[no_mangle]
 pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u128x2
 #[no_mangle]
 pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u128x4
 #[no_mangle]
 pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
     simd_saturating_sub(x, y)
 }
index 543664014868c5ad07606c2053bf3f6f0a866701..cd8130f92314856320a11dbb181882a71ca856ea 100644 (file)
@@ -29,7 +29,7 @@ pub struct i8x16(
 // CHECK-LABEL: @bitmask_int
 #[no_mangle]
 pub unsafe fn bitmask_int(x: i32x2) -> u8 {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
     // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -39,7 +39,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 {
 // CHECK-LABEL: @bitmask_uint
 #[no_mangle]
 pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
     // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -49,7 +49,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
 // CHECK-LABEL: @bitmask_int16
 #[no_mangle]
 pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9a-z]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
     // CHECK-NOT: zext
index 3b1f4398f90054e3de104711b478a3751512878b..3389104219ddf7df27afbb77ab9a062c05148d5b 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-emscripten
 // ignore-tidy-linelength
 
 // compile-flags: -C no-prepopulate-passes
index 9fce849e5238c572b20a0534b23af7053ce71ab2..dd0a9801bc5fa6b9b59e9093fea6b44df3fced0e 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-emscripten
 // ignore-tidy-linelength
 
 // compile-flags: -C no-prepopulate-passes
index 98a9ff9cbe441da5b50473fe093740cdd359ad78..7339df17b057a230004e2eb3fbc703fc534ce668 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-emscripten vectors passed directly
 // compile-flags: -C no-prepopulate-passes
 
 // This test that using union forward the abi of the inner type, as
index 3fa3822831b5275b54d7e43df427a68f04a2d825..768b936dc2713492462dbc190fea536e871c28e6 100644 (file)
@@ -1,7 +1,7 @@
 // aux-build:weak-lang-items.rs
 // error-pattern: `#[panic_handler]` function required, but not found
 // error-pattern: language item required, but not found: `eh_personality`
-// ignore-emscripten compiled with panic=abort, personality not required
+// ignore-wasm32-bare compiled with panic=abort, personality not required
 
 #![no_std]
 
index 2bcb06d6eb8b7c976ac80659c75912b29cdda788..f5d1acb621be38e65e868ab3ef75df8b297c5bb4 100644 (file)
@@ -1,7 +1,6 @@
 // Test that we detect changes to the `dep_kind` query. If the change is not
 // detected then -Zincremental-verify-ich will trigger an assertion.
 
-// ignore-emscripten compiled with panic=abort by default
 // revisions:cfail1 cfail2
 // compile-flags: -Z query-dep-graph -Cpanic=unwind
 // build-pass (FIXME(62277): could be check-pass?)
index 08a0232f661f72f9c8765f2151c5eced51bb8bc5..e5b84267b290312ecf08518de9b08518d1ea78ee 100644 (file)
@@ -1,7 +1,6 @@
 // Test that changing a tracked commandline argument invalidates
 // the cache while changing an untracked one doesn't.
 
-// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2 rpass3
 // compile-flags: -Z query-dep-graph
 
index b01f02444eae8dfa516799efc3e30177dee12b19..12411a928799f2e3a39cbfc6708fdb98f325f924 100644 (file)
@@ -2,7 +2,6 @@
 // compile-flags: -Z query-dep-graph -g
 // aux-build:extern_crate.rs
 
-// ignore-asmjs wasm2js does not support source maps yet
 // This test case makes sure that we detect if paths emitted into debuginfo
 // are changed, even when the change happens in an external crate.
 
index 367416430f86b5a63c81aa0b637976982510753e..f1d7de1455938d218b8e47cff51d45d7a8db2d74 100644 (file)
@@ -3,7 +3,6 @@
 // the spans and this test makes sure that we handle them correctly by hashing
 // file:line:column instead of raw byte offset.
 
-// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2
 // compile-flags: -g -Z query-dep-graph
 
index f5cae15a4bc7cf22a3d4021625bd4e3af3ffdbba..8ed469db6e6336b7c8a810a2d249f4394443b690 100644 (file)
@@ -1,7 +1,6 @@
 // Test that moving a type definition within a source file does not affect
 // re-compilation.
 
-// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2
 // compile-flags: -Z query-dep-graph -g
 
index e6fdc7cb3a0fc24138d3ea1e113fff88757a592e..87c97ba06c46a0c97b0d25bb02179f1243e466f8 100644 (file)
@@ -3,7 +3,6 @@
 
 // revisions:rpass1 rpass2
 
-// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g -Z query-dep-graph
 
 #![feature(rustc_attrs)]
index 4b66c07b0934b48560f6276bfbaae6f4de180bca..8dc6b73edf6d473ecd804cdd314597fbdb86dcd9 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(box_syntax)]
 
index b595c100039d6bed04a7c5ae388a61668ad8e0b7..109304d6d22ccdd4cb9368c12bbea673702e2f76 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 // Test that we generate StorageDead on unwind paths for generators.
 //
index 8824496fdb07cc4a68530ae82a862828d20c52a6..e73390f52b5d552fc3287e923a0f52ac9a117c52 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 // check that we don't emit multiple drop flags when they are not needed.
 
index 93250fd48d82d00935eb568c10135625baa5b78c..a3b517e9bca87bfa0cf295af84a7496c3ad5fe65 100644 (file)
@@ -1,7 +1,7 @@
 // check that we don't forget to drop the Box if we early return before
 // initializing it
 // ignore-tidy-linelength
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(box_syntax)]
 
index 370cd593b02bb75aad365419f82e84c6bfa35965..782bc31186ca5fb8eb8a4931bc077d8579e4d351 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 // Test that after the call to `std::mem::drop` we do not generate a
 // MIR drop of the argument. (We used to have a `DROP(_2)` in the code
index eaa1fbd69ecc6beec8277fa021d44118a4bc577a..da73cc96348f059e4c15e29ce839204b2b824ed4 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 fn main() {
     let mut x = Packed(Aligned(Droppy(0)));
index 71beaa736639ddfa8151b6b953a779f3dfc2d129..3245d38b2580bd20a03a44463524eee16b645ca9 100644 (file)
@@ -1,6 +1,6 @@
 // Test that the fake borrows for matches are removed after borrow checking.
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare
 
 fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
     match x {
index a0bdfb3ab8ba94c9fb5fae19aafb2fe6cf476c0c..db36a1fab5f2104f48e2dc3a3dedea1532753d86 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // ignore-tidy-linelength
 // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
 
index 2f48b852566e0370e2ff9dbb2f0a48fcf128181b..7c64dc58bf791a7561ff5fe2e1da263a0b67f2d5 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) foo.rs --target wasm32-unknown-unknown
index 76698c0aae3ba509a6e942522c9fb1df09876812..fec7643d20c537151e3c3a6aaafad8047893c239 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) foo.rs -O --target wasm32-unknown-unknown
index 7e47ba4850e38a2047082f3143467d6b5b050736..15403d8d4109d88ba8b4088ab691493304f0ad81 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) bar.rs --target wasm32-unknown-unknown
index fe63e66f242b4c5e03fd0bc271fdb7c6e24c7378..255d8f1ef0e63f3bd6b76da6b96a8afa46be1585 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
- # only-wasm32-bare
+ # only-wasm32
 
 all:
        $(RUSTC) foo.rs --target wasm32-unknown-unknown
index 68397e4bc6e18332b5875f9327759f3374d13039..b9141f93d538ceb07e8ce82f54fff10cdce4746e 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg a
index 62bd0f0872ebee45a5306b8f8f551b4be02ff356..b17e04b77177356822bca5ff7a6b1e06582d7ea1 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) foo.rs --target wasm32-unknown-unknown
index 7a923375c1813720912b3b075f7f599c03834289..b8f64e06f31ef844accfbd0b4a16f4e8d19f7544 100644 (file)
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32-bare
+# only-wasm32
 
 all:
        $(RUSTC) foo.rs --target wasm32-unknown-unknown
index b30e8f00e4035c93067b64624a8c52c085608c99..5d6fa416b9895e7e3aa2a1890a64f3c9846589cb 100644 (file)
@@ -5,10 +5,6 @@
 
 // ignore-wasm32-bare no libc to test ffi with
 
-// FIXME: This will work on emscripten once libc is updated to include
-// rust-lang/libc/#1478
-// ignore-emscripten libc type mismatch
-
 #![feature(rustc_private)]
 
 extern crate libc;
index 15bebce47dd6a145c7d62f35334eb583e90354c3..4309373f123f9d3e6c4164bdafc927cd55166b11 100644 (file)
@@ -23,3 +23,4 @@ LL |    bar(foo, x)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 62b4cb10911fbe6721c0ec4d30fb9326f3c6b751..b8b1a979c363a95a38a258a73e55ee6504a025f5 100644 (file)
@@ -19,3 +19,4 @@ LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs b/src/test/ui/async-await/async-assoc-fn-anon-lifetimes.rs
new file mode 100644 (file)
index 0000000..8e08b82
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+// Check that the anonymous lifetimes used here aren't considered to shadow one
+// another. Note that `async fn` is different to `fn` here because the lifetimes
+// are numbered by HIR lowering, rather than lifetime resolution.
+
+// edition:2018
+
+struct A<'a, 'b>(&'a &'b i32);
+struct B<'a>(&'a i32);
+
+impl A<'_, '_> {
+    async fn assoc(x: &u32, y: B<'_>) {
+        async fn nested(x: &u32, y: A<'_, '_>) {}
+    }
+
+    async fn assoc2(x: &u32, y: A<'_, '_>) {
+        impl A<'_, '_> {
+            async fn nested_assoc(x: &u32, y: B<'_>) {}
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed b/src/test/ui/async-await/async-borrowck-escaping-block-error.fixed
new file mode 100644 (file)
index 0000000..f004b41
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2018
+// run-rustfix
+
+fn foo() -> Box<impl std::future::Future<Output = u32>> {
+    let x = 0u32;
+    Box::new(async move { x } )
+    //~^ ERROR E0373
+}
+
+fn main() {
+    let _foo = foo();
+}
diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.rs b/src/test/ui/async-await/async-borrowck-escaping-block-error.rs
new file mode 100644 (file)
index 0000000..4f35fd5
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2018
+// run-rustfix
+
+fn foo() -> Box<impl std::future::Future<Output = u32>> {
+    let x = 0u32;
+    Box::new(async { x } )
+    //~^ ERROR E0373
+}
+
+fn main() {
+    let _foo = foo();
+}
diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
new file mode 100644 (file)
index 0000000..af17ecc
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
+  --> $DIR/async-borrowck-escaping-block-error.rs:6:20
+   |
+LL |     Box::new(async { x } )
+   |                    ^^-^^
+   |                    | |
+   |                    | `x` is borrowed here
+   |                    may outlive borrowed value `x`
+   |
+note: generator is returned here
+  --> $DIR/async-borrowck-escaping-block-error.rs:4:13
+   |
+LL | fn foo() -> Box<impl std::future::Future<Output = u32>> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |     Box::new(async move { x } )
+   |                    ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.
index b63d5408a7147f9d66bcdd72b684db25d6003fb1..c266644fd702c87ab6f2e2820ca881c443307150 100644 (file)
@@ -7,7 +7,7 @@
 //
 // See issue #59123 for a full explanation.
 
-// ignore-emscripten (sizes don't match)
+// ignore-wasm32-bare (sizes don't match)
 // run-pass
 
 // edition:2018
@@ -22,7 +22,8 @@
 impl BigFut {
     fn new() -> Self {
         BigFut([0; BIG_FUT_SIZE])
-    } }
+    }
+}
 
 impl Drop for BigFut {
     fn drop(&mut self) {}
diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs
new file mode 100644 (file)
index 0000000..ad20237
--- /dev/null
@@ -0,0 +1,103 @@
+// Test that we don't store uninitialized locals in futures from `async fn`.
+//
+// The exact sizes can change by a few bytes (we'd like to know when they do).
+// What we don't want to see is the wrong multiple of 1024 (the size of `Big`)
+// being reflected in the size.
+
+// ignore-wasm32-bare (sizes don't match)
+// run-pass
+
+// edition:2018
+
+#![allow(unused_variables, unused_assignments)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+const BIG_FUT_SIZE: usize = 1024;
+struct Big([u8; BIG_FUT_SIZE]);
+
+impl Big {
+    fn new() -> Self {
+        Big([0; BIG_FUT_SIZE])
+    }
+}
+
+impl Drop for Big {
+    fn drop(&mut self) {}
+}
+
+#[allow(dead_code)]
+struct Joiner {
+    a: Option<Big>,
+    b: Option<Big>,
+    c: Option<Big>,
+}
+
+impl Future for Joiner {
+    type Output = ();
+
+    fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll<Self::Output> {
+        Poll::Ready(())
+    }
+}
+
+fn noop() {}
+async fn fut() {}
+
+async fn single() {
+    let x;
+    fut().await;
+    x = Big::new();
+}
+
+async fn single_with_noop() {
+    let x;
+    fut().await;
+    noop();
+    x = Big::new();
+    noop();
+}
+
+async fn joined() {
+    let joiner;
+    let a = Big::new();
+    let b = Big::new();
+    let c = Big::new();
+
+    fut().await;
+    noop();
+    joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) };
+    noop();
+}
+
+async fn joined_with_noop() {
+    let joiner;
+    let a = Big::new();
+    let b = Big::new();
+    let c = Big::new();
+
+    fut().await;
+    noop();
+    joiner = Joiner { a: Some(a), b: Some(b), c: Some(c) };
+    noop();
+}
+
+async fn join_retval() -> Joiner {
+    let a = Big::new();
+    let b = Big::new();
+    let c = Big::new();
+
+    fut().await;
+    noop();
+    Joiner { a: Some(a), b: Some(b), c: Some(c) }
+}
+
+fn main() {
+    assert_eq!(8, std::mem::size_of_val(&single()));
+    assert_eq!(12, std::mem::size_of_val(&single_with_noop()));
+    assert_eq!(3084, std::mem::size_of_val(&joined()));
+    assert_eq!(3084, std::mem::size_of_val(&joined_with_noop()));
+    assert_eq!(3080, std::mem::size_of_val(&join_retval()));
+}
index b5c94ecb716902bc14b2bb4efc956ecc0fff5e21..b313992db4ecbc38883d389a3d365735ac0c3dce 100644 (file)
@@ -89,10 +89,10 @@ fn main() {
     assert_eq!(8, std::mem::size_of_val(&await1_level1()));
     assert_eq!(12, std::mem::size_of_val(&await2_level1()));
     assert_eq!(12, std::mem::size_of_val(&await3_level1()));
-    assert_eq!(20, std::mem::size_of_val(&await3_level2()));
-    assert_eq!(28, std::mem::size_of_val(&await3_level3()));
-    assert_eq!(36, std::mem::size_of_val(&await3_level4()));
-    assert_eq!(44, std::mem::size_of_val(&await3_level5()));
+    assert_eq!(24, std::mem::size_of_val(&await3_level2()));
+    assert_eq!(36, std::mem::size_of_val(&await3_level3()));
+    assert_eq!(48, std::mem::size_of_val(&await3_level4()));
+    assert_eq!(60, std::mem::size_of_val(&await3_level5()));
 
     assert_eq!(1,   wait(base()));
     assert_eq!(1,   wait(await1_level1()));
index 61f6ed1b7b2ce4fac4e4a2237c85c1afc4e92225..9ee419c4a56fb16c0d2058c50cc33d8ef2f7c49c 100644 (file)
@@ -3,7 +3,6 @@
 // compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018
 
 // run-pass
-// ignore-asmjs wasm2js does not support source maps yet
 
 use std::future::Future;
 use std::task::Poll;
index ae21984c06d723c36ab4e8902f657565f5784ea6..d797f30a2fc8cb2885482c8ac3ab96806bd08978 100644 (file)
@@ -18,4 +18,5 @@ LL | auto trait MyTrait { fn foo() {} }
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0380`.
+Some errors have detailed explanations: E0380, E0567.
+For more information about an error, try `rustc --explain E0380`.
index 4e0a238c5d48d9b86c02a4abe18a389cc7182a1c..ea4a9e5afa50157279c76ac8d737e16e329f2ab7 100644 (file)
@@ -2,7 +2,7 @@
 // Check that partially moved from function parameters are dropped after the
 // named bindings that move from them.
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 use std::{panic, cell::RefCell};
 
index e6d17def1477e0ff7dec6967047903bc2e7ec8e3..5f7e357eeb2a9f591c03502c1a516c64512c461c 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 // compile-flags: -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 #[derive(PartialEq, Eq)]
 struct NewBool(bool);
index 1fd91440a7884b4d07006a24b01c213f0674dfdf..339bcfa1060a48e6a3c560176a987535317c2230 100644 (file)
@@ -2,7 +2,7 @@
 
 #![allow(unused_variables)]
 #![allow(unused_imports)]
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 // Test that builtin implementations of `Clone` cleanup everything
 // in case of unwinding.
index b986d0c24350615783699b8fce02bc5dd18bf820..3d552f88ba6673e20c342ba43d0e31975deab487 100644 (file)
@@ -209,4 +209,5 @@ LL | | }
 
 error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0495.
+For more information about an error, try `rustc --explain E0308`.
index c2c21bca7ef71be79dfafb356545828905e463f0..f181991713b2cd3fb4add9cec8f6f0db83a35bfb 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 fn worker() -> ! {
     panic!()
index 6b15b7ebbe9ee6e6924c5a8d110e22a132d2af00..832f5c3ac2bb7ec3f57cba28eec4b48fdfb67bc8 100644 (file)
@@ -66,3 +66,4 @@ LL | | }
 
 error: aborting due to 8 previous errors
 
+For more information about this error, try `rustc --explain E0566`.
index 72369ab24ebfc5ddfe1ebca3d874ae0c30418c60..380a70d664e05939a032bf5041b79ffd158a82f5 100644 (file)
@@ -12,8 +12,8 @@ error[E0308]: mismatched types
 LL |     let _: ConstString<"Hello"> = ConstString::<"World">;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"`
    |
-   = note: expected type `ConstString<>`
-              found type `ConstString<>`
+   = note: expected type `ConstString<"Hello">`
+              found type `ConstString<"World">`
 
 error[E0308]: mismatched types
   --> $DIR/slice-const-param-mismatch.rs:11:33
@@ -21,8 +21,8 @@ error[E0308]: mismatched types
 LL |     let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">;
    |                                  ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"`
    |
-   = note: expected type `ConstString<>`
-              found type `ConstString<>`
+   = note: expected type `ConstString<"ℇ㇈↦">`
+              found type `ConstString<"ℇ㇈↥">`
 
 error[E0308]: mismatched types
   --> $DIR/slice-const-param-mismatch.rs:13:33
@@ -30,8 +30,8 @@ error[E0308]: mismatched types
 LL |     let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
    |                                 ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"`
    |
-   = note: expected type `ConstBytes<>`
-              found type `ConstBytes<>`
+   = note: expected type `ConstBytes<b"AAA">`
+              found type `ConstBytes<b"BBB">`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs
new file mode 100644 (file)
index 0000000..b25b733
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+// tests the diagnostic output of type mismatches for types that have const generics arguments.
+
+use std::marker::PhantomData;
+
+struct A<'a, T, const X: u32, const Y: u32> {
+    data: PhantomData<&'a T>
+}
+
+fn a<'a, 'b>() {
+    let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
+    //~^ ERROR mismatched types
+    let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+    //~^ ERROR mismatched types
+}
+
+pub fn main() {}
diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.stderr
new file mode 100644 (file)
index 0000000..805a306
--- /dev/null
@@ -0,0 +1,29 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/types-mismatch-const-args.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:13:41
+   |
+LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
+   |
+   = note: expected type `A<'_, _, 2u32, _>`
+              found type `A<'_, _, 4u32, _>`
+
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:15:41
+   |
+LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u16, found u32
+   |
+   = note: expected type `A<'a, u16, _, _>`
+              found type `A<'b, u32, _, _>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 274967ef60de54cb477ee0948057e7133d342a0c..b85cecda16e9550fb45726a14b0e55c367ff4cfb 100644 (file)
@@ -11,7 +11,6 @@ impl Unsigned for U8 {
 
 impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
     const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error
-    //~| ERROR any use of this value will cause an error
 }
 
 fn foo<T>(_: T) -> &'static u8 {
index de3459c72dd2b0397ab80996ed1dae5c62814d9f..707dfee7cd5b89c96b2128a858a80a5ebf91ef64 100644 (file)
@@ -9,21 +9,13 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = note: `#[deny(const_err)]` on by default
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814.rs:18:5
+  --> $DIR/issue-50814.rs:17:5
    |
 LL |     &Sum::<U8,U8>::MAX
    |     ^-----------------
    |      |
    |      referenced constant has errors
 
-error: any use of this value will cause an error
-  --> $DIR/issue-50814.rs:13:21
-   |
-LL |     const MAX: u8 = A::MAX + B::MAX;
-   |     ----------------^^^^^^^^^^^^^^^-
-   |                     |
-   |                     attempt to add with overflow
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-64908.rs b/src/test/ui/consts/const-eval/issue-64908.rs
new file mode 100644 (file)
index 0000000..d2e0950
--- /dev/null
@@ -0,0 +1,20 @@
+// run-pass
+
+// This test verifies that the `ConstProp` pass doesn't cause an ICE when evaluating polymorphic
+// promoted MIR.
+
+pub trait ArrowPrimitiveType {
+    type Native;
+}
+
+pub fn new<T: ArrowPrimitiveType>() {
+    assert_eq!(0, std::mem::size_of::<T::Native>());
+}
+
+impl ArrowPrimitiveType for () {
+    type Native = ();
+}
+
+fn main() {
+    new::<()>();
+}
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
new file mode 100644 (file)
index 0000000..7c6a574
--- /dev/null
@@ -0,0 +1,23 @@
+#![feature(const_extern_fn)]
+
+extern "C" {
+    fn regular_in_block();
+}
+
+const extern fn bar() {
+    unsafe {
+        regular_in_block();
+        //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
+    }
+}
+
+extern fn regular() {}
+
+const extern fn foo() {
+    unsafe {
+        regular();
+        //~^ ERROR: cannot call functions with `"C"` abi in `min_const_fn`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
new file mode 100644 (file)
index 0000000..d8bdf0a
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
+  --> $DIR/const-extern-fn-call-extern-fn.rs:9:9
+   |
+LL |         regular_in_block();
+   |         ^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0723]: cannot call functions with `"C"` abi in `min_const_fn`
+  --> $DIR/const-extern-fn-call-extern-fn.rs:18:9
+   |
+LL |         regular();
+   |         ^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
new file mode 100644 (file)
index 0000000..5619811
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(const_extern_fn)]
+
+const extern fn unsize(x: &[u8; 3]) -> &[u8] { x }
+//~^ ERROR unsizing casts are not allowed in const fn
+const unsafe extern "C" fn closure() -> fn() { || {} }
+//~^ ERROR function pointers in const fn are unstable
+const unsafe extern fn use_float() { 1.0 + 1.0; }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
+//~^ ERROR casting pointers to ints is unstable in const fn
+
+
+fn main() {}
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
new file mode 100644 (file)
index 0000000..0ab1ddd
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0723]: unsizing casts are not allowed in const fn
+  --> $DIR/const-extern-fn-min-const-fn.rs:3:48
+   |
+LL | const extern fn unsize(x: &[u8; 3]) -> &[u8] { x }
+   |                                                ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0723]: function pointers in const fn are unstable
+  --> $DIR/const-extern-fn-min-const-fn.rs:5:41
+   |
+LL | const unsafe extern "C" fn closure() -> fn() { || {} }
+   |                                         ^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0723]: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/const-extern-fn-min-const-fn.rs:7:38
+   |
+LL | const unsafe extern fn use_float() { 1.0 + 1.0; }
+   |                                      ^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0723]: casting pointers to ints is unstable in const fn
+  --> $DIR/const-extern-fn-min-const-fn.rs:9:48
+   |
+LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
+   |                                                ^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
new file mode 100644 (file)
index 0000000..cab175b
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(const_extern_fn)]
+
+const unsafe extern fn foo() -> usize { 5 }
+
+fn main() {
+    let a: [u8; foo()];
+    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    foo();
+    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+}
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.stderr
new file mode 100644 (file)
index 0000000..5196b8e
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/const-extern-fn-requires-unsafe.rs:8:5
+   |
+LL |     foo();
+   |     ^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/const-extern-fn-requires-unsafe.rs:6:17
+   |
+LL |     let a: [u8; foo()];
+   |                 ^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn.rs
new file mode 100644 (file)
index 0000000..1dc0f83
--- /dev/null
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(const_extern_fn)]
+
+const extern fn foo1(val: u8) -> u8 {
+    val + 1
+}
+
+const extern "C" fn foo2(val: u8) -> u8 {
+    val + 1
+}
+
+const unsafe extern fn bar1(val: bool) -> bool {
+    !val
+}
+
+const unsafe extern "C" fn bar2(val: bool) -> bool {
+    !val
+}
+
+
+fn main() {
+    let a: [u8; foo1(25) as usize] = [0; 26];
+    let b: [u8; foo2(25) as usize] = [0; 26];
+    assert_eq!(a, b);
+
+    let bar1_res = unsafe { bar1(false) };
+    let bar2_res = unsafe { bar2(false) };
+    assert!(bar1_res);
+    assert_eq!(bar1_res, bar2_res);
+
+    let _foo1_cast: extern fn(u8) -> u8 = foo1;
+    let _foo2_cast: extern fn(u8) -> u8 = foo2;
+    let _bar1_cast: unsafe extern fn(bool) -> bool = bar1;
+    let _bar2_cast: unsafe extern fn(bool) -> bool = bar2;
+}
diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs
new file mode 100644 (file)
index 0000000..d39f2c1
--- /dev/null
@@ -0,0 +1,12 @@
+// Check that `const extern fn` and `const unsafe extern fn` are feature-gated.
+
+#[cfg(FALSE)] const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable
+#[cfg(FALSE)] const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable
+#[cfg(FALSE)] const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable
+#[cfg(FALSE)] const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable
+#[cfg(FALSE)] const unsafe extern "C" fn bar2() {}
+//~^ ERROR `const extern fn` definitions are unstable
+#[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {}
+//~^ ERROR `const extern fn` definitions are unstable
+
+fn main() {}
diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr
new file mode 100644 (file)
index 0000000..f138620
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:3:15
+   |
+LL | #[cfg(FALSE)] const extern fn foo1() {}
+   |               ^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:4:15
+   |
+LL | #[cfg(FALSE)] const extern "C" fn foo2() {}
+   |               ^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:5:15
+   |
+LL | #[cfg(FALSE)] const extern "Rust" fn foo3() {}
+   |               ^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:6:15
+   |
+LL | #[cfg(FALSE)] const unsafe extern fn bar1() {}
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:7:15
+   |
+LL | #[cfg(FALSE)] const unsafe extern "C" fn bar2() {}
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/feature-gate-const_extern_fn.rs:9:15
+   |
+LL | #[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {}
+   |               ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index d0a3eccd17763ec157559bc839e760e79955fbfc..394d6c17f5adfcb69b760274be4e062a50be7a91 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-emscripten no i128 support
 #![feature(const_saturating_int_methods)]
 
 const INT_U32_NO: u32 = (42 as u32).saturating_add(2);
index 43f75b0344be76f2cc7e87c2575b0c17f0f6d64c..e4beee9e737ba3cc0e6d0773ddc45143b30f5344 100644 (file)
@@ -7,7 +7,6 @@
 // aux-build:debuginfo-lto-aux.rs
 // compile-flags: -C lto -g
 // no-prefer-dynamic
-// ignore-asmjs wasm2js does not support source maps yet
 
 extern crate debuginfo_lto_aux;
 
index 15afa78b140d5eb2aa09e7f660fe2fd3304392a3..57143d68105540f9edf7576c568e963589ec6c2e 100644 (file)
@@ -54,5 +54,5 @@ LL | #[deprecated(since = "a", since = "b", note = "c")]
 
 error: aborting due to 9 previous errors
 
-Some errors have detailed explanations: E0538, E0541, E0550, E0565.
+Some errors have detailed explanations: E0538, E0541, E0550, E0551, E0565.
 For more information about an error, try `rustc --explain E0538`.
index 6902779f33d23c7a3497e96c1a5ba43d5ee7aa30..189335520543331b5aea5c52951a28cd83ed0e37 100644 (file)
@@ -1,16 +1,8 @@
-fn foo() {
+fn main() {
     (0..13).collect<Vec<i32>>();
     //~^ ERROR chained comparison
-}
-
-fn bar() {
     Vec<i32>::new();
     //~^ ERROR chained comparison
-}
-
-fn qux() {
     (0..13).collect<Vec<i32>();
     //~^ ERROR chained comparison
 }
-
-fn main() {}
index 7a08fda27e355c3d6816cfafe251d57443fcc19c..7fc7c2628c472ddbc46f76f1d1d7e28c9a5986e4 100644 (file)
@@ -2,28 +2,31 @@ error: chained comparison operators require parentheses
   --> $DIR/issue-40396.rs:2:20
    |
 LL |     (0..13).collect<Vec<i32>>();
-   |                    ^^^^^^^^
+   |                    ^^^^^
+help: use `::<...>` instead of `<...>` to specify type arguments
    |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
-   = help: or use `(...)` if you meant to specify fn arguments
+LL |     (0..13).collect::<Vec<i32>>();
+   |                    ^^
 
 error: chained comparison operators require parentheses
-  --> $DIR/issue-40396.rs:7:8
+  --> $DIR/issue-40396.rs:4:8
    |
 LL |     Vec<i32>::new();
-   |        ^^^^^^^
+   |        ^^^^^
+help: use `::<...>` instead of `<...>` to specify type arguments
    |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
-   = help: or use `(...)` if you meant to specify fn arguments
+LL |     Vec::<i32>::new();
+   |        ^^
 
 error: chained comparison operators require parentheses
-  --> $DIR/issue-40396.rs:12:20
+  --> $DIR/issue-40396.rs:6:20
    |
 LL |     (0..13).collect<Vec<i32>();
-   |                    ^^^^^^^^
+   |                    ^^^^^
+help: use `::<...>` instead of `<...>` to specify type arguments
    |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
-   = help: or use `(...)` if you meant to specify fn arguments
+LL |     (0..13).collect::<Vec<i32>();
+   |                    ^^
 
 error: aborting due to 3 previous errors
 
index d02f30152d687720dcc3b776175306c546a16a8c..d8826d4072a9d3d8d7217c1ec7e340dbb9a67f12 100644 (file)
@@ -5,10 +5,10 @@ LL |     let x = Option(1);
    |             ^^^^^^
 help: try using one of the enum's variants
    |
-LL |     let x = std::prelude::v1::Option::None(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     let x = std::prelude::v1::Option::Some(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let x = std::option::Option::None(1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let x = std::option::Option::Some(1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0532]: expected tuple struct/variant, found enum `Option`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12
@@ -17,10 +17,10 @@ LL |     if let Option(_) = x {
    |            ^^^^^^
 help: try using one of the enum's variants
    |
-LL |     if let std::prelude::v1::Option::None(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     if let std::prelude::v1::Option::Some(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     if let std::option::Option::None(_) = x {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     if let std::option::Option::Some(_) = x {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0532]: expected tuple struct/variant, found enum `Example`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12
@@ -47,14 +47,14 @@ LL |     let z = ManyVariants();
    |             ^^^^^^^^^^^^
 help: try using one of the enum's variants
    |
-LL |     let z = ManyVariants::Eight();
+LL |     let z = ManyVariants::One();
+   |             ^^^^^^^^^^^^^^^^^
+LL |     let z = ManyVariants::Two();
+   |             ^^^^^^^^^^^^^^^^^
+LL |     let z = ManyVariants::Three();
    |             ^^^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Five();
-   |             ^^^^^^^^^^^^^^^^^^
 LL |     let z = ManyVariants::Four();
    |             ^^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Nine();
-   |             ^^^^^^^^^^^^^^^^^^
 and 6 other candidates
 
 error: aborting due to 5 previous errors
index bec86d6465ae94e261e9357fb499a82c15bdd38a..91063edf0f6c4badf45a759ad86bcb9722290287 100644 (file)
@@ -5,7 +5,7 @@
 
 // run-pass
 // edition:2018
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(slice_patterns)]
 #![allow(unused)]
index 7fd3f420a6d5bab7cd08c449f7cb4bc47395c819..8516bc3d96424cb452adb6ccd7051d11d21728b0 100644 (file)
@@ -2,7 +2,7 @@
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(generators, generator_trait, untagged_unions)]
 #![feature(slice_patterns)]
index f50c64780118b4235438b15e1863dd87caa6b441..feca7f10b706b22890178427631abd62ee72cbff 100644 (file)
@@ -27,3 +27,4 @@ LL |     invoke(&x, |a, b| if a > b { a } else { b });
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 9d96b4f63fb6c2e6b97af4db1fc5547c874d1935..0eec9fb3ee647c3143b0c7bc4d8e695f48c07fcd 100644 (file)
@@ -5,8 +5,7 @@
 // compile. To sidestep this by using one that *is* defined.
 
 // run-rustfix
-// ignore-wasm32-bare no external library to link to.
-// ignore-asmjs wasm2js does not support source maps yet
+// ignore-wasm32 no external library to link to.
 // compile-flags: -g
 #![feature(rustc_private)]
 extern crate libc;
index 7cef5b3497b5a22b4a7d56fdcd9d2135fba49fa9..ca5d7ddf27e3ab9a1f84e5bc9edd1795a4f6ccf4 100644 (file)
@@ -5,8 +5,7 @@
 // compile. To sidestep this by using one that *is* defined.
 
 // run-rustfix
-// ignore-wasm32-bare no external library to link to.
-// ignore-asmjs wasm2js does not support source maps yet
+// ignore-wasm32 no external library to link to.
 // compile-flags: -g
 #![feature(rustc_private)]
 extern crate libc;
index 258202b6903d31cc3e18070a31b5ffa057e7f25d..77406be2095cff1d52277d043441650d501a8040 100644 (file)
@@ -1,5 +1,5 @@
 error: extern items cannot be `const`
-  --> $DIR/extern-const.rs:16:5
+  --> $DIR/extern-const.rs:15:5
    |
 LL |     const rust_dbg_static_mut: libc::c_int;
    |     ^^^^^ help: try using a static value: `static`
index dfaa85bc5f014efeb96c63c05fd6f3f1d805e786..02c8400e03e8202258163d9d2cbfbd1fcd176394 100644 (file)
@@ -26,4 +26,5 @@ LL | #[repr(simd)]
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0566, E0658.
+For more information about an error, try `rustc --explain E0566`.
diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.rs b/src/test/ui/feature-gates/feature-gate-track_caller.rs
new file mode 100644 (file)
index 0000000..5865cf0
--- /dev/null
@@ -0,0 +1,5 @@
+#[track_caller]
+fn f() {}
+//~^^ ERROR the `#[track_caller]` attribute is an experimental feature
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.stderr b/src/test/ui/feature-gates/feature-gate-track_caller.stderr
new file mode 100644 (file)
index 0000000..b890019
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: the `#[track_caller]` attribute is an experimental feature
+  --> $DIR/feature-gate-track_caller.rs:1:1
+   |
+LL | #[track_caller]
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/47809
+   = help: add `#![feature(track_caller)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index d42d09d401e874655082fbb9a019c15049eb78ba..43b37a9afc2cc9f26284625ef86f912e14557424 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 #![feature(generators, generator_trait)]
 
index b1a5cc67e86b368e4045a9c0768c70e360510f1f..5ac97585f4b575339f8f06cdeb6eb2d06cd391b6 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled as panic=abort by default
 
 #![feature(generators, generator_trait)]
 
index 06c026180190a08ebb8998815f8e241c09f3277f..5f6778674dce13a5e9fd32e8ff61ff3c2bbef2bb 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(generators, generator_trait)]
 
index ab18be58155df89db560adfdf37305939c2a206c..71a68ff684af31c6656fb61cc9bd20ecafa0e7fa 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(generators, generator_trait)]
 
index 2864fbb2f3c8d4dcfe565f9b0e4df00586a5caa1..01db971434bbc8c9e0e36ab34cdd41dbc854ba33 100644 (file)
@@ -11,7 +11,6 @@
 
 // edition:2018
 // ignore-wasm32 issue #62807
-// ignore-asmjs issue #62807
 
 #![feature(generators, generator_trait)]
 
index cbf52476ae37f5dffe46478494984365de7212ee..0936f3b9e38e856c313cb33272fcaffa658de498 100644 (file)
@@ -2,7 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:18:8
    |
 LL |     if b_ref() {}
-   |        ^^^^^^^ expected bool, found &bool
+   |        ^^^^^^^
+   |        |
+   |        expected bool, found &bool
+   |        help: consider dereferencing the borrow: `*b_ref()`
    |
    = note: expected type `bool`
               found type `&bool`
@@ -11,7 +14,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:19:8
    |
 LL |     if b_mut_ref() {}
-   |        ^^^^^^^^^^^ expected bool, found &mut bool
+   |        ^^^^^^^^^^^
+   |        |
+   |        expected bool, found &mut bool
+   |        help: consider dereferencing the borrow: `*b_mut_ref()`
    |
    = note: expected type `bool`
               found type `&mut bool`
@@ -20,7 +26,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:20:8
    |
 LL |     if &true {}
-   |        ^^^^^ expected bool, found &bool
+   |        ^^^^^
+   |        |
+   |        expected bool, found &bool
+   |        help: consider removing the borrow: `true`
    |
    = note: expected type `bool`
               found type `&bool`
@@ -29,7 +38,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:21:8
    |
 LL |     if &mut true {}
-   |        ^^^^^^^^^ expected bool, found &mut bool
+   |        ^^^^^^^^^
+   |        |
+   |        expected bool, found &mut bool
+   |        help: consider removing the borrow: `true`
    |
    = note: expected type `bool`
               found type `&mut bool`
@@ -38,7 +50,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:24:11
    |
 LL |     while b_ref() {}
-   |           ^^^^^^^ expected bool, found &bool
+   |           ^^^^^^^
+   |           |
+   |           expected bool, found &bool
+   |           help: consider dereferencing the borrow: `*b_ref()`
    |
    = note: expected type `bool`
               found type `&bool`
@@ -47,7 +62,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:25:11
    |
 LL |     while b_mut_ref() {}
-   |           ^^^^^^^^^^^ expected bool, found &mut bool
+   |           ^^^^^^^^^^^
+   |           |
+   |           expected bool, found &mut bool
+   |           help: consider dereferencing the borrow: `*b_mut_ref()`
    |
    = note: expected type `bool`
               found type `&mut bool`
@@ -56,7 +74,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:26:11
    |
 LL |     while &true {}
-   |           ^^^^^ expected bool, found &bool
+   |           ^^^^^
+   |           |
+   |           expected bool, found &bool
+   |           help: consider removing the borrow: `true`
    |
    = note: expected type `bool`
               found type `&bool`
@@ -65,7 +86,10 @@ error[E0308]: mismatched types
   --> $DIR/if-no-match-bindings.rs:27:11
    |
 LL |     while &mut true {}
-   |           ^^^^^^^^^ expected bool, found &mut bool
+   |           ^^^^^^^^^
+   |           |
+   |           expected bool, found &mut bool
+   |           help: consider removing the borrow: `true`
    |
    = note: expected type `bool`
               found type `&mut bool`
index eb824def24687e19502ab4d94c0368de4a0956e5..af120fa977caab609bc9f01448575654d91dbbc7 100644 (file)
@@ -19,3 +19,4 @@ LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index b50a926c63795aa4a6e08a759097535a730247a0..c1ec536ef43620da3c5a26a89b8caec29d222714 100644 (file)
@@ -18,3 +18,4 @@ LL | |     }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index cd65bab2d4668688d6c83df001b8203c83bc4ee1..a80ebaf8dd29d81892e5a9b789eb88a3f90f6dd3 100644 (file)
@@ -22,3 +22,4 @@ LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 80f15b7c5847f4cbc82b051dd67e2e28c5d3d308..4dee83d6eefe37ef0379d4b42d13f8ba74c1f7d0 100644 (file)
@@ -32,3 +32,4 @@ LL |         x
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/include-single-expr-helper-1.rs b/src/test/ui/include-single-expr-helper-1.rs
new file mode 100644 (file)
index 0000000..aa6380b
--- /dev/null
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+
+// trailing comment permitted
diff --git a/src/test/ui/include-single-expr-helper.rs b/src/test/ui/include-single-expr-helper.rs
new file mode 100644 (file)
index 0000000..84d8b69
--- /dev/null
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+10
+100
diff --git a/src/test/ui/include-single-expr.rs b/src/test/ui/include-single-expr.rs
new file mode 100644 (file)
index 0000000..0f4c29e
--- /dev/null
@@ -0,0 +1,6 @@
+// error-pattern include macro expected single expression
+
+fn main() {
+    include!("include-single-expr-helper.rs");
+    include!("include-single-expr-helper-1.rs");
+}
diff --git a/src/test/ui/include-single-expr.stderr b/src/test/ui/include-single-expr.stderr
new file mode 100644 (file)
index 0000000..80eecf8
--- /dev/null
@@ -0,0 +1,10 @@
+error: include macro expected single expression in source
+  --> $DIR/include-single-expr-helper.rs:4:1
+   |
+LL | 10
+   | ^^
+   |
+   = note: `#[deny(incomplete_include)]` on by default
+
+error: aborting due to previous error
+
index dfc663e4a79f84b88916c81b63d08dd643077aa3..1e74445af55cb0327bb4facb4604e54d0212e01b 100644 (file)
@@ -2,9 +2,7 @@ error[E0401]: can't use generic parameters from outer function
   --> $DIR/inner-static-type-parameter.rs:6:19
    |
 LL | fn foo<T>() {
-   |    --- - type parameter from outer function
-   |    |
-   |    try adding a local generic parameter in this method instead
+   |        - type parameter from outer function
 LL |     static a: Bar<T> = Bar::What;
    |                   ^ use of generic parameter from outer function
 
index bac6c8d872b401236efcd33516224d4be52c6459..0154f0499502959fe95372e12aa730acd6f61217 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-emscripten no i128 support
 
 #![feature(intrinsics)]
 
index 29e974ad83d1e27079a740d0eee6b53a5a7dd294..a2fd796245822dcb3056890324bc512574f2c170 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare always compiled as panic=abort right now
 
 // Check that values are not leaked when a dtor panics (#14875)
 
index 771a2ddf240f59ae643ccdb037138e28ef83a5f6..a047893a168a487f182f79b309aa3addfd51506b 100644 (file)
@@ -27,3 +27,4 @@ LL | trait T<'a> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 0ef3b98719d341c949d0ce4830dd65f869a5aeb0..28a1be59840a1fd79a16cb1f62c152ec91ddaee2 100644 (file)
@@ -28,3 +28,4 @@ LL | trait Foo<'a> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 64e3cdc64c1127d3522a1283fbd3ac3c6e069d55..dd895985c1430acb2c3e6a7a8da35646285feda2 100644 (file)
@@ -94,4 +94,5 @@ LL | impl<'a> Publisher<'a> for MyStruct<'a> {
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0495.
+For more information about an error, try `rustc --explain E0308`.
index 988ebe03ccf6644e6e787f349e38d07b2c84d681..1ce05ba390d76aee7401a08636191c2b982881b4 100644 (file)
@@ -1,5 +1,4 @@
 // build-pass
-// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g
 
 pub struct Dst {
index f08bcdfe6d16cfececeffc4a1f66f80ba5ed5479..773792c7a3f1f3492ecf737a50ea7d5fa50eb6a4 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 // aux-build:issue-24687-lib.rs
 // compile-flags:-g
-// ignore-asmjs wasm2js does not support source maps yet
 
 extern crate issue_24687_lib as d;
 
index 0f92fc2f7f31add41fb1e5587aaa35c6e676ae9a..cf3834952c6a6da264c672e4e8da017a41b45f8b 100644 (file)
@@ -3,7 +3,6 @@
 // as options to the compiler.
 
 // compile-flags:-g -g -O -O
-// ignore-asmjs wasm2js does not support source maps yet
 
 fn main() {
     assert_eq!(1, 1);
index 2a8750d3e431fbb53145878efa9fedae346b21f0..3b40b3dd8f075480a4fb09e392540cceafd439f9 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags:-g
-// ignore-asmjs wasm2js does not support source maps yet
 
 fn helper<F: FnOnce(usize) -> bool>(_f: F) {
     print!("");
index 5237a2f67bdd7036d2dd512eb72237b3294287c5..8ede8143ea6572a1b718fb0298ccde7248f6e1b9 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 use std::panic;
 
index 2501e1430b3d1ee658291e9cc42872f35052f0d6..f0b472e2fe821e8a489f56eee942cb6618c5410c 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 use std::ops::Deref;
 
index a6b137ba64594d21b6a68a5f045ef635265e1265..94fccff9fc65db7908ad92af58e516019a816104 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // ignore-windows
 // ignore-macos
-// ignore-emscripten common linkage not implemented right now
+// ignore-wasm32-bare common linkage not implemented right now
 
 #![feature(linkage)]
 
index 88dcdd4113807cb4fc3473abfad566c194592957..1f68560509e8c6a5c2e24ad04912c91f8780cb02 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags:-g
-// ignore-asmjs wasm2js does not support source maps yet
 
 // In this test we just want to make sure that the code below does not lead to
 // a debuginfo verification assertion during compilation. This was caused by the
index 28555a15afae1f487f699310f1eed9bc769e3ebd..856d6506f2a9f98971abc041f0cb2420c1c5d5d6 100644 (file)
@@ -63,7 +63,7 @@ LL | fn qux() -> Some {
    |             ^^^^
    |             |
    |             not a type
-   |             help: try using the variant's enum: `Option`
+   |             help: try using the variant's enum: `std::option::Option`
 
 error: aborting due to 7 previous errors
 
index 5657ba69f9449eb9d7e3bc9bcfa6f284acbf00a4..f2dfaf3dd367e71b368949866f7dc8182766d4d1 100644 (file)
@@ -2,7 +2,6 @@
 // Regression test for #36856.
 
 // compile-flags:-g
-// ignore-asmjs wasm2js does not support source maps yet
 
 fn g() -> bool {
     false
index 05c8ce4c3f11e5d7908cebe237d007b9ff3f2143..b98bc572a397c6c87cbf8b6ed148beb919fe5b1f 100644 (file)
@@ -5,7 +5,7 @@ LL |         self.boom();
    |         -----^^^^
    |         |    |
    |         |    this is an associated function, not a method
-   |         help: use associated function syntax instead: `&Obj::boom`
+   |         help: use associated function syntax instead: `Obj::boom`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
 note: the candidate is defined in an impl for the type `Obj`
index 01a5d563639b53900885d06d37d4d6a2e1b89d2b..318e3099f98ba4139df86f2dbaf881881d5ed754 100644 (file)
@@ -2,7 +2,6 @@
 // Regression test for #42210.
 
 // compile-flags: -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 trait Foo {
     fn foo() { }
index 2a932db05af26142c2e2913699fecff765079fef..47c3ab59aa2eb9c2eba273f77eb142336a9cbc48 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 use std::panic;
 
index 5c5ac59873a3a386eddee4e4fccf5b18cabf4e14..d20c07276a8c50667fda628a0456540c8ec00be9 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(unused_variables)]
 // compile-flags:--test -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 #[cfg(target_os = "macos")]
 #[test]
index 40c3117f01ce904b6d03ef3e760464e4e952e0da..461ea2498b0d47f0f4c633fe639e839ee65db00e 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // compile-flags:--test -O
 
-// ignore-emscripten compiled with panic=abort by default
-
 #[test]
 #[should_panic(expected = "creating inhabited type")]
 fn test() {
index b7aa6422876389ee90f8b80933c36e9dac44f309..385192b882ba80acf76c84d9e1e4a8678e7f5d07 100644 (file)
@@ -8,7 +8,6 @@
 
 // compile-flags:-g
 // ignore-pretty issue #37195
-// ignore-asmjs wasm2js does not support source maps yet
 
 #![feature(non_ascii_idents)]
 
index 767e06c4e90c5b3358fb68a0c16850c4fb846785..79cc107d4fec216eb56e66f707a76c477362cce8 100644 (file)
@@ -1,4 +1,5 @@
 // build-pass (FIXME(62277): could be check-pass?)
+// ignore-emscripten no i128 support
 
 fn fibs(n: u32) -> impl Iterator<Item=u128> {
     (0 .. n)
index 67feb3ff6aec3a98457c1b87efba2fdfb27e706b..24c61425b8e29e2b7cce1e00efff8fd10eb616b1 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(inner_deref)]
-
 fn main() {
     let _result = &Some(42).as_deref();
 //~^ ERROR no method named `as_deref` found for type `std::option::Option<{integer}>`
index 345f91437b82725ea92e7b25d0ada275d9938db7..0eb7bf0247565d5a4bfd61ff34811520d40e904e 100644 (file)
@@ -1,5 +1,5 @@
 error[E0599]: no method named `as_deref` found for type `std::option::Option<{integer}>` in the current scope
-  --> $DIR/option-as_deref.rs:4:29
+  --> $DIR/option-as_deref.rs:2:29
    |
 LL |     let _result = &Some(42).as_deref();
    |                             ^^^^^^^^ help: there is a method with a similar name: `as_ref`
index 56aead8d0e00d2bcda6c445dbad592e37645b6d2..67ad73f58477396e6801f47bf01f1860c6fa3e8f 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(inner_deref)]
-
 fn main() {
     let _result = &mut Some(42).as_deref_mut();
 //~^ ERROR no method named `as_deref_mut` found for type `std::option::Option<{integer}>`
index 29fd15fb396e99143e6340240ca81669035de956..845ddb52319c722a043faa2f54e6e862ca0b3e15 100644 (file)
@@ -1,5 +1,5 @@
 error[E0599]: no method named `as_deref_mut` found for type `std::option::Option<{integer}>` in the current scope
-  --> $DIR/option-as_deref_mut.rs:4:33
+  --> $DIR/option-as_deref_mut.rs:2:33
    |
 LL |     let _result = &mut Some(42).as_deref_mut();
    |                                 ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>`
index b4df10efc5d8da322c755f7b5107d8bac7ea8b3c..8d74b8ecb881e772c23a5124b6d9cca7b72916f3 100644 (file)
@@ -25,3 +25,4 @@ LL |         ((u,),) => u,
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/issues/issue-52262.rs b/src/test/ui/issues/issue-52262.rs
new file mode 100644 (file)
index 0000000..2195b89
--- /dev/null
@@ -0,0 +1,25 @@
+// compile-flags:-Ztreat-err-as-bug=5
+#[derive(Debug)]
+enum MyError {
+    NotFound { key: Vec<u8> },
+    Err41,
+}
+
+impl std::error::Error for MyError {}
+
+impl std::fmt::Display for MyError {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            MyError::NotFound { key } => write!(
+                f,
+                "unknown error with code {}.",
+                String::from_utf8(*key).unwrap()
+                //~^ ERROR cannot move out of `*key` which is behind a shared reference
+            ),
+            MyError::Err41 => write!(f, "Sit by a lake"),
+        }
+    }
+}
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/issues/issue-52262.stderr b/src/test/ui/issues/issue-52262.stderr
new file mode 100644 (file)
index 0000000..7312976
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0507]: cannot move out of `*key` which is behind a shared reference
+  --> $DIR/issue-52262.rs:16:35
+   |
+LL |                 String::from_utf8(*key).unwrap()
+   |                                   ^^^^ move occurs because `*key` has type `std::vec::Vec<u8>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
index 9e67e5e125f625567e0b11e06cc310852b8afe59..7cf597d3a98f81b5d2c1c2448a4504b53478b1f1 100644 (file)
@@ -42,3 +42,4 @@ LL |         Box::new(self.in_edges(u).map(|e| e.target()))
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0495`.
index af93f76221d4e2d271258fb44d06dc93ececc90f..8ab845366b7b4b873687dbc9e7aa6c4b82cd4237 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 // compile-flags:-C debuginfo=2
-// ignore-asmjs wasm2js does not support source maps yet
-
 fn foo() -> impl Copy {
     foo
 }
index fdd285dcad2a13334a8484581bfd4fca3ab7a679..d6612035750836e49accc865a8f2d05dcaeb35b3 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 // only-32bit too impatient for 2⁶⁴ items
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes -C opt-level=3
 
 use std::panic;
index b578999af8e948ed6cf29d6fd8b75d77318ad746..f1eded31702c4449d4ebf383127d13b251d84b81 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 // only-32bit too impatient for 2⁶⁴ items
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes -C opt-level=3
 
 use std::panic;
index 3872a03b682592cabce8cf18b7cfc8a7a51d8091..5d67c7cbb42565e00898ee95cb7d5b155a201c7f 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
index 4a9e8cdb72e70bb7fac183549d792d85f47cabf7..ee4ab4d24c6ab22da3d6c2579bf01308c144c0cf 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
index 6bd1425e32465f05451fbba66d6891fd197c073e..429f8e0bc9648a61aeecc631e91202fce4770891 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -C overflow-checks
 
 use std::panic;
index 1c791bb1ca3d61f061c6f79668c3db65c620b82b..9f1a31d1ae2741cb033adf3598d713f25211c1e9 100644 (file)
@@ -13,8 +13,6 @@
 // compile-flags: --test -C debug_assertions=yes
 // revisions: std core
 
-// ignore-emscripten compiled with panic=abort by default
-
 #![cfg_attr(core, no_std)]
 
 #[cfg(std)] use std::fmt;
index de8d958af45e34a144561acecba37cb6c7db61d4..6f13d5612ce51b93a333eaf4dfbcb558e68f5b17 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(fn_traits)]
 #![feature(never_type)]
index 2bc5cf1c976373b83721ac4a3e0648212bec3312..2949437b1e4b659db6463f812ae0239c8c6fdb5b 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 use std::cell::RefCell;
 use std::panic;
index ffb94ed7dd7c0eab3ee8a3bbe82708c546aacdaa..e00e6f36f1af41d1ac4c34e056e20aa2202b5f93 100644 (file)
@@ -27,3 +27,4 @@ LL | impl Foo<'_> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 951e73e7fd76555659eb5261b618e7493a626f2a..77a372d9cf5589778676ec2b2669c1a3dd17e209 100644 (file)
@@ -20,3 +20,4 @@ LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 00d58d34362e644c78a445592e7a1e2f9fb8ffdc..746517417520a5909ca590a015cd85222a5ee281 100644 (file)
@@ -50,3 +50,4 @@ LL | impl<'a> FromTuple<'a> for C<'a> {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0495`.
index 77e1339dc161d7ed43667e6ff2f4e4fdc8f7728e..f5657f9e4eada21c131b76e2671b990824502cbc 100644 (file)
@@ -21,3 +21,4 @@ LL |     <Foo<'a>>::C
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 77655fe091b6275fedbd0721f22cff7b94929a31..f7db4038b8af43cff1f9e2b16e5dc4afa828817a 100644 (file)
@@ -21,3 +21,4 @@ LL |     T::C
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 680430a05ee8ad98e66783bd1090e5ae1ebc4ad5..f21df68d5a2cc52e5fca6f26879ed9b86ac0da08 100644 (file)
@@ -18,5 +18,5 @@ LL |     m!((bad, pat));
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0130, E0642.
+Some errors have detailed explanations: E0130, E0561, E0642.
 For more information about an error, try `rustc --explain E0130`.
index b65e0ecd253e65ae6fa5195316b0d43af06ec57c..1c2ce86646787e65eecc1462a06d16b20f35f52c 100644 (file)
@@ -30,4 +30,5 @@ LL | type A2 = fn(&arg: u8);
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0130`.
+Some errors have detailed explanations: E0130, E0561.
+For more information about an error, try `rustc --explain E0130`.
index aa18b923044c6a52d8db6ad3d1b082eb9755b28b..2362ccd32de994d0239ba0ce9ac3a336273d7a09 100644 (file)
@@ -8,6 +8,7 @@ LL |     assert::<&mut i32>();
    |     ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
    |
    = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32`
+   = note: `std::panic::UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
 
 error: aborting due to previous error
 
index ced3c61ec162a6d784e3382ca31f04af1111f803..d210abdf499d0422e94cbe1ef49635a48381c278 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-emscripten no i128 support
 
 #![deny(const_err)]
 
index ef558c0aa0c02c54ae8cd4f3aeb750423c029ada..ea0ef95e4f1af3d5c8bf3a1ff6aa6eb10221ea1a 100644 (file)
@@ -1,6 +1,9 @@
 // run-pass
 #![allow(overflowing_literals)]
 
+// ignore-emscripten i128 doesn't work
+
+
 #![feature(test)]
 
 extern crate test;
index c1959866e5c257ceea998dfd25c57324f2ff7bab..e9927304f23f8c380a0f1c9ea5fa0d76a79e2536 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 // compile-flags: -C debug_assertions=yes
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // ignore-emscripten dies with an LLVM error
 
 use std::panic;
index 2671a267f4a870c57f11976648bde8acaf346656..bef7deb62760e45191fbb7d118a1429a0ab3df75 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-emscripten u128 not supported
 
 #![feature(test)]
 #![deny(overflowing_literals)]
index 0b2305c6e8b1acc9c34ac28e2fb99a0f61f584f7..9394071632377eec0b7ec4baa72fb1d9cdeba500 100644 (file)
@@ -1,4 +1,6 @@
 // run-pass
+// ignore-emscripten u128 not supported
+
 
 #![feature(test)]
 
index 2cdd6c5d890f2721ffa94bd6f70e351867e80a8c..217e8504aa3c94ed62a49fa1af415f33e944c999 100644 (file)
@@ -50,3 +50,4 @@ LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0495`.
index 6dcb852a3669f66f31cf49db429d4ea5f83c9f16..5d72771c2dcff1bdff532ec1214b0acb67daa901 100644 (file)
@@ -4,7 +4,7 @@
 // aux-build:wants-panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
 // error-pattern: is not compiled with this crate's panic strategy `unwind`
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
index e7811d40b5b9a74f1e3bf1be6df673eeaa58c207..4c25c09d6438f3146ca04a355be849481707add5 100644 (file)
@@ -1,7 +1,7 @@
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
index 44671796c01a3e37b4cc77f50806e4c4fc189e58..478af451e7f657bbd73ecceb3ca5b180027019ca 100644 (file)
@@ -2,7 +2,7 @@
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
index 72b844d8b4886d366a4a81eea4bc2e2d792365d8..b0d6629561803077c5324c0c2d9d61e553657557 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare always compiled as panic=abort right now and this requires unwinding
 // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
 // in a runtime panic.
 
index 22f80a8aae866f254a8623a196f7c08ab0a85851..7291732cebe4a3751062346c6920758f349d38c5 100644 (file)
@@ -3,6 +3,7 @@
 impl S {
     fn f(*, a: u8) -> u8 {}
     //~^ ERROR expected parameter name, found `*`
+    //~| ERROR mismatched types
 }
 
 fn main() {}
index 9e1178e8ac1f352d3f4fc53d8dc1f401f7cfbeeb..7e5c348e36ceac5073e18730a04b066186b5f148 100644 (file)
@@ -4,5 +4,17 @@ error: expected parameter name, found `*`
 LL |     fn f(*, a: u8) -> u8 {}
    |          ^ expected parameter name
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/issue-33413.rs:4:23
+   |
+LL |     fn f(*, a: u8) -> u8 {}
+   |        -              ^^ expected u8, found ()
+   |        |
+   |        implicitly returns `()` as its body has no tail or `return` expression
+   |
+   = note: expected type `u8`
+              found type `()`
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs
new file mode 100644 (file)
index 0000000..97a405b
--- /dev/null
@@ -0,0 +1,26 @@
+// Regression test; used to ICE with 'visit_mac disabled by default' due to a
+// `MutVisitor` in `fn make_all_value_bindings_mutable` (`parse/parser/pat.rs`).
+
+macro_rules! mac1 {
+    ($eval:expr) => {
+        let mut $eval = ();
+        //~^ ERROR `mut` must be followed by a named binding
+    };
+}
+
+macro_rules! mac2 {
+    ($eval:pat) => {
+        let mut $eval = ();
+        //~^ ERROR `mut` must be followed by a named binding
+        //~| ERROR expected identifier, found `does_not_exist!()`
+    };
+}
+
+fn foo() {
+    mac1! { does_not_exist!() }
+    //~^ ERROR cannot find macro `does_not_exist` in this scope
+    mac2! { does_not_exist!() }
+    //~^ ERROR cannot find macro `does_not_exist` in this scope
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr
new file mode 100644 (file)
index 0000000..dd193d6
--- /dev/null
@@ -0,0 +1,45 @@
+error: `mut` must be followed by a named binding
+  --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:6:13
+   |
+LL |         let mut $eval = ();
+   |             ^^^^^^^^^ help: remove the `mut` prefix: `does_not_exist!()`
+...
+LL |     mac1! { does_not_exist!() }
+   |     --------------------------- in this macro invocation
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: expected identifier, found `does_not_exist!()`
+  --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:17
+   |
+LL |         let mut $eval = ();
+   |                 ^^^^^ expected identifier
+...
+LL |     mac2! { does_not_exist!() }
+   |     --------------------------- in this macro invocation
+
+error: `mut` must be followed by a named binding
+  --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13
+   |
+LL |         let mut $eval = ();
+   |             ^^^ help: remove the `mut` prefix: `does_not_exist!()`
+...
+LL |     mac2! { does_not_exist!() }
+   |     --------------------------- in this macro invocation
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: cannot find macro `does_not_exist` in this scope
+  --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13
+   |
+LL |     mac1! { does_not_exist!() }
+   |             ^^^^^^^^^^^^^^
+
+error: cannot find macro `does_not_exist` in this scope
+  --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13
+   |
+LL |     mac2! { does_not_exist!() }
+   |             ^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.rs b/src/test/ui/parser/no-const-fn-in-extern-block.rs
new file mode 100644 (file)
index 0000000..29f2638
--- /dev/null
@@ -0,0 +1,8 @@
+extern {
+    const fn foo();
+    //~^ ERROR extern items cannot be `const`
+    const unsafe fn bar();
+    //~^ ERROR extern items cannot be `const`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.stderr b/src/test/ui/parser/no-const-fn-in-extern-block.stderr
new file mode 100644 (file)
index 0000000..5b4663a
--- /dev/null
@@ -0,0 +1,14 @@
+error: extern items cannot be `const`
+  --> $DIR/no-const-fn-in-extern-block.rs:2:5
+   |
+LL |     const fn foo();
+   |     ^^^^^
+
+error: extern items cannot be `const`
+  --> $DIR/no-const-fn-in-extern-block.rs:4:5
+   |
+LL |     const unsafe fn bar();
+   |     ^^^^^
+
+error: aborting due to 2 previous errors
+
index 3dcc0c8f3d496eb03e6cd0a641c264b868014117..9c7a25d589a1f9aafa988098042db58979b5dc5a 100644 (file)
@@ -3,15 +3,24 @@ fn f<T>() {}
 
 fn main() {
     false == false == false;
-    //~^ ERROR: chained comparison operators require parentheses
+    //~^ ERROR chained comparison operators require parentheses
 
     false == 0 < 2;
-    //~^ ERROR: chained comparison operators require parentheses
-    //~| ERROR: mismatched types
-    //~| ERROR: mismatched types
+    //~^ ERROR chained comparison operators require parentheses
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
 
     f<X>();
     //~^ ERROR chained comparison operators require parentheses
-    //~| HELP: use `::<...>` instead of `<...>`
-    //~| HELP: or use `(...)`
+    //~| HELP use `::<...>` instead of `<...>` to specify type arguments
+
+    f<Result<Option<X>, Option<Option<X>>>(1, 2);
+    //~^ ERROR chained comparison operators require parentheses
+    //~| HELP use `::<...>` instead of `<...>` to specify type arguments
+
+    use std::convert::identity;
+    let _ = identity<u8>;
+    //~^ ERROR chained comparison operators require parentheses
+    //~| HELP use `::<...>` instead of `<...>` to specify type arguments
+    //~| HELP or use `(...)` if you meant to specify fn arguments
 }
index e927f4c32484ededce5d662205d609a516e8fb77..5aa37a40cbd3dc23d1383eae5f2325096400bb16 100644 (file)
@@ -2,21 +2,41 @@ error: chained comparison operators require parentheses
   --> $DIR/require-parens-for-chained-comparison.rs:5:11
    |
 LL |     false == false == false;
-   |           ^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^
 
 error: chained comparison operators require parentheses
   --> $DIR/require-parens-for-chained-comparison.rs:8:11
    |
 LL |     false == 0 < 2;
-   |           ^^^^^^^^
+   |           ^^^^^^
 
 error: chained comparison operators require parentheses
   --> $DIR/require-parens-for-chained-comparison.rs:13:6
    |
 LL |     f<X>();
-   |      ^^^^
+   |      ^^^
+help: use `::<...>` instead of `<...>` to specify type arguments
    |
-   = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+LL |     f::<X>();
+   |      ^^
+
+error: chained comparison operators require parentheses
+  --> $DIR/require-parens-for-chained-comparison.rs:17:6
+   |
+LL |     f<Result<Option<X>, Option<Option<X>>>(1, 2);
+   |      ^^^^^^^^
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     f::<Result<Option<X>, Option<Option<X>>>(1, 2);
+   |      ^^
+
+error: chained comparison operators require parentheses
+  --> $DIR/require-parens-for-chained-comparison.rs:22:21
+   |
+LL |     let _ = identity<u8>;
+   |                     ^^^^
+   |
+   = help: use `::<...>` instead of `<...>` to specify type arguments
    = help: or use `(...)` if you meant to specify fn arguments
 
 error[E0308]: mismatched types
@@ -37,6 +57,6 @@ LL |     false == 0 < 2;
    = note: expected type `bool`
               found type `{integer}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 690a76ef3e0afe8a0c9531355bfe78db3abd5056..418178d0f0ead071c24efda048d43721ac535eec 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 // aux-build:expand-with-a-macro.rs
 
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![deny(warnings)]
 
index 26c51efea1e1ca8ed7310f741aece8cb5c3bffc4..f1e53a0d8b4266658134f0953db9b546126ee211 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // aux-build:reachable-unnameable-items.rs
 
 extern crate reachable_unnameable_items;
index 0c5e22ebae2835d3726b914f482d49b3a6d73600..cc8d150d04cc513a90f8dc67a9b89bffd630b64f 100644 (file)
@@ -27,3 +27,4 @@ LL |     x.borrowed()
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index e737d27d5606f67f8c769899328334bae85f41bb..23fd4d03628d9aa8c959baae4813d6ebd233f5e4 100644 (file)
@@ -27,3 +27,4 @@ LL |     x.borrowed()
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 8209fa1840d05d12611aacf30e80edc54c27d419..3ccb8866ca44b1bcc1d1774b31918d2e8a927814 100644 (file)
@@ -48,4 +48,5 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0621`.
+Some errors have detailed explanations: E0495, E0621.
+For more information about an error, try `rustc --explain E0495`.
index 2274e9341dbc974f475beec9ae91ff6279368edc..a0b8b6b51e5a1b36572ad8567ad4cbfd94ce81b7 100644 (file)
@@ -26,3 +26,4 @@ LL |         let p: &'static mut usize = &mut self.cats_chased;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index d02caeb44f1a82380acbdb042adb28dab39485c6..ac5e5e9aabc5bfa41e98ed87d428c99ec2ec8b50 100644 (file)
@@ -23,3 +23,4 @@ LL |             let p: &'static mut usize = &mut self.food;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 9732cd12ce15fbd76f20147165e4cee2ca71fc56..d01e991103923eda4f18b6600ab12d5a8fd461d2 100644 (file)
@@ -46,3 +46,4 @@ LL | impl<'a,'b> Foo<'b> for &'a i64 {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0495`.
index 2067bc3946c92f81717eaf661404208a5bc8d14e..33a4ea01ce2e570161afde26fa16ecf1f4407221 100644 (file)
@@ -21,3 +21,4 @@ LL | impl<'a> Foo for &'a i32 {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index fa203debb3a1b4705923fb25f1ef6ba0005c369d..7af608d2c801d422970cd76b52f1039c35ad3b4a 100644 (file)
@@ -21,3 +21,4 @@ LL |     box B(&*v) as Box<dyn X>
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index f5e66f84a9ee7657edad02d8a7cd890a840a3170..ef47db18d392c06261b22c43748c310a56a1a300 100644 (file)
@@ -21,3 +21,4 @@ LL |     box B(&*v) as Box<dyn X>
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 8b3dbc8b64902c6f1f1d8c9a6ddf678dbe115e08..6f7466a8b0edd14f46346995e09777715d9d3698 100644 (file)
@@ -25,3 +25,4 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait +
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index e13cbe9960ab8fc7ac754b3da8ca4e2f4f36cf76..4d00783d180b6aeb7371c5ee6ea27459725d71ed 100644 (file)
@@ -23,3 +23,4 @@ LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index d867448e1372abbc6b54383ebab539aaaa6e41db..b93dd0d4c57c9e06785409bd9e8e4adf359ca715 100644 (file)
@@ -25,3 +25,4 @@ LL |     s.f(|p| p)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index c8a02683d1000bad004b4d43c9f98452cca385bd..a6b165e2d444474e563ff45d1f7b5a95e3320295 100644 (file)
@@ -25,3 +25,4 @@ LL |     with(|o| o)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 5fad6de2a62af661b0654e3539d4170e643e2b63..676e96a038b43fbed2e3124e269e4bdd2f01a410 100644 (file)
@@ -30,3 +30,4 @@ LL | |         }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 151c8307a14f605e224806c75a69d537c8b9fa72..1d6dbdb2c7b57f3de79825376cb789249ffde81f 100644 (file)
@@ -27,3 +27,4 @@ LL |     let z = with(|y| { select(x, y) });
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 904dee6998c9bbe7c720c044edaa3c63aff4aa48..bc3c06d7ff3b3242af945d07deddbcca92a4edf5 100644 (file)
@@ -57,4 +57,5 @@ LL | fn nested<'x>(x: &'x isize) {
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0312`.
+Some errors have detailed explanations: E0312, E0495.
+For more information about an error, try `rustc --explain E0312`.
index 912e118316271a80e8ee02ed62efddf58776bf4d..c44edf1f03bc3e74a937d3ba069e72be26cc73ab 100644 (file)
@@ -23,3 +23,4 @@ LL | fn bar<'a, 'b>()
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 403af2a9e6a44c55a3607daf7041f3606ffcc38f..72e47cea094c58899ad984ee586e06659437603d 100644 (file)
@@ -25,3 +25,4 @@ LL |     with(|o| o)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 5d1f26da6c78371daef835c2e2ef29fa323733ca..ce0c429ccb24713e86ea583cc416979d2282dee4 100644 (file)
@@ -25,3 +25,4 @@ LL |     with(|o| o)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 291b8367f7b75e2c3582154c98d49271fd2fb689..be441bc48082ed16a97865d3c625d1c8696987cc 100644 (file)
@@ -27,3 +27,4 @@ LL |         let y = f();
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 6de92f13840b3310b3a931a63a05e6702736315f..d88be05cb87e62aafe6422166f7a8373fa3e497b 100644 (file)
@@ -61,5 +61,5 @@ LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dum
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0308, E0478.
+Some errors have detailed explanations: E0308, E0478, E0495.
 For more information about an error, try `rustc --explain E0308`.
index 08aca3bb14c26cbf521881068a69369f030f54f4..16d27c9d961eefb8333c7aed62b393212828b743 100644 (file)
@@ -111,5 +111,5 @@ LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
 
 error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0308, E0366, E0367.
+Some errors have detailed explanations: E0308, E0366, E0367, E0495.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.rs
new file mode 100644 (file)
index 0000000..ce45f63
--- /dev/null
@@ -0,0 +1,10 @@
+unsafe fn foo<A>() {
+    extern "C" {
+        static baz: *const A;
+        //~^ ERROR can't use generic parameters from outer function
+    }
+
+    let bar: *const u64 = core::mem::transmute(&baz);
+}
+
+fn main() { }
diff --git a/src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/src/test/ui/resolve/issue-65025-extern-static-parent-generics.stderr
new file mode 100644 (file)
index 0000000..6bbf76d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65025-extern-static-parent-generics.rs:3:28
+   |
+LL | unsafe fn foo<A>() {
+   |               - type parameter from outer function
+LL |     extern "C" {
+LL |         static baz: *const A;
+   |                            ^ use of generic parameter from outer function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs b/src/test/ui/resolve/issue-65035-static-with-parent-generics.rs
new file mode 100644 (file)
index 0000000..63d3431
--- /dev/null
@@ -0,0 +1,29 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn f<T>() {
+    extern "C" {
+        static a: *const T;
+        //~^ ERROR can't use generic parameters from outer function
+    }
+}
+
+fn g<T: Default>() {
+    static a: *const T = Default::default();
+    //~^ ERROR can't use generic parameters from outer function
+}
+
+fn h<const N: usize>() {
+    extern "C" {
+        static a: [u8; N];
+        //~^ ERROR can't use generic parameters from outer function
+    }
+}
+
+fn i<const N: usize>() {
+    static a: [u8; N] = [0; N];
+    //~^ ERROR can't use generic parameters from outer function
+    //~^^ ERROR can't use generic parameters from outer function
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
new file mode 100644 (file)
index 0000000..82e2aa2
--- /dev/null
@@ -0,0 +1,53 @@
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65035-static-with-parent-generics.rs:6:26
+   |
+LL | fn f<T>() {
+   |      - type parameter from outer function
+LL |     extern "C" {
+LL |         static a: *const T;
+   |                          ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65035-static-with-parent-generics.rs:12:22
+   |
+LL | fn g<T: Default>() {
+   |      - type parameter from outer function
+LL |     static a: *const T = Default::default();
+   |                      ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65035-static-with-parent-generics.rs:18:24
+   |
+LL | fn h<const N: usize>() {
+   |            - const parameter from outer function
+LL |     extern "C" {
+LL |         static a: [u8; N];
+   |                        ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65035-static-with-parent-generics.rs:24:20
+   |
+LL | fn i<const N: usize>() {
+   |            - const parameter from outer function
+LL |     static a: [u8; N] = [0; N];
+   |                    ^ use of generic parameter from outer function
+
+error[E0401]: can't use generic parameters from outer function
+  --> $DIR/issue-65035-static-with-parent-generics.rs:24:29
+   |
+LL | fn i<const N: usize>() {
+   |            - const parameter from outer function
+LL |     static a: [u8; N] = [0; N];
+   |                             ^ use of generic parameter from outer function
+
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/issue-65035-static-with-parent-generics.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
index c8e8b9dcfc6a7e6788aa2b43c0e73d20b8272214..39825c4f9a93890ce663f31422b39d0b33a3cdcb 100644 (file)
@@ -1,8 +1,6 @@
 // compile-flags: --test
 // run-pass
 
-// ignore-emscripten compiled with panic=abort by default
-
 #![feature(test)]
 
 extern crate test;
diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs
new file mode 100644 (file)
index 0000000..1a187d0
--- /dev/null
@@ -0,0 +1,31 @@
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+#[repr(C)]
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct TupleStruct (pub u16, pub u16);
+
+#[repr(C)]
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    #[non_exhaustive] Tuple(u32),
+    #[non_exhaustive] Struct { field: u32 }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs
new file mode 100644 (file)
index 0000000..900b933
--- /dev/null
@@ -0,0 +1,24 @@
+// aux-build:types.rs
+#![deny(improper_ctypes)]
+
+extern crate types;
+
+// This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered
+// improper.
+
+use types::{NonExhaustiveEnum, NormalStruct, UnitStruct, TupleStruct, NonExhaustiveVariants};
+
+extern {
+    pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
+    //~^ ERROR `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
+    pub fn non_exhaustive_normal_struct(_: NormalStruct);
+    //~^ ERROR `extern` block uses type `types::NormalStruct`, which is not FFI-safe
+    pub fn non_exhaustive_unit_struct(_: UnitStruct);
+    //~^ ERROR `extern` block uses type `types::UnitStruct`, which is not FFI-safe
+    pub fn non_exhaustive_tuple_struct(_: TupleStruct);
+    //~^ ERROR `extern` block uses type `types::TupleStruct`, which is not FFI-safe
+    pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
+    //~^ ERROR `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr
new file mode 100644 (file)
index 0000000..7fbf115
--- /dev/null
@@ -0,0 +1,47 @@
+error: `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe
+  --> $DIR/extern_crate_improper.rs:12:35
+   |
+LL |     pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
+   |                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: lint level defined here
+  --> $DIR/extern_crate_improper.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: this enum is non-exhaustive
+
+error: `extern` block uses type `types::NormalStruct`, which is not FFI-safe
+  --> $DIR/extern_crate_improper.rs:14:44
+   |
+LL |     pub fn non_exhaustive_normal_struct(_: NormalStruct);
+   |                                            ^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: this struct is non-exhaustive
+
+error: `extern` block uses type `types::UnitStruct`, which is not FFI-safe
+  --> $DIR/extern_crate_improper.rs:16:42
+   |
+LL |     pub fn non_exhaustive_unit_struct(_: UnitStruct);
+   |                                          ^^^^^^^^^^ not FFI-safe
+   |
+   = note: this struct is non-exhaustive
+
+error: `extern` block uses type `types::TupleStruct`, which is not FFI-safe
+  --> $DIR/extern_crate_improper.rs:18:43
+   |
+LL |     pub fn non_exhaustive_tuple_struct(_: TupleStruct);
+   |                                           ^^^^^^^^^^^ not FFI-safe
+   |
+   = note: this struct is non-exhaustive
+
+error: `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe
+  --> $DIR/extern_crate_improper.rs:20:38
+   |
+LL |     pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: this enum has non-exhaustive variants
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/same_crate_proper.rs
new file mode 100644 (file)
index 0000000..3f38e3c
--- /dev/null
@@ -0,0 +1,46 @@
+// check-pass
+#![feature(non_exhaustive)]
+#![deny(improper_ctypes)]
+
+// This test checks that non-exhaustive types with `#[repr(C)]` are considered proper within
+// the defining crate.
+
+#[non_exhaustive]
+#[repr(C)]
+pub enum NonExhaustiveEnum {
+    Unit,
+    Tuple(u32),
+    Struct { field: u32 }
+}
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct NormalStruct {
+    pub first_field: u16,
+    pub second_field: u16,
+}
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+#[repr(C)]
+pub struct TupleStruct (pub u16, pub u16);
+
+#[repr(C)]
+pub enum NonExhaustiveVariants {
+    #[non_exhaustive] Unit,
+    #[non_exhaustive] Tuple(u32),
+    #[non_exhaustive] Struct { field: u32 }
+}
+
+extern {
+    // Unit structs aren't tested here because they will trigger `improper_ctypes` anyway.
+    pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
+    pub fn non_exhaustive_normal_struct(_: NormalStruct);
+    pub fn non_exhaustive_tuple_struct(_: TupleStruct);
+    pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
new file mode 100644 (file)
index 0000000..d400db8
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+#[track_caller(1)]
+fn f() {}
+//~^^ ERROR malformed `track_caller` attribute input
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
new file mode 100644 (file)
index 0000000..a53a8ee
--- /dev/null
@@ -0,0 +1,16 @@
+error: malformed `track_caller` attribute input
+  --> $DIR/error-odd-syntax.rs:3:1
+   |
+LL | #[track_caller(1)]
+   | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
+
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-odd-syntax.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
new file mode 100644 (file)
index 0000000..2994f3c
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+#[track_caller]
+extern "C" fn f() {}
+//~^^ ERROR rust ABI is required to use `#[track_caller]`
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
new file mode 100644 (file)
index 0000000..a34acf3
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-with-invalid-abi.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0737]: rust ABI is required to use `#[track_caller]`
+  --> $DIR/error-with-invalid-abi.rs:3:1
+   |
+LL | #[track_caller]
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0737`.
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
new file mode 100644 (file)
index 0000000..bbbcec3
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+#[track_caller]
+#[naked]
+fn f() {}
+//~^^^ ERROR cannot use `#[track_caller]` with `#[naked]`
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
new file mode 100644 (file)
index 0000000..93e6f7a
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-with-naked.rs:1:29
+   |
+LL | #![feature(naked_functions, track_caller)]
+   |                             ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0736]: cannot use `#[track_caller]` with `#[naked]`
+  --> $DIR/error-with-naked.rs:3:1
+   |
+LL | #[track_caller]
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0736`.
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
new file mode 100644 (file)
index 0000000..1cd45c8
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+trait Trait {
+    #[track_caller]
+    fn unwrap(&self);
+    //~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
+}
+
+impl Trait for u64 {
+    fn unwrap(&self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
new file mode 100644 (file)
index 0000000..fb3732b
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-with-trait-decl.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0738]: `#[track_caller]` is not supported in trait declarations.
+  --> $DIR/error-with-trait-decl.rs:4:5
+   |
+LL |     #[track_caller]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0738`.
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
new file mode 100644 (file)
index 0000000..0f2020d
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+trait Trait {
+    #[track_caller]
+    fn unwrap(&self) {}
+    //~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
new file mode 100644 (file)
index 0000000..c212a71
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-with-trait-default-impl.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0738]: `#[track_caller]` is not supported in trait declarations.
+  --> $DIR/error-with-trait-default-impl.rs:4:5
+   |
+LL |     #[track_caller]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0738`.
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
new file mode 100644 (file)
index 0000000..1378eba
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+trait Trait {
+    fn unwrap(&self);
+}
+
+impl Trait for u64 {
+    #[track_caller]
+    fn unwrap(&self) {}
+    //~^^ ERROR: `#[track_caller]` is not supported in traits yet.
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
new file mode 100644 (file)
index 0000000..2662fbf
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/error-with-trait-fn-impl.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0738]: `#[track_caller]` is not supported in traits yet.
+  --> $DIR/error-with-trait-fn-impl.rs:8:5
+   |
+LL |     #[track_caller]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0738`.
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
new file mode 100644 (file)
index 0000000..01ebf13
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+#[track_caller]
+struct S;
+//~^^ ERROR attribute should be applied to function
+
+fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
new file mode 100644 (file)
index 0000000..3301da7
--- /dev/null
@@ -0,0 +1,18 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/only-for-fns.rs:1:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0739]: attribute should be applied to function
+  --> $DIR/only-for-fns.rs:3:1
+   |
+LL | #[track_caller]
+   | ^^^^^^^^^^^^^^^
+LL | struct S;
+   | --------- not a function
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs
new file mode 100644 (file)
index 0000000..f2c3f0d
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+
+#[track_caller]
+fn f() {}
+
+fn main() {
+    f();
+}
diff --git a/src/test/ui/rfc-2091-track-caller/pass.stderr b/src/test/ui/rfc-2091-track-caller/pass.stderr
new file mode 100644 (file)
index 0000000..b1fd23a
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `track_caller` is incomplete and may cause the compiler to crash
+  --> $DIR/pass.rs:2:12
+   |
+LL | #![feature(track_caller)]
+   |            ^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
index 4edc00efc7e722cb37a4bfde5984912ef9c80f2e..ad4686c1915d67de9ef1e40b89cff1bca1e80770 100644 (file)
@@ -517,7 +517,10 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:32:8
    |
 LL |     if &let 0 = 0 {}
-   |        ^^^^^^^^^^ expected bool, found &bool
+   |        ^^^^^^^^^^
+   |        |
+   |        expected bool, found &bool
+   |        help: consider removing the borrow: `let 0 = 0`
    |
    = note: expected type `bool`
               found type `&bool`
@@ -702,7 +705,10 @@ error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:96:11
    |
 LL |     while &let 0 = 0 {}
-   |           ^^^^^^^^^^ expected bool, found &bool
+   |           ^^^^^^^^^^
+   |           |
+   |           expected bool, found &bool
+   |           help: consider removing the borrow: `let 0 = 0`
    |
    = note: expected type `bool`
               found type `&bool`
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs
new file mode 100644 (file)
index 0000000..14345ba
--- /dev/null
@@ -0,0 +1,8 @@
+#[link(name="foo")]
+extern {
+    #[link_ordinal(42)]
+    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    fn foo();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr
new file mode 100644 (file)
index 0000000..0869d7a
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+  --> $DIR/feature-gate-raw-dylib-2.rs:3:5
+   |
+LL |     #[link_ordinal(42)]
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/58713
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs
new file mode 100644 (file)
index 0000000..f0f83e0
--- /dev/null
@@ -0,0 +1,5 @@
+#[link(name="foo", kind="raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+extern {}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr
new file mode 100644 (file)
index 0000000..0ca9de2
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: kind="raw-dylib" is unstable
+  --> $DIR/feature-gate-raw-dylib.rs:1:1
+   |
+LL | #[link(name="foo", kind="raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/58713
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
new file mode 100644 (file)
index 0000000..5769366
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+
+#[link(name="foo")]
+extern {
+    #[link_name="foo"]
+    #[link_ordinal(42)]
+    //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
+    fn foo();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
new file mode 100644 (file)
index 0000000..303a1c0
--- /dev/null
@@ -0,0 +1,16 @@
+warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+  --> $DIR/link-ordinal-and-name.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: cannot use `#[link_name]` with `#[link_ordinal]`
+  --> $DIR/link-ordinal-and-name.rs:7:5
+   |
+LL |     #[link_ordinal(42)]
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
new file mode 100644 (file)
index 0000000..82fb115
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+
+#[link(name="foo")]
+extern {
+    #[link_ordinal("JustMonika")]
+    //~^ ERROR illegal ordinal format in `link_ordinal`
+    fn foo();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
new file mode 100644 (file)
index 0000000..14556a7
--- /dev/null
@@ -0,0 +1,18 @@
+warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+  --> $DIR/link-ordinal-invalid-format.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: illegal ordinal format in `link_ordinal`
+  --> $DIR/link-ordinal-invalid-format.rs:6:5
+   |
+LL |     #[link_ordinal("JustMonika")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: an unsuffixed integer value, e.g., `1`, is expected
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
new file mode 100644 (file)
index 0000000..69596ad
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete and may cause the compiler to crash
+
+#[link(name="foo")]
+extern {
+    #[link_ordinal(18446744073709551616)]
+    //~^ ERROR ordinal value in `link_ordinal` is too large: `18446744073709551616`
+    fn foo();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
new file mode 100644 (file)
index 0000000..b3b22f9
--- /dev/null
@@ -0,0 +1,18 @@
+warning: the feature `raw_dylib` is incomplete and may cause the compiler to crash
+  --> $DIR/link-ordinal-too-large.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: ordinal value in `link_ordinal` is too large: `18446744073709551616`
+  --> $DIR/link-ordinal-too-large.rs:6:5
+   |
+LL |     #[link_ordinal(18446744073709551616)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the value may not exceed `std::usize::MAX`
+
+error: aborting due to previous error
+
index b10b6ec11b53a346f19d47a7cdb891a5a19664b0..7923aa7c0e22f31affe992fabc45afaa67d844f9 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 
 #![allow(dead_code, unreachable_code)]
 
index 51a572899f81952979ee056fd9e0d1eb6c91cc0e..164ae79c254faaeb6ce9ad8e3cf5ee327cfac3e0 100644 (file)
@@ -4,7 +4,6 @@
 
 // aux-build:sepcomp_lib.rs
 // compile-flags: -C lto -g
-// ignore-asmjs wasm2js does not support source maps yet
 // no-prefer-dynamic
 
 extern crate sepcomp_lib;
index 5cf975b5752f0e54c198792df47025ca627268d7..1e5555355c3b319d3d6586d4319fd2d2e44d4d6d 100644 (file)
@@ -22,7 +22,9 @@ pub trait Bar {
     fn bar(&self) -> i32 { 0 }
 }
 
-impl<T> Bar for T {} // use the provided method
+impl<T> Bar for T {
+    default fn bar(&self) -> i32 { 0 }
+}
 
 impl Bar for i32 {
     fn bar(&self) -> i32 { 1 }
index 36cb939bc48fbdb069d08c28b966c5fa67e50746..9546a5dd5f51699d64f466a3c9c94b2c4198ad2c 100644 (file)
@@ -13,6 +13,10 @@ impl<'a, I, T: 'a> Iterator for Cloned<I>
     fn next(&mut self) -> Option<T> {
         unimplemented!()
     }
+
+    default fn count(self) -> usize where Self: Sized {
+        self.fold(0, |cnt, _| cnt + 1)
+    }
 }
 
 impl<'a, I, T: 'a> Iterator for Cloned<I>
diff --git a/src/test/ui/specialization/non-defaulted-item-fail.rs b/src/test/ui/specialization/non-defaulted-item-fail.rs
new file mode 100644 (file)
index 0000000..403f718
--- /dev/null
@@ -0,0 +1,53 @@
+#![feature(specialization, associated_type_defaults)]
+
+// Test that attempting to override a non-default method or one not in the
+// parent impl causes an error.
+
+trait Foo {
+    type Ty = ();
+    const CONST: u8 = 123;
+    fn foo(&self) -> bool { true }
+}
+
+// Specialization tree for Foo:
+//
+//       Box<T>              Vec<T>
+//        / \                 / \
+// Box<i32>  Box<i64>   Vec<()>  Vec<bool>
+
+impl<T> Foo for Box<T> {
+    type Ty = bool;
+    const CONST: u8 = 0;
+    fn foo(&self) -> bool { false }
+}
+
+// Allowed
+impl Foo for Box<i32> {}
+
+// Can't override a non-`default` fn
+impl Foo for Box<i64> {
+    type Ty = Vec<()>;
+//~^ error: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
+    const CONST: u8 = 42;
+//~^ error: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
+    fn foo(&self) -> bool { true }
+//~^ error: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+}
+
+
+// Doesn't mention the item = provided body/value is used and the method is final.
+impl<T> Foo for Vec<T> {}
+
+// Allowed
+impl Foo for Vec<()> {}
+
+impl Foo for Vec<bool> {
+    type Ty = Vec<()>;
+//~^ error: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
+    const CONST: u8 = 42;
+//~^ error: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
+    fn foo(&self) -> bool { true }
+//~^ error: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr
new file mode 100644 (file)
index 0000000..e6c5fc1
--- /dev/null
@@ -0,0 +1,81 @@
+error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:29:5
+   |
+LL | / impl<T> Foo for Box<T> {
+LL | |     type Ty = bool;
+LL | |     const CONST: u8 = 0;
+LL | |     fn foo(&self) -> bool { false }
+LL | | }
+   | |_- parent `impl` is here
+...
+LL |       type Ty = Vec<()>;
+   |       ^^^^^^^^^^^^^^^^^^ cannot specialize default item `Ty`
+   |
+   = note: to specialize, `Ty` in the parent `impl` must be marked `default`
+
+error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:31:5
+   |
+LL | / impl<T> Foo for Box<T> {
+LL | |     type Ty = bool;
+LL | |     const CONST: u8 = 0;
+LL | |     fn foo(&self) -> bool { false }
+LL | | }
+   | |_- parent `impl` is here
+...
+LL |       const CONST: u8 = 42;
+   |       ^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `CONST`
+   |
+   = note: to specialize, `CONST` in the parent `impl` must be marked `default`
+
+error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:33:5
+   |
+LL | / impl<T> Foo for Box<T> {
+LL | |     type Ty = bool;
+LL | |     const CONST: u8 = 0;
+LL | |     fn foo(&self) -> bool { false }
+LL | | }
+   | |_- parent `impl` is here
+...
+LL |       fn foo(&self) -> bool { true }
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo`
+   |
+   = note: to specialize, `foo` in the parent `impl` must be marked `default`
+
+error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:45:5
+   |
+LL | impl<T> Foo for Vec<T> {}
+   | ------------------------- parent `impl` is here
+...
+LL |     type Ty = Vec<()>;
+   |     ^^^^^^^^^^^^^^^^^^ cannot specialize default item `Ty`
+   |
+   = note: to specialize, `Ty` in the parent `impl` must be marked `default`
+
+error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:47:5
+   |
+LL | impl<T> Foo for Vec<T> {}
+   | ------------------------- parent `impl` is here
+...
+LL |     const CONST: u8 = 42;
+   |     ^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `CONST`
+   |
+   = note: to specialize, `CONST` in the parent `impl` must be marked `default`
+
+error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/non-defaulted-item-fail.rs:49:5
+   |
+LL | impl<T> Foo for Vec<T> {}
+   | ------------------------- parent `impl` is here
+...
+LL |     fn foo(&self) -> bool { true }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot specialize default item `foo`
+   |
+   = note: to specialize, `foo` in the parent `impl` must be marked `default`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0520`.
index 5d65a0457e7916820df2618fb6babe28bbd66cbf..9ae3d1e9f3931cb58b3dd1f0e595a1a306903b4c 100644 (file)
@@ -55,8 +55,9 @@ fn bar(&self) -> i32 { 0 }
 //                   /  \
 //            Vec<i32>  $Vec<i64>
 
-// use the provided method
-impl<T> Bar for T {}
+impl<T> Bar for T {
+    default fn bar(&self) -> i32 { 0 }
+}
 
 impl Bar for i32 {
     fn bar(&self) -> i32 { 1 }
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.rs b/src/test/ui/suggestions/imm-ref-trait-object-literal.rs
new file mode 100644 (file)
index 0000000..22ca6dd
--- /dev/null
@@ -0,0 +1,14 @@
+trait Trait {}
+
+struct S;
+
+impl<'a> Trait for &'a mut S {}
+
+fn foo<X: Trait>(_: X) {}
+
+
+fn main() {
+  let s = S;
+  foo(&s); //~ ERROR the trait bound `&S: Trait` is not satisfied
+  foo(s); //~ ERROR the trait bound `S: Trait` is not satisfied
+}
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr
new file mode 100644 (file)
index 0000000..ccaceef
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `&S: Trait` is not satisfied
+  --> $DIR/imm-ref-trait-object-literal.rs:12:7
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |    ---    ----- required by this bound in `foo`
+...
+LL |   foo(&s);
+   |       -^
+   |       |
+   |       the trait `Trait` is not implemented for `&S`
+   |       help: consider changing this borrow's mutability: `&mut`
+   |
+   = help: the following implementations were found:
+             <&'a mut S as Trait>
+
+error[E0277]: the trait bound `S: Trait` is not satisfied
+  --> $DIR/imm-ref-trait-object-literal.rs:13:7
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |    ---    ----- required by this bound in `foo`
+...
+LL |   foo(s);
+   |       ^ the trait `Trait` is not implemented for `S`
+   |
+   = help: the following implementations were found:
+             <&'a mut S as Trait>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/imm-ref-trait-object.rs b/src/test/ui/suggestions/imm-ref-trait-object.rs
new file mode 100644 (file)
index 0000000..288d6c6
--- /dev/null
@@ -0,0 +1,8 @@
+fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
+     t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
+}
+
+fn main() {
+     let array = [0u64];
+     test(&mut array.iter());
+}
diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr
new file mode 100644 (file)
index 0000000..9185eaa
--- /dev/null
@@ -0,0 +1,10 @@
+error: the `min` method cannot be invoked on a trait object
+  --> $DIR/imm-ref-trait-object.rs:2:8
+   |
+LL |      t.min().unwrap()
+   |        ^^^
+   |
+   = note: you need `&mut dyn std::iter::Iterator<Item = &u64>` instead of `&dyn std::iter::Iterator<Item = &u64>`
+
+error: aborting due to previous error
+
index fb3e1096ad54cbf86589f8e407e01a9e31b56da5..a1e1f4d13572a703736c33b7dbf8cdb5d53bfff4 100644 (file)
@@ -8,6 +8,7 @@ LL |     foo(String::new());
    |     ^^^ the trait `std::convert::From<std::string::String>` is not implemented for `&str`
    |
    = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix
+   = note: `std::convert::From<std::string::String>` is implemented for `&mut str`, but not for `&str`
    = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
new file mode 100644 (file)
index 0000000..dcef2ad
--- /dev/null
@@ -0,0 +1,23 @@
+use std::env::args;
+use std::fs::File;
+use std::io::{stdout, Write, BufWriter};
+
+fn main() {
+    let mut args = args();
+    let _ = args.next();
+    let dest = args.next();
+
+    let h1; let h2; let h3;
+
+    let fp: &dyn Write = match dest {
+        Some(path) => { h1 = File::create(path).unwrap(); &h1 },
+        None => { h2 = stdout(); h3 = h2.lock(); &h3 }
+    };
+
+    let fp = BufWriter::new(fp);
+    //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+    //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+    //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+
+    writeln!(fp, "hello world").unwrap(); //~ ERROR no method named `write_fmt` found for type
+}
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
new file mode 100644 (file)
index 0000000..daa8e11
--- /dev/null
@@ -0,0 +1,41 @@
+error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+  --> $DIR/mut-borrow-needed-by-trait.rs:17:29
+   |
+LL |     let fp = BufWriter::new(fp);
+   |                             ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
+   |
+   = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
+   = note: required by `std::io::BufWriter::<W>::new`
+
+error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+  --> $DIR/mut-borrow-needed-by-trait.rs:17:14
+   |
+LL |     let fp = BufWriter::new(fp);
+   |              ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
+   |
+   = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
+   = note: required by `std::io::BufWriter`
+
+error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
+  --> $DIR/mut-borrow-needed-by-trait.rs:17:14
+   |
+LL |     let fp = BufWriter::new(fp);
+   |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
+   |
+   = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
+   = note: required by `std::io::BufWriter`
+
+error[E0599]: no method named `write_fmt` found for type `std::io::BufWriter<&dyn std::io::Write>` in the current scope
+  --> $DIR/mut-borrow-needed-by-trait.rs:22:5
+   |
+LL |     writeln!(fp, "hello world").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>`
+   |
+   = note: the method `write_fmt` exists but the following trait bounds were not satisfied:
+           `std::io::BufWriter<&dyn std::io::Write> : std::io::Write`
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/remove-as_str.rs b/src/test/ui/suggestions/remove-as_str.rs
new file mode 100644 (file)
index 0000000..d10300b
--- /dev/null
@@ -0,0 +1,21 @@
+fn foo1(s: &str) {
+    s.as_str();
+    //~^ ERROR no method named `as_str` found for type `&str` in the current scope
+}
+
+fn foo2<'a>(s: &'a str) {
+    s.as_str();
+    //~^ ERROR no method named `as_str` found for type `&'a str` in the current scope
+}
+
+fn foo3(s: &mut str) {
+    s.as_str();
+    //~^ ERROR no method named `as_str` found for type `&mut str` in the current scope
+}
+
+fn foo4(s: &&str) {
+    s.as_str();
+    //~^ ERROR no method named `as_str` found for type `&&str` in the current scope
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/remove-as_str.stderr b/src/test/ui/suggestions/remove-as_str.stderr
new file mode 100644 (file)
index 0000000..eae9cc0
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0599]: no method named `as_str` found for type `&str` in the current scope
+  --> $DIR/remove-as_str.rs:2:7
+   |
+LL |     s.as_str();
+   |      -^^^^^^-- help: remove this method call
+
+error[E0599]: no method named `as_str` found for type `&'a str` in the current scope
+  --> $DIR/remove-as_str.rs:7:7
+   |
+LL |     s.as_str();
+   |      -^^^^^^-- help: remove this method call
+
+error[E0599]: no method named `as_str` found for type `&mut str` in the current scope
+  --> $DIR/remove-as_str.rs:12:7
+   |
+LL |     s.as_str();
+   |      -^^^^^^-- help: remove this method call
+
+error[E0599]: no method named `as_str` found for type `&&str` in the current scope
+  --> $DIR/remove-as_str.rs:17:7
+   |
+LL |     s.as_str();
+   |      -^^^^^^-- help: remove this method call
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.rs
new file mode 100644 (file)
index 0000000..5480adb
--- /dev/null
@@ -0,0 +1,13 @@
+use std::cell::RefCell;
+
+struct HasAssocMethod;
+
+impl HasAssocMethod {
+    fn hello() {}
+}
+fn main() {
+    let shared_state = RefCell::new(HasAssocMethod);
+    let state = shared_state.borrow_mut();
+    state.hello();
+    //~^ ERROR no method named `hello` found for type `std::cell::RefMut<'_, HasAssocMethod>`
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr
new file mode 100644 (file)
index 0000000..a1c0126
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0599]: no method named `hello` found for type `std::cell::RefMut<'_, HasAssocMethod>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11
+   |
+LL |     state.hello();
+   |     ------^^^^^
+   |     |     |
+   |     |     this is an associated function, not a method
+   |     help: use associated function syntax instead: `HasAssocMethod::hello`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `HasAssocMethod`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:6:5
+   |
+LL |     fn hello() {}
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs
new file mode 100644 (file)
index 0000000..ef4b38d
--- /dev/null
@@ -0,0 +1,11 @@
+struct GenericAssocMethod<T>(T);
+
+impl<T> GenericAssocMethod<T> {
+    fn default_hello() {}
+}
+
+fn main() {
+    let x = GenericAssocMethod(33i32);
+    x.default_hello();
+    //~^ ERROR no method named `default_hello` found for type `GenericAssocMethod<i32>`
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
new file mode 100644 (file)
index 0000000..8cfa7de
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0599]: no method named `default_hello` found for type `GenericAssocMethod<i32>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:9:7
+   |
+LL | struct GenericAssocMethod<T>(T);
+   | -------------------------------- method `default_hello` not found for this
+...
+LL |     x.default_hello();
+   |     --^^^^^^^^^^^^^
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `GenericAssocMethod::<i32>::default_hello`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `GenericAssocMethod<_>`
+  --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5
+   |
+LL |     fn default_hello() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
index 55b743ab7c7ea315b3527e0f1002e3d3060356e3..1a478460efc6c8954c6714450b848652cd700a85 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: --test
 #![feature(allow_fail)]
 
index 2284953fbbe947365182df835157d8ce835eee35..9fa759f9eb4837a25ff0b215cba976b78f849412 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: --test
 #[test]
 #[should_panic(expected = "foo")]
index fb417b82d15ce6f98dd428181540c240dc3ef388..4c63d6097758ebdf3d6cacc62d7eca4eedc65967 100644 (file)
@@ -20,3 +20,4 @@ LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 5d1e00d2d3535edac4eae6ca5f88ce9bbf34187f..f86499e2e3f86d9130f34c69da1ecef4844af05d 100644 (file)
@@ -10,7 +10,6 @@
 // This is a regression test for issue #17021.
 //
 // compile-flags: -g
-// ignore-asmjs wasm2js does not support source maps yet
 
 use std::ptr;
 
index 92e5ac282e4d63a427229d18bfbcae51c00923ad..d0475bf08c38d2bb8fe602ac25f40ae2e1af2b4b 100644 (file)
@@ -24,3 +24,4 @@ LL |     Box::new(items.iter())
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0495`.
index 3ec90f00448a9af75800748d172939ce482adfa6..da4e8ebf9c05c0e1a80d1beb81ecc9844e44d41e 100644 (file)
@@ -105,5 +105,5 @@ LL |     <IndirectEvil>::static_evil(b)
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0312, E0478.
+Some errors have detailed explanations: E0312, E0478, E0495.
 For more information about an error, try `rustc --explain E0312`.
index 8b0561d68f12eeb1d72e07ceef464ebf6032a1bc..a429e8cc4614a46a86322a0777a477e2baa83f1c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8b0561d68f12eeb1d72e07ceef464ebf6032a1bc
+Subproject commit a429e8cc4614a46a86322a0777a477e2baa83f1c
index 648e5b90b49af483d07caa8e413473a4517853d6..5cb983338e924ec85898880d60e65f2a1291b7be 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 648e5b90b49af483d07caa8e413473a4517853d6
+Subproject commit 5cb983338e924ec85898880d60e65f2a1291b7be
index 03094885065847b8a7f9624af9a1d9fe5e9ef647..df56448dd225df39686f1ef541cb395776f8ee5d 100644 (file)
@@ -141,10 +141,7 @@ pub fn from_file(config: &Config, testfile: &Path) -> Self {
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
                     props.ignore = Ignore::Ignore;
                 }
-                // FIXME: Re-enable run-fail once panics are handled correctly
-                if config.target.contains("emscripten") && config.mode == common::RunFail {
-                    props.ignore = Ignore::Ignore;
-                }
+
             }
 
             if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
index 592b3f14c85aff7bf8309f75d44071385aafae54..c59533da1dc39c06eb0e982fafe5a2a21c4f6cdb 100644 (file)
@@ -15,7 +15,7 @@ fn main() {
             println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
             let file = fs::read_to_string(entry.path()).unwrap()
                 .replace("syntax::register_diagnostics!", "register_diagnostics!");
-            let contents = format!("(|| {{\n{}\n}})();", file);
+            let contents = format!("(|| {{\n{}\n}})()", file);
 
             fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();
 
index 1ed39f45d3e701ab7f97a72444dbb62557428532..8e46ca6cd2990e199e9ad47ab49b09ead44d7334 100644 (file)
@@ -89,6 +89,7 @@
     Crate("crc32fast"),
     Crate("crossbeam-deque"),
     Crate("crossbeam-epoch"),
+    Crate("crossbeam-queue"),
     Crate("crossbeam-utils"),
     Crate("datafrog"),
     Crate("dlmalloc"),
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
new file mode 100644 (file)
index 0000000..159baff
--- /dev/null
@@ -0,0 +1,137 @@
+//! Checks that all error codes have at least one test to prevent having error
+//! codes that are silently not thrown by the compiler anymore.
+
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::path::Path;
+
+// A few of those error codes can't be tested but all the others can and *should* be tested!
+const WHITELIST: &[&str] = &[
+    "E0183",
+    "E0227",
+    "E0279",
+    "E0280",
+    "E0311",
+    "E0313",
+    "E0314",
+    "E0315",
+    "E0377",
+    "E0456",
+    "E0461",
+    "E0462",
+    "E0464",
+    "E0465",
+    "E0472",
+    "E0473",
+    "E0474",
+    "E0475",
+    "E0476",
+    "E0479",
+    "E0480",
+    "E0481",
+    "E0482",
+    "E0483",
+    "E0484",
+    "E0485",
+    "E0486",
+    "E0487",
+    "E0488",
+    "E0489",
+    "E0514",
+    "E0519",
+    "E0523",
+    "E0526",
+    "E0554",
+    "E0570",
+    "E0629",
+    "E0630",
+    "E0640",
+    "E0717",
+    "E0727",
+    "E0729",
+];
+
+fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>) {
+    let mut reached_no_explanation = false;
+    let mut last_error_code = None;
+
+    for line in f.lines() {
+        let s = line.trim();
+        if s.starts_with('E') && s.ends_with(": r##\"") {
+            if let Some(err_code) = s.splitn(2, ':').next() {
+                let err_code = err_code.to_owned();
+                last_error_code = Some(err_code.clone());
+                if !error_codes.contains_key(&err_code) {
+                    error_codes.insert(err_code, false);
+                }
+            }
+        } else if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
+            if let Some(err_code) = s.splitn(2, 'E').skip(1).next() {
+                if let Some(err_code) = err_code.splitn(2, ',').next() {
+                    let nb = error_codes.entry(format!("E{}", err_code)).or_insert(false);
+                    *nb = true;
+                }
+            }
+        } else if s == ";" {
+            reached_no_explanation = true;
+        } else if reached_no_explanation && s.starts_with('E') {
+            if let Some(err_code) = s.splitn(2, ',').next() {
+                let err_code = err_code.to_owned();
+                if !error_codes.contains_key(&err_code) { // this check should *never* fail!
+                    error_codes.insert(err_code, false);
+                }
+            }
+        } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
+            if let Some(last) = last_error_code {
+                error_codes.get_mut(&last).map(|x| *x = true);
+            }
+            last_error_code = None;
+        }
+    }
+}
+
+fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, bool>) {
+    for line in f.lines() {
+        let s = line.trim();
+        if s.starts_with("error[E") || s.starts_with("warning[E") {
+            if let Some(err_code) = s.splitn(2, ']').next() {
+                if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() {
+                    let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
+                    *nb = true;
+                }
+            }
+        }
+    }
+}
+
+pub fn check(path: &Path, bad: &mut bool) {
+    println!("Checking which error codes lack tests...");
+    let mut error_codes: HashMap<String, bool> = HashMap::new();
+    super::walk(path,
+                &mut |path| super::filter_dirs(path),
+                &mut |entry, contents| {
+        let file_name = entry.file_name();
+        if file_name == "error_codes.rs" {
+            extract_error_codes(contents, &mut error_codes);
+        } else if entry.path().extension() == Some(OsStr::new("stderr")) {
+            extract_error_codes_from_tests(contents, &mut error_codes);
+        }
+    });
+    println!("Found {} error codes", error_codes.len());
+
+    let mut errors = Vec::new();
+    for (err_code, nb) in &error_codes {
+        if !*nb && !WHITELIST.contains(&err_code.as_str()) {
+            errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+        }
+    }
+    errors.sort();
+    for err in &errors {
+        eprintln!("{}", err);
+    }
+    println!("Found {} error codes with no tests", errors.len());
+    if !errors.is_empty() {
+        *bad = true;
+    }
+    println!("Done!");
+}
index 337f9c4d6dbedcc20b8c24a058dcdf5277658f51..eb93eb297479d03e37bc7fb15babcad4fb5c294b 100644 (file)
@@ -41,6 +41,7 @@ macro_rules! tidy_error {
 pub mod ui_tests;
 pub mod unit_tests;
 pub mod unstable_book;
+pub mod error_codes_check;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
index a57238ad8148ae81ad0c7e17778a53dff157fa07..e08c23c01fe2d337ef332352433716d0ceab0d8d 100644 (file)
@@ -35,6 +35,7 @@ fn main() {
     deps::check_whitelist(&path, &cargo, &mut bad);
     extdeps::check(&path, &mut bad);
     ui_tests::check(&path, &mut bad);
+    error_codes_check::check(&path, &mut bad);
 
     if bad {
         eprintln!("some tidy checks failed");
index f3509897bdf9c834db18b2bc7cbda5754c9af270..d87c5b64c21c26c0fb7ba6a0c797af768235ac97 100644 (file)
@@ -3,7 +3,8 @@ allow-unauthenticated = [
     "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
     "requires-nightly",
     # I-* without I-nominated
-    "I-compilemem", "I-compiletime", "I-crash", "I-hang", "I-ICE", "I-slow",
+    "I-*", "!I-nominated",
+    "AsyncAwait-OnDeck",
 ]
 
 [assign]