]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #95643 - WaffleLapkin:ptr_convenience, r=joshtriplett
authorbors <bors@rust-lang.org>
Wed, 18 May 2022 23:18:03 +0000 (23:18 +0000)
committerbors <bors@rust-lang.org>
Wed, 18 May 2022 23:18:03 +0000 (23:18 +0000)
Add convenience byte offset/check align functions to pointers

This PR adds the following APIs:
```rust
impl *const T {
    // feature gates `pointer_byte_offsets` and `const_pointer_byte_offsets
    pub const unsafe fn byte_offset(self, count: isize) -> Self;
    pub const fn wrapping_byte_offset(self, count: isize) -> Self;
    pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize;
    pub const unsafe fn byte_add(self, count: usize) -> Self;
    pub const unsafe fn byte_sub(self, count: usize) -> Self;
    pub const fn wrapping_byte_add(self, count: usize) -> Self;
    pub const fn wrapping_byte_sub(self, count: usize) -> Self;

    // feature gate `pointer_is_aligned`
    pub fn is_aligned(self) -> bool where T: Sized;
    pub fn is_aligned_to(self, align: usize) -> bool;
}
// ... and the same for` *mut T`
```

Note that all functions except `is_aligned` do **not** require `T: Sized` as their pointee-sized-offset counterparts.

cc `@oli-obk` (you may want to check that I've correctly placed `const`s)
cc `@RalfJung`

556 files changed:
Cargo.lock
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/find_use.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/build_backend.rs
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/build_system/mod.rs
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
compiler/rustc_codegen_cranelift/scripts/config.sh [deleted file]
compiler/rustc_codegen_cranelift/scripts/ext_config.sh [deleted file]
compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs [deleted file]
compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs [deleted file]
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_gcc/src/asm.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/const_eval/valtrees.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/mod.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_error_codes/src/error_codes/E0455.md
compiler/rustc_error_codes/src/error_codes/E0458.md
compiler/rustc_error_messages/locales/en-US/parser.ftl
compiler/rustc_error_messages/locales/en-US/typeck.ftl
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/diagnostic_builder.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/lib.rs
compiler/rustc_graphviz/src/lib.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/itemlikevisit.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_index/src/interval.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/traits/mod.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/build.rs
compiler/rustc_macros/src/diagnostics/diagnostic.rs
compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
compiler/rustc_macros/src/diagnostics/utils.rs
compiler/rustc_macros/src/lib.rs
compiler/rustc_metadata/src/lib.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/nested_filter.rs
compiler/rustc_middle/src/mir/generic_graph.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/interpret/pointer.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/patch.rs
compiler/rustc_middle/src/mir/predecessors.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/traversal.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/adt.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/simplify.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/misc.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/cx/mod.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/framework/engine.rs
compiler/rustc_mir_dataflow/src/framework/graphviz.rs
compiler/rustc_mir_dataflow/src/lib.rs
compiler/rustc_mir_dataflow/src/rustc_peek.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/coverage/debug.rs
compiler/rustc_mir_transform/src/coverage/graph.rs
compiler/rustc_mir_transform/src/function_item_references.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/inline/cycle.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/lower_intrinsics.rs
compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/debugger_visualizer.rs
compiler/rustc_passes/src/diagnostic_items.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/intrinsicck.rs
compiler/rustc_passes/src/layout_test.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/loops.rs
compiler/rustc_passes/src/naked_functions.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/check_unused.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_session/src/config.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/source_map/tests.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/test.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/windows_gnullvm_base.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/opaque_types.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/dropck_outlives.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/needs_drop.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/generator_interior.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
compiler/rustc_typeck/src/check/intrinsic.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/check_unused.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/outlives/implicit_infer.rs
library/alloc/src/alloc.rs
library/alloc/src/raw_vec.rs
library/core/src/alloc/global.rs
library/core/src/alloc/mod.rs
library/core/src/array/iter.rs
library/core/src/hint.rs
library/core/src/iter/adapters/by_ref_sized.rs
library/core/src/num/dec2flt/common.rs
library/core/src/num/dec2flt/parse.rs
library/core/src/num/nonzero.rs
library/core/src/option.rs
library/core/src/task/wake.rs
library/core/tests/array.rs
library/proc_macro/src/bridge/client.rs
library/proc_macro/src/bridge/scoped_cell.rs
library/std/src/os/fd/owned.rs
library/std/src/os/fd/tests.rs
library/std/src/os/windows/io/handle.rs
library/std/src/os/windows/io/mod.rs
library/std/src/os/windows/io/raw.rs
library/std/src/os/windows/io/socket.rs
library/std/src/os/windows/io/tests.rs [new file with mode: 0644]
library/std/src/path/tests.rs
library/std/src/process.rs
library/std/src/sys/unix/futex.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/handle.rs
library/std/src/sys/windows/pipe.rs
library/std/src/sys/windows/rand.rs
library/unwind/build.rs
library/unwind/src/lib.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
src/ci/pgo.sh
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/command-line-arguments.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/pc-windows-gnullvm.md [new file with mode: 0644]
src/doc/rustdoc/src/how-to-read-rustdoc.md
src/doc/rustdoc/src/write-documentation/what-to-include.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/docfs.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/.eslintrc.js
src/librustdoc/html/static/css/noscript.css
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/settings.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/scrape-examples.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/storage.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/page.html
src/librustdoc/json/conversions.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/scrape_examples.rs
src/llvm-project
src/rustdoc-json-types/lib.rs
src/test/codegen/asm-clobber_abi.rs
src/test/codegen/asm-target-clobbers.rs
src/test/codegen/remap_path_prefix/main.rs
src/test/codegen/simd-wide-sum.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
src/test/mir-opt/inline/cycle.g.Inline.diff
src/test/mir-opt/inline/cycle.main.Inline.diff
src/test/mir-opt/inline/dyn-trait.rs [new file with mode: 0644]
src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff [new file with mode: 0644]
src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff [new file with mode: 0644]
src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff [new file with mode: 0644]
src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
src/test/run-make-fulldeps/obtain-borrowck/driver.rs
src/test/run-make/remap-path-prefix-dwarf/Makefile [new file with mode: 0644]
src/test/run-make/remap-path-prefix-dwarf/src/quux.rs [new file with mode: 0644]
src/test/rustdoc-gui/search-filter.goml
src/test/rustdoc-gui/settings.goml
src/test/rustdoc-gui/shortcuts.goml
src/test/rustdoc-gui/theme-change.goml
src/test/rustdoc-js/prototype.js [new file with mode: 0644]
src/test/rustdoc-js/prototype.rs [new file with mode: 0644]
src/test/rustdoc-json/fn_pointer/generics.rs [new file with mode: 0644]
src/test/rustdoc-json/fns/generic_args.rs
src/test/rustdoc-ui/intra-doc/macro-rules-error.rs
src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
src/test/ui/asm/generic-const.rs [new file with mode: 0644]
src/test/ui/asm/type-check-1.rs
src/test/ui/asm/type-check-1.stderr
src/test/ui/associated-consts/issue-88599-ref-self.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-projection-1.stderr
src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs [new file with mode: 0644]
src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr [new file with mode: 0644]
src/test/ui/binop/issue-77910-1.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
src/test/ui/coherence/coherence-with-closure.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-with-closure.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-with-generator.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-with-generator.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/closures.rs
src/test/ui/const-generics/generic_const_exprs/closures.stderr
src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr
src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr
src/test/ui/consts/const-fn-ptr.rs [new file with mode: 0644]
src/test/ui/consts/const-fn-ptr.stderr [new file with mode: 0644]
src/test/ui/consts/issue-56164.stderr
src/test/ui/consts/miri_unleashed/ptr_arith.rs
src/test/ui/consts/miri_unleashed/ptr_arith.stderr
src/test/ui/consts/validate_never_arrays.32bit.stderr
src/test/ui/consts/validate_never_arrays.64bit.stderr
src/test/ui/empty/empty-linkname.rs
src/test/ui/empty/empty-linkname.stderr
src/test/ui/error-codes/E0138.stderr
src/test/ui/error-codes/E0454.stderr
src/test/ui/error-codes/E0458.stderr
src/test/ui/error-codes/E0459.stderr
src/test/ui/feature-gates/feature-gate-asm_const.rs
src/test/ui/feature-gates/feature-gate-asm_const.stderr
src/test/ui/feature-gates/feature-gate-asm_sym.rs
src/test/ui/feature-gates/feature-gate-asm_sym.stderr
src/test/ui/feature-gates/feature-gate-link_cfg.stderr
src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr
src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr
src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs
src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr
src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs
src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib.rs
src/test/ui/feature-gates/feature-gate-raw-dylib.stderr
src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr
src/test/ui/feature-gates/feature-gate-static-nobundle.rs
src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-59311.rs
src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs
src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-54895.rs
src/test/ui/impl-trait/issues/issue-54895.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issues/issue-67830.nll.stderr [deleted file]
src/test/ui/impl-trait/issues/issue-67830.rs
src/test/ui/impl-trait/issues/issue-67830.stderr
src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr [deleted file]
src/test/ui/impl-trait/issues/issue-88236-2.rs
src/test/ui/impl-trait/issues/issue-88236-2.stderr
src/test/ui/impl-trait/issues/issue-88236.rs
src/test/ui/impl-trait/issues/issue-88236.stderr [new file with mode: 0644]
src/test/ui/impl-trait/nested-rpit-hrtb.rs [new file with mode: 0644]
src/test/ui/impl-trait/nested-rpit-hrtb.stderr [new file with mode: 0644]
src/test/ui/imports/unused-imports-in-test-mode.rs [new file with mode: 0644]
src/test/ui/imports/unused-imports-in-test-mode.stderr [new file with mode: 0644]
src/test/ui/inference/issue-28935.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-generic.rs
src/test/ui/inline-const/const-match-pat-generic.stderr
src/test/ui/issues/issue-11515.stderr
src/test/ui/issues/issue-37725.rs
src/test/ui/issues/issue-43925.rs
src/test/ui/issues/issue-43925.stderr
src/test/ui/issues/issue-43926.rs
src/test/ui/issues/issue-43926.stderr
src/test/ui/issues/issue-5239-1.stderr
src/test/ui/linkage-attr/bad-extern-link-attrs.rs [deleted file]
src/test/ui/linkage-attr/bad-extern-link-attrs.stderr [deleted file]
src/test/ui/linkage-attr/link-attr-validation-early.rs [new file with mode: 0644]
src/test/ui/linkage-attr/link-attr-validation-early.stderr [new file with mode: 0644]
src/test/ui/linkage-attr/link-attr-validation-late.rs [new file with mode: 0644]
src/test/ui/linkage-attr/link-attr-validation-late.stderr [new file with mode: 0644]
src/test/ui/macros/macro-comma-support-rpass.rs
src/test/ui/main-wrong-location.stderr
src/test/ui/manual/manual-link-bad-form.rs
src/test/ui/manual/manual-link-bad-form.stderr
src/test/ui/manual/manual-link-bad-kind.rs
src/test/ui/manual/manual-link-bad-kind.stderr
src/test/ui/manual/manual-link-framework.rs
src/test/ui/manual/manual-link-framework.stderr
src/test/ui/manual/manual-link-unsupported-kind.rs
src/test/ui/manual/manual-link-unsupported-kind.stderr
src/test/ui/native-library-link-flags/empty-kind-1.rs
src/test/ui/native-library-link-flags/empty-kind-1.stderr
src/test/ui/native-library-link-flags/empty-kind-2.rs
src/test/ui/native-library-link-flags/empty-kind-2.stderr
src/test/ui/native-library-link-flags/modifiers-override-2.stderr
src/test/ui/native-library-link-flags/modifiers-override.rs
src/test/ui/native-library-link-flags/modifiers-override.stderr
src/test/ui/nll/issue-54779-anon-static-lifetime.rs [new file with mode: 0644]
src/test/ui/nll/issue-54779-anon-static-lifetime.stderr [new file with mode: 0644]
src/test/ui/osx-frameworks.rs
src/test/ui/osx-frameworks.stderr
src/test/ui/parser/issue-81804.rs [new file with mode: 0644]
src/test/ui/parser/issue-81804.stderr [new file with mode: 0644]
src/test/ui/privacy/auxiliary/ctor_aux.rs [new file with mode: 0644]
src/test/ui/privacy/ctor.rs [new file with mode: 0644]
src/test/ui/rfc-1717-dllimport/rename-modifiers.rs [new file with mode: 0644]
src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr [new file with mode: 0644]
src/test/ui/rfc-2294-if-let-guard/typeck.stderr
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
src/test/ui/suggestions/imm-ref-trait-object-literal-bound-regions.stderr
src/test/ui/suggestions/mut-ref-reassignment.stderr
src/test/ui/symbol-names/basic.legacy.stderr
src/test/ui/symbol-names/issue-60925.legacy.stderr
src/test/ui/traits/assoc-type-in-superbad.stderr
src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.rs [new file with mode: 0644]
src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr [new file with mode: 0644]
src/test/ui/traits/object/enforce-supertrait-projection.rs
src/test/ui/traits/object/enforce-supertrait-projection.stderr
src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr [new file with mode: 0644]
src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
src/test/ui/type-alias-impl-trait/issue-53092.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-53092.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-60564-working.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-60564.rs
src/test/ui/type-alias-impl-trait/issue-60564.stderr
src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/wf_check_closures.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/wf_check_closures.stderr [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-derefmut.fixed [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-derefmut.rs [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-derefmut.stderr [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-mut-ref.fixed [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-mut-ref.rs [new file with mode: 0644]
src/test/ui/typeck/assign-non-lval-mut-ref.stderr [new file with mode: 0644]
src/test/ui/typeck/issue-93486.stderr
src/test/ui/wasm/wasm-import-module.rs
src/test/ui/wasm/wasm-import-module.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/collapsible_match.rs
src/tools/clippy/clippy_lints/src/derivable_impls.rs
src/tools/clippy/clippy_lints/src/derive.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
src/tools/clippy/clippy_lints/src/mut_reference.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
src/tools/clippy/clippy_lints/src/redundant_clone.rs
src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_utils/src/attrs.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/miri
src/tools/rustdoc-gui/tester.js
src/tools/rustdoc-js/tester.js
src/version

index f5aacba20cd2363675a0f022b5f69c97f384986d..afe1814de67201b1c5d18a17827b147713525867 100644 (file)
@@ -2509,9 +2509,9 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.28.1"
+version = "0.28.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084"
+checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
 dependencies = [
  "crc32fast",
  "flate2",
@@ -3617,7 +3617,7 @@ dependencies = [
  "itertools",
  "jobserver",
  "libc",
- "object 0.28.1",
+ "object 0.28.4",
  "pathdiff",
  "regex",
  "rustc_apfloat",
@@ -5207,7 +5207,7 @@ checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be"
 dependencies = [
  "gimli 0.26.1",
  "hashbrown 0.11.2",
- "object 0.28.1",
+ "object 0.28.4",
  "tracing",
 ]
 
index cc772ac74f251aadd85a5157634dc56de97a600a..42213cf69661b504dac2ef80db5adb7b4a8ec631 100644 (file)
@@ -326,7 +326,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         ItemKind::ForeignMod(ref foreign_module) => {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
-        ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
+        ItemKind::GlobalAsm(ref asm) => visitor.visit_inline_asm(asm),
         ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
@@ -897,7 +897,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         }
         ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
-        ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
+        ExprKind::InlineAsm(ref asm) => visitor.visit_inline_asm(asm),
         ExprKind::Yield(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
index 410ed3f0bdcdd2c581812f76025ede40de542354..3aff04f78fb8500fcba53063bef1ab0f14bc1142 100644 (file)
@@ -505,8 +505,14 @@ fn wrap_in_try_constructor(
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
         let pat = self.lower_pat(&arm.pat);
         let guard = arm.guard.as_ref().map(|cond| {
-            if let ExprKind::Let(ref pat, ref scrutinee, _) = cond.kind {
-                hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
+            if let ExprKind::Let(ref pat, ref scrutinee, span) = cond.kind {
+                hir::Guard::IfLet(self.arena.alloc(hir::Let {
+                    hir_id: self.next_id(),
+                    span: self.lower_span(span),
+                    pat: self.lower_pat(pat),
+                    ty: None,
+                    init: self.lower_expr(scrutinee),
+                }))
             } else {
                 hir::Guard::If(self.lower_expr(cond))
             }
index 0e8af549692fc2f9e42e85125e936edce4cd2e8a..2774bda24f1484ba824e5f20b975ec2017ac1a45 100644 (file)
@@ -396,37 +396,6 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
             }
         }
 
-        // Check for unstable modifiers on `#[link(..)]` attribute
-        if attr.has_name(sym::link) {
-            for nested_meta in attr.meta_item_list().unwrap_or_default() {
-                if nested_meta.has_name(sym::modifiers) {
-                    if let Some(modifiers) = nested_meta.value_str() {
-                        for modifier in modifiers.as_str().split(',') {
-                            if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
-                                macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
-                                    $(if modifier == $name {
-                                        let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
-                                        gate_feature_post!(
-                                            self,
-                                            $feature,
-                                            nested_meta.name_value_literal_span().unwrap(),
-                                            msg
-                                        );
-                                    })*
-                                }}
-
-                                gate_modifier!(
-                                    "bundle" => native_link_modifiers_bundle
-                                    "verbatim" => native_link_modifiers_verbatim
-                                    "as-needed" => native_link_modifiers_as_needed
-                                );
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
         // Emit errors for non-staged-api crates.
         if !self.features.staged_api {
             if attr.has_name(sym::rustc_deprecated)
index 5a79cf68f113e192d745abd3b630802bf11e9d90..3d4bd222715c3950a54ca4a4f4bdef75ff22279b 100644 (file)
@@ -868,177 +868,180 @@ pub fn is_signed(self) -> bool {
 /// structure layout, `packed` to remove padding, and `transparent` to delegate representation
 /// concerns to the only non-ZST field.
 pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
-    use ReprAttr::*;
+    if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() }
+}
 
+pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
+    assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr);
+    use ReprAttr::*;
     let mut acc = Vec::new();
     let diagnostic = &sess.parse_sess.span_diagnostic;
-    if attr.has_name(sym::repr) {
-        if let Some(items) = attr.meta_item_list() {
-            for item in items {
-                let mut recognised = false;
-                if item.is_word() {
-                    let hint = match item.name_or_empty() {
-                        sym::C => Some(ReprC),
-                        sym::packed => Some(ReprPacked(1)),
-                        sym::simd => Some(ReprSimd),
-                        sym::transparent => Some(ReprTransparent),
-                        sym::no_niche => Some(ReprNoNiche),
-                        sym::align => {
-                            let mut err = struct_span_err!(
-                                diagnostic,
-                                item.span(),
-                                E0589,
-                                "invalid `repr(align)` attribute: `align` needs an argument"
-                            );
-                            err.span_suggestion(
-                                item.span(),
-                                "supply an argument here",
-                                "align(...)".to_string(),
-                                Applicability::HasPlaceholders,
-                            );
-                            err.emit();
-                            recognised = true;
-                            None
-                        }
-                        name => int_type_of_word(name).map(ReprInt),
-                    };
 
-                    if let Some(h) = hint {
+    if let Some(items) = attr.meta_item_list() {
+        for item in items {
+            let mut recognised = false;
+            if item.is_word() {
+                let hint = match item.name_or_empty() {
+                    sym::C => Some(ReprC),
+                    sym::packed => Some(ReprPacked(1)),
+                    sym::simd => Some(ReprSimd),
+                    sym::transparent => Some(ReprTransparent),
+                    sym::no_niche => Some(ReprNoNiche),
+                    sym::align => {
+                        let mut err = struct_span_err!(
+                            diagnostic,
+                            item.span(),
+                            E0589,
+                            "invalid `repr(align)` attribute: `align` needs an argument"
+                        );
+                        err.span_suggestion(
+                            item.span(),
+                            "supply an argument here",
+                            "align(...)".to_string(),
+                            Applicability::HasPlaceholders,
+                        );
+                        err.emit();
                         recognised = true;
-                        acc.push(h);
+                        None
                     }
-                } else if let Some((name, value)) = item.name_value_literal() {
-                    let mut literal_error = None;
-                    if name == sym::align {
-                        recognised = true;
-                        match parse_alignment(&value.kind) {
-                            Ok(literal) => acc.push(ReprAlign(literal)),
-                            Err(message) => literal_error = Some(message),
-                        };
-                    } else if name == sym::packed {
-                        recognised = true;
-                        match parse_alignment(&value.kind) {
-                            Ok(literal) => acc.push(ReprPacked(literal)),
-                            Err(message) => literal_error = Some(message),
-                        };
-                    } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
-                        || int_type_of_word(name).is_some()
-                    {
-                        recognised = true;
-                        struct_span_err!(
+                    name => int_type_of_word(name).map(ReprInt),
+                };
+
+                if let Some(h) = hint {
+                    recognised = true;
+                    acc.push(h);
+                }
+            } else if let Some((name, value)) = item.name_value_literal() {
+                let mut literal_error = None;
+                if name == sym::align {
+                    recognised = true;
+                    match parse_alignment(&value.kind) {
+                        Ok(literal) => acc.push(ReprAlign(literal)),
+                        Err(message) => literal_error = Some(message),
+                    };
+                } else if name == sym::packed {
+                    recognised = true;
+                    match parse_alignment(&value.kind) {
+                        Ok(literal) => acc.push(ReprPacked(literal)),
+                        Err(message) => literal_error = Some(message),
+                    };
+                } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
+                    || int_type_of_word(name).is_some()
+                {
+                    recognised = true;
+                    struct_span_err!(
                                 diagnostic,
                                 item.span(),
                                 E0552,
                                 "invalid representation hint: `{}` does not take a parenthesized argument list",
                                 name.to_ident_string(),
                             ).emit();
-                    }
-                    if let Some(literal_error) = literal_error {
-                        struct_span_err!(
+                }
+                if let Some(literal_error) = literal_error {
+                    struct_span_err!(
+                        diagnostic,
+                        item.span(),
+                        E0589,
+                        "invalid `repr({})` attribute: {}",
+                        name.to_ident_string(),
+                        literal_error
+                    )
+                    .emit();
+                }
+            } else if let Some(meta_item) = item.meta_item() {
+                if let MetaItemKind::NameValue(ref value) = meta_item.kind {
+                    if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
+                        let name = meta_item.name_or_empty().to_ident_string();
+                        recognised = true;
+                        let mut err = struct_span_err!(
                             diagnostic,
                             item.span(),
-                            E0589,
-                            "invalid `repr({})` attribute: {}",
-                            name.to_ident_string(),
-                            literal_error
-                        )
-                        .emit();
-                    }
-                } else if let Some(meta_item) = item.meta_item() {
-                    if let MetaItemKind::NameValue(ref value) = meta_item.kind {
-                        if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
-                            let name = meta_item.name_or_empty().to_ident_string();
-                            recognised = true;
-                            let mut err = struct_span_err!(
-                                diagnostic,
-                                item.span(),
-                                E0693,
-                                "incorrect `repr({})` attribute format",
-                                name,
-                            );
-                            match value.kind {
-                                ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
-                                    err.span_suggestion(
-                                        item.span(),
-                                        "use parentheses instead",
-                                        format!("{}({})", name, int),
-                                        Applicability::MachineApplicable,
-                                    );
-                                }
-                                ast::LitKind::Str(s, _) => {
-                                    err.span_suggestion(
-                                        item.span(),
-                                        "use parentheses instead",
-                                        format!("{}({})", name, s),
-                                        Applicability::MachineApplicable,
-                                    );
-                                }
-                                _ => {}
+                            E0693,
+                            "incorrect `repr({})` attribute format",
+                            name,
+                        );
+                        match value.kind {
+                            ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
+                                err.span_suggestion(
+                                    item.span(),
+                                    "use parentheses instead",
+                                    format!("{}({})", name, int),
+                                    Applicability::MachineApplicable,
+                                );
                             }
-                            err.emit();
-                        } else {
-                            if matches!(
-                                meta_item.name_or_empty(),
-                                sym::C | sym::simd | sym::transparent | sym::no_niche
-                            ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                            {
-                                recognised = true;
-                                struct_span_err!(
-                                    diagnostic,
-                                    meta_item.span,
-                                    E0552,
-                                    "invalid representation hint: `{}` does not take a value",
-                                    meta_item.name_or_empty().to_ident_string(),
-                                )
-                                .emit();
+                            ast::LitKind::Str(s, _) => {
+                                err.span_suggestion(
+                                    item.span(),
+                                    "use parentheses instead",
+                                    format!("{}({})", name, s),
+                                    Applicability::MachineApplicable,
+                                );
                             }
+                            _ => {}
                         }
-                    } else if let MetaItemKind::List(_) = meta_item.kind {
-                        if meta_item.has_name(sym::align) {
+                        err.emit();
+                    } else {
+                        if matches!(
+                            meta_item.name_or_empty(),
+                            sym::C | sym::simd | sym::transparent | sym::no_niche
+                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                        {
                             recognised = true;
                             struct_span_err!(
                                 diagnostic,
                                 meta_item.span,
-                                E0693,
-                                "incorrect `repr(align)` attribute format: \
-                                 `align` takes exactly one argument in parentheses"
+                                E0552,
+                                "invalid representation hint: `{}` does not take a value",
+                                meta_item.name_or_empty().to_ident_string(),
                             )
                             .emit();
-                        } else if meta_item.has_name(sym::packed) {
-                            recognised = true;
-                            struct_span_err!(
-                                diagnostic,
-                                meta_item.span,
-                                E0552,
-                                "incorrect `repr(packed)` attribute format: \
+                        }
+                    }
+                } else if let MetaItemKind::List(_) = meta_item.kind {
+                    if meta_item.has_name(sym::align) {
+                        recognised = true;
+                        struct_span_err!(
+                            diagnostic,
+                            meta_item.span,
+                            E0693,
+                            "incorrect `repr(align)` attribute format: \
+                                 `align` takes exactly one argument in parentheses"
+                        )
+                        .emit();
+                    } else if meta_item.has_name(sym::packed) {
+                        recognised = true;
+                        struct_span_err!(
+                            diagnostic,
+                            meta_item.span,
+                            E0552,
+                            "incorrect `repr(packed)` attribute format: \
                                  `packed` takes exactly one parenthesized argument, \
                                  or no parentheses at all"
-                            )
-                            .emit();
-                        } else if matches!(
-                            meta_item.name_or_empty(),
-                            sym::C | sym::simd | sym::transparent | sym::no_niche
-                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                        {
-                            recognised = true;
-                            struct_span_err!(
+                        )
+                        .emit();
+                    } else if matches!(
+                        meta_item.name_or_empty(),
+                        sym::C | sym::simd | sym::transparent | sym::no_niche
+                    ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                    {
+                        recognised = true;
+                        struct_span_err!(
                                 diagnostic,
                                 meta_item.span,
                                 E0552,
                                 "invalid representation hint: `{}` does not take a parenthesized argument list",
                                 meta_item.name_or_empty().to_ident_string(),
                             ).emit();
-                        }
                     }
                 }
-                if !recognised {
-                    // Not a word we recognize. This will be caught and reported by
-                    // the `check_mod_attrs` pass, but this pass doesn't always run
-                    // (e.g. if we only pretty-print the source), so we have to gate
-                    // the `delay_span_bug` call as follows:
-                    if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
-                        diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
-                    }
+            }
+            if !recognised {
+                // Not a word we recognize. This will be caught and reported by
+                // the `check_mod_attrs` pass, but this pass doesn't always run
+                // (e.g. if we only pretty-print the source), so we have to gate
+                // the `delay_span_bug` call as follows:
+                if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
+                    diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
                 }
             }
         }
index d38e89cd79edd785476d5a49c810d3ee8d01567c..5252b0b50c308a4c6a47529491ce95977386a303 100644 (file)
@@ -199,7 +199,7 @@ fn precompute_borrows_out_of_scope(
                 // Add successor BBs to the work list, if necessary.
                 let bb_data = &self.body[bb];
                 debug_assert!(hi == bb_data.statements.len());
-                for &succ_bb in bb_data.terminator().successors() {
+                for succ_bb in bb_data.terminator().successors() {
                     if !self.visited.insert(succ_bb) {
                         if succ_bb == location.block && first_lo > 0 {
                             // `succ_bb` has been seen before. If it wasn't
index bbb631730d346b3c5add18042c25e9f66d70d72f..a3c9da302120471c8e65cc640107a8b299240999 100644 (file)
@@ -13,7 +13,9 @@
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::ty::{
+    self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty,
+};
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, Span};
@@ -336,7 +338,7 @@ fn suggest_borrow_fn_like(
         let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
             predicates.iter().find_map(|(pred, _)| {
                 let pred = if let Some(substs) = substs {
-                    pred.subst(tcx, substs).kind().skip_binder()
+                    EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder()
                 } else {
                     pred.kind().skip_binder()
                 };
index ffea15bdc33ebd4593b8dd76e868c9862e615108..6ec6b76bb5f856fb968be66a80e8520858733c88 100644 (file)
@@ -467,7 +467,7 @@ fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Locatio
                     block
                         .terminator()
                         .successors()
-                        .map(|bb| Location { statement_index: 0, block: *bb })
+                        .map(|bb| Location { statement_index: 0, block: bb })
                         .filter(|s| visited_locations.insert(*s))
                         .map(|s| {
                             if self.is_back_edge(location, s) {
@@ -526,7 +526,7 @@ fn find_loop_head_dfs(
                 }
             } else {
                 for bb in block.terminator().successors() {
-                    let successor = Location { statement_index: 0, block: *bb };
+                    let successor = Location { statement_index: 0, block: bb };
 
                     if !visited_locations.contains(&successor)
                         && self.find_loop_head_dfs(successor, loop_head, visited_locations)
index ab4536f00fc4289d702989625a8ff46b44b60b5c..22e7cd9e52c9f793ce060ad75c13d64037cec64d 100644 (file)
@@ -67,8 +67,8 @@ fn find(&mut self) -> Option<Cause> {
                             block_data
                                 .terminator()
                                 .successors()
-                                .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
-                                .map(|&bb| Location { statement_index: 0, block: bb }),
+                                .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
+                                .map(|bb| Location { statement_index: 0, block: bb }),
                         );
                     }
                 }
index 927eb080b2008a687cbcc15143c694b2e0d78b57..6f8fae2de29a7994e847498c7f5414cb98fdfd77 100644 (file)
@@ -108,7 +108,7 @@ fn populate_polonius_move_facts(
                     // We are at the terminator of an init that has a panic path,
                     // and where the init should not happen on panic
 
-                    for &successor in block_data.terminator().successors() {
+                    for successor in block_data.terminator().successors() {
                         if body[successor].is_cleanup {
                             continue;
                         }
index f3d37a6be7b48a2b4642d83fbdc7fbcaef8aa537..810737587912b6e1795e33ce87b97110d2146f9d 100644 (file)
@@ -1,11 +1,8 @@
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::DefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
-use rustc_span::Span;
 use rustc_trait_selection::opaque_types::InferCtxtExt;
 
 use super::RegionInferenceContext;
@@ -107,21 +104,11 @@ pub(crate) fn infer_opaque_types(
 
             let opaque_type_key =
                 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
-            let remapped_type = infcx.infer_opaque_definition_from_instantiation(
+            let ty = infcx.infer_opaque_definition_from_instantiation(
                 opaque_type_key,
                 universal_concrete_type,
                 origin,
             );
-            let ty = if check_opaque_type_parameter_valid(
-                infcx.tcx,
-                opaque_type_key,
-                origin,
-                concrete_type.span,
-            ) {
-                remapped_type
-            } else {
-                infcx.tcx.ty_error()
-            };
             // Sometimes two opaque types are the same only after we remap the generic parameters
             // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
             // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -184,95 +171,3 @@ pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
         })
     }
 }
-
-fn check_opaque_type_parameter_valid(
-    tcx: TyCtxt<'_>,
-    opaque_type_key: OpaqueTypeKey<'_>,
-    origin: OpaqueTyOrigin,
-    span: Span,
-) -> bool {
-    match origin {
-        // No need to check return position impl trait (RPIT)
-        // because for type and const parameters they are correct
-        // by construction: we convert
-        //
-        // fn foo<P0..Pn>() -> impl Trait
-        //
-        // into
-        //
-        // type Foo<P0...Pn>
-        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
-        //
-        // For lifetime parameters we convert
-        //
-        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-        //
-        // into
-        //
-        // type foo::<'p0..'pn>::Foo<'q0..'qm>
-        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-        //
-        // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
-        // Check these
-        OpaqueTyOrigin::TyAlias => {}
-    }
-    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
-    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
-    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
-        let arg_is_param = match arg.unpack() {
-            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if lt.is_static() => {
-                tcx.sess
-                    .struct_span_err(span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
-                        "cannot use static lifetime; use a bound lifetime \
-                                    instead or remove the lifetime parameter from the \
-                                    opaque type",
-                    )
-                    .emit();
-                return false;
-            }
-            GenericArgKind::Lifetime(lt) => {
-                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
-            }
-            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
-        };
-
-        if arg_is_param {
-            seen_params.entry(arg).or_default().push(i);
-        } else {
-            // Prevent `fn foo() -> Foo<u32>` from being defining.
-            let opaque_param = opaque_generics.param_at(i, tcx);
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(
-                    tcx.def_span(opaque_param.def_id),
-                    &format!(
-                        "used non-generic {} `{}` for generic parameter",
-                        opaque_param.kind.descr(),
-                        arg,
-                    ),
-                )
-                .emit();
-            return false;
-        }
-    }
-
-    for (_, indices) in seen_params {
-        if indices.len() > 1 {
-            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
-            let spans: Vec<_> = indices
-                .into_iter()
-                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
-                .collect();
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(spans, &format!("{} used multiple times", descr))
-                .emit();
-            return false;
-        }
-    }
-    true
-}
index c06fe881410aee4c441bb8658cc2dc30decc6971..0fcac9a1c6c7b8ddddcd2155aa912a5c2bf112b6 100644 (file)
@@ -477,8 +477,11 @@ fn build(self) -> UniversalRegions<'tcx> {
                     .infcx
                     .tcx
                     .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid()));
-                let va_list_ty =
-                    self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]);
+                let va_list_ty = self
+                    .infcx
+                    .tcx
+                    .bound_type_of(va_list_did)
+                    .subst(self.infcx.tcx, &[region.into()]);
 
                 unnormalized_input_tys = self.infcx.tcx.mk_type_list(
                     unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
index 3aba528abfd6d193bb09847884514a4cb32d9af1..aa556a21bf8c30506b9f28471cf02b17af5cc5ea 100644 (file)
@@ -10,7 +10,7 @@ jobs:
     timeout-minutes: 10
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Install rustfmt
       run: |
@@ -39,7 +39,7 @@ jobs:
               TARGET_TRIPLE: aarch64-unknown-linux-gnu
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -127,7 +127,7 @@ jobs:
     timeout-minutes: 60
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     #- name: Cache cargo installed crates
     #  uses: actions/cache@v2
index a019793edd8d25481d6b1a4d733097b1fd3eaf89..0a3e7ca073b45debb68785811cf0f727a7e0bde7 100644 (file)
@@ -11,7 +11,7 @@ jobs:
     timeout-minutes: 60
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -34,7 +34,7 @@ jobs:
         sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
         sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 
-        sed -i 's/gimli = { version = "0.25.0", default-features = false, features = \["write"\]}/gimli = { version = "0.26.1", default-features = false, features = ["write"] }/' Cargo.toml
+        sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
 
         cat Cargo.toml
 
index 1c08e5ece33d27e67fc01b5012f1ac237f2fc51c..b8a98b83ebe5eb1a5d292f5fa6b2b7df1168a5a9 100644 (file)
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -46,7 +46,7 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
index 74fde9c27c0e47475e96f95fed6dd695fce4986f..ecb20f22d8c92005c4b488785c4cc428ccc8289e 100644 (file)
@@ -5,7 +5,7 @@
     "rust-analyzer.assist.importEnforceGranularity": true,
     "rust-analyzer.assist.importPrefix": "crate",
     "rust-analyzer.cargo.runBuildScripts": true,
-    "rust-analyzer.cargo.features": ["unstable-features"]
+    "rust-analyzer.cargo.features": ["unstable-features"],
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
         //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
index 74f50808a980a7de298a943e74ac3c4301f07473..18d7f41cf408a7713cf1fc4ae9066dad23987b8a 100644 (file)
@@ -41,15 +41,5 @@ unstable-features = ["jit", "inline_asm"]
 jit = ["cranelift-jit", "libloading"]
 inline_asm = []
 
-# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
-# execution time of build scripts is so fast that optimizing them slows down the total build time.
-[profile.release.build-override]
-opt-level = 0
-debug = false
-
-[profile.release.package.cranelift-codegen-meta]
-opt-level = 0
-debug = false
-
 [package.metadata.rust-analyzer]
 rustc_private = true
index 51ba0dbfcc7920e2868531cc897bd70c48a9909b..efee6ef3f3780192943ec1b2dd34332d8692b57a 100644 (file)
@@ -112,9 +112,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -134,18 +134,18 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.124"
+version = "0.2.125"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
+checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
index 0a56eb131ed30f3a7e2a0bd13ef5e74a39569115..48faec8bc4b9434f5e9f278d88d3e8a2f5149455 100644 (file)
@@ -34,18 +34,6 @@ pub(crate) fn build_backend(
         _ => unreachable!(),
     }
 
-    // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing
-    // LD_LIBRARY_PATH
-    if cfg!(unix) {
-        if cfg!(target_os = "macos") {
-            rustflags += " -Csplit-debuginfo=unpacked \
-                -Clink-arg=-Wl,-rpath,@loader_path/../lib \
-                -Zosx-rpath-install-name";
-        } else {
-            rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib ";
-        }
-    }
-
     cmd.env("RUSTFLAGS", rustflags);
 
     eprintln!("[BUILD] rustc_codegen_cranelift");
index c9c003d461095754bb0425786ab3ab796a3490b0..8682204f4fd30b355fa0d11f83adbb1705af8eae 100644 (file)
@@ -1,4 +1,3 @@
-use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
@@ -22,35 +21,28 @@ pub(crate) fn build_sysroot(
     fs::create_dir_all(target_dir.join("lib")).unwrap();
 
     // Copy the backend
-    for file in ["cg_clif", "cg_clif_build_sysroot"] {
-        try_hard_link(
-            cg_clif_build_dir.join(get_file_name(file, "bin")),
-            target_dir.join("bin").join(get_file_name(file, "bin")),
-        );
-    }
-
     let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
-    try_hard_link(
-        cg_clif_build_dir.join(&cg_clif_dylib),
-        target_dir
-            .join(if cfg!(windows) {
-                // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
-                // binaries.
-                "bin"
-            } else {
-                "lib"
-            })
-            .join(cg_clif_dylib),
-    );
-
-    // Build and copy cargo wrapper
-    let mut build_cargo_wrapper_cmd = Command::new("rustc");
-    build_cargo_wrapper_cmd
-        .arg("scripts/cargo-clif.rs")
-        .arg("-o")
-        .arg(target_dir.join("cargo-clif"))
-        .arg("-g");
-    spawn_and_wait(build_cargo_wrapper_cmd);
+    let cg_clif_dylib_path = target_dir
+        .join(if cfg!(windows) {
+            // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
+            // binaries.
+            "bin"
+        } else {
+            "lib"
+        })
+        .join(&cg_clif_dylib);
+    try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
+
+    // Build and copy rustc and cargo wrappers
+    for wrapper in ["rustc-clif", "cargo-clif"] {
+        let mut build_cargo_wrapper_cmd = Command::new("rustc");
+        build_cargo_wrapper_cmd
+            .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
+            .arg("-o")
+            .arg(target_dir.join(wrapper))
+            .arg("-g");
+        spawn_and_wait(build_cargo_wrapper_cmd);
+    }
 
     let default_sysroot = super::rustc_info::get_default_sysroot();
 
@@ -117,7 +109,13 @@ pub(crate) fn build_sysroot(
             }
         }
         SysrootKind::Clif => {
-            build_clif_sysroot_for_triple(channel, target_dir, host_triple, None);
+            build_clif_sysroot_for_triple(
+                channel,
+                target_dir,
+                host_triple,
+                &cg_clif_dylib_path,
+                None,
+            );
 
             if host_triple != target_triple {
                 // When cross-compiling it is often necessary to manually pick the right linker
@@ -126,14 +124,21 @@ pub(crate) fn build_sysroot(
                 } else {
                     None
                 };
-                build_clif_sysroot_for_triple(channel, target_dir, target_triple, linker);
+                build_clif_sysroot_for_triple(
+                    channel,
+                    target_dir,
+                    target_triple,
+                    &cg_clif_dylib_path,
+                    linker,
+                );
             }
 
             // Copy std for the host to the lib dir. This is necessary for the jit mode to find
             // libstd.
             for file in fs::read_dir(host_rustlib_lib).unwrap() {
                 let file = file.unwrap().path();
-                if file.file_name().unwrap().to_str().unwrap().contains("std-") {
+                let filename = file.file_name().unwrap().to_str().unwrap();
+                if filename.contains("std-") && !filename.contains(".rlib") {
                     try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
                 }
             }
@@ -145,6 +150,7 @@ fn build_clif_sysroot_for_triple(
     channel: &str,
     target_dir: &Path,
     triple: &str,
+    cg_clif_dylib_path: &Path,
     linker: Option<&str>,
 ) {
     match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
@@ -168,18 +174,18 @@ fn build_clif_sysroot_for_triple(
     let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
 
     if !super::config::get_bool("keep_sysroot") {
-        // Cleanup the target dir with the exception of build scripts and the incremental cache
-        for dir in ["build", "deps", "examples", "native"] {
-            if build_dir.join(dir).exists() {
-                fs::remove_dir_all(build_dir.join(dir)).unwrap();
-            }
+        // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
+        // recompilation as they are not affected by changes in cg_clif.
+        if build_dir.join("deps").exists() {
+            fs::remove_dir_all(build_dir.join("deps")).unwrap();
         }
     }
 
     // Build sysroot
     let mut build_cmd = Command::new("cargo");
     build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
-    let mut rustflags = "--clif -Zforce-unstable-if-unmarked".to_string();
+    let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
+    rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
     if channel == "release" {
         build_cmd.arg("--release");
         rustflags.push_str(" -Zmir-opt-level=3");
@@ -189,10 +195,6 @@ fn build_clif_sysroot_for_triple(
         write!(rustflags, " -Clinker={}", linker).unwrap();
     }
     build_cmd.env("RUSTFLAGS", rustflags);
-    build_cmd.env(
-        "RUSTC",
-        env::current_dir().unwrap().join(target_dir).join("bin").join("cg_clif_build_sysroot"),
-    );
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     spawn_and_wait(build_cmd);
 
index b228da3981fdb58913fe2ee7692188e083896f15..b897b7fbacfcdf54426583790ed5116d2450ddd6 100644 (file)
@@ -86,6 +86,7 @@ pub fn main() {
             arg => arg_error!("Unexpected argument {}", arg),
         }
     }
+    target_dir = std::env::current_dir().unwrap().join(target_dir);
 
     let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
         host_triple
index 785c7383783741701feea05580f26d527cfd0757..33f146e7ba27aec13e57e55d40ebb79e3f28e359 100644 (file)
@@ -19,7 +19,7 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
 > You should prefer using the Cargo method.
 
 ```bash
-$ $cg_clif_dir/build/bin/cg_clif my_crate.rs
+$ $cg_clif_dir/build/rustc-clif my_crate.rs
 ```
 
 ## Jit mode
@@ -38,7 +38,7 @@ $ $cg_clif_dir/build/cargo-clif jit
 or
 
 ```bash
-$ $cg_clif_dir/build/bin/cg_clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
 ```
 
 There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
@@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell
 
 ```bash
 function jit_naked() {
-    echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+    echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
 }
 
 function jit() {
index 8e6652af3747b8bb6a93fceade8da19c371251f8..ce1c6c99b40c8b9964e8549c9d82eb2c43b7d5f5 100644 (file)
@@ -21,7 +21,7 @@ index 092b7cf..158cf71 100644
 -#[cfg(target_has_atomic_load_store = "128")]
 -#[unstable(feature = "integer_atomics", issue = "32976")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
+
  #[cfg(target_has_atomic_load_store = "ptr")]
  #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 @@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
@@ -31,14 +31,14 @@ index 092b7cf..158cf71 100644
 -#[cfg(target_has_atomic_load_store = "128")]
 -#[unstable(feature = "integer_atomics", issue = "32976")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
+
  #[cfg(target_has_atomic_load_store = "8")]
  #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
 index d9de37e..8293fce 100644
 --- a/library/core/src/sync/atomic.rs
 +++ b/library/core/src/sync/atomic.rs
-@@ -2234,44 +2234,6 @@ atomic_int! {
+@@ -2234,46 +2234,6 @@ atomic_int! {
      "AtomicU64::new(0)",
      u64 AtomicU64 ATOMIC_U64_INIT
  }
@@ -54,6 +54,7 @@ index d9de37e..8293fce 100644
 -    unstable(feature = "integer_atomics", issue = "32976"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 -    unstable(feature = "integer_atomics", issue = "32976"),
+-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
 -    "i128",
 -    "#![feature(integer_atomics)]\n\n",
 -    atomic_min, atomic_max,
@@ -73,6 +74,7 @@ index d9de37e..8293fce 100644
 -    unstable(feature = "integer_atomics", issue = "32976"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 -    unstable(feature = "integer_atomics", issue = "32976"),
+-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
 -    "u128",
 -    "#![feature(integer_atomics)]\n\n",
 -    atomic_umin, atomic_umax,
@@ -98,6 +100,6 @@ index b735957..ea728b6 100644
      #[cfg(target_has_atomic = "ptr")]
      assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
      #[cfg(target_has_atomic = "ptr")]
--- 
+--
 2.26.2.7.g19db9cfb68
 
index 966097c248b6f6c98d6d250a369f5df0b8d797c9..e98e92e468e93dacc140a5c23b22a147710917e3 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-04-21"
+channel = "nightly-2022-05-15"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 41d82b581cd8cc07111c7f5b6a6f491a178dc801..9362b47fa6d83137701069fc9c9aced1a9b0ab22 100644 (file)
@@ -5,20 +5,11 @@
 use std::process::Command;
 
 fn main() {
-    if env::var("RUSTC_WRAPPER").map_or(false, |wrapper| wrapper.contains("sccache")) {
-        eprintln!(
-            "\x1b[1;93m=== Warning: Unsetting RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
-        );
-        env::remove_var("RUSTC_WRAPPER");
-    }
-
     let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
 
-    env::set_var("RUSTC", sysroot.join("bin/cg_clif".to_string() + env::consts::EXE_SUFFIX));
-
-    let mut rustdoc_flags = env::var("RUSTDOCFLAGS").unwrap_or(String::new());
-    rustdoc_flags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
-    rustdoc_flags.push_str(
+    let mut rustflags = String::new();
+    rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
+    rustflags.push_str(
         sysroot
             .join(if cfg!(windows) { "bin" } else { "lib" })
             .join(
@@ -29,9 +20,10 @@ fn main() {
             .to_str()
             .unwrap(),
     );
-    rustdoc_flags.push_str(" --sysroot ");
-    rustdoc_flags.push_str(sysroot.to_str().unwrap());
-    env::set_var("RUSTDOCFLAGS", rustdoc_flags);
+    rustflags.push_str(" --sysroot ");
+    rustflags.push_str(sysroot.to_str().unwrap());
+    env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags);
+    env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
 
     // Ensure that the right toolchain is used
     env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
@@ -46,7 +38,7 @@ fn main() {
                 .chain(env::args().skip(2))
                 .chain([
                     "--".to_string(),
-                    "-Zunstable-features".to_string(),
+                    "-Zunstable-options".to_string(),
                     "-Cllvm-args=mode=jit".to_string(),
                 ])
                 .collect()
@@ -60,7 +52,7 @@ fn main() {
                 .chain(env::args().skip(2))
                 .chain([
                     "--".to_string(),
-                    "-Zunstable-features".to_string(),
+                    "-Zunstable-options".to_string(),
                     "-Cllvm-args=mode=jit-lazy".to_string(),
                 ])
                 .collect()
diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh
deleted file mode 100644 (file)
index 53ada36..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# Note to people running shellcheck: this file should only be sourced, not executed directly.
-
-set -e
-
-export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH"
-export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
deleted file mode 100644 (file)
index 11d6c4c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# Note to people running shellcheck: this file should only be sourced, not executed directly.
-
-# Various env vars that should only be set for the build system
-
-set -e
-
-export CG_CLIF_DISPLAY_CG_TIME=1
-export CG_CLIF_DISABLE_INCR_CACHE=1
-
-export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
-export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
-
-export RUN_WRAPPER=''
-export JIT_SUPPORTED=1
-if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
-   export JIT_SUPPORTED=0
-   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
-      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
-      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
-      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
-   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
-      # We are cross-compiling for Windows. Run tests in wine.
-      export RUN_WRAPPER='wine'
-   else
-      echo "Unknown non-native platform"
-   fi
-fi
-
-# FIXME fix `#[linkage = "extern_weak"]` without this
-if [[ "$(uname)" == 'Darwin' ]]; then
-   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
-fi
index f4e863e5494b51f34154bfc0730cd9758e73b999..e6f60d1c0cb230985bf85311076b15199291a807 100755 (executable)
@@ -2,8 +2,7 @@
 #![forbid(unsafe_code)]/* This line is ignored by bash
 # This block is ignored by rustc
 pushd $(dirname "$0")/../
-source scripts/config.sh
-RUSTC="$(pwd)/build/bin/cg_clif"
+RUSTC="$(pwd)/build/rustc-clif"
 popd
 PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
 #*/
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
new file mode 100644 (file)
index 0000000..3abfcd8
--- /dev/null
@@ -0,0 +1,36 @@
+use std::env;
+use std::ffi::OsString;
+#[cfg(unix)]
+use std::os::unix::process::CommandExt;
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+
+    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+        env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
+    );
+
+    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    args.push(OsString::from("-Cpanic=abort"));
+    args.push(OsString::from("-Zpanic-abort-tests"));
+    let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
+    codegen_backend_arg.push(cg_clif_dylib_path);
+    args.push(codegen_backend_arg);
+    if !args.contains(&OsString::from("--sysroot")) {
+        args.push(OsString::from("--sysroot"));
+        args.push(OsString::from(sysroot.to_str().unwrap()));
+    }
+
+    // Ensure that the right toolchain is used
+    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+
+    #[cfg(unix)]
+    Command::new("rustc").args(args).exec();
+
+    #[cfg(not(unix))]
+    std::process::exit(
+        Command::new("rustc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
+    );
+}
index cabbaaa8922517351dc70eeb3bb0730f752b0c17..4d0dfa16c5ecf88488e6a360b752e65fbb200012 100644 (file)
@@ -2,7 +2,6 @@
 set -e
 
 ./y.rs build --no-unstable-features
-source scripts/config.sh
 
 echo "[SETUP] Rust fork"
 git clone https://github.com/rust-lang/rust.git || true
@@ -26,21 +25,6 @@ index d95b5b7f17f..00b6f0e3635 100644
  [dev-dependencies]
  rand = "0.7"
  rand_xorshift = "0.2"
-diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
-index 887d27fd6dca4..2c2239f2b83d1 100644
---- a/src/tools/compiletest/src/header.rs
-+++ b/src/tools/compiletest/src/header.rs
-@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
-     cfg: Option<&str>,
- ) -> test::TestDesc {
-     let mut ignore = false;
-     #[cfg(not(bootstrap))]
--    let ignore_message: Option<String> = None;
-+    let ignore_message: Option<&str> = None;
-     let mut should_fail = false;
-
-     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
-
 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
 index 8431aa7b818..a3ff7e68ce5 100644
 --- a/src/tools/compiletest/src/runtest.rs
@@ -67,7 +51,7 @@ changelog-seen = 2
 ninja = false
 
 [build]
-rustc = "$(pwd)/../build/bin/cg_clif"
+rustc = "$(pwd)/../build/rustc-clif"
 cargo = "$(rustup which cargo)"
 full-bootstrap = true
 local-rebuild = true
index 4cf24c02235df731a81e36def7900d4c9e390afd..9bdb9f22c549a56d34850f97cbf2461a0d83585d 100755 (executable)
@@ -101,11 +101,10 @@ rm src/test/incremental/spike-neg1.rs # errors out for some reason
 rm src/test/incremental/spike-neg2.rs # same
 rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
 rm src/test/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
+rm src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
 
 rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
-
 # bugs in the test suite
 # ======================
 rm src/test/ui/backtrace.rs # TODO warning
index aae626081f62be5c93b3e7d92c08c811105c4d8f..9b5ffa4096049c04b9b2b509e9ec80107a7e1a92 100755 (executable)
@@ -2,10 +2,43 @@
 
 set -e
 
-source scripts/config.sh
-source scripts/ext_config.sh
-export RUSTC=false # ensure that cg_llvm isn't accidentally used
-MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
+export CG_CLIF_DISPLAY_CG_TIME=1
+export CG_CLIF_DISABLE_INCR_CACHE=1
+
+export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
+
+export RUN_WRAPPER=''
+
+case "$TARGET_TRIPLE" in
+   x86_64*)
+      export JIT_SUPPORTED=1
+      ;;
+   *)
+      export JIT_SUPPORTED=0
+      ;;
+esac
+
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+   export JIT_SUPPORTED=0
+   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
+      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
+      # We are cross-compiling for Windows. Run tests in wine.
+      export RUN_WRAPPER='wine'
+   else
+      echo "Unknown non-native platform"
+   fi
+fi
+
+# FIXME fix `#[linkage = "extern_weak"]` without this
+if [[ "$(uname)" == 'Darwin' ]]; then
+   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
+fi
+
+MY_RUSTC="$(pwd)/build/rustc-clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
 
 function no_sysroot_tests() {
     echo "[BUILD] mini_core"
@@ -39,7 +72,7 @@ function base_sysroot_tests() {
     $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/issue_91827_extern_types
 
-    echo "[AOT] alloc_system"
+    echo "[BUILD] alloc_system"
     $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
 
     echo "[AOT] alloc_example"
@@ -56,14 +89,14 @@ function base_sysroot_tests() {
         echo "[JIT] std_example (skipped)"
     fi
 
-    echo "[AOT] dst_field_align"
-    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
-    $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
-
     echo "[AOT] std_example"
     $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/std_example arg
 
+    echo "[AOT] dst_field_align"
+    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
+    $RUN_WRAPPER ./target/out/dst_field_align
+
     echo "[AOT] subslice-patterns-const-eval"
     $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
@@ -97,7 +130,7 @@ function extended_sysroot_tests() {
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         echo "[BENCH COMPILE] ebobby/simple-raytracer"
         hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
-        "RUSTC=rustc RUSTFLAGS='' cargo build" \
+        "RUSTFLAGS='' cargo build" \
         "../build/cargo-clif build"
 
         echo "[BENCH RUN] ebobby/simple-raytracer"
index ef56fb191bff5aabbbb884150ea83421b560c5b3..b163a42619172d2739142d1f689a821ab8fcb3e1 100644 (file)
@@ -309,7 +309,7 @@ fn codegen_call_argument_operand<'tcx>(
 
 pub(crate) fn codegen_terminator_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    span: Span,
+    source_info: mir::SourceInfo,
     func: &Operand<'tcx>,
     args: &[Operand<'tcx>],
     mir_dest: Option<(Place<'tcx>, BasicBlock)>,
@@ -340,7 +340,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
         match instance.def {
             InstanceDef::Intrinsic(_) => {
-                crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span);
+                crate::intrinsics::codegen_intrinsic_call(
+                    fx,
+                    instance,
+                    args,
+                    destination,
+                    source_info,
+                );
                 return;
             }
             InstanceDef::DropGlue(_, None) => {
@@ -402,7 +408,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
     // Pass the caller location for `#[track_caller]`.
     if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
-        let caller_location = fx.get_caller_location(span);
+        let caller_location = fx.get_caller_location(source_info);
         args.push(CallArgument { value: caller_location, is_owned: false });
     }
 
@@ -479,9 +485,10 @@ enum CallTarget {
         // FIXME find a cleaner way to support varargs
         if fn_sig.c_variadic {
             if !matches!(fn_sig.abi, Abi::C { .. }) {
-                fx.tcx
-                    .sess
-                    .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
+                fx.tcx.sess.span_fatal(
+                    source_info.span,
+                    &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
+                );
             }
             let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
             let abi_params = call_args
@@ -490,9 +497,10 @@ enum CallTarget {
                     let ty = fx.bcx.func.dfg.value_type(arg);
                     if !ty.is_int() {
                         // FIXME set %al to upperbound on float args once floats are supported
-                        fx.tcx
-                            .sess
-                            .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
+                        fx.tcx.sess.span_fatal(
+                            source_info.span,
+                            &format!("Non int ty {:?} for variadic call", ty),
+                        );
                     }
                     AbiParam::new(ty)
                 })
@@ -513,7 +521,7 @@ enum CallTarget {
 
 pub(crate) fn codegen_drop<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    span: Span,
+    source_info: mir::SourceInfo,
     drop_place: CPlace<'tcx>,
 ) {
     let ty = drop_place.layout().ty;
@@ -560,7 +568,7 @@ pub(crate) fn codegen_drop<'tcx>(
 
                 if drop_instance.def.requires_caller_location(fx.tcx) {
                     // Pass the caller location for `#[track_caller]`.
-                    let caller_location = fx.get_caller_location(span);
+                    let caller_location = fx.get_caller_location(source_info);
                     call_args.extend(
                         adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
                     );
index 65346cb39622aa0e7bc2a7de747820af62b3d519..65e5812a8a5b0e00f35b57a5ddf399af51c040f7 100644 (file)
@@ -325,7 +325,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                     AssertKind::BoundsCheck { ref len, ref index } => {
                         let len = codegen_operand(fx, len).load_scalar(fx);
                         let index = codegen_operand(fx, index).load_scalar(fx);
-                        let location = fx.get_caller_location(source_info.span).load_scalar(fx);
+                        let location = fx.get_caller_location(source_info).load_scalar(fx);
 
                         codegen_panic_inner(
                             fx,
@@ -336,7 +336,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                     }
                     _ => {
                         let msg_str = msg.description();
-                        codegen_panic(fx, msg_str, source_info.span);
+                        codegen_panic(fx, msg_str, source_info);
                     }
                 }
             }
@@ -398,7 +398,13 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                 from_hir_call: _,
             } => {
                 fx.tcx.sess.time("codegen call", || {
-                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
+                    crate::abi::codegen_terminator_call(
+                        fx,
+                        mir::SourceInfo { span: *fn_span, ..source_info },
+                        func,
+                        args,
+                        *destination,
+                    )
                 });
             }
             TerminatorKind::InlineAsm {
@@ -450,7 +456,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
             }
             TerminatorKind::Drop { place, target, unwind: _ } => {
                 let drop_place = codegen_place(fx, *place);
-                crate::abi::codegen_drop(fx, source_info.span, drop_place);
+                crate::abi::codegen_drop(fx, source_info, drop_place);
 
                 let target_block = fx.get_block(*target);
                 fx.bcx.ins().jump(target_block, &[]);
@@ -471,7 +477,7 @@ fn codegen_stmt<'tcx>(
 
     fx.set_debug_loc(stmt.source_info);
 
-    #[cfg(disabled)]
+    #[cfg(any())] // This is never true
     match &stmt.kind {
         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
         _ => {
@@ -898,14 +904,18 @@ pub(crate) fn codegen_operand<'tcx>(
     }
 }
 
-pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
-    let location = fx.get_caller_location(span).load_scalar(fx);
+pub(crate) fn codegen_panic<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    msg_str: &str,
+    source_info: mir::SourceInfo,
+) {
+    let location = fx.get_caller_location(source_info).load_scalar(fx);
 
     let msg_ptr = fx.anonymous_str(msg_str);
     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
     let args = [msg_ptr, msg_len, location];
 
-    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span);
+    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
 }
 
 pub(crate) fn codegen_panic_inner<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
deleted file mode 100644 (file)
index 5984ec8..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#![feature(rustc_private)]
-#![warn(rust_2018_idioms)]
-#![warn(unused_lifetimes)]
-#![warn(unreachable_pub)]
-
-extern crate rustc_data_structures;
-extern crate rustc_driver;
-extern crate rustc_interface;
-extern crate rustc_session;
-extern crate rustc_target;
-
-use std::panic;
-
-use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
-use rustc_interface::interface;
-use rustc_session::config::{ErrorOutputType, TrimmedDefPaths};
-use rustc_session::early_error;
-use rustc_target::spec::PanicStrategy;
-
-// FIXME use std::lazy::SyncLazy once it stabilizes
-use once_cell::sync::Lazy;
-
-const BUG_REPORT_URL: &str = "https://github.com/bjorn3/rustc_codegen_cranelift/issues/new";
-
-static DEFAULT_HOOK: Lazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    Lazy::new(|| {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            (*DEFAULT_HOOK)(info);
-
-            // Separate the output with an empty line
-            eprintln!();
-
-            // Print the ICE message
-            rustc_driver::report_ice(info, BUG_REPORT_URL);
-        }));
-        hook
-    });
-
-#[derive(Default)]
-pub struct CraneliftPassesCallbacks {
-    time_passes: bool,
-}
-
-impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
-    fn config(&mut self, config: &mut interface::Config) {
-        // If a --prints=... option has been given, we don't print the "total"
-        // time because it will mess up the --prints output. See #64339.
-        self.time_passes = config.opts.prints.is_empty()
-            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
-
-        config.opts.cg.panic = Some(PanicStrategy::Abort);
-        config.opts.debugging_opts.panic_abort_tests = true;
-        config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| {
-            std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned()
-        }));
-
-        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
-    }
-}
-
-fn main() {
-    let start_time = std::time::Instant::now();
-    let start_rss = get_resident_set_size();
-    rustc_driver::init_rustc_env_logger();
-    let mut callbacks = CraneliftPassesCallbacks::default();
-    Lazy::force(&DEFAULT_HOOK); // Install ice hook
-    let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let args = std::env::args_os()
-            .enumerate()
-            .map(|(i, arg)| {
-                arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    )
-                })
-            })
-            .collect::<Vec<_>>();
-        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
-        run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
-        })));
-        run_compiler.run()
-    });
-
-    if callbacks.time_passes {
-        let end_rss = get_resident_set_size();
-        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
-    }
-
-    std::process::exit(exit_code)
-}
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
deleted file mode 100644 (file)
index bde4d71..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-//! The only difference between this and cg_clif.rs is that this binary defaults to using cg_llvm
-//! instead of cg_clif and requires `--clif` to use cg_clif and that this binary doesn't have JIT
-//! support.
-//! This is necessary as with Cargo `RUSTC` applies to both target crates and host crates. The host
-//! crates must be built with cg_llvm as we are currently building a sysroot for cg_clif.
-//! `RUSTFLAGS` however is only applied to target crates, so `--clif` would only be passed to the
-//! target crates.
-
-#![feature(rustc_private)]
-#![warn(rust_2018_idioms)]
-#![warn(unused_lifetimes)]
-#![warn(unreachable_pub)]
-
-extern crate rustc_driver;
-extern crate rustc_interface;
-extern crate rustc_session;
-extern crate rustc_target;
-
-use std::path::PathBuf;
-
-use rustc_interface::interface;
-use rustc_session::config::ErrorOutputType;
-use rustc_session::early_error;
-use rustc_target::spec::PanicStrategy;
-
-fn find_sysroot() -> String {
-    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
-    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
-    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
-    match (home, toolchain) {
-        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
-        _ => option_env!("RUST_SYSROOT")
-            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
-            .to_owned(),
-    }
-}
-
-pub struct CraneliftPassesCallbacks {
-    use_clif: bool,
-}
-
-impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
-    fn config(&mut self, config: &mut interface::Config) {
-        if !self.use_clif {
-            config.opts.maybe_sysroot = Some(PathBuf::from(find_sysroot()));
-            return;
-        }
-
-        config.opts.cg.panic = Some(PanicStrategy::Abort);
-        config.opts.debugging_opts.panic_abort_tests = true;
-        config.opts.maybe_sysroot =
-            Some(std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned());
-    }
-}
-
-fn main() {
-    rustc_driver::init_rustc_env_logger();
-    rustc_driver::install_ice_hook();
-    let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let mut use_clif = false;
-
-        let args = std::env::args_os()
-            .enumerate()
-            .map(|(i, arg)| {
-                arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    )
-                })
-            })
-            .filter(|arg| {
-                if arg == "--clif" {
-                    use_clif = true;
-                    false
-                } else {
-                    true
-                }
-            })
-            .collect::<Vec<_>>();
-
-        let mut callbacks = CraneliftPassesCallbacks { use_clif };
-
-        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
-        if use_clif {
-            run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-                Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
-            })));
-        }
-        run_compiler.run()
-    });
-    std::process::exit(exit_code)
-}
index ffa629ca16c8b19d7bbc372fcc4055c8d94262a8..f9dc1b5169e1a624c35949691a5a8f0f6f0e6f8c 100644 (file)
@@ -340,22 +340,46 @@ pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
         self.bcx.set_srcloc(SourceLoc::new(index as u32));
     }
 
-    pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
-        if let Some(loc) = self.caller_location {
-            // `#[track_caller]` is used; return caller location instead of current location.
-            return loc;
+    // Note: must be kept in sync with get_caller_location from cg_ssa
+    pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
+        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
+            let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+            let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
+            let const_loc = fx.tcx.const_caller_location((
+                rustc_span::symbol::Symbol::intern(
+                    &caller.file.name.prefer_remapped().to_string_lossy(),
+                ),
+                caller.line as u32,
+                caller.col_display as u32 + 1,
+            ));
+            crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty())
+        };
+
+        // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
+        // If so, the starting `source_info.span` is in the innermost inlined
+        // function, and will be replaced with outer callsite spans as long
+        // as the inlined functions were `#[track_caller]`.
+        loop {
+            let scope_data = &self.mir.source_scopes[source_info.scope];
+
+            if let Some((callee, callsite_span)) = scope_data.inlined {
+                // Stop inside the most nested non-`#[track_caller]` function,
+                // before ever reaching its caller (which is irrelevant).
+                if !callee.def.requires_caller_location(self.tcx) {
+                    return span_to_caller_location(self, source_info.span);
+                }
+                source_info.span = callsite_span;
+            }
+
+            // Skip past all of the parents with `inlined: None`.
+            match scope_data.inlined_parent_scope {
+                Some(parent) => source_info.scope = parent,
+                None => break,
+            }
         }
 
-        let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
-        let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
-        let const_loc = self.tcx.const_caller_location((
-            rustc_span::symbol::Symbol::intern(
-                &caller.file.name.prefer_remapped().to_string_lossy(),
-            ),
-            caller.line as u32,
-            caller.col_display as u32 + 1,
-        ));
-        crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty())
+        // No inlined `SourceScope`s, or all of them were `#[track_caller]`.
+        self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span))
     }
 
     pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
index 7f15bc75fda23e8fc933c892d4b94712ce9afa20..1b01f4edbb3f3313bdd1ba9a4943822e3625667d 100644 (file)
@@ -74,6 +74,7 @@ fn create_jit_module<'tcx>(
     jit_builder.hotswap(hotswap);
     crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
     jit_builder.symbols(imported_symbols);
+    jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
     let mut jit_module = JITModule::new(jit_builder);
 
     let mut cx = crate::CodegenCx::new(
@@ -210,8 +211,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
     }
 }
 
-#[no_mangle]
-extern "C" fn __clif_jit_fn(
+extern "C" fn clif_jit_fn(
     instance_ptr: *const Instance<'static>,
     trampoline_ptr: *const u8,
 ) -> *const u8 {
index f7a83373e870bed0b8893c9e36e2a10484078913..29b3f36b2bef2c389bb79d54bec9ebcf191a7308 100644 (file)
@@ -218,7 +218,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     instance: Instance<'tcx>,
     args: &[mir::Operand<'tcx>],
     destination: Option<(CPlace<'tcx>, BasicBlock)>,
-    span: Span,
+    source_info: mir::SourceInfo,
 ) {
     let intrinsic = fx.tcx.item_name(instance.def_id());
     let substs = instance.substs;
@@ -232,7 +232,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                     fx.bcx.ins().trap(TrapCode::User(0));
                 }
                 sym::transmute => {
-                    crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
+                    crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
                 }
                 _ => unimplemented!("unsupported instrinsic {}", intrinsic),
             }
@@ -241,7 +241,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     };
 
     if intrinsic.as_str().starts_with("simd_") {
-        self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span);
+        self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, source_info.span);
         let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
         fx.bcx.ins().jump(ret_block, &[]);
     } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) {
@@ -255,7 +255,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             substs,
             args,
             ret,
-            span,
+            source_info,
             destination,
         );
     }
@@ -339,7 +339,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
     substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
-    span: Span,
+    source_info: mir::SourceInfo,
     destination: Option<(CPlace<'tcx>, BasicBlock)>,
 ) {
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
@@ -347,7 +347,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
     intrinsic_match! {
         fx, intrinsic, args,
         _ => {
-            fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic));
+            fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
         };
 
         assume, (c _a) {};
@@ -658,7 +658,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
-                        span,
+                        source_info,
                     )
                 });
                 return;
@@ -669,7 +669,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
-                        span,
+                        source_info,
                     );
                 });
                 return;
@@ -680,7 +680,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
-                        span,
+                        source_info,
                     )
                 });
                 return;
@@ -715,19 +715,19 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
         ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) {
             let ty = substs.type_at(0);
-            let isize_layout = fx.layout_of(fx.tcx.types.isize);
 
             let pointee_size: u64 = fx.layout_of(ty).size.bytes();
             let diff_bytes = fx.bcx.ins().isub(ptr, base);
             // FIXME this can be an exact division.
-            let diff = if intrinsic == sym::ptr_offset_from_unsigned {
+            let val = if intrinsic == sym::ptr_offset_from_unsigned {
+                let usize_layout = fx.layout_of(fx.tcx.types.usize);
                 // Because diff_bytes ULE isize::MAX, this would be fine as signed,
                 // but unsigned is slightly easier to codegen, so might as well.
-                fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64)
+                CValue::by_val(fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64), usize_layout)
             } else {
-                fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64)
+                let isize_layout = fx.layout_of(fx.tcx.types.isize);
+                CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout)
             };
-            let val = CValue::by_val(diff, isize_layout);
             ret.write_cvalue(fx, val);
         };
 
@@ -742,7 +742,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
         };
 
         caller_location, () {
-            let caller_location = fx.get_caller_location(span);
+            let caller_location = fx.get_caller_location(source_info);
             ret.write_cvalue(fx, caller_location);
         };
 
@@ -765,12 +765,12 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
+                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
                     return;
                 }
             }
@@ -793,12 +793,12 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
+                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
                     return;
                 }
             }
@@ -812,7 +812,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -830,7 +830,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -850,7 +850,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -868,7 +868,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -886,7 +886,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -904,7 +904,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -922,7 +922,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -940,7 +940,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -958,7 +958,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -976,7 +976,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -994,7 +994,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -1012,7 +1012,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
index 8f80b02ae0d4e7d98d588cd255f2ac210bdf209e..a68225de58b32d160dd2302ed54eaf352b3d8831 100644 (file)
@@ -828,6 +828,7 @@ pub(crate) fn assert_assignable<'tcx>(
                 }
             }
         }
+        (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b),
         _ => {
             assert_eq!(
                 from_ty, to_ty,
index 2e8cd934eb2986fb22f6633618722ec912ab8f44..20d91b80e8c52821904c449c572e2fa681225c8c 100644 (file)
@@ -592,7 +592,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
             InlineAsmRegClass::X86(
-                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
                 bug!("GCC backend does not support SPIR-V")
@@ -656,6 +656,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::tmm_reg) => unimplemented!(),
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
@@ -787,7 +788,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
index e994001f96fd9b47cd6fa2e3c550c9ee1351b04d..a53946995ee1c43d484f35369c4e31d72fb9fecf 100644 (file)
@@ -604,7 +604,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             InlineAsmRegClass::X86(
                 X86InlineAsmRegClass::x87_reg
                 | X86InlineAsmRegClass::mmx_reg
-                | X86InlineAsmRegClass::kreg0,
+                | X86InlineAsmRegClass::kreg0
+                | X86InlineAsmRegClass::tmm_reg,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
@@ -692,7 +693,8 @@ fn modifier_to_llvm(
         InlineAsmRegClass::X86(
             X86InlineAsmRegClass::x87_reg
             | X86InlineAsmRegClass::mmx_reg
-            | X86InlineAsmRegClass::kreg0,
+            | X86InlineAsmRegClass::kreg0
+            | X86InlineAsmRegClass::tmm_reg,
         ) => {
             unreachable!("clobber-only")
         }
@@ -766,7 +768,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         InlineAsmRegClass::X86(
             X86InlineAsmRegClass::x87_reg
             | X86InlineAsmRegClass::mmx_reg
-            | X86InlineAsmRegClass::kreg0,
+            | X86InlineAsmRegClass::kreg0
+            | X86InlineAsmRegClass::tmm_reg,
         ) => {
             unreachable!("clobber-only")
         }
index c098ce36f022fae5d0d5d4fe4e4dea196b4a38af..9394d60134f8c0e9ba0b942b0b3abbc40da657fd 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::OptLevel;
+use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
@@ -329,9 +330,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     ) {
         let span = cx
             .tcx
-            .get_attrs(instance.def_id())
-            .iter()
-            .find(|a| a.has_name(rustc_span::sym::target_feature))
+            .get_attr(instance.def_id(), sym::target_feature)
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
         let msg = format!(
             "the target features {} must all be either enabled or disabled together",
index f814cc930433151171551fc9f2abb7064d3136f5..8f6438e85ad7f7955205e022d69b9773d42a6dc7 100644 (file)
@@ -152,8 +152,10 @@ fn inject_dll_import_lib(
         };
 
         let target = &self.config.sess.target;
-        let mingw_gnu_toolchain =
-            target.vendor == "pc" && target.os == "windows" && target.env == "gnu";
+        let mingw_gnu_toolchain = target.vendor == "pc"
+            && target.os == "windows"
+            && target.env == "gnu"
+            && target.abi.is_empty();
 
         let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
index f2cf3b1ef5c1eea396fdd208024118f7a9b7deb6..97d3acb34ce75ee360eb4acfd0fd5f2e4a723916 100644 (file)
 use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES};
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
+use rustc_span::FileName;
 use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash};
+use rustc_span::{self, SourceFile};
 use rustc_target::abi::{Align, Size};
 use smallvec::smallvec;
 use tracing::debug;
 
 use libc::{c_longlong, c_uint};
 use std::borrow::Cow;
-use std::collections::hash_map::Entry;
 use std::fmt::{self, Write};
 use std::hash::{Hash, Hasher};
 use std::iter;
 use std::path::{Path, PathBuf};
 use std::ptr;
+use tracing::instrument;
 
 impl PartialEq for llvm::Metadata {
     fn eq(&self, other: &Self) -> bool {
@@ -527,78 +528,105 @@ fn hex_encode(data: &[u8]) -> String {
 }
 
 pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
-    debug!("file_metadata: file_name: {:?}", source_file.name);
-
-    let hash = Some(&source_file.src_hash);
-    let file_name = Some(source_file.name.prefer_remapped().to_string());
-    let directory = if source_file.is_real_file() && !source_file.is_imported() {
-        Some(
-            cx.sess()
-                .opts
-                .working_dir
-                .to_string_lossy(FileNameDisplayPreference::Remapped)
-                .to_string(),
-        )
-    } else {
-        // If the path comes from an upstream crate we assume it has been made
-        // independent of the compiler's working directory one way or another.
-        None
-    };
-    file_metadata_raw(cx, file_name, directory, hash)
-}
-
-pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
-    file_metadata_raw(cx, None, None, None)
-}
-
-fn file_metadata_raw<'ll>(
-    cx: &CodegenCx<'ll, '_>,
-    file_name: Option<String>,
-    directory: Option<String>,
-    hash: Option<&SourceFileHash>,
-) -> &'ll DIFile {
-    let key = (file_name, directory);
-
-    match debug_context(cx).created_files.borrow_mut().entry(key) {
-        Entry::Occupied(o) => o.get(),
-        Entry::Vacant(v) => {
-            let (file_name, directory) = v.key();
-            debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory);
-
-            let file_name = file_name.as_deref().unwrap_or("<unknown>");
-            let directory = directory.as_deref().unwrap_or("");
-
-            let (hash_kind, hash_value) = match hash {
-                Some(hash) => {
-                    let kind = match hash.kind {
-                        rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
-                        rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
-                        rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
-                    };
-                    (kind, hex_encode(hash.hash_bytes()))
+    let cache_key = Some((source_file.name_hash, source_file.src_hash));
+    return debug_context(cx)
+        .created_files
+        .borrow_mut()
+        .entry(cache_key)
+        .or_insert_with(|| alloc_new_file_metadata(cx, source_file));
+
+    #[instrument(skip(cx, source_file), level = "debug")]
+    fn alloc_new_file_metadata<'ll>(
+        cx: &CodegenCx<'ll, '_>,
+        source_file: &SourceFile,
+    ) -> &'ll DIFile {
+        debug!(?source_file.name);
+
+        let (directory, file_name) = match &source_file.name {
+            FileName::Real(filename) => {
+                let working_directory = &cx.sess().opts.working_dir;
+                debug!(?working_directory);
+
+                let filename = cx
+                    .sess()
+                    .source_map()
+                    .path_mapping()
+                    .to_embeddable_absolute_path(filename.clone(), working_directory);
+
+                // Construct the absolute path of the file
+                let abs_path = filename.remapped_path_if_available();
+                debug!(?abs_path);
+
+                if let Ok(rel_path) =
+                    abs_path.strip_prefix(working_directory.remapped_path_if_available())
+                {
+                    // If the compiler's working directory (which also is the DW_AT_comp_dir of
+                    // the compilation unit) is a prefix of the path we are about to emit, then
+                    // only emit the part relative to the working directory.
+                    // Because of path remapping we sometimes see strange things here: `abs_path`
+                    // might actually look like a relative path
+                    // (e.g. `<crate-name-and-version>/src/lib.rs`), so if we emit it without
+                    // taking the working directory into account, downstream tooling will
+                    // interpret it as `<working-directory>/<crate-name-and-version>/src/lib.rs`,
+                    // which makes no sense. Usually in such cases the working directory will also
+                    // be remapped to `<crate-name-and-version>` or some other prefix of the path
+                    // we are remapping, so we end up with
+                    // `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
+                    // By moving the working directory portion into the `directory` part of the
+                    // DIFile, we allow LLVM to emit just the relative path for DWARF, while
+                    // still emitting the correct absolute path for CodeView.
+                    (
+                        working_directory.to_string_lossy(FileNameDisplayPreference::Remapped),
+                        rel_path.to_string_lossy().into_owned(),
+                    )
+                } else {
+                    ("".into(), abs_path.to_string_lossy().into_owned())
                 }
-                None => (llvm::ChecksumKind::None, String::new()),
-            };
+            }
+            other => ("".into(), other.prefer_remapped().to_string_lossy().into_owned()),
+        };
 
-            let file_metadata = unsafe {
-                llvm::LLVMRustDIBuilderCreateFile(
-                    DIB(cx),
-                    file_name.as_ptr().cast(),
-                    file_name.len(),
-                    directory.as_ptr().cast(),
-                    directory.len(),
-                    hash_kind,
-                    hash_value.as_ptr().cast(),
-                    hash_value.len(),
-                )
-            };
+        let hash_kind = match source_file.src_hash.kind {
+            rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
+            rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
+            rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
+        };
+        let hash_value = hex_encode(source_file.src_hash.hash_bytes());
 
-            v.insert(file_metadata);
-            file_metadata
+        unsafe {
+            llvm::LLVMRustDIBuilderCreateFile(
+                DIB(cx),
+                file_name.as_ptr().cast(),
+                file_name.len(),
+                directory.as_ptr().cast(),
+                directory.len(),
+                hash_kind,
+                hash_value.as_ptr().cast(),
+                hash_value.len(),
+            )
         }
     }
 }
 
+pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
+    debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
+        let file_name = "<unknown>";
+        let directory = "";
+        let hash_value = "";
+
+        llvm::LLVMRustDIBuilderCreateFile(
+            DIB(cx),
+            file_name.as_ptr().cast(),
+            file_name.len(),
+            directory.as_ptr().cast(),
+            directory.len(),
+            llvm::ChecksumKind::None,
+            hash_value.as_ptr().cast(),
+            hash_value.len(),
+        )
+    })
+}
+
 trait MsvcBasicName {
     fn msvc_basic_name(self) -> &'static str;
 }
index 6a164557a4719ae97fac9a1bbe98610d8242d6f4..0910e7c94ea122579c798737a16e7d42983f1e25 100644 (file)
@@ -31,7 +31,7 @@
 use rustc_session::config::{self, DebugInfo};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
-use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span};
+use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span};
 use rustc_target::abi::Size;
 
 use libc::c_uint;
@@ -61,7 +61,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> {
     llcontext: &'ll llvm::Context,
     llmod: &'ll llvm::Module,
     builder: &'ll mut DIBuilder<'ll>,
-    created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'ll DIFile>>,
+    created_files: RefCell<FxHashMap<Option<(u128, SourceFileHash)>, &'ll DIFile>>,
 
     type_map: metadata::TypeMap<'ll, 'tcx>,
     namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
index 87d0680bf6f308fa8427b7919e61872f87a76676..93b10a07e449d1be6977cd61cae8fd1f24463086 100644 (file)
@@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.28.0"
+version = "0.28.4"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
index 2e42272805682ec71881c2fc07162ac265f1872b..6aa96f9f40300d8346e65b66feae63291608e5aa 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::Session;
 use rustc_target::abi::Endian;
-use rustc_target::spec::Target;
+use rustc_target::spec::{RelocModel, Target};
 
 use crate::METADATA_FILENAME;
 
@@ -132,15 +132,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
     let mut file = write::Object::new(binary_format, architecture, endianness);
     match architecture {
         Architecture::Mips => {
-            // copied from `mipsel-linux-gnu-gcc foo.c -c` and
-            // inspecting the resulting `e_flags` field.
-            let e_flags = elf::EF_MIPS_CPIC
-                | elf::EF_MIPS_PIC
-                | if sess.target.options.cpu.contains("r6") {
-                    elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008
-                } else {
-                    elf::EF_MIPS_ARCH_32R2
-                };
+            let arch = match sess.target.options.cpu.as_ref() {
+                "mips1" => elf::EF_MIPS_ARCH_1,
+                "mips2" => elf::EF_MIPS_ARCH_2,
+                "mips3" => elf::EF_MIPS_ARCH_3,
+                "mips4" => elf::EF_MIPS_ARCH_4,
+                "mips5" => elf::EF_MIPS_ARCH_5,
+                s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
+                _ => elf::EF_MIPS_ARCH_32R2,
+            };
+            // The only ABI LLVM supports for 32-bit MIPS CPUs is o32.
+            let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch;
+            if sess.target.options.relocation_model != RelocModel::Static {
+                e_flags |= elf::EF_MIPS_PIC;
+            }
+            if sess.target.options.cpu.contains("r6") {
+                e_flags |= elf::EF_MIPS_NAN2008;
+            }
             file.flags = FileFlags::Elf { e_flags };
         }
         Architecture::Mips64 => {
index fa39e8dd247d5071d3dda5639a18ff2e211276ad..80dab115fac46044b1fb78a090a2d0006ea7f155 100644 (file)
@@ -328,7 +328,7 @@ fn propagate<'tcx>(result: &mut IndexVec<mir::BasicBlock, CleanupKind>, mir: &mi
                 bb, data, result[bb], funclet
             );
 
-            for &succ in data.terminator().successors() {
+            for succ in data.terminator().successors() {
                 let kind = result[succ];
                 debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind);
                 match kind {
index 38fecf7232ebc704436755d752b000401df2afbb..d7cbc48e0328185b53fb55d415bcdfe3757a238b 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, subst::Subst, TyCtxt};
+use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{self, Abi};
 use std::borrow::Cow;
@@ -47,7 +47,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         "Unexpected DefKind: {:?}",
         ecx.tcx.def_kind(cid.instance.def_id())
     );
-    let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
+    let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
 
@@ -135,7 +135,7 @@ pub(super) fn op_to_const<'tcx>(
     } else {
         // It is guaranteed that any non-slice scalar pair is actually ByRef here.
         // When we come back from raw const eval, we are always by-ref. The only way our op here is
-        // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we
+        // by-val is if we are in destructure_mir_constant, i.e., if this is (a field of) something that we
         // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
         // structs containing such.
         op.try_as_mplace()
index 1f291db55be96d596501997cdc5f9e85cc095516..777f4393458e2b3f4033790c02d1e98366ef5de5 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::abi::Abi;
 
 /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
 pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
@@ -34,10 +33,7 @@ fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
         hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
             // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
             // foreign items cannot be evaluated at compile-time.
-            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-            let is_const = if let Abi::RustIntrinsic | Abi::PlatformIntrinsic =
-                tcx.hir().get_foreign_abi(hir_id)
-            {
+            let is_const = if tcx.is_intrinsic(def_id) {
                 tcx.lookup_const_stability(def_id).is_some()
             } else {
                 false
index d57504deeab90594d79bd30d4c7baec4dbbda4a5..c5a11aaceaf9a09f9f73fae9674888c4af16fa88 100644 (file)
@@ -18,7 +18,7 @@
 
 use crate::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
-    OpTy, PlaceTy, Scalar, StackPopUnwind,
+    OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
 };
 
 use super::error::*;
@@ -443,6 +443,14 @@ fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>
         Ok(())
     }
 
+    #[inline(always)]
+    fn expose_ptr(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _ptr: Pointer<AllocId>,
+    ) -> InterpResult<'tcx> {
+        Err(ConstEvalErrKind::NeedsRfc("exposing pointers".to_string()).into())
+    }
+
     #[inline(always)]
     fn init_frame_extra(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
index 96c18d488ee8c1e38aa6186cdad0be6f64d6190d..db43f7a425ce66558658b0889f31da6b82703bc3 100644 (file)
@@ -4,6 +4,7 @@
 
 use rustc_hir::Mutability;
 use rustc_middle::mir;
+use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
 
@@ -22,7 +23,7 @@
 pub use eval_queries::*;
 pub use fn_queries::*;
 pub use machine::*;
-pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value};
+pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
 
 pub(crate) fn const_caller_location(
     tcx: TyCtxt<'_>,
@@ -38,6 +39,57 @@ pub(crate) fn const_caller_location(
     ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
 }
 
+// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
+const VALTREE_MAX_NODES: usize = 1000;
+
+pub(crate) enum ValTreeCreationError {
+    NodesOverflow,
+    NonSupportedType,
+    Other,
+}
+pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
+
+/// Evaluates a constant and turns it into a type-level constant value.
+pub(crate) fn eval_to_valtree<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    cid: GlobalId<'tcx>,
+) -> EvalToValTreeResult<'tcx> {
+    let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
+    let ecx = mk_eval_cx(
+        tcx, DUMMY_SP, param_env,
+        // It is absolutely crucial for soundness that
+        // we do not read from static items or other mutable memory.
+        false,
+    );
+    let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
+    debug!(?place);
+
+    let mut num_nodes = 0;
+    let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
+
+    match valtree_result {
+        Ok(valtree) => Ok(Some(valtree)),
+        Err(err) => {
+            let did = cid.instance.def_id();
+            let s = cid.display(tcx);
+            match err {
+                ValTreeCreationError::NodesOverflow => {
+                    let msg = format!("maximum number of nodes exceeded in constant {}", &s);
+                    let mut diag = match tcx.hir().span_if_local(did) {
+                        Some(span) => tcx.sess.struct_span_err(span, &msg),
+                        None => tcx.sess.struct_err(&msg),
+                    };
+                    diag.emit();
+
+                    Ok(None)
+                }
+                ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None),
+            }
+        }
+    }
+}
+
 /// This function should never fail for validated constants. However, it is also invoked from the
 /// pretty printer which might attempt to format invalid constants and in that case it might fail.
 pub(crate) fn try_destructure_const<'tcx>(
@@ -48,7 +100,6 @@ pub(crate) fn try_destructure_const<'tcx>(
     trace!("destructure_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.const_to_op(val, None)?;
-
     // We go to `usize` as we cannot allocate anything bigger anyway.
     let (field_count, variant, down) = match val.ty().kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
@@ -64,7 +115,6 @@ pub(crate) fn try_destructure_const<'tcx>(
         ty::Tuple(substs) => (substs.len(), None, op),
         _ => bug!("cannot destructure constant {:?}", val),
     };
-
     let fields = (0..field_count)
         .map(|i| {
             let field_op = ecx.operand_field(&down, i)?;
@@ -73,10 +123,46 @@ pub(crate) fn try_destructure_const<'tcx>(
         })
         .collect::<InterpResult<'tcx, Vec<_>>>()?;
     let fields = tcx.arena.alloc_from_iter(fields);
-
     Ok(mir::DestructuredConst { variant, fields })
 }
 
+#[instrument(skip(tcx), level = "debug")]
+pub(crate) fn try_destructure_mir_constant<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    val: mir::ConstantKind<'tcx>,
+) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> {
+    trace!("destructure_mir_constant: {:?}", val);
+    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let op = ecx.mir_const_to_op(&val, None)?;
+
+    // We go to `usize` as we cannot allocate anything bigger anyway.
+    let (field_count, variant, down) = match val.ty().kind() {
+        ty::Array(_, len) => (len.eval_usize(tcx, param_env) as usize, None, op),
+        ty::Adt(def, _) if def.variants().is_empty() => {
+            throw_ub!(Unreachable)
+        }
+        ty::Adt(def, _) => {
+            let variant = ecx.read_discriminant(&op).unwrap().1;
+            let down = ecx.operand_downcast(&op, variant).unwrap();
+            (def.variants()[variant].fields.len(), Some(variant), down)
+        }
+        ty::Tuple(substs) => (substs.len(), None, op),
+        _ => bug!("cannot destructure mir constant {:?}", val),
+    };
+
+    let fields_iter = (0..field_count)
+        .map(|i| {
+            let field_op = ecx.operand_field(&down, i)?;
+            let val = op_to_const(&ecx, &field_op);
+            Ok(mir::ConstantKind::Val(val, field_op.layout.ty))
+        })
+        .collect::<InterpResult<'tcx, Vec<_>>>()?;
+    let fields = tcx.arena.alloc_from_iter(fields_iter);
+
+    Ok(mir::DestructuredMirConstant { variant, fields })
+}
+
 #[instrument(skip(tcx), level = "debug")]
 pub(crate) fn deref_const<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -113,3 +199,39 @@ pub(crate) fn deref_const<'tcx>(
 
     tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
 }
+
+#[instrument(skip(tcx), level = "debug")]
+pub(crate) fn deref_mir_constant<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    val: mir::ConstantKind<'tcx>,
+) -> mir::ConstantKind<'tcx> {
+    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let op = ecx.mir_const_to_op(&val, None).unwrap();
+    let mplace = ecx.deref_operand(&op).unwrap();
+    if let Some(alloc_id) = mplace.ptr.provenance {
+        assert_eq!(
+            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
+            Mutability::Not,
+            "deref_const cannot be used with mutable allocations as \
+            that could allow pattern matching to observe mutable statics",
+        );
+    }
+
+    let ty = match mplace.meta {
+        MemPlaceMeta::None => mplace.layout.ty,
+        MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
+        // In case of unsized types, figure out the real type behind.
+        MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
+            ty::Str => bug!("there's no sized equivalent of a `str`"),
+            ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
+            _ => bug!(
+                "type {} should not have metadata, but had {:?}",
+                mplace.layout.ty,
+                mplace.meta
+            ),
+        },
+    };
+
+    mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty)
+}
index 374179d0cc24da0f7f230518ade0909d178674e4..7346d69bb5de3f11c1d9429765ba47a82d703a8d 100644 (file)
@@ -1,33 +1,16 @@
 use super::eval_queries::{mk_eval_cx, op_to_const};
 use super::machine::CompileTimeEvalContext;
+use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
     MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
 };
-use rustc_middle::mir::interpret::ConstAlloc;
-use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_target::abi::{Align, VariantIdx};
 
 use crate::interpret::MPlaceTy;
 use crate::interpret::Value;
-
-/// Convert an evaluated constant to a type level constant
-#[instrument(skip(tcx), level = "debug")]
-pub(crate) fn const_to_valtree<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    raw: ConstAlloc<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let ecx = mk_eval_cx(
-        tcx, DUMMY_SP, param_env,
-        // It is absolutely crucial for soundness that
-        // we do not read from static items or other mutable memory.
-        false,
-    );
-    let place = ecx.raw_const_to_mplace(raw).unwrap();
-    const_to_valtree_inner(&ecx, &place)
-}
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 
 #[instrument(skip(ecx), level = "debug")]
 fn branches<'tcx>(
@@ -35,7 +18,8 @@ fn branches<'tcx>(
     place: &MPlaceTy<'tcx>,
     n: usize,
     variant: Option<VariantIdx>,
-) -> Option<ty::ValTree<'tcx>> {
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
     let place = match variant {
         Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
         None => *place,
@@ -43,80 +27,116 @@ fn branches<'tcx>(
     let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
     debug!(?place, ?variant);
 
-    let fields = (0..n).map(|i| {
+    let mut fields = Vec::with_capacity(n);
+    for i in 0..n {
         let field = ecx.mplace_field(&place, i).unwrap();
-        const_to_valtree_inner(ecx, &field)
-    });
-    // For enums, we preped their variant index before the variant's fields so we can figure out
+        let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
+        fields.push(Some(valtree));
+    }
+
+    // For enums, we prepend their variant index before the variant's fields so we can figure out
     // the variant again when just seeing a valtree.
-    let branches = variant.into_iter().chain(fields);
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+    let branches = variant
+        .into_iter()
+        .chain(fields.into_iter())
+        .collect::<Option<Vec<_>>>()
+        .expect("should have already checked for errors in ValTree creation");
+
+    // Have to account for ZSTs here
+    if branches.len() == 0 {
+        *num_nodes += 1;
+    }
+
+    Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches)))
 }
 
 #[instrument(skip(ecx), level = "debug")]
 fn slice_branches<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let n = place.len(&ecx.tcx.tcx).expect(&format!("expected to use len of place {:?}", place));
-    let branches = (0..n).map(|i| {
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
+    let n = place
+        .len(&ecx.tcx.tcx)
+        .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place));
+
+    let mut elems = Vec::with_capacity(n as usize);
+    for i in 0..n {
         let place_elem = ecx.mplace_index(place, i).unwrap();
-        const_to_valtree_inner(ecx, &place_elem)
-    });
+        let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?;
+        elems.push(valtree);
+    }
 
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+    Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems)))
 }
 
 #[instrument(skip(ecx), level = "debug")]
-fn const_to_valtree_inner<'tcx>(
+pub(crate) fn const_to_valtree_inner<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    match place.layout.ty.kind() {
-        ty::FnDef(..) => Some(ty::ValTree::zst()),
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
+    if *num_nodes >= VALTREE_MAX_NODES {
+        return Err(ValTreeCreationError::NodesOverflow);
+    }
+
+    let ty = place.layout.ty;
+    debug!("ty kind: {:?}", ty.kind());
+
+    match ty.kind() {
+        ty::FnDef(..) => {
+            *num_nodes += 1;
+            Ok(ty::ValTree::zst())
+        }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
-            let val = ecx.read_immediate(&place.into()).unwrap();
+            let Ok(val) = ecx.read_immediate(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
             let val = val.to_scalar().unwrap();
-            Some(ty::ValTree::Leaf(val.assert_int()))
+            *num_nodes += 1;
+
+            Ok(ty::ValTree::Leaf(val.assert_int()))
         }
 
         // Raw pointers are not allowed in type level constants, as we cannot properly test them for
         // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
         // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
         // agree with runtime equality tests.
-        ty::FnPtr(_) | ty::RawPtr(_) => None,
+        ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
 
         ty::Ref(_, _, _)  => {
-            let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
+            let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
             debug!(?derefd_place);
 
-            const_to_valtree_inner(ecx, &derefd_place)
+            const_to_valtree_inner(ecx, &derefd_place, num_nodes)
         }
 
         ty::Str | ty::Slice(_) | ty::Array(_, _) => {
-            let valtree = slice_branches(ecx, place);
-            debug!(?valtree);
-
-            valtree
+            slice_branches(ecx, place, num_nodes)
         }
         // Trait objects are not allowed in type level constants, as we have no concept for
         // resolving their backing type, even if we can do that at const eval time. We may
         // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
         // but it is unclear if this is useful.
-        ty::Dynamic(..) => None,
+        ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
 
-        ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
+        ty::Tuple(elem_tys) => {
+            branches(ecx, place, elem_tys.len(), None, num_nodes)
+        }
 
         ty::Adt(def, _) => {
             if def.is_union() {
-                return None
+                return Err(ValTreeCreationError::NonSupportedType);
             } else if def.variants().is_empty() {
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
 
-            let variant = ecx.read_discriminant(&place.into()).unwrap().1;
-
-            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
+            let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
+            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
         }
 
         ty::Never
@@ -134,7 +154,7 @@ fn const_to_valtree_inner<'tcx>(
         // FIXME(oli-obk): we can probably encode closures just like structs
         | ty::Closure(..)
         | ty::Generator(..)
-        | ty::GeneratorWitness(..) => None,
+        | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
     }
 }
 
@@ -223,8 +243,11 @@ fn create_pointee_place<'tcx>(
             .unwrap();
         debug!(?ptr);
 
-        let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout);
-        place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64));
+        let place = MPlaceTy::from_aligned_ptr_with_meta(
+            ptr.into(),
+            layout,
+            MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
+        );
         debug!(?place);
 
         place
@@ -235,11 +258,11 @@ fn create_pointee_place<'tcx>(
 
 /// Converts a `ValTree` to a `ConstValue`, which is needed after mir
 /// construction has finished.
-// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function
+// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
 #[instrument(skip(tcx), level = "debug")]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    ty: Ty<'tcx>,
     valtree: ty::ValTree<'tcx>,
 ) -> ConstValue<'tcx> {
     // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
@@ -249,8 +272,8 @@ pub fn valtree_to_const_value<'tcx>(
     // create inner `MPlace`s which are filled recursively.
     // FIXME Does this need an example?
 
-    let (param_env, ty) = param_env_ty.into_parts();
-    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::empty(), false);
+    let param_env_ty = ty::ParamEnv::empty().and(ty);
 
     match ty.kind() {
         ty::FnDef(..) => {
@@ -273,7 +296,7 @@ pub fn valtree_to_const_value<'tcx>(
             };
             debug!(?place);
 
-            fill_place_recursively(&mut ecx, &mut place, valtree);
+            valtree_into_mplace(&mut ecx, &mut place, valtree);
             dump_place(&ecx, place.into());
             intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
 
@@ -315,7 +338,7 @@ pub fn valtree_to_const_value<'tcx>(
 
 // FIXME Needs a better/correct name
 #[instrument(skip(ecx), level = "debug")]
-fn fill_place_recursively<'tcx>(
+fn valtree_into_mplace<'tcx>(
     ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
     place: &mut MPlaceTy<'tcx>,
     valtree: ty::ValTree<'tcx>,
@@ -347,7 +370,7 @@ fn fill_place_recursively<'tcx>(
             let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
             debug!(?pointee_place);
 
-            fill_place_recursively(ecx, &mut pointee_place, valtree);
+            valtree_into_mplace(ecx, &mut pointee_place, valtree);
             dump_place(ecx, pointee_place.into());
             intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
 
@@ -435,7 +458,7 @@ fn fill_place_recursively<'tcx>(
                 };
 
                 debug!(?place_inner);
-                fill_place_recursively(ecx, &mut place_inner, *inner_valtree);
+                valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
                 dump_place(&ecx, place_inner.into());
             }
 
index 3ea3729dbcd17d765c1be73eba98948927cb08c5..92eeafc5df098f9cd3ff6eb4880ac310c5095ca4 100644 (file)
@@ -98,7 +98,7 @@ pub fn cast(
     }
 
     pub fn misc_cast(
-        &self,
+        &mut self,
         src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
@@ -139,7 +139,9 @@ pub fn misc_cast(
                 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
                     assert!(src.layout.is_zst());
                     let discr_layout = self.layout_of(discr.ty)?;
-                    return Ok(self.cast_from_int_like(discr.val, discr_layout, cast_ty).into());
+
+                    let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size());
+                    return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into());
                 }
             }
             Variants::Multiple { .. } => {}
@@ -170,38 +172,65 @@ pub fn misc_cast(
         }
 
         // # The remaining source values are scalar and "int-like".
+        let scalar = src.to_scalar()?;
+
+        // If we are casting from a pointer to something
+        // that is not a pointer, mark the pointer as exposed
+        if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() {
+            let ptr = self.scalar_to_ptr(scalar)?;
+
+            match ptr.into_pointer_or_addr() {
+                Ok(ptr) => {
+                    M::expose_ptr(self, ptr)?;
+                }
+                Err(_) => {
+                    // do nothing, exposing an invalid pointer
+                    // has no meaning
+                }
+            };
+        }
 
-        // For all remaining casts, we either
-        // (a) cast a raw ptr to usize, or
-        // (b) cast from an integer-like (including bool, char, enums).
-        // In both cases we want the bits.
-        let bits = src.to_scalar()?.to_bits(src.layout.size)?;
-        Ok(self.cast_from_int_like(bits, src.layout, cast_ty).into())
+        Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
 
-    fn cast_from_int_like(
+    pub fn cast_from_int_like(
         &self,
-        v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
+        scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
         src_layout: TyAndLayout<'tcx>,
         cast_ty: Ty<'tcx>,
-    ) -> Scalar<M::PointerTag> {
+    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
         // Let's make sure v is sign-extended *if* it has a signed type.
         let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
+
+        let v = scalar.to_bits(src_layout.size)?;
         let v = if signed { self.sign_extend(v, src_layout) } else { v };
         trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
         use rustc_middle::ty::TyKind::*;
-        match *cast_ty.kind() {
-            Int(_) | Uint(_) | RawPtr(_) => {
+
+        Ok(match *cast_ty.kind() {
+            Int(_) | Uint(_) => {
                 let size = match *cast_ty.kind() {
                     Int(t) => Integer::from_int_ty(self, t).size(),
                     Uint(t) => Integer::from_uint_ty(self, t).size(),
-                    RawPtr(_) => self.pointer_size(),
                     _ => bug!(),
                 };
                 let v = size.truncate(v);
                 Scalar::from_uint(v, size)
             }
 
+            RawPtr(_) => {
+                assert!(src_layout.ty.is_integral());
+
+                let size = self.pointer_size();
+                let addr = u64::try_from(size.truncate(v)).unwrap();
+
+                let ptr = M::ptr_from_addr_cast(&self, addr);
+                if addr == 0 {
+                    assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
+                }
+                Scalar::from_maybe_pointer(ptr, self)
+            }
+
             Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
             Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
             Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
@@ -214,7 +243,7 @@ fn cast_from_int_like(
 
             // Casts to bool are not permitted by rustc, no need to handle them here.
             _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
-        }
+        })
     }
 
     fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
index 827959113b90734ce321673ab5c56bbc359469d7..dfb81a2afc4f776bcf39388647d8912482b88d93 100644 (file)
@@ -905,7 +905,8 @@ fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult
             trace!(
                 "deallocating local {:?}: {:?}",
                 local,
-                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id())
+                // Locals always have a `alloc_id` (they are never the result of a int2ptr).
+                self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
             );
             self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
         };
@@ -1013,9 +1014,13 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                     }
                 }
 
-                write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs))
+                write!(
+                    fmt,
+                    ": {:?}",
+                    self.ecx.dump_allocs(allocs.into_iter().filter_map(|x| x).collect())
+                )
             }
-            Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) {
+            Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) {
                 Some(alloc_id) => write!(
                     fmt,
                     "by align({}) ref {:?}: {:?}",
index 058903dcdee55f90d0b8b807852173033082faff..5ece19d7fb3d34ef843da492817fc9d1e43d447c 100644 (file)
@@ -95,7 +95,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Allocate memory for `CallerLocation` struct.
         let loc_ty = self
             .tcx
-            .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
+            .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
             .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
         let loc_layout = self.layout_of(loc_ty).unwrap();
         // This can fail if rustc runs out of memory right here. Trying to emit an error would be
index 7721485771b3b0a121ea08e321b326889869d982..a79751ccb55b481af55bc6cd7bf1bfd038430d20 100644 (file)
@@ -286,19 +286,36 @@ fn tag_alloc_base_pointer(
     ) -> Pointer<Self::PointerTag>;
 
     /// "Int-to-pointer cast"
-    fn ptr_from_addr(
+    fn ptr_from_addr_cast(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         addr: u64,
     ) -> Pointer<Option<Self::PointerTag>>;
 
+    // FIXME: Transmuting an integer to a pointer should just always return a `None`
+    // provenance, but that causes problems with function pointers in Miri.
+    /// Hook for returning a pointer from a transmute-like operation on an addr.
+    fn ptr_from_addr_transmute(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        addr: u64,
+    ) -> Pointer<Option<Self::PointerTag>>;
+
+    /// Marks a pointer as exposed, allowing it's provenance
+    /// to be recovered. "Pointer-to-int cast"
+    fn expose_ptr(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        ptr: Pointer<Self::PointerTag>,
+    ) -> InterpResult<'tcx>;
+
     /// Convert a pointer with provenance into an allocation-offset pair
     /// and extra provenance info.
     ///
     /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
+    ///
+    /// When this fails, that means the pointer does not point to a live allocation.
     fn ptr_get_alloc(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer<Self::PointerTag>,
-    ) -> (AllocId, Size, Self::TagExtra);
+    ) -> Option<(AllocId, Size, Self::TagExtra)>;
 
     /// Called to initialize the "extra" state of an allocation and make the pointers
     /// it contains (in relocations) tagged.  The way we construct allocations is
@@ -480,7 +497,18 @@ fn tag_alloc_base_pointer(
     }
 
     #[inline(always)]
-    fn ptr_from_addr(_ecx: &InterpCx<$mir, $tcx, Self>, addr: u64) -> Pointer<Option<AllocId>> {
+    fn ptr_from_addr_transmute(
+        _ecx: &InterpCx<$mir, $tcx, Self>,
+        addr: u64,
+    ) -> Pointer<Option<AllocId>> {
+        Pointer::new(None, Size::from_bytes(addr))
+    }
+
+    #[inline(always)]
+    fn ptr_from_addr_cast(
+        _ecx: &InterpCx<$mir, $tcx, Self>,
+        addr: u64,
+    ) -> Pointer<Option<AllocId>> {
         Pointer::new(None, Size::from_bytes(addr))
     }
 
@@ -488,9 +516,9 @@ fn ptr_from_addr(_ecx: &InterpCx<$mir, $tcx, Self>, addr: u64) -> Pointer<Option
     fn ptr_get_alloc(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         ptr: Pointer<AllocId>,
-    ) -> (AllocId, Size, Self::TagExtra) {
+    ) -> Option<(AllocId, Size, Self::TagExtra)> {
         // We know `offset` is relative to the allocation, so we can use `into_parts`.
         let (alloc_id, offset) = ptr.into_parts();
-        (alloc_id, offset, ())
+        Some((alloc_id, offset, ()))
     }
 }
index b1d7ab6a098beccc7954322739b348f6551678d1..33162a01ed201358af5e910e383a10323ecdae8c 100644 (file)
@@ -770,7 +770,9 @@ pub fn leak_report(&self, static_roots: &[AllocId]) -> usize {
                 if reachable.insert(id) {
                     // This is a new allocation, add its relocations to `todo`.
                     if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
-                        todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id()));
+                        todo.extend(
+                            alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()),
+                        );
                     }
                 }
             }
@@ -805,7 +807,7 @@ fn write_allocation_track_relocs<'tcx, Tag: Provenance, Extra>(
             allocs_to_print: &mut VecDeque<AllocId>,
             alloc: &Allocation<Tag, Extra>,
         ) -> std::fmt::Result {
-            for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) {
+            for alloc_id in alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()) {
                 allocs_to_print.push_back(alloc_id);
             }
             write!(fmt, "{}", display_allocation(tcx, alloc))
@@ -1142,7 +1144,7 @@ pub fn scalar_to_ptr(
                 Err(ptr) => ptr.into(),
                 Ok(bits) => {
                     let addr = u64::try_from(bits).unwrap();
-                    let ptr = M::ptr_from_addr(&self, addr);
+                    let ptr = M::ptr_from_addr_transmute(&self, addr);
                     if addr == 0 {
                         assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
                     }
@@ -1182,10 +1184,14 @@ pub fn ptr_try_get_alloc_id(
         ptr: Pointer<Option<M::PointerTag>>,
     ) -> Result<(AllocId, Size, M::TagExtra), u64> {
         match ptr.into_pointer_or_addr() {
-            Ok(ptr) => {
-                let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr);
-                Ok((alloc_id, offset, extra))
-            }
+            Ok(ptr) => match M::ptr_get_alloc(self, ptr) {
+                Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)),
+                None => {
+                    assert!(M::PointerTag::OFFSET_IS_ADDR);
+                    let (_, addr) = ptr.into_parts();
+                    Err(addr.bytes())
+                }
+            },
             Err(addr) => Err(addr.bytes()),
         }
     }
index d627ddb39d00c685f953b67d9d2b7d4031c78697..5c85c86107fea3c8a2418f52c00b4337bbc84f3b 100644 (file)
@@ -741,17 +741,18 @@ pub fn read_discriminant(
         // Figure out which discriminant and variant this corresponds to.
         Ok(match *tag_encoding {
             TagEncoding::Direct => {
+                let scalar = tag_val.to_scalar()?;
                 // Generate a specific error if `tag_val` is not an integer.
                 // (`tag_bits` itself is only used for error messages below.)
-                let tag_bits = tag_val
-                    .to_scalar()?
+                let tag_bits = scalar
                     .try_to_int()
                     .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
                     .assert_bits(tag_layout.size);
                 // Cast bits from tag layout to discriminant layout.
-                // After the checks we did above, this cannot fail.
+                // After the checks we did above, this cannot fail, as
+                // discriminants are int-like.
                 let discr_val =
-                    self.misc_cast(&tag_val, discr_layout.ty).unwrap().to_scalar().unwrap();
+                    self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
                 let discr_bits = discr_val.assert_bits(discr_layout.size);
                 // Convert discriminant to variant index, and catch invalid discriminants.
                 let index = match *op.layout.ty.kind() {
index 95d6f431391fce86045b7b18eac1c645140a66c8..62f9c8f990d709bad5d6248ca44bea4968507b50 100644 (file)
@@ -115,12 +115,6 @@ fn deref(&self) -> &MemPlace<Tag> {
     }
 }
 
-impl<'tcx, Tag: Provenance> std::ops::DerefMut for MPlaceTy<'tcx, Tag> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.mplace
-    }
-}
-
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
@@ -196,6 +190,18 @@ pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) ->
         MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
     }
 
+    #[inline]
+    pub fn from_aligned_ptr_with_meta(
+        ptr: Pointer<Option<Tag>>,
+        layout: TyAndLayout<'tcx>,
+        meta: MemPlaceMeta<Tag>,
+    ) -> Self {
+        let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi);
+        mplace.meta = meta;
+
+        MPlaceTy { mplace, layout }
+    }
+
     #[inline]
     pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
@@ -495,7 +501,7 @@ pub(crate) fn mplace_downcast(
 
     /// Project into an mplace
     #[instrument(skip(self), level = "debug")]
-    pub(crate) fn mplace_projection(
+    pub(super) fn mplace_projection(
         &self,
         base: &MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
index c2664565f15cb18b7dce2a22621f7537769e2678..25f9d4baca30446b1743ccd910e0f6d83d77494f 100644 (file)
@@ -312,8 +312,8 @@ pub(crate) fn eval_fn_call(
         };
 
         match instance.def {
-            ty::InstanceDef::Intrinsic(..) => {
-                assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
+            ty::InstanceDef::Intrinsic(def_id) => {
+                assert!(self.tcx.is_intrinsic(def_id));
                 // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
                 M::call_intrinsic(self, instance, args, ret, unwind)
             }
index 2dab9ff89868f9114399dad2088594c8f1c90fd5..8770ed956e61f99ceee6929bb3df87c9c89ac541 100644 (file)
@@ -412,22 +412,27 @@ fn check_safe_pointer(
             self.path,
             err_ub!(AlignmentCheckFailed { required, has }) =>
                 {
-                    "an unaligned {} (required {} byte alignment but found {})",
-                    kind,
+                    "an unaligned {kind} (required {} byte alignment but found {})",
                     required.bytes(),
                     has.bytes()
                 },
             err_ub!(DanglingIntPointer(0, _)) =>
-                { "a null {}", kind },
+                { "a null {kind}" },
             err_ub!(DanglingIntPointer(i, _)) =>
-                { "a dangling {} (address 0x{:x} is unallocated)", kind, i },
+                { "a dangling {kind} (address 0x{i:x} is unallocated)" },
             err_ub!(PointerOutOfBounds { .. }) =>
-                { "a dangling {} (going beyond the bounds of its allocation)", kind },
+                { "a dangling {kind} (going beyond the bounds of its allocation)" },
             // This cannot happen during const-eval (because interning already detects
             // dangling pointers), but it can happen in Miri.
             err_ub!(PointerUseAfterFree(..)) =>
-                { "a dangling {} (use-after-free)", kind },
+                { "a dangling {kind} (use-after-free)" },
         );
+        // Do not allow pointers to uninhabited types.
+        if place.layout.abi.is_uninhabited() {
+            throw_validation_failure!(self.path,
+                { "a {kind} pointing to uninhabited type {}", place.layout.ty }
+            )
+        }
         // Recursive checking
         if let Some(ref mut ref_tracking) = self.ref_tracking {
             // Proceed recursively even for ZST, no reason to skip them!
index 1ab461a9421291ed788c7d36f37d728f5459b722..8b6689ca213ab0772acac31065e71b3eb1ecf8a9 100644 (file)
 pub mod util;
 
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::ParamEnv;
 
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
-    providers.try_destructure_const = |tcx, param_env_and_value| {
-        let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::try_destructure_const(tcx, param_env, value).ok()
+    providers.try_destructure_const = |tcx, param_env_and_val| {
+        let (param_env, c) = param_env_and_val.into_parts();
+        const_eval::try_destructure_const(tcx, param_env, c).ok()
     };
-    providers.const_to_valtree = |tcx, param_env_and_value| {
+    providers.eval_to_valtree = |tcx, param_env_and_value| {
         let (param_env, raw) = param_env_and_value.into_parts();
-        const_eval::const_to_valtree(tcx, param_env, raw)
+        const_eval::eval_to_valtree(tcx, param_env, raw)
     };
-    providers.valtree_to_const_val = |tcx, (ty, valtree)| {
-        const_eval::valtree_to_const_value(tcx, ParamEnv::empty().and(ty), valtree)
+    providers.try_destructure_mir_constant = |tcx, param_env_and_value| {
+        let (param_env, value) = param_env_and_value.into_parts();
+        const_eval::try_destructure_mir_constant(tcx, param_env, value).ok()
     };
+    providers.valtree_to_const_val =
+        |tcx, (ty, valtree)| const_eval::valtree_to_const_value(tcx, ty, valtree);
     providers.deref_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::deref_const(tcx, param_env, value)
     };
+    providers.deref_mir_constant = |tcx, param_env_and_value| {
+        let (param_env, value) = param_env_and_value.into_parts();
+        const_eval::deref_mir_constant(tcx, param_env, value)
+    };
 }
index 7e2a50444db062d24cf0b06757927c07c034ba38..1104bbf4716826d24aea7b647423598f90496a8c 100644 (file)
@@ -312,11 +312,7 @@ pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
 
             Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
                 let unstable_in_stable = self.ccx.is_const_stable_const_fn()
-                    && !super::rustc_allow_const_fn_unstable(
-                        self.tcx,
-                        self.def_id().to_def_id(),
-                        gate,
-                    );
+                    && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
                 if unstable_in_stable {
                     emit_unstable_in_stable_error(self.ccx, span, gate);
                 }
@@ -706,14 +702,12 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        use rustc_target::spec::abi::Abi::RustIntrinsic;
-
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
             TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
                 let ConstCx { tcx, body, param_env, .. } = *self.ccx;
-                let caller = self.def_id().to_def_id();
+                let caller = self.def_id();
 
                 let fn_ty = func.ty(body, tcx);
 
@@ -797,7 +791,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                             // trait.
                             let callee_trait = tcx.trait_of_item(callee);
                             if callee_trait.is_some()
-                                && tcx.has_attr(caller, sym::default_method_body_is_const)
+                                && tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const)
                                 && callee_trait == tcx.trait_of_item(caller)
                                 // Can only call methods when it's `<Self as TheTrait>::f`.
                                 && tcx.types.self_param == substs.type_at(0)
@@ -889,7 +883,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     return;
                 }
 
-                let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+                let is_intrinsic = tcx.is_intrinsic(callee);
 
                 if !tcx.is_const_fn_raw(callee) {
                     if tcx.trait_of_item(callee).is_some() {
index 25ba97ee60567d0ba3f882256925f77d89db5781..23e2afae79183bd1d15b0e9f84ff09f1510d6ded 100644 (file)
@@ -66,8 +66,12 @@ fn is_async(&self) -> bool {
     }
 }
 
-pub fn rustc_allow_const_fn_unstable(tcx: TyCtxt<'_>, def_id: DefId, feature_gate: Symbol) -> bool {
-    let attrs = tcx.get_attrs(def_id);
+pub fn rustc_allow_const_fn_unstable(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+    feature_gate: Symbol,
+) -> bool {
+    let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
     attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
 }
 
index ba248a3b6cbe59e286d9b84a1e21770f6c962c41..4e71baa77b0fd4a4d1ac6c8bf6323b2723d0f9af 100644 (file)
@@ -1,5 +1,6 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
+use hir::def_id::LocalDefId;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -88,14 +89,17 @@ fn build_error(
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
+        ccx.tcx.sess.struct_span_err(
+            span,
+            &format!("function pointer calls are not allowed in {}s", ccx.const_kind()),
+        )
     }
 }
 
 /// A function call where the callee is not marked as `const`.
 #[derive(Debug, Clone, Copy)]
 pub struct FnCallNonConst<'tcx> {
-    pub caller: DefId,
+    pub caller: LocalDefId,
     pub callee: DefId,
     pub substs: SubstsRef<'tcx>,
     pub span: Span,
@@ -117,13 +121,8 @@ fn build_error(
             match self_ty.kind() {
                 Param(param_ty) => {
                     debug!(?param_ty);
-                    if let Some(generics) = caller
-                        .as_local()
-                        .map(|id| tcx.hir().local_def_id_to_hir_id(id))
-                        .map(|id| tcx.hir().get(id))
-                        .as_ref()
-                        .and_then(|node| node.generics())
-                    {
+                    let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller);
+                    if let Some(generics) = tcx.hir().get(caller_hir_id).generics() {
                         let constraint = with_no_trimmed_paths!(format!(
                             "~const {}",
                             trait_ref.print_only_trait_path()
index 84689b3ece6104787ae318862eef80dab3c4e751..437dacaff22ec4c027dfab0b5c7709f7d91ad0f2 100644 (file)
@@ -1,6 +1,11 @@
+Some linking kinds are target-specific and not supported on all platforms.
+
 Linking with `kind=framework` is only supported when targeting macOS,
 as frameworks are specific to that operating system.
 
+Similarly, `kind=raw-dylib` is only supported when targeting Windows-like
+platforms.
+
 Erroneous code example:
 
 ```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos)
index 359aeb6fd9a0ab85a2b4dca71ac1b58431900951..1b280cba44f5331891078b046a0b8de89713ca16 100644 (file)
@@ -12,3 +12,4 @@ Please specify a valid "kind" value, from one of the following:
 * static
 * dylib
 * framework
+* raw-dylib
index 3143b81b6098f2b2aa580a716c77dc76748350cb..c98989b23c1a5edde8a615e7066103bc490e6903 100644 (file)
@@ -5,3 +5,12 @@ parser-struct-literal-body-without-path =
 parser-maybe-report-ambiguous-plus =
     ambiguous `+` in a type
     .suggestion = use parentheses to disambiguate
+
+parser-maybe-recover-from-bad-type-plus =
+    expected a path on the left-hand side of `+`, not `{$ty}`
+
+parser-add-paren = try adding parentheses
+
+parser-forgot-paren = perhaps you forgot parentheses?
+
+parser-expect-path = expected a path
index 9195d7a2b8f9248a1afd8e75be4bf67f7613d6eb..95b348ec61353e5bca87292dc00084aefae38d08 100644 (file)
@@ -99,6 +99,33 @@ typeck-explicit-generic-args-with-impl-trait =
     cannot provide explicit generic arguments when `impl Trait` is used in argument position
     .label = explicit generic argument not allowed
     .note = see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+    .help = add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
 
-typeck-explicit-generic-args-with-impl-trait-feature =
-    add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
+typeck-missing-type-params =
+    the type {$parameterCount ->
+        [one] parameter
+        *[other] parameters
+    } {$parameters} must be explicitly specified
+    .label = type {$parameterCount ->
+        [one] parameter
+        *[other] parameters
+    } {$parameters} must be specified for this
+    .suggestion = set the type {$parameterCount ->
+        [one] parameter
+        *[other] parameters
+    } to the desired {$parameterCount ->
+        [one] type
+        *[other] types
+    }
+    .no-suggestion-label = missing {$parameterCount ->
+        [one] reference
+        *[other] references
+    } to {$parameters}
+    .note = because of the default `Self` reference, type parameters must be specified on object types
+
+typeck-manual-implementation =
+    manual implementations of `{$trait_name}` are experimental
+    .label = manual implementations of `{$trait_name}` are experimental
+    .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
+typeck-substs-on-overridden-impl = could not resolve substs on overridden impl
index 83e6a751394f5a44c9227b8eb1a68ef9f91c6a19..909ed566f64ea9c45d11b234bed23a6269f44174 100644 (file)
@@ -821,9 +821,9 @@ pub fn args(&self) -> &[DiagnosticArg<'static>] {
     pub fn set_arg(
         &mut self,
         name: impl Into<Cow<'static, str>>,
-        arg: DiagnosticArgValue<'static>,
+        arg: impl IntoDiagnosticArg,
     ) -> &mut Self {
-        self.args.push((name.into(), arg));
+        self.args.push((name.into(), arg.into_diagnostic_arg()));
         self
     }
 
index 96b730c2baaffd6885518af9e50c8d20c4e36f14..53ad6e5a0edea56ce07c06bb7a2e3188024e1a38 100644 (file)
@@ -1,4 +1,4 @@
-use crate::diagnostic::DiagnosticArgValue;
+use crate::diagnostic::IntoDiagnosticArg;
 use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed};
 use crate::{Handler, Level, MultiSpan, StashKey};
 use rustc_lint_defs::Applicability;
@@ -528,7 +528,7 @@ pub fn span_labels(
     forward!(pub fn set_arg(
         &mut self,
         name: impl Into<Cow<'static, str>>,
-        arg: DiagnosticArgValue<'static>,
+        arg: impl IntoDiagnosticArg,
     ) -> &mut Self);
 
     forward!(pub fn subdiagnostic(
index 29f354d572802bc0664b0df3ff79732d9e415912..ddfbef945efaa29bbef4a0ce98812f0304e36b35 100644 (file)
@@ -76,6 +76,7 @@
 use crate::mbe::{KleeneOp, TokenTree};
 
 use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
+use rustc_lint_defs::pluralize;
 use rustc_parse::parser::{NtOrTt, Parser};
 use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
@@ -668,8 +669,7 @@ fn ambiguity_error(
                 self.macro_name,
                 match self.next_mps.len() {
                     0 => format!("built-in NTs {}.", nts),
-                    1 => format!("built-in NTs {} or 1 other option.", nts),
-                    n => format!("built-in NTs {} or {} other options.", nts, n),
+                    n => format!("built-in NTs {} or {n} other option{s}.", nts, s = pluralize!(n)),
                 }
             ),
         )
index ba0b35470b6ba5645b84f00b387e701f19dfc478..4cc3169180ea5ea01638bd0f83c7afd09512a792 100644 (file)
@@ -175,7 +175,7 @@ fn expand<'cx>(
         if !self.valid {
             return DummyResult::any(sp);
         }
-        generic_extension(
+        expand_macro(
             cx,
             sp,
             self.span,
@@ -202,8 +202,9 @@ fn trace_macros_note(cx_expansions: &mut FxHashMap<Span, Vec<String>>, sp: Span,
     cx_expansions.entry(sp).or_default().push(message);
 }
 
-/// Given `lhses` and `rhses`, this is the new macro we create
-fn generic_extension<'cx, 'tt>(
+/// Expands the rules based macro defined by `lhses` and `rhses` for a given
+/// input `arg`.
+fn expand_macro<'cx, 'tt>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     def_span: Span,
index c5f42aa7af72438e85ee45a71d60ed7e7814f0bb..097493e8985fb25ea4c8ec5339b57a940db871f8 100644 (file)
@@ -147,6 +147,16 @@ pub enum AttributeDuplicates {
     FutureWarnPreceding,
 }
 
+/// A conveniece macro to deal with `$($expr)?`.
+macro_rules! or_default {
+    ($default:expr,) => {
+        $default
+    };
+    ($default:expr, $next:expr) => {
+        $next
+    };
+}
+
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
@@ -168,9 +178,10 @@ macro_rules! template {
 }
 
 macro_rules! ungated {
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)? $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            only_local: or_default!(false, $($only_local)?),
             type_: $typ,
             template: $tpl,
             gate: Ungated,
@@ -180,18 +191,20 @@ macro_rules! ungated {
 }
 
 macro_rules! gated {
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $gate:ident, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $gate:ident, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            only_local: or_default!(false, $($only_local)?),
             type_: $typ,
             template: $tpl,
             duplicates: $duplicates,
             gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
         }
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            only_local: or_default!(false, $($only_local)?),
             type_: $typ,
             template: $tpl,
             duplicates: $duplicates,
@@ -201,12 +214,13 @@ macro_rules! gated {
 }
 
 macro_rules! rustc_attr {
-    (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(,)?) => {
+    (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(, @only_local: $only_local:expr)? $(,)?) => {
         rustc_attr!(
             $attr,
             $typ,
             $tpl,
             $duplicate,
+            $(@only_local: $only_local,)?
             concat!(
                 "the `#[",
                 stringify!($attr),
@@ -215,9 +229,10 @@ macro_rules! rustc_attr {
             ),
         )
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
+            only_local: or_default!(false, $($only_local)?),
             type_: $typ,
             template: $tpl,
             duplicates: $duplicates,
@@ -237,6 +252,10 @@ macro_rules! experimental {
 
 pub struct BuiltinAttribute {
     pub name: Symbol,
+    /// Whether this attribute is only used in the local crate.
+    ///
+    /// If so, it is not encoded in the crate metadata.
+    pub only_local: bool,
     pub type_: AttributeType,
     pub template: AttributeTemplate,
     pub duplicates: AttributeDuplicates,
@@ -295,7 +314,7 @@ pub struct BuiltinAttribute {
     ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
     gated!(
         must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
-        must_not_suspend, experimental!(must_not_suspend)
+        experimental!(must_not_suspend)
     ),
     ungated!(
         deprecated, Normal,
@@ -324,8 +343,8 @@ pub struct BuiltinAttribute {
     ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
     ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
-    ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
-    ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing),
+    ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
+    ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true),
 
     // Limits:
     ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
@@ -358,8 +377,8 @@ pub struct BuiltinAttribute {
     ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
 
     // Code generation:
-    ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
-    ungated!(cold, Normal, template!(Word), WarnFollowing),
+    ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
+    ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
     ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
     ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
     ungated!(track_caller, Normal, template!(Word), WarnFollowing),
@@ -385,7 +404,7 @@ pub struct BuiltinAttribute {
     ),
 
     // Linking:
-    gated!(naked, Normal, template!(Word), WarnFollowing, naked_functions, experimental!(naked)),
+    gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)),
     gated!(
         link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
         experimental!(link_ordinal)
@@ -394,6 +413,7 @@ pub struct BuiltinAttribute {
     // Plugins:
     BuiltinAttribute {
         name: sym::plugin,
+        only_local: false,
         type_: CrateLevel,
         template: template!(List: "name"),
         duplicates: DuplicatesOk,
@@ -475,7 +495,7 @@ pub struct BuiltinAttribute {
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
-        stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk
+        stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
     ),
     ungated!(
         unstable, Normal,
@@ -546,11 +566,11 @@ pub struct BuiltinAttribute {
     // ==========================================================================
 
     gated!(
-        linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding,
+        linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, @only_local: true,
         "the `linkage` attribute is experimental and not portable across platforms",
     ),
     rustc_attr!(
-        rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
+        rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, @only_local: true, INTERNAL_UNSTABLE
     ),
 
     // ==========================================================================
@@ -633,7 +653,7 @@ pub struct BuiltinAttribute {
     // Internal attributes, Misc:
     // ==========================================================================
     gated!(
-        lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
+        lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, @only_local: true, lang_items,
         "language items are subject to change",
     ),
     rustc_attr!(
@@ -642,11 +662,11 @@ pub struct BuiltinAttribute {
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
     ),
     rustc_attr!(
-        rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing,
+        rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
         "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
     ),
     rustc_attr!(
-        rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing,
+        rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
         "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
     ),
     rustc_attr!(
@@ -656,6 +676,8 @@ pub struct BuiltinAttribute {
     ),
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
+        // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
+        only_local: false,
         type_: Normal,
         template: template!(NameValueStr: "name"),
         duplicates: ErrorFollowing,
@@ -676,7 +698,7 @@ pub struct BuiltinAttribute {
         "unboxed_closures are still evolving",
     ),
     rustc_attr!(
-        rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing,
+        rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true,
         "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
         overflow checking behavior of several libcore functions that are inlined \
         across crates and will never be stable",
@@ -778,6 +800,10 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
+pub fn is_builtin_only_local(name: Symbol) -> bool {
+    BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
+}
+
 pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> =
     SyncLazy::new(|| {
         let mut map = FxHashMap::default();
index 940c4ecdcc23a07b5106f74ef5c7da35c77b371a..26e0538b0eb4e8e4618265aa30b81d10e38e2a40 100644 (file)
@@ -149,7 +149,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU3
 pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
 pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
-    deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate,
-    AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
+    AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
+    BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
index e318090ebe15aec658917b35b2c4b903589f3a01..676c66f41a9ae9eb8c19c413b72f99fdd298a1ef 100644 (file)
@@ -4,18 +4,16 @@
 //! use with [Graphviz](https://www.graphviz.org/) by walking a labeled
 //! graph. (Graphviz can then automatically lay out the nodes and edges
 //! of the graph, and also optionally render the graph as an image or
-//! other [output formats](
-//! https://www.graphviz.org/content/output-formats), such as SVG.)
+//! other [output formats](https://www.graphviz.org/docs/outputs), such as SVG.)
 //!
 //! Rather than impose some particular graph data structure on clients,
 //! this library exposes two traits that clients can implement on their
 //! own structs before handing them over to the rendering function.
 //!
 //! Note: This library does not yet provide access to the full
-//! expressiveness of the [DOT language](
-//! https://www.graphviz.org/doc/info/lang.html). For example, there are
-//! many [attributes](https://www.graphviz.org/content/attrs) related to
-//! providing layout hints (e.g., left-to-right versus top-down, which
+//! expressiveness of the [DOT language](https://www.graphviz.org/doc/info/lang.html).
+//! For example, there are many [attributes](https://www.graphviz.org/doc/info/attrs.html)
+//! related to providing layout hints (e.g., left-to-right versus top-down, which
 //! algorithm to use, etc). The current intention of this library is to
 //! emit a human-readable .dot file with very regular structure suitable
 //! for easy post-processing.
@@ -292,7 +290,7 @@ pub enum LabelText<'a> {
     LabelStr(Cow<'a, str>),
 
     /// This kind of label uses the graphviz label escString type:
-    /// <https://www.graphviz.org/content/attrs#kescString>
+    /// <https://www.graphviz.org/docs/attr-types/escString>
     ///
     /// Occurrences of backslashes (`\`) are not escaped; instead they
     /// are interpreted as initiating an escString escape sequence.
@@ -307,12 +305,12 @@ pub enum LabelText<'a> {
     /// printed exactly as given, but between `<` and `>`. **No
     /// escaping is performed.**
     ///
-    /// [html]: https://www.graphviz.org/content/node-shapes#html
+    /// [html]: https://www.graphviz.org/doc/info/shapes.html#html
     HtmlStr(Cow<'a, str>),
 }
 
 /// The style for a node or edge.
-/// See <https://www.graphviz.org/doc/info/attrs.html#k:style> for descriptions.
+/// See <https://www.graphviz.org/docs/attr-types/style/> for descriptions.
 /// Note that some of these are not valid for edges.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum Style {
@@ -439,7 +437,7 @@ pub trait Labeller<'a> {
     /// Maps `n` to one of the [graphviz `shape` names][1]. If `None`
     /// is returned, no `shape` attribute is specified.
     ///
-    /// [1]: https://www.graphviz.org/content/node-shapes
+    /// [1]: https://www.graphviz.org/doc/info/shapes.html
     fn node_shape(&'a self, _node: &Self::Node) -> Option<LabelText<'a>> {
         None
     }
index bce9ba12ac0c424045e391a05f420f714307d4f7..5c32dd372dde1c0278b93eeab74ccddf3e118fa3 100644 (file)
@@ -261,14 +261,16 @@ pub enum DefPathData {
     // they are treated specially by the `def_path` function.
     /// The crate root (marker).
     CrateRoot,
-    // Catch-all for random `DefId` things like `DUMMY_NODE_ID`.
-    Misc,
 
     // Different kinds of items and item-like things:
     /// An impl.
     Impl,
     /// An `extern` block.
     ForeignMod,
+    /// A `use` item.
+    Use,
+    /// A global asm item.
+    GlobalAsm,
     /// Something in the type namespace.
     TypeNs(Symbol),
     /// Something in the value namespace.
@@ -443,9 +445,8 @@ pub fn get_opt_name(&self) -> Option<Symbol> {
         match *self {
             TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
 
-            Impl | ForeignMod | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => {
-                None
-            }
+            Impl | ForeignMod | CrateRoot | Use | GlobalAsm | ClosureExpr | Ctor | AnonConst
+            | ImplTrait => None,
         }
     }
 
@@ -459,7 +460,8 @@ pub fn name(&self) -> DefPathDataName {
             CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
             Impl => DefPathDataName::Anon { namespace: kw::Impl },
             ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
-            Misc => DefPathDataName::Anon { namespace: sym::misc },
+            Use => DefPathDataName::Anon { namespace: kw::Use },
+            GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
             ClosureExpr => DefPathDataName::Anon { namespace: sym::closure },
             Ctor => DefPathDataName::Anon { namespace: sym::constructor },
             AnonConst => DefPathDataName::Anon { namespace: sym::constant },
index 4d4d4a28499af439e1a881202a6b305a2a1f4993..81d544c7b96dcf13bd5b722700d7a6099c589d2b 100644 (file)
@@ -1320,8 +1320,7 @@ pub struct Let<'hir> {
 #[derive(Debug, HashStable_Generic)]
 pub enum Guard<'hir> {
     If(&'hir Expr<'hir>),
-    // FIXME use hir::Let for this.
-    IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>),
+    IfLet(&'hir Let<'hir>),
 }
 
 #[derive(Debug, HashStable_Generic)]
index 977c0eb3cd2bcf11075dc2668488ab009855fdcd..5b83a29bb33c30bc027398b9068ba7632085e9a3 100644 (file)
@@ -1,7 +1,40 @@
 //! HIR walker for walking the contents of nodes.
 //!
-//! **For an overview of the visitor strategy, see the docs on the
-//! `super::itemlikevisit::ItemLikeVisitor` trait.**
+//! Here are the three available patterns for the visitor strategy,
+//! in roughly the order of desirability:
+//!
+//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
+//!    - Example: find all items with a `#[foo]` attribute on them.
+//!    - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
+//!       (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
+//!       access actual item-like thing, respectively.
+//!    - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
+//!       the hir_owners themselves or not.
+//!    - Con: Don't get information about nesting
+//!    - Con: Don't have methods for specific bits of HIR, like "on
+//!      every expr, do this".
+//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
+//!    an item, but don't care about how item-like things are nested
+//!    within one another.
+//!    - Example: Examine each expression to look for its type and do some check or other.
+//!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+//!      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
+//!      `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your
+//!      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
+//!      `intravisit::walk_expr()` to keep walking the subparts).
+//!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+//!    - Pro: Integrates well into dependency tracking.
+//!    - Con: Don't get information about nesting between items
+//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
+//!    item-like things.
+//!    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
+//!      impl into scope while visiting the impl-items, and then back out again.
+//!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+//!      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
+//!      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
+//!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+//!    - Pro: Preserves nesting information
+//!    - Con: Does not integrate well into dependency tracking.
 //!
 //! If you have decided to use this visitor, here are some general
 //! notes on how to do so:
 //! example generator inference, and possibly also HIR borrowck.
 
 use crate::hir::*;
-use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
+use crate::itemlikevisit::ParItemLikeVisitor;
 use rustc_ast::walk_list;
 use rustc_ast::{Attribute, Label};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
-pub struct DeepVisitor<'v, V> {
-    visitor: &'v mut V,
-}
-
-impl<'v, V> DeepVisitor<'v, V> {
-    pub fn new(base: &'v mut V) -> Self {
-        DeepVisitor { visitor: base }
-    }
-}
-
-impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
-where
-    V: Visitor<'hir>,
-{
-    fn visit_item(&mut self, item: &'hir Item<'hir>) {
-        self.visitor.visit_item(item);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) {
-        self.visitor.visit_trait_item(trait_item);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
-        self.visitor.visit_impl_item(impl_item);
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) {
-        self.visitor.visit_foreign_item(foreign_item);
-    }
-}
-
 pub trait IntoVisitor<'hir> {
     type Visitor: Visitor<'hir>;
     fn into_visitor(&self) -> Self::Visitor;
@@ -315,16 +317,6 @@ fn visit_body(&mut self, b: &'v Body<'v>) {
         walk_body(self, b);
     }
 
-    /// When invoking `visit_all_item_likes()`, you need to supply an
-    /// item-like visitor. This method converts an "intra-visit"
-    /// visitor into an item-like visitor that walks the entire tree.
-    /// If you use this, you probably don't want to process the
-    /// contents of nested item-like things, since the outer loop will
-    /// visit them as well.
-    fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> {
-        DeepVisitor::new(self)
-    }
-
     ///////////////////////////////////////////////////////////////////////////
 
     fn visit_id(&mut self, _hir_id: HirId) {
@@ -1233,9 +1225,8 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
     if let Some(ref g) = arm.guard {
         match g {
             Guard::If(ref e) => visitor.visit_expr(e),
-            Guard::IfLet(ref pat, ref e) => {
-                visitor.visit_pat(pat);
-                visitor.visit_expr(e);
+            Guard::IfLet(ref l) => {
+                visitor.visit_let_expr(l);
             }
         }
     }
index b2c6ca1354f107204af0e517e424135d8da00b8c..a490268dc9f94d46b4b6d8edca2ade54a807e656 100644 (file)
@@ -1,55 +1,5 @@
 use super::{ForeignItem, ImplItem, Item, TraitItem};
 
-/// The "item-like visitor" defines only the top-level methods
-/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
-/// this trait is the right one to implement will depend on the
-/// overall pattern you need. Here are the three available patterns,
-/// in roughly the order of desirability:
-///
-/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
-///    - Example: find all items with a `#[foo]` attribute on them.
-///    - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
-///    - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
-///    - Con: Don't get information about nesting
-///    - Con: Don't have methods for specific bits of HIR, like "on
-///      every expr, do this".
-/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
-///    an item, but don't care about how item-like things are nested
-///    within one another.
-///    - Example: Examine each expression to look for its type and do some check or other.
-///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-///      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
-///      `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
-///      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
-///      `intravisit::walk_expr()` to keep walking the subparts).
-///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
-///    - Pro: Integrates well into dependency tracking.
-///    - Con: Don't get information about nesting between items
-/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
-///    item-like things.
-///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
-///      impl into scope while visiting the impl-items, and then back out again.
-///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-///      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
-///      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
-///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
-///    - Pro: Preserves nesting information
-///    - Con: Does not integrate well into dependency tracking.
-///
-/// Note: the methods of `ItemLikeVisitor` intentionally have no
-/// defaults, so that as we expand the list of item-like things, we
-/// revisit the various visitors to see if they need to change. This
-/// is harder to do with `intravisit::Visitor`, so when you add a new
-/// `visit_nested_foo()` method, it is recommended that you search for
-/// existing `fn visit_nested` methods to see where changes are
-/// needed.
-pub trait ItemLikeVisitor<'hir> {
-    fn visit_item(&mut self, item: &'hir Item<'hir>);
-    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
-    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
-    fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>);
-}
-
 /// A parallel variant of `ItemLikeVisitor`.
 pub trait ParItemLikeVisitor<'hir> {
     fn visit_item(&self, item: &'hir Item<'hir>);
index 7af9622b2cf76753b142dd3d1fcfeceaabb5a4da..4558a3d10c4fbf2b2d8663ff17fc6d24ae244e01 100644 (file)
@@ -1915,14 +1915,9 @@ pub fn print_arm(&mut self, arm: &hir::Arm<'_>) {
                     self.print_expr(&e);
                     self.space();
                 }
-                hir::Guard::IfLet(pat, e) => {
+                hir::Guard::IfLet(hir::Let { pat, ty, init, .. }) => {
                     self.word_nbsp("if");
-                    self.word_nbsp("let");
-                    self.print_pat(&pat);
-                    self.space();
-                    self.word_space("=");
-                    self.print_expr(&e);
-                    self.space();
+                    self.print_let(pat, *ty, init);
                 }
             }
         }
index f69ae8ebe410fd6139d7f15e4c8b3ed3b1c4befc..a89b9eafaa62d6e24825306622e6aeff2ed9c939 100644 (file)
@@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
             visitor.process_attrs(hir::CRATE_HIR_ID);
-            tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor());
+            tcx.hir().deep_visit_all_item_likes(&mut visitor);
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
 
index aaf24636598b9c98a95574ee7def5b42fd869768..424164d8760c4e8176a351416ca8ec105f1ffca3 100644 (file)
@@ -183,10 +183,7 @@ pub struct DirtyCleanVisitor<'tcx> {
 impl<'tcx> DirtyCleanVisitor<'tcx> {
     /// Possibly "deserialize" the attribute into a clean/dirty assertion
     fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
-        if !attr.has_name(sym::rustc_clean) {
-            // skip: not rustc_clean/dirty
-            return None;
-        }
+        assert!(attr.has_name(sym::rustc_clean));
         if !check_config(self.tcx, attr) {
             // skip: not the correct `cfg=`
             return None;
@@ -384,7 +381,7 @@ fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) {
     fn check_item(&mut self, item_id: LocalDefId) {
         let item_span = self.tcx.def_span(item_id.to_def_id());
         let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
-        for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
+        for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) {
             let Some(assertion) = self.assertion_maybe(item_id, attr) else {
                 continue;
             };
index ed504938e8aa7f6948301c5c75851a21838b47a9..347c88560225609908f377032cf9d1853eb8ccce 100644 (file)
@@ -70,7 +70,7 @@ pub fn insert(&mut self, point: I) -> bool {
     /// Returns true if we increased the number of elements present.
     pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
         let start = inclusive_start(range.clone());
-        let Some(mut end) = inclusive_end(self.domain, range) else {
+        let Some(end) = inclusive_end(self.domain, range) else {
             // empty range
             return false;
         };
@@ -78,59 +78,56 @@ pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
             return false;
         }
 
-        loop {
-            // This condition looks a bit weird, but actually makes sense.
-            //
-            // if r.0 == end + 1, then we're actually adjacent, so we want to
-            // continue to the next range. We're looking here for the first
-            // range which starts *non-adjacently* to our end.
-            let next = self.map.partition_point(|r| r.0 <= end + 1);
-            if let Some(last) = next.checked_sub(1) {
-                let (prev_start, prev_end) = &mut self.map[last];
-                if *prev_end + 1 >= start {
-                    // If the start for the inserted range is adjacent to the
-                    // end of the previous, we can extend the previous range.
-                    if start < *prev_start {
-                        // Our range starts before the one we found. We'll need
-                        // to *remove* it, and then try again.
-                        //
-                        // FIXME: This is not so efficient; we may need to
-                        // recurse a bunch of times here. Instead, it's probably
-                        // better to do something like drain_filter(...) on the
-                        // map to be able to delete or modify all the ranges in
-                        // start..=end and then potentially re-insert a new
-                        // range.
-                        end = std::cmp::max(end, *prev_end);
-                        self.map.remove(last);
-                    } else {
-                        // We overlap with the previous range, increase it to
-                        // include us.
-                        //
-                        // Make sure we're actually going to *increase* it though --
-                        // it may be that end is just inside the previously existing
-                        // set.
-                        return if end > *prev_end {
-                            *prev_end = end;
-                            true
-                        } else {
-                            false
-                        };
+        // This condition looks a bit weird, but actually makes sense.
+        //
+        // if r.0 == end + 1, then we're actually adjacent, so we want to
+        // continue to the next range. We're looking here for the first
+        // range which starts *non-adjacently* to our end.
+        let next = self.map.partition_point(|r| r.0 <= end + 1);
+        if let Some(right) = next.checked_sub(1) {
+            let (prev_start, prev_end) = self.map[right];
+            if prev_end + 1 >= start {
+                // If the start for the inserted range is adjacent to the
+                // end of the previous, we can extend the previous range.
+                if start < prev_start {
+                    // The first range which ends *non-adjacently* to our start.
+                    // And we can ensure that left <= right.
+                    let left = self.map.partition_point(|l| l.1 + 1 < start);
+                    let min = std::cmp::min(self.map[left].0, start);
+                    let max = std::cmp::max(prev_end, end);
+                    self.map[right] = (min, max);
+                    if left != right {
+                        self.map.drain(left..right);
                     }
-                } else {
-                    // Otherwise, we don't overlap, so just insert
-                    self.map.insert(last + 1, (start, end));
                     return true;
-                }
-            } else {
-                if self.map.is_empty() {
-                    // Quite common in practice, and expensive to call memcpy
-                    // with length zero.
-                    self.map.push((start, end));
                 } else {
-                    self.map.insert(next, (start, end));
+                    // We overlap with the previous range, increase it to
+                    // include us.
+                    //
+                    // Make sure we're actually going to *increase* it though --
+                    // it may be that end is just inside the previously existing
+                    // set.
+                    return if end > prev_end {
+                        self.map[right].1 = end;
+                        true
+                    } else {
+                        false
+                    };
                 }
+            } else {
+                // Otherwise, we don't overlap, so just insert
+                self.map.insert(right + 1, (start, end));
                 return true;
             }
+        } else {
+            if self.map.is_empty() {
+                // Quite common in practice, and expensive to call memcpy
+                // with length zero.
+                self.map.push((start, end));
+            } else {
+                self.map.insert(next, (start, end));
+            }
+            return true;
         }
     }
 
index aa3f0600cccc850fe1317421fde9738382392f55..534106ac446cf8b147f4d73a3e9d615ce874e27e 100644 (file)
@@ -776,21 +776,6 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
     fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
 }
 
-pub trait RelateResultCompare<'tcx, T> {
-    fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
-    where
-        F: FnOnce() -> TypeError<'tcx>;
-}
-
-impl<'tcx, T: Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
-    fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
-    where
-        F: FnOnce() -> TypeError<'tcx>,
-    {
-        self.clone().and_then(|s| if s == t { self.clone() } else { Err(f()) })
-    }
-}
-
 pub fn const_unification_error<'tcx>(
     a_is_expected: bool,
     (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
index af81f5cde2c41778bbdcdb14f94006ab65b140b3..02caae7a90a91d5185e367273793cdd63fdc9a1e 100644 (file)
@@ -70,7 +70,7 @@
     self,
     error::TypeError,
     subst::{GenericArgKind, Subst, SubstsRef},
-    Binder, List, Region, Ty, TyCtxt, TypeFoldable,
+    Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
@@ -961,12 +961,14 @@ fn strip_generic_default_params(
         for (def_id, actual) in iter::zip(default_params, substs.iter().rev()) {
             match actual.unpack() {
                 GenericArgKind::Const(c) => {
-                    if self.tcx.const_param_default(def_id).subst(self.tcx, substs) != c {
+                    if EarlyBinder(self.tcx.const_param_default(def_id)).subst(self.tcx, substs)
+                        != c
+                    {
                         break;
                     }
                 }
                 GenericArgKind::Type(ty) => {
-                    if self.tcx.type_of(def_id).subst(self.tcx, substs) != ty {
+                    if self.tcx.bound_type_of(def_id).subst(self.tcx, substs) != ty {
                         break;
                     }
                 }
@@ -1383,8 +1385,8 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2);
                 let mut values = self.cmp_fn_sig(&sig1, &sig2);
                 let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1));
                 let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2));
@@ -1395,7 +1397,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1);
                 let mut values = self.cmp_fn_sig(&sig1, sig2);
                 values.0.push_highlighted(format!(
                     " {{{}}}",
@@ -1405,7 +1407,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => {
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2);
                 let mut values = self.cmp_fn_sig(sig1, &sig2);
                 values.1.push_normal(format!(
                     " {{{}}}",
@@ -1847,9 +1849,9 @@ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<
             // Future::Output
             let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
-            let bounds = self.tcx.explicit_item_bounds(*def_id);
+            let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
 
-            for (predicate, _) in bounds {
+            for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
                 let predicate = predicate.subst(self.tcx, substs);
                 let output = predicate
                     .kind()
index 78e0864d918d99360d8d8fe47a3b10aea2845d0e..62edfc6495cf655d3facdb2fbeaa81d3b28f46c6 100644 (file)
@@ -739,7 +739,7 @@ pub fn emit_inference_failure_err(
                 {
                     let mut eraser = TypeParamEraser(self.tcx);
                     let candidate_len = impl_candidates.len();
-                    let mut suggestions: Vec<_> = impl_candidates.iter().map(|candidate| {
+                    let mut suggestions: Vec<_> = impl_candidates.iter().filter_map(|candidate| {
                         let trait_item = self.tcx
                             .associated_items(candidate.def_id)
                             .find_by_name_and_kind(
@@ -748,6 +748,9 @@ pub fn emit_inference_failure_err(
                                 ty::AssocKind::Fn,
                                 candidate.def_id
                             );
+                        if trait_item.is_none() {
+                            return None;
+                        }
                         let prefix = if let Some(trait_item) = trait_item
                             && let Some(trait_m) = trait_item.def_id.as_local()
                             && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind
@@ -761,24 +764,26 @@ pub fn emit_inference_failure_err(
                             ""
                         };
                         let candidate = candidate.super_fold_with(&mut eraser);
-                        vec![
+                        Some(vec![
                             (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)),
                             if exprs.len() == 1 {
                                 (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
                             } else {
                                 (expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
                             },
-                        ]
+                        ])
                     }).collect();
                     suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
-                    err.multipart_suggestions(
-                        &format!(
-                            "use the fully qualified path for the potential candidate{}",
-                            pluralize!(candidate_len),
-                        ),
-                        suggestions.into_iter(),
-                        Applicability::MaybeIncorrect,
-                    );
+                    if !suggestions.is_empty() {
+                        err.multipart_suggestions(
+                            &format!(
+                                "use the fully qualified path for the potential candidate{}",
+                                pluralize!(candidate_len),
+                            ),
+                            suggestions.into_iter(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
                 // Suggest specifying type params or point out the return type of the call:
                 //
index 94a795f613e9dbfa08da38aae9ed373a92376dcd..6592e0ae8ec8f66c7e0fef7505d8786bce0cc93b 100644 (file)
@@ -859,7 +859,7 @@ struct TypeGeneralizer<'me, 'tcx, D>
 
     delegate: &'me mut D,
 
-    /// After we generalize this type, we are going to relative it to
+    /// After we generalize this type, we are going to relate it to
     /// some other type. What will be the variance at this point?
     ambient_variance: ty::Variance,
 
index d25484efabc5fd613c1eb76817ab68855008177a..92c0ed84057a6f572478c1669860963ca6c1256f 100644 (file)
@@ -561,9 +561,9 @@ pub fn register_hidden_type(
             obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
         }
 
-        let item_bounds = tcx.explicit_item_bounds(def_id);
+        let item_bounds = tcx.bound_explicit_item_bounds(def_id);
 
-        for (predicate, _) in item_bounds {
+        for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
             debug!(?predicate);
             let predicate = predicate.subst(tcx, substs);
 
index ab565d4396191bd60ecbd2cf7e16072870c02577..1c521c90686d6c0bf3392268bd405bd94fd29312 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
 /// obligation into a series of `'a: 'b` constraints and "verifys", as
@@ -290,7 +290,7 @@ fn declared_projection_bounds_from_trait(
         debug!("projection_bounds(projection_ty={:?})", projection_ty);
         let tcx = self.tcx;
         self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
-            .map(move |r| r.subst(tcx, projection_ty.substs))
+            .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
     }
 
     /// Given the `DefId` of an associated item, returns any region
index 85bb727a6c8048dac439d5ff02d65dbec78f089e..4df4de21a0f0789666f663b879ddde3f12f5f32c 100644 (file)
@@ -69,7 +69,7 @@ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tc
     }
 }
 
-impl TraitObligation<'_> {
+impl<'tcx> TraitObligation<'tcx> {
     /// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
     pub fn is_const(&self) -> bool {
         match (self.predicate.skip_binder().constness, self.param_env.constness()) {
@@ -77,6 +77,13 @@ pub fn is_const(&self) -> bool {
             _ => false,
         }
     }
+
+    pub fn derived_cause(
+        &self,
+        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        self.cause.clone().derived_cause(self.predicate, variant)
+    }
 }
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
index 22ab62ac372f218b97cbcad9de86929075f645e6..136f0443fa0a36e4285366095e2c788af36a800d 100644 (file)
@@ -258,10 +258,7 @@ pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
     /// an error.
     fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
         let Some((def_id, _)) = tcx.entry_fn(()) else { return };
-
-        let attrs = &*tcx.get_attrs(def_id);
-        let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error));
-        for attr in attrs {
+        for attr in tcx.get_attrs(def_id, sym::rustc_error) {
             match attr.meta_item_list() {
                 // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
                 Some(list)
index 4141d952683efd62f25d35dcc73beddf70b02321..585edfc47e1b8c2743f8cf1ccb95c90132c3c439 100644 (file)
@@ -551,7 +551,7 @@ fn check_missing_docs_attrs(
             }
         }
 
-        let attrs = cx.tcx.get_attrs(def_id.to_def_id());
+        let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
         let has_doc = attrs.iter().any(has_doc);
         if !has_doc {
             cx.struct_span_lint(
@@ -1252,7 +1252,6 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        use rustc_target::spec::abi::Abi::RustIntrinsic;
         if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
@@ -1287,8 +1286,7 @@ fn get_transmute_from_to<'tcx>(
         }
 
         fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
-            cx.tcx.fn_sig(def_id).abi() == RustIntrinsic
-                && cx.tcx.item_name(def_id) == sym::transmute
+            cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
         }
     }
 }
@@ -2738,11 +2736,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName
                 // bottleneck, this does just fine.
                 (
                     overridden_link_name,
-                    tcx.get_attrs(fi.def_id.to_def_id())
-                        .iter()
-                        .find(|at| at.has_name(sym::link_name))
-                        .unwrap()
-                        .span,
+                    tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
                 )
             })
         {
index dfce30171ff2b851234e0a242fa1e1a929e1f996..62d427fcd0238bcb3b3cbe6c5bfad67ea39f80d7 100644 (file)
@@ -668,7 +668,7 @@ enum FfiResult<'tcx> {
 }
 
 crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
-    tcx.get_attrs(def.did()).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
+    tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
 }
 
 /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
index 494bdaa1e2b9cf3640912d89c80744ecb50a3004..8cae95f46dc377acb809c1bfc63eced274990b57 100644 (file)
@@ -303,26 +303,25 @@ fn check_must_use_def(
             descr_pre_path: &str,
             descr_post_path: &str,
         ) -> bool {
-            for attr in cx.tcx.get_attrs(def_id).iter() {
-                if attr.has_name(sym::must_use) {
-                    cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        let msg = format!(
-                            "unused {}`{}`{} that must be used",
-                            descr_pre_path,
-                            cx.tcx.def_path_str(def_id),
-                            descr_post_path
-                        );
-                        let mut err = lint.build(&msg);
-                        // check for #[must_use = "..."]
-                        if let Some(note) = attr.value_str() {
-                            err.note(note.as_str());
-                        }
-                        err.emit();
-                    });
-                    return true;
-                }
+            if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
+                cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
+                    let msg = format!(
+                        "unused {}`{}`{} that must be used",
+                        descr_pre_path,
+                        cx.tcx.def_path_str(def_id),
+                        descr_post_path
+                    );
+                    let mut err = lint.build(&msg);
+                    // check for #[must_use = "..."]
+                    if let Some(note) = attr.value_str() {
+                        err.note(note.as_str());
+                    }
+                    err.emit();
+                });
+                true
+            } else {
+                false
             }
-            false
         }
     }
 }
index 7ebb1e85cdb235456a81ec861f4df9706daf2ce7..f942970278399b17e89ba17b641280ba43509aad 100644 (file)
     /// ### Example
     ///
     /// ```rust
+    /// #[warn(unused_macro_rules)]
     /// macro_rules! unused_empty {
     ///     (hello) => { println!("Hello, world!") }; // This rule is unused
     ///     () => { println!("empty") }; // This rule is used
     ///
     /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
     pub UNUSED_MACRO_RULES,
-    Warn,
+    Allow,
     "detects macro rules that were not used"
 }
 
index ac758c15cca7875fce627f5f92879c881d258307..7729ec6bef4a7409eff955dc96b90e90524fcf4a 100644 (file)
@@ -324,9 +324,10 @@ fn main() {
 
     let stdcppname = if target.contains("openbsd") {
         if target.contains("sparc64") { "estdc++" } else { "c++" }
-    } else if target.contains("freebsd") {
-        "c++"
-    } else if target.contains("darwin") {
+    } else if target.contains("darwin")
+        || target.contains("freebsd")
+        || target.contains("windows-gnullvm")
+    {
         "c++"
     } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
         // NetBSD uses a separate library when relocation is required
@@ -365,7 +366,7 @@ fn main() {
 
     // Libstdc++ depends on pthread which Rust doesn't link on MinGW
     // since nothing else requires it.
-    if target.contains("windows-gnu") {
+    if target.ends_with("windows-gnu") {
         println!("cargo:rustc-link-lib=static:-bundle=pthread");
     }
 }
index 83fc7bcde8ab47d385da4f3325726252aae1a5c2..dac3e986e7ad4bc142377300304f92262f8c3f68 100644 (file)
@@ -5,10 +5,10 @@
     SessionDiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    report_error_if_not_applied_to_span, type_matches_path, Applicability, FieldInfo, FieldInnerTy,
-    HasFieldMap, SetOnce,
+    report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
+    Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
 };
-use proc_macro2::TokenStream;
+use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
 use std::collections::HashMap;
 use std::str::FromStr;
@@ -113,7 +113,7 @@ pub(crate) fn into_tokens(self) -> TokenStream {
                         quote! {
                             #diag.set_arg(
                                 stringify!(#ident),
-                                #field_binding.into_diagnostic_arg()
+                                #field_binding
                             );
                         }
                     } else {
@@ -388,7 +388,8 @@ fn generate_inner_field_code(
     ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
         let diag = &self.diag;
 
-        let name = attr.path.segments.last().unwrap().ident.to_string();
+        let ident = &attr.path.segments.last().unwrap().ident;
+        let name = ident.to_string();
         let name = name.as_str();
 
         let meta = attr.parse_meta()?;
@@ -405,9 +406,18 @@ fn generate_inner_field_code(
                         #diag.set_span(#binding);
                     })
                 }
-                "label" | "note" | "help" => {
+                "label" => {
                     report_error_if_not_applied_to_span(attr, &info)?;
-                    Ok(self.add_subdiagnostic(binding, name, name))
+                    Ok(self.add_spanned_subdiagnostic(binding, ident, name))
+                }
+                "note" | "help" => {
+                    if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                        Ok(self.add_spanned_subdiagnostic(binding, ident, name))
+                    } else if type_is_unit(&info.ty) {
+                        Ok(self.add_subdiagnostic(ident, name))
+                    } else {
+                        report_type_error(attr, "`Span` or `()`")?;
+                    }
                 }
                 "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
                 _ => throw_invalid_attr!(attr, &meta, |diag| {
@@ -416,9 +426,18 @@ fn generate_inner_field_code(
                 }),
             },
             Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
-                "label" | "note" | "help" => {
+                "label" => {
                     report_error_if_not_applied_to_span(attr, &info)?;
-                    Ok(self.add_subdiagnostic(binding, name, &s.value()))
+                    Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
+                }
+                "note" | "help" => {
+                    if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                        Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
+                    } else if type_is_unit(&info.ty) {
+                        Ok(self.add_subdiagnostic(ident, &s.value()))
+                    } else {
+                        report_type_error(attr, "`Span` or `()`")?;
+                    }
                 }
                 _ => throw_invalid_attr!(attr, &meta, |diag| {
                     diag.help("only `label`, `note` and `help` are valid field attributes")
@@ -510,12 +529,12 @@ fn generate_inner_field_code(
         }
     }
 
-    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and
-    /// `fluent_attr_identifier`.
-    fn add_subdiagnostic(
+    /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
+    /// and `fluent_attr_identifier`.
+    fn add_spanned_subdiagnostic(
         &self,
         field_binding: TokenStream,
-        kind: &str,
+        kind: &Ident,
         fluent_attr_identifier: &str,
     ) -> TokenStream {
         let diag = &self.diag;
@@ -531,6 +550,16 @@ fn add_subdiagnostic(
         }
     }
 
+    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
+    /// and `fluent_attr_identifier`.
+    fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream {
+        let diag = &self.diag;
+        let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug");
+        quote! {
+            #diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier));
+        }
+    }
+
     fn span_and_applicability_of_ty(
         &self,
         info: FieldInfo<'_>,
index 65b1328682f823243b4aefed836e2d5c969f11f8..ae5b9dbd9ba1c2677c604253eccefbd36b82eceb 100644 (file)
@@ -349,7 +349,7 @@ fn generate_field_code(
         let generated = quote! {
             #diag.set_arg(
                 stringify!(#ident),
-                #binding.into_diagnostic_arg()
+                #binding
             );
         };
 
index aba861fc6aafa4a0954216f969e07e9da7812a39..af5a30880e05f2fdce5c5eaa4f19cf97d85d3c0c 100644 (file)
@@ -4,7 +4,7 @@
 use quote::{format_ident, quote, ToTokens};
 use std::collections::BTreeSet;
 use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility};
+use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple, Visibility};
 use synstructure::BindingInfo;
 
 /// Checks whether the type name of `ty` matches `name`.
@@ -25,7 +25,35 @@ pub(crate) fn type_matches_path(ty: &Type, name: &[&str]) -> bool {
     }
 }
 
-/// Reports an error if the field's type is not `Applicability`.
+/// Checks whether the type `ty` is `()`.
+pub(crate) fn type_is_unit(ty: &Type) -> bool {
+    if let Type::Tuple(TypeTuple { elems, .. }) = ty { elems.is_empty() } else { false }
+}
+
+/// Reports a type error for field with `attr`.
+pub(crate) fn report_type_error(
+    attr: &Attribute,
+    ty_name: &str,
+) -> Result<!, SessionDiagnosticDeriveError> {
+    let name = attr.path.segments.last().unwrap().ident.to_string();
+    let meta = attr.parse_meta()?;
+
+    throw_span_err!(
+        attr.span().unwrap(),
+        &format!(
+            "the `#[{}{}]` attribute can only be applied to fields of type {}",
+            name,
+            match meta {
+                Meta::Path(_) => "",
+                Meta::NameValue(_) => " = ...",
+                Meta::List(_) => "(...)",
+            },
+            ty_name
+        )
+    );
+}
+
+/// Reports an error if the field's type does not match `path`.
 fn report_error_if_not_applied_to_ty(
     attr: &Attribute,
     info: &FieldInfo<'_>,
@@ -33,23 +61,7 @@ fn report_error_if_not_applied_to_ty(
     ty_name: &str,
 ) -> Result<(), SessionDiagnosticDeriveError> {
     if !type_matches_path(&info.ty, path) {
-        let name = attr.path.segments.last().unwrap().ident.to_string();
-        let name = name.as_str();
-        let meta = attr.parse_meta()?;
-
-        throw_span_err!(
-            attr.span().unwrap(),
-            &format!(
-                "the `#[{}{}]` attribute can only be applied to fields of type `{}`",
-                name,
-                match meta {
-                    Meta::Path(_) => "",
-                    Meta::NameValue(_) => " = ...",
-                    Meta::List(_) => "(...)",
-                },
-                ty_name
-            )
-        );
+        report_type_error(attr, ty_name)?;
     }
 
     Ok(())
@@ -64,7 +76,7 @@ pub(crate) fn report_error_if_not_applied_to_applicability(
         attr,
         info,
         &["rustc_errors", "Applicability"],
-        "Applicability",
+        "`Applicability`",
     )
 }
 
@@ -73,7 +85,7 @@ pub(crate) fn report_error_if_not_applied_to_span(
     attr: &Attribute,
     info: &FieldInfo<'_>,
 ) -> Result<(), SessionDiagnosticDeriveError> {
-    report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "Span")
+    report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`")
 }
 
 /// Inner type of a field and type of wrapper.
index b01e01414e878cd725b893f40178278bfe195187..0baebdb713062eba1c1ada8c8cdd8f16ee0aaddb 100644 (file)
@@ -1,5 +1,6 @@
 #![feature(allow_internal_unstable)]
 #![feature(let_else)]
+#![feature(never_type)]
 #![feature(proc_macro_diagnostic)]
 #![allow(rustc::default_hash_types)]
 #![recursion_limit = "128"]
index dfed9dd15a72173acddb6304ff87350393dd4974..2d13675e61550ff349cf5eee6415368273ca9f62 100644 (file)
@@ -1,7 +1,9 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
+#![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(generators)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(nll)]
 #![feature(once_cell)]
index f468399930d3a3b533754253f2389cbdfe52ac79..628516fa13827673f49fdfb6c71c4b410d62423b 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_ast::CRATE_NODE_ID;
+use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
@@ -9,8 +9,7 @@
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
@@ -51,283 +50,315 @@ fn process_item(&mut self, id: rustc_hir::ItemId) {
 
         // Process all of the #[link(..)]-style arguments
         let sess = &self.tcx.sess;
+        let features = self.tcx.features();
         for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
             let Some(items) = m.meta_item_list() else {
                 continue;
             };
-            let mut lib = NativeLib {
-                name: None,
-                kind: NativeLibKind::Unspecified,
-                cfg: None,
-                foreign_module: Some(it.def_id.to_def_id()),
-                wasm_import_module: None,
-                verbatim: None,
-                dll_imports: Vec::new(),
-            };
-            let mut kind_specified = false;
 
+            let mut name = None;
+            let mut kind = None;
+            let mut modifiers = None;
+            let mut cfg = None;
+            let mut wasm_import_module = None;
             for item in items.iter() {
-                if item.has_name(sym::kind) {
-                    kind_specified = true;
-                    let Some(kind) = item.value_str() else {
-                        continue; // skip like historical compilers
-                    };
-                    lib.kind = match kind.as_str() {
-                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-                        "static-nobundle" => {
-                            sess.struct_span_warn(
-                                item.span(),
-                                "library kind `static-nobundle` has been superseded by specifying \
-                                modifier `-bundle` with library kind `static`",
-                            )
-                            .emit();
-                            if !self.tcx.features().static_nobundle {
-                                feature_err(
-                                    &self.tcx.sess.parse_sess,
-                                    sym::static_nobundle,
-                                    item.span(),
-                                    "kind=\"static-nobundle\" is unstable",
-                                )
-                                .emit();
-                            }
-                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+                match item.name_or_empty() {
+                    sym::name => {
+                        if name.is_some() {
+                            let msg = "multiple `name` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
                         }
-                        "dylib" => NativeLibKind::Dylib { as_needed: None },
-                        "framework" => NativeLibKind::Framework { as_needed: None },
-                        "raw-dylib" => NativeLibKind::RawDylib,
-                        k => {
-                            struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
-                                .span_label(item.span(), "unknown kind")
-                                .span_label(m.span, "")
+                        let Some(link_name) = item.value_str() else {
+                            let msg = "link name must be of the form `name = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        let span = item.name_value_literal_span().unwrap();
+                        if link_name.is_empty() {
+                            struct_span_err!(sess, span, E0454, "link name must not be empty")
+                                .span_label(span, "empty link name")
                                 .emit();
-                            NativeLibKind::Unspecified
                         }
-                    };
-                } else if item.has_name(sym::name) {
-                    lib.name = item.value_str();
-                } else if item.has_name(sym::cfg) {
-                    let Some(cfg) = item.meta_item_list() else {
-                        continue; // skip like historical compilers
-                    };
-                    if cfg.is_empty() {
-                        sess.span_err(item.span(), "`cfg()` must have an argument");
-                    } else if let cfg @ Some(..) = cfg[0].meta_item() {
-                        lib.cfg = cfg.cloned();
-                    } else {
-                        sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
+                        name = Some((link_name, span));
                     }
-                } else if item.has_name(sym::wasm_import_module) {
-                    match item.value_str() {
-                        Some(s) => lib.wasm_import_module = Some(s),
-                        None => {
-                            let msg = "must be of the form `#[link(wasm_import_module = \"...\")]`";
+                    sym::kind => {
+                        if kind.is_some() {
+                            let msg = "multiple `kind` arguments in a single `#[link]` attribute";
                             sess.span_err(item.span(), msg);
+                            continue;
                         }
-                    }
-                } else {
-                    // currently, like past compilers, ignore unknown
-                    // directives here.
-                }
-            }
-
-            // Do this outside the above loop so we don't depend on modifiers coming
-            // after kinds
-            let mut modifiers_count = 0;
-            for item in items.iter().filter(|item| item.has_name(sym::modifiers)) {
-                if let Some(modifiers) = item.value_str() {
-                    modifiers_count += 1;
-                    let span = item.name_value_literal_span().unwrap();
-                    let mut has_duplicate_modifiers = false;
-                    for modifier in modifiers.as_str().split(',') {
-                        let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
-                            Some(m) => (m, modifier.starts_with('+')),
-                            None => {
-                                // Note: this error also excludes the case with empty modifier
-                                // string, like `modifiers = ""`.
-                                sess.span_err(
-                                    span,
-                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
-                                    before one of: bundle, verbatim, whole-archive, as-needed",
-                                );
-                                continue;
-                            }
+                        let Some(link_kind) = item.value_str() else {
+                            let msg = "link kind must be of the form `kind = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
                         };
 
-                        match (modifier, &mut lib.kind) {
-                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
-                                if bundle.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *bundle = Some(value);
-                            }
-                            ("bundle", _) => {
-                                sess.span_err(
+                        let span = item.name_value_literal_span().unwrap();
+                        let link_kind = match link_kind.as_str() {
+                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                            "static-nobundle" => {
+                                sess.struct_span_warn(
                                     span,
-                                    "bundle linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("verbatim", _) => {
-                                if lib.verbatim.is_some() {
-                                    has_duplicate_modifiers = true;
+                                    "link kind `static-nobundle` has been superseded by specifying \
+                                     modifier `-bundle` with link kind `static`",
+                                )
+                                .emit();
+                                if !features.static_nobundle {
+                                    feature_err(
+                                        &sess.parse_sess,
+                                        sym::static_nobundle,
+                                        span,
+                                        "link kind `static-nobundle` is unstable",
+                                    )
+                                    .emit();
                                 }
-                                lib.verbatim = Some(value);
+                                NativeLibKind::Static { bundle: Some(false), whole_archive: None }
                             }
-
-                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                                if whole_archive.is_some() {
-                                    has_duplicate_modifiers = true;
+                            "dylib" => NativeLibKind::Dylib { as_needed: None },
+                            "framework" => {
+                                if !sess.target.is_like_osx {
+                                    struct_span_err!(
+                                        sess,
+                                        span,
+                                        E0455,
+                                        "link kind `framework` is only supported on Apple targets"
+                                    )
+                                    .emit();
                                 }
-                                *whole_archive = Some(value);
+                                NativeLibKind::Framework { as_needed: None }
                             }
-                            ("whole-archive", _) => {
-                                sess.span_err(
-                                    span,
-                                    "whole-archive linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("as-needed", NativeLibKind::Dylib { as_needed })
-                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                                if as_needed.is_some() {
-                                    has_duplicate_modifiers = true;
+                            "raw-dylib" => {
+                                if !sess.target.is_like_windows {
+                                    struct_span_err!(
+                                        sess,
+                                        span,
+                                        E0455,
+                                        "link kind `raw-dylib` is only supported on Windows targets"
+                                    )
+                                    .emit();
+                                } else if !features.raw_dylib {
+                                    feature_err(
+                                        &sess.parse_sess,
+                                        sym::raw_dylib,
+                                        span,
+                                        "link kind `raw-dylib` is unstable",
+                                    )
+                                    .emit();
                                 }
-                                *as_needed = Some(value);
+                                NativeLibKind::RawDylib
                             }
-                            ("as-needed", _) => {
-                                sess.span_err(
-                                    span,
-                                    "as-needed linking modifier is only compatible with \
-                                `dylib` and `framework` linking kinds",
-                                );
-                            }
-
-                            _ => {
-                                sess.span_err(
-                                    span,
-                                    &format!(
-                                        "unrecognized linking modifier `{}`, expected one \
-                                    of: bundle, verbatim, whole-archive, as-needed",
-                                        modifier
-                                    ),
+                            kind => {
+                                let msg = format!(
+                                    "unknown link kind `{kind}`, expected one of: \
+                                     static, dylib, framework, raw-dylib"
                                 );
+                                struct_span_err!(sess, span, E0458, "{}", msg)
+                                    .span_label(span, "unknown link kind")
+                                    .emit();
+                                continue;
                             }
+                        };
+                        kind = Some(link_kind);
+                    }
+                    sym::modifiers => {
+                        if modifiers.is_some() {
+                            let msg =
+                                "multiple `modifiers` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_modifiers) = item.value_str() else {
+                            let msg = "link modifiers must be of the form `modifiers = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
+                    }
+                    sym::cfg => {
+                        if cfg.is_some() {
+                            let msg = "multiple `cfg` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_cfg) = item.meta_item_list() else {
+                            let msg = "link cfg must be of the form `cfg(/* predicate */)`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
+                            let msg = "link cfg must have a single predicate argument";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        if !features.link_cfg {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::link_cfg,
+                                item.span(),
+                                "link cfg is unstable",
+                            )
+                            .emit();
+                        }
+                        cfg = Some(link_cfg.clone());
+                    }
+                    sym::wasm_import_module => {
+                        if wasm_import_module.is_some() {
+                            let msg = "multiple `wasm_import_module` arguments \
+                                       in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
                         }
+                        let Some(link_wasm_import_module) = item.value_str() else {
+                            let msg = "wasm import module must be of the form \
+                                       `wasm_import_module = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        wasm_import_module = Some((link_wasm_import_module, item.span()));
                     }
-                    if has_duplicate_modifiers {
-                        let msg =
-                            "same modifier is used multiple times in a single `modifiers` argument";
+                    _ => {
+                        let msg = "unexpected `#[link]` argument, expected one of: \
+                                   name, kind, modifiers, cfg, wasm_import_module";
                         sess.span_err(item.span(), msg);
                     }
-                } else {
-                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
-                    sess.span_err(item.span(), msg);
                 }
             }
 
-            if modifiers_count > 1 {
-                let msg = "multiple `modifiers` arguments in a single `#[link]` attribute";
-                sess.span_err(m.span, msg);
+            // Do this outside the above loop so we don't depend on modifiers coming after kinds
+            let mut verbatim = None;
+            if let Some((modifiers, span)) = modifiers {
+                for modifier in modifiers.as_str().split(',') {
+                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
+                        Some(m) => (m, modifier.starts_with('+')),
+                        None => {
+                            sess.span_err(
+                                span,
+                                "invalid linking modifier syntax, expected '+' or '-' prefix \
+                                before one of: bundle, verbatim, whole-archive, as-needed",
+                            );
+                            continue;
+                        }
+                    };
+
+                    macro report_unstable_modifier($feature: ident) {
+                        if !features.$feature {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::$feature,
+                                span,
+                                &format!("linking modifier `{modifier}` is unstable"),
+                            )
+                            .emit();
+                        }
+                    }
+                    let assign_modifier = |dst: &mut Option<bool>| {
+                        if dst.is_some() {
+                            let msg = format!(
+                                "multiple `{modifier}` modifiers in a single `modifiers` argument"
+                            );
+                            sess.span_err(span, &msg);
+                        } else {
+                            *dst = Some(value);
+                        }
+                    };
+                    match (modifier, &mut kind) {
+                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
+                            report_unstable_modifier!(native_link_modifiers_bundle);
+                            assign_modifier(bundle)
+                        }
+                        ("bundle", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `bundle` is only compatible with \
+                                 `static` linking kind",
+                            );
+                        }
+
+                        ("verbatim", _) => {
+                            report_unstable_modifier!(native_link_modifiers_verbatim);
+                            assign_modifier(&mut verbatim)
+                        }
+
+                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
+                            assign_modifier(whole_archive)
+                        }
+                        ("whole-archive", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `whole-archive` is only compatible with \
+                                 `static` linking kind",
+                            );
+                        }
+
+                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
+                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
+                            report_unstable_modifier!(native_link_modifiers_as_needed);
+                            assign_modifier(as_needed)
+                        }
+                        ("as-needed", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `as-needed` is only compatible with \
+                                 `dylib` and `framework` linking kinds",
+                            );
+                        }
+
+                        _ => {
+                            sess.span_err(
+                                span,
+                                format!(
+                                    "unknown linking modifier `{modifier}`, expected one of: \
+                                     bundle, verbatim, whole-archive, as-needed"
+                                ),
+                            );
+                        }
+                    }
+                }
             }
 
-            // In general we require #[link(name = "...")] but we allow
-            // #[link(wasm_import_module = "...")] without the `name`.
-            let requires_name = kind_specified || lib.wasm_import_module.is_none();
-            if lib.name.is_none() && requires_name {
+            if let Some((_, span)) = wasm_import_module {
+                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
+                    let msg = "`wasm_import_module` is incompatible with \
+                               other arguments in `#[link]` attributes";
+                    sess.span_err(span, msg);
+                }
+            } else if name.is_none() {
                 struct_span_err!(
                     sess,
                     m.span,
                     E0459,
-                    "`#[link(...)]` specified without \
-                                  `name = \"foo\"`"
+                    "`#[link]` attribute requires a `name = \"string\"` argument"
                 )
                 .span_label(m.span, "missing `name` argument")
                 .emit();
             }
 
-            if lib.kind == NativeLibKind::RawDylib {
-                lib.dll_imports.extend(
+            let dll_imports = match kind {
+                Some(NativeLibKind::RawDylib) => {
+                    if let Some((name, span)) = name && name.as_str().contains('\0') {
+                        sess.span_err(
+                            span,
+                            "link name must not contain NUL characters if link kind is `raw-dylib`",
+                        );
+                    }
                     foreign_mod_items
                         .iter()
-                        .map(|child_item| self.build_dll_import(abi, child_item)),
-                );
-            }
-
-            self.register_native_lib(Some(m.span), lib);
-        }
-    }
-
-    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
-        if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
-            match span {
-                Some(span) => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0454,
-                        "`#[link(name = \"\")]` given with empty name"
-                    )
-                    .span_label(span, "empty name given")
-                    .emit();
-                }
-                None => {
-                    self.tcx.sess.err("empty library name given via `-l`");
-                }
-            }
-            return;
-        }
-        let is_osx = self.tcx.sess.target.is_like_osx;
-        if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx {
-            let msg = "native frameworks are only available on macOS targets";
-            match span {
-                Some(span) => {
-                    struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit();
-                }
-                None => {
-                    self.tcx.sess.err(msg);
+                        .map(|child_item| self.build_dll_import(abi, child_item))
+                        .collect()
                 }
-            }
-        }
-        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::link_cfg,
-                span.unwrap(),
-                "kind=\"link_cfg\" is unstable",
-            )
-            .emit();
-        }
-        // this just unwraps lib.name; we already established that it isn't empty above.
-        if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
-            let Some(span) = span else {
-                bug!("raw-dylib libraries are not supported on the command line");
+                _ => Vec::new(),
             };
-
-            if !self.tcx.sess.target.options.is_like_windows {
-                self.tcx.sess.span_fatal(
-                    span,
-                    "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
-                );
-            }
-
-            if lib_name.as_str().contains('\0') {
-                self.tcx.sess.span_err(span, "library name may not contain NUL characters");
-            }
-
-            if !self.tcx.features().raw_dylib {
-                feature_err(
-                    &self.tcx.sess.parse_sess,
-                    sym::raw_dylib,
-                    span,
-                    "kind=\"raw-dylib\" is unstable",
-                )
-                .emit();
-            }
+            self.libs.push(NativeLib {
+                name: name.map(|(name, _)| name),
+                kind: kind.unwrap_or(NativeLibKind::Unspecified),
+                cfg,
+                foreign_module: Some(it.def_id.to_def_id()),
+                wasm_import_module: wasm_import_module.map(|(name, _)| name),
+                verbatim,
+                dll_imports,
+            });
         }
-
-        self.libs.push(lib);
     }
 
     // Process libs passed on the command line
@@ -335,6 +366,10 @@ fn process_command_line(&mut self) {
         // First, check for errors
         let mut renames = FxHashSet::default();
         for lib in &self.tcx.sess.opts.libs {
+            if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
+                // Cannot check this when parsing options because the target is not yet available.
+                self.tcx.sess.err("library kind `framework` is only supported on Apple targets");
+            }
             if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
                     .libs
@@ -342,19 +377,19 @@ fn process_command_line(&mut self) {
                     .filter_map(|lib| lib.name.as_ref())
                     .any(|n| n.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "an empty renaming target was specified for library `{}`",
                         lib.name
                     ));
                 } else if !any_duplicate {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library",
                         lib.name
                     ));
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "multiple renamings were \
                                                 specified for library `{}`",
                         lib.name
@@ -404,7 +439,7 @@ fn process_command_line(&mut self) {
             if existing.is_empty() {
                 // Add if not found
                 let new_name: Option<&str> = passed_lib.new_name.as_deref();
-                let lib = NativeLib {
+                self.libs.push(NativeLib {
                     name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
                     kind: passed_lib.kind,
                     cfg: None,
@@ -412,8 +447,7 @@ fn process_command_line(&mut self) {
                     wasm_import_module: None,
                     verbatim: passed_lib.verbatim,
                     dll_imports: Vec::new(),
-                };
-                self.register_native_lib(None, lib);
+                });
             } else {
                 // Move all existing libraries with the same name to the
                 // end of the command line.
index b25522cfd96a80f06ae5f540ec2f1d763cbf33f4..de1e96ebfe722ed6388e1b342aceffc7a8c886ae 100644 (file)
@@ -1752,6 +1752,10 @@ fn get_generator_diagnostic_data(
     fn get_may_have_doc_links(self, index: DefIndex) -> bool {
         self.root.tables.may_have_doc_links.get(self, index).is_some()
     }
+
+    fn get_is_intrinsic(self, index: DefIndex) -> bool {
+        self.root.tables.is_intrinsic.get(self, index).is_some()
+    }
 }
 
 impl CrateMetadata {
index 9f7ef3981c75b6ff5a922a5164bb2b1abde43b21..065224a2a65d7570a8a4935c90487f0cab0d4b94 100644 (file)
@@ -224,6 +224,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
+    is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
     missing_lang_items => { cdata.get_missing_lang_items(tcx) }
index 81388a0bf585ddac473097ad7c799a4524dc2a2c..086f1bd94b6c01475946e23f91b2422931289852 100644 (file)
@@ -14,7 +14,6 @@
 };
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
+use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
-use rustc_span::{
-    hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind},
-    RealFileName,
-};
 use rustc_target::abi::VariantIdx;
 use std::hash::Hash;
 use std::num::NonZeroUsize;
-use std::path::Path;
 use tracing::{debug, trace};
 
 pub(super) struct EncodeContext<'a, 'tcx> {
@@ -453,7 +448,7 @@ fn encode_info_for_items(&mut self) {
             return;
         }
 
-        self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor());
+        self.tcx.hir().deep_visit_all_item_likes(self);
     }
 
     fn encode_def_path_table(&mut self) {
@@ -491,6 +486,8 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
         // is done.
         let required_source_files = self.required_source_files.take().unwrap();
 
+        let working_directory = &self.tcx.sess.opts.working_dir;
+
         let adapted = all_source_files
             .iter()
             .enumerate()
@@ -503,66 +500,40 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
                 (!source_file.is_imported() || self.is_proc_macro)
             })
             .map(|(_, source_file)| {
-                let mut adapted = match source_file.name {
-                    FileName::Real(ref realname) => {
-                        let mut adapted = (**source_file).clone();
-                        adapted.name = FileName::Real(match realname {
-                            RealFileName::LocalPath(path_to_file) => {
-                                // Prepend path of working directory onto potentially
-                                // relative paths, because they could become relative
-                                // to a wrong directory.
-                                // We include `working_dir` as part of the crate hash,
-                                // so it's okay for us to use it as part of the encoded
-                                // metadata.
-                                let working_dir = &self.tcx.sess.opts.working_dir;
-                                match working_dir {
-                                    RealFileName::LocalPath(absolute) => {
-                                        // Although neither working_dir or the file name were subject
-                                        // to path remapping, the concatenation between the two may
-                                        // be. Hence we need to do a remapping here.
-                                        let joined = Path::new(absolute).join(path_to_file);
-                                        let (joined, remapped) =
-                                            source_map.path_mapping().map_prefix(joined);
-                                        if remapped {
-                                            RealFileName::Remapped {
-                                                local_path: None,
-                                                virtual_name: joined,
-                                            }
-                                        } else {
-                                            RealFileName::LocalPath(joined)
-                                        }
-                                    }
-                                    RealFileName::Remapped { local_path: _, virtual_name } => {
-                                        // If working_dir has been remapped, then we emit
-                                        // Remapped variant as the expanded path won't be valid
-                                        RealFileName::Remapped {
-                                            local_path: None,
-                                            virtual_name: Path::new(virtual_name)
-                                                .join(path_to_file),
-                                        }
-                                    }
-                                }
-                            }
-                            RealFileName::Remapped { local_path: _, virtual_name } => {
-                                RealFileName::Remapped {
-                                    // We do not want any local path to be exported into metadata
-                                    local_path: None,
-                                    virtual_name: virtual_name.clone(),
-                                }
-                            }
-                        });
-                        adapted.name_hash = {
-                            let mut hasher: StableHasher = StableHasher::new();
-                            adapted.name.hash(&mut hasher);
-                            hasher.finish::<u128>()
-                        };
-                        Lrc::new(adapted)
+                // At export time we expand all source file paths to absolute paths because
+                // downstream compilation sessions can have a different compiler working
+                // directory, so relative paths from this or any other upstream crate
+                // won't be valid anymore.
+                //
+                // At this point we also erase the actual on-disk path and only keep
+                // the remapped version -- as is necessary for reproducible builds.
+                match source_file.name {
+                    FileName::Real(ref original_file_name) => {
+                        let adapted_file_name =
+                            source_map.path_mapping().to_embeddable_absolute_path(
+                                original_file_name.clone(),
+                                working_directory,
+                            );
+
+                        if adapted_file_name != *original_file_name {
+                            let mut adapted: SourceFile = (**source_file).clone();
+                            adapted.name = FileName::Real(adapted_file_name);
+                            adapted.name_hash = {
+                                let mut hasher: StableHasher = StableHasher::new();
+                                adapted.name.hash(&mut hasher);
+                                hasher.finish::<u128>()
+                            };
+                            Lrc::new(adapted)
+                        } else {
+                            // Nothing to adapt
+                            source_file.clone()
+                        }
                     }
-
                     // expanded code, not from a file
                     _ => source_file.clone(),
-                };
-
+                }
+            })
+            .map(|mut source_file| {
                 // We're serializing this `SourceFile` into our crate metadata,
                 // so mark it as coming from this crate.
                 // This also ensures that we don't try to deserialize the
@@ -570,9 +541,9 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
                 // dependencies aren't loaded when we deserialize a proc-macro,
                 // trying to remap the `CrateNum` would fail.
                 if self.is_proc_macro {
-                    Lrc::make_mut(&mut adapted).cnum = LOCAL_CRATE;
+                    Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE;
                 }
-                adapted
+                source_file
             })
             .collect::<Vec<_>>();
 
@@ -985,11 +956,17 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn encode_attrs(&mut self, def_id: DefId) {
-        let attrs = self.tcx.get_attrs(def_id);
-        record!(self.tables.attributes[def_id] <- attrs);
-        if attrs.iter().any(|attr| attr.may_have_doc_links()) {
-            self.tables.may_have_doc_links.set(def_id.index, ());
+    fn encode_attrs(&mut self, def_id: LocalDefId) {
+        let mut attrs = self
+            .tcx
+            .hir()
+            .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id))
+            .iter()
+            .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
+
+        record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
+        if attrs.any(|attr| attr.may_have_doc_links()) {
+            self.tables.may_have_doc_links.set(def_id.local_def_index, ());
         }
     }
 
@@ -1005,7 +982,7 @@ fn encode_def_ids(&mut self) {
             let Some(def_kind) = def_kind else { continue };
             self.tables.opt_def_kind.set(def_id.index, def_kind);
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
-            self.encode_attrs(def_id);
+            self.encode_attrs(local_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
             if def_kind.has_codegen_attrs() {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
@@ -1313,6 +1290,9 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
     }
 
@@ -1557,6 +1537,9 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
         }
         if let hir::ItemKind::Fn(..) = item.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
         if let hir::ItemKind::Impl { .. } = item.kind {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@@ -1670,7 +1653,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
 
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
-            self.encode_attrs(LOCAL_CRATE.as_def_id());
+            self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
             record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
@@ -1711,7 +1694,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 let def_id = id.to_def_id();
                 self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
-                self.encode_attrs(def_id);
+                self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
                 record!(self.tables.def_span[def_id] <- span);
@@ -1953,6 +1936,9 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
     }
 }
@@ -2237,26 +2223,16 @@ pub fn provide(providers: &mut Providers) {
         traits_in_crate: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
 
-            #[derive(Default)]
-            struct TraitsVisitor {
-                traits: Vec<DefId>,
-            }
-            impl ItemLikeVisitor<'_> for TraitsVisitor {
-                fn visit_item(&mut self, item: &hir::Item<'_>) {
-                    if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind {
-                        self.traits.push(item.def_id.to_def_id());
-                    }
+            let mut traits = Vec::new();
+            for id in tcx.hir().items() {
+                if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
+                    traits.push(id.def_id.to_def_id())
                 }
-                fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-                fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-                fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
             }
 
-            let mut visitor = TraitsVisitor::default();
-            tcx.hir().visit_all_item_likes(&mut visitor);
             // Bring everything into deterministic order.
-            visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
-            tcx.arena.alloc_slice(&visitor.traits)
+            traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
+            tcx.arena.alloc_slice(&traits)
         },
 
         ..*providers
index 356dad4b56be1b404a19836fbd20c266bae3d734..1c5774db579a58125267031ceb3025072cf3835d 100644 (file)
@@ -340,6 +340,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     impl_parent: Table<DefIndex, RawDefId>,
     impl_polarity: Table<DefIndex, ty::ImplPolarity>,
     impl_constness: Table<DefIndex, hir::Constness>,
+    is_intrinsic: Table<DefIndex, ()>,
     impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,
index 20c8b0bb70f8b43c73bf84db0d6ef2cf8e729284..9976b0e9862041ba63e52ea09c21b8e8633a627c 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::Idx;
 use rustc_middle::hir::nested_filter;
@@ -161,6 +160,10 @@ pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
         self.tcx.hir_crate_items(()).items.iter().copied()
     }
 
+    pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir {
+        self.tcx.hir_module_items(module).items()
+    }
+
     pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) {
         par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id));
     }
@@ -603,16 +606,16 @@ pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
     }
 
     /// Visits all items in the crate in some deterministic (but
-    /// unspecified) order. If you just need to process every item,
-    /// but don't care about nesting, this method is the best choice.
+    /// unspecified) order. If you need to process every item,
+    /// and care about nesting -- usually because your algorithm
+    /// follows lexical scoping rules -- then this method is the best choice.
+    /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query
+    /// or `items()` instead.
     ///
-    /// If you do care about nesting -- usually because your algorithm
-    /// follows lexical scoping rules -- then you want a different
-    /// approach. You should override `visit_nested_item` in your
-    /// visitor and then call `intravisit::walk_crate` instead.
-    pub fn visit_all_item_likes<V>(self, visitor: &mut V)
+    /// Please see the notes in `intravisit.rs` for more information.
+    pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V)
     where
-        V: itemlikevisit::ItemLikeVisitor<'hir>,
+        V: Visitor<'hir>,
     {
         let krate = self.krate();
         for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
@@ -643,9 +646,12 @@ pub fn par_visit_all_item_likes<V>(self, visitor: &V)
         })
     }
 
-    pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
+    /// If you don't care about nesting, you should use the
+    /// `tcx.hir_module_items()` query or `module_items()` instead.
+    /// Please see notes in `deep_visit_all_item_likes`.
+    pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
     where
-        V: ItemLikeVisitor<'hir>,
+        V: Visitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
 
@@ -666,7 +672,7 @@ pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
         }
     }
 
-    pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
+    pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
         let crate_items = self.tcx.hir_crate_items(());
         for module in crate_items.submodules.iter() {
             f(*module)
index 48efae8045bddd9eaf5d0463f979a8cd7aff3413..d56e87bbb47453c77c30831ec126d2a6ddf251cb 100644 (file)
@@ -8,7 +8,7 @@
 /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
 ///
 /// **This is the most common choice.** A very common pattern is
-/// to use `visit_all_item_likes()` as an outer loop,
+/// to use `deep_visit_all_item_likes()` as an outer loop,
 /// and to have the visitor that visits the contents of each item
 /// using this setting.
 pub struct OnlyBodies(());
index dbebed67c2bd1c6d4759e328c0814ddb7a9363ca..a4d78911b2760a471c12e816c031fee6d6c9caf4 100644 (file)
@@ -24,7 +24,7 @@ pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Grap
         let terminator = body[source].terminator();
         let labels = terminator.kind.fmt_successor_labels();
 
-        for (&target, label) in terminator.successors().zip(labels) {
+        for (target, label) in terminator.successors().zip(labels) {
             let src = node(def_id, source);
             let trg = node(def_id, target);
             edges.push(Edge::new(src, trg, label.to_string()));
index 9afe9523fcab0438f102cf84226e57f6ee5df2b5..bb6b10149ab49de8b9d2d72b97aa6c782432719d 100644 (file)
@@ -1,7 +1,7 @@
 use super::{AllocId, ConstAlloc, Pointer, Scalar};
 
 use crate::mir::interpret::ConstValue;
-use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
+use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
 
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
@@ -35,6 +35,7 @@ fn from(err: ErrorGuaranteed) -> ErrorHandled {
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
 pub fn struct_error<'tcx>(
     tcx: TyCtxtAt<'tcx>,
index d8cba39c6d97bf9bc58a14321f8f12646e86d081..0fa4b10399a4b081dbb426960949e698853698a4 100644 (file)
@@ -119,9 +119,9 @@ macro_rules! throw_machine_stop {
 
 pub use self::error::{
     struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
-    InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
-    ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess,
-    UnsupportedOpInfo,
+    EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
+    MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
+    UninitBytesAccess, UnsupportedOpInfo,
 };
 
 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
index c71aea417eca0143279c565a813ed0da9203dabc..26da93b9dcebc90c45bf71a188037feec25477b4 100644 (file)
@@ -120,9 +120,11 @@ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
     where
         Self: Sized;
 
-    /// Provenance must always be able to identify the allocation this ptr points to.
+    /// If `OFFSET_IS_ADDR == false`, provenance must always be able to
+    /// identify the allocation this ptr points to (i.e., this must return `Some`).
+    /// Otherwise this function is best-effort (but must agree with `Machine::ptr_get_alloc`).
     /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
-    fn get_alloc_id(self) -> AllocId;
+    fn get_alloc_id(self) -> Option<AllocId>;
 }
 
 impl Provenance for AllocId {
@@ -147,8 +149,8 @@ fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         Ok(())
     }
 
-    fn get_alloc_id(self) -> AllocId {
-        self
+    fn get_alloc_id(self) -> Option<AllocId> {
+        Some(self)
     }
 }
 
index 7e5989b4112cff868e76f7e7f6da8fcb991365ad..5fb8e911124d26dbb5f2d9887caea4d4a944d3b8 100644 (file)
@@ -110,11 +110,22 @@ fn eval_to_allocation(
         Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
     }
 
-    /// Destructure a constant ADT or array into its variant index and its field values.
+    /// Destructure a type-level constant ADT or array into its variant index and its field values.
+    /// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
     pub fn destructure_const(
         self,
         param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
     ) -> mir::DestructuredConst<'tcx> {
         self.try_destructure_const(param_env_and_val).unwrap()
     }
+
+    /// Destructure a mir constant ADT or array into its variant index and its field values.
+    /// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
+    pub fn destructure_mir_constant(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        constant: mir::ConstantKind<'tcx>,
+    ) -> mir::DestructuredMirConstant<'tcx> {
+        self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
+    }
 }
index 9cffdf2993ed5bdb97c2ddba9a2beddb0a3ae61c..eeee170f43f949d95d567581686923523189ac5c 100644 (file)
@@ -344,7 +344,8 @@ pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
                 } else {
                     // We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
                     let (tag, offset) = ptr.into_parts();
-                    Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id(), offset), sz))
+                    // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail.
+                    Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz))
                 }
             }
         }
index 20ab3536222382a01c0dff814aac2defcea49b2f..7b68b1d755df7a40ef83b7fd7908b38e9c5ab18f 100644 (file)
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::codec::{TyDecoder, TyEncoder};
@@ -1355,10 +1355,7 @@ pub enum InlineAsmOperand<'tcx> {
 /// Type for MIR `Assert` terminator error messages.
 pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 
-// FIXME: Change `Successors` to `impl Iterator<Item = BasicBlock>`.
-#[allow(rustc::pass_by_value)]
-pub type Successors<'a> =
-    iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
+pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a;
 pub type SuccessorsMut<'a> =
     iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
 
@@ -2393,7 +2390,7 @@ pub fn function_handle(
         substs: SubstsRef<'tcx>,
         span: Span,
     ) -> Self {
-        let ty = tcx.type_of(def_id).subst(tcx, substs);
+        let ty = tcx.bound_type_of(def_id).subst(tcx, substs);
         Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
@@ -3078,6 +3075,58 @@ pub fn from_anon_const(
         Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
     }
 
+    #[instrument(skip(tcx), level = "debug")]
+    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def_id.to_def_id()),
+                "from_inline_const can only process anonymous constants"
+            ),
+        };
+        let expr = &tcx.hir().body(body_id).value;
+        let ty = tcx.typeck(def_id).node_type(hir_id);
+
+        let lit_input = match expr.kind {
+            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
+                hir::ExprKind::Lit(ref lit) => {
+                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+                }
+                _ => None,
+            },
+            _ => None,
+        };
+        if let Some(lit_input) = lit_input {
+            // If an error occurred, ignore that it's a literal and leave reporting the error up to
+            // mir.
+            match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
+                Ok(c) => return c,
+                Err(_) => {}
+            }
+        }
+
+        let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+        let parent_substs =
+            tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+        let substs =
+            ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
+                .substs;
+        let uneval_const = tcx.mk_const(ty::ConstS {
+            val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                def: ty::WithOptConstParam::unknown(def_id).to_global(),
+                substs,
+                promoted: None,
+            }),
+            ty,
+        });
+        debug!(?uneval_const);
+        debug_assert!(!uneval_const.has_free_regions());
+
+        Self::Ty(uneval_const)
+    }
+
     #[instrument(skip(tcx), level = "debug")]
     fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
@@ -3434,13 +3483,13 @@ fn start_node(&self) -> Self::Node {
 impl<'tcx> graph::WithSuccessors for Body<'tcx> {
     #[inline]
     fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
-        self.basic_blocks[node].terminator().successors().cloned()
+        self.basic_blocks[node].terminator().successors()
     }
 }
 
 impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
     type Item = BasicBlock;
-    type Iter = iter::Cloned<Successors<'b>>;
+    type Iter = Successors<'b>;
 }
 
 impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> {
index d03f9235efd587e621d95e8a1ca09565e8f22585..3bcb8f9c34c9a560d290a99f57acdfb6783a782c 100644 (file)
@@ -166,9 +166,7 @@ pub fn apply(self, body: &mut Body<'tcx>) {
             // get terminator's targets and apply the statement to all of them.
             if loc.statement_index > body[loc.block].statements.len() {
                 let term = body[loc.block].terminator();
-                let successors = term.successors().clone();
-
-                for i in successors {
+                for i in term.successors() {
                     stmts_and_targets
                         .push((Statement { source_info, kind: stmt.clone() }, i.clone()));
                 }
index 4fe2cde753290226889e54fc4591db806410d0f7..ad09328585d27bda542ed76b50273588a3ef1f54 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn compute(
             let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
             for (bb, data) in basic_blocks.iter_enumerated() {
                 if let Some(term) = &data.terminator {
-                    for &succ in term.successors() {
+                    for succ in term.successors() {
                         preds[succ].push(bb);
                     }
                 }
index 4d4eed179ca9decda55a9e01beaab400cffa4f26..7f7b8bdfc146172209da89890e85074c29d413e7 100644 (file)
@@ -1,6 +1,6 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{Body, Promoted};
+use crate::mir::{self, Body, Promoted};
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
@@ -413,13 +413,20 @@ pub enum ClosureOutlivesSubject<'tcx> {
     Region(ty::RegionVid),
 }
 
-/// The constituent parts of an ADT or array.
+/// The constituent parts of a type level constant of kind ADT or array.
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
     pub fields: &'tcx [ty::Const<'tcx>],
 }
 
+/// The constituent parts of a mir constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredMirConstant<'tcx> {
+    pub variant: Option<VariantIdx>,
+    pub fields: &'tcx [mir::ConstantKind<'tcx>],
+}
+
 /// Coverage information summarized from a MIR if instrumented for source code coverage (see
 /// compiler option `-Cinstrument-coverage`). This information is generated by the
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
index f1d5201454d698389430528b811e7ad7ba6c2b28..c93b7a955022925bd0b01d2168dd9a2f8a7ac3b2 100644 (file)
@@ -202,7 +202,9 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
                 AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))),
-                AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs),
+                AggregateKind::Adt(did, _, substs, _, _) => {
+                    tcx.bound_type_of(did).subst(tcx, substs)
+                }
                 AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs),
                 AggregateKind::Generator(did, substs, movability) => {
                     tcx.mk_generator(did, substs, movability)
index e6eb63fd3b2b8307556dff18bebe92542b26e055..fb3856b4952a032726dfeee9aaac585ffcd17835 100644 (file)
@@ -416,32 +416,36 @@ pub fn successors(&self) -> Successors<'_> {
             | Return
             | Unreachable
             | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]),
-            Goto { target: ref t }
-            | Call { destination: None, cleanup: Some(ref t), .. }
-            | Call { destination: Some((_, ref t)), cleanup: None, .. }
-            | Yield { resume: ref t, drop: None, .. }
-            | DropAndReplace { target: ref t, unwind: None, .. }
-            | Drop { target: ref t, unwind: None, .. }
-            | Assert { target: ref t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref t, unwind: None }
-            | InlineAsm { destination: Some(ref t), cleanup: None, .. }
-            | InlineAsm { destination: None, cleanup: Some(ref t), .. } => {
-                Some(t).into_iter().chain(&[])
+            | InlineAsm { destination: None, cleanup: None, .. } => {
+                None.into_iter().chain((&[]).into_iter().copied())
             }
-            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
-            | Yield { resume: ref t, drop: Some(ref u), .. }
-            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
-            | Drop { target: ref t, unwind: Some(ref u), .. }
-            | Assert { target: ref t, cleanup: Some(ref u), .. }
-            | FalseUnwind { real_target: ref t, unwind: Some(ref u) }
-            | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => {
-                Some(t).into_iter().chain(slice::from_ref(u))
+            Goto { target: t }
+            | Call { destination: None, cleanup: Some(t), .. }
+            | Call { destination: Some((_, t)), cleanup: None, .. }
+            | Yield { resume: t, drop: None, .. }
+            | DropAndReplace { target: t, unwind: None, .. }
+            | Drop { target: t, unwind: None, .. }
+            | Assert { target: t, cleanup: None, .. }
+            | FalseUnwind { real_target: t, unwind: None }
+            | InlineAsm { destination: Some(t), cleanup: None, .. }
+            | InlineAsm { destination: None, cleanup: Some(t), .. } => {
+                Some(t).into_iter().chain((&[]).into_iter().copied())
             }
-            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets),
-            FalseEdge { ref real_target, ref imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
+            Call { destination: Some((_, t)), cleanup: Some(ref u), .. }
+            | Yield { resume: t, drop: Some(ref u), .. }
+            | DropAndReplace { target: t, unwind: Some(ref u), .. }
+            | Drop { target: t, unwind: Some(ref u), .. }
+            | Assert { target: t, cleanup: Some(ref u), .. }
+            | FalseUnwind { real_target: t, unwind: Some(ref u) }
+            | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
+                Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
             }
+            SwitchInt { ref targets, .. } => {
+                None.into_iter().chain(targets.targets.iter().copied())
+            }
+            FalseEdge { real_target, ref imaginary_target } => Some(real_target)
+                .into_iter()
+                .chain(slice::from_ref(imaginary_target).into_iter().copied()),
         }
     }
 
index 8d831cc73b8a40409d5cb8b0deb3caa85c342e78..1cbfed621560d6a516edb278817535b54f2a03c4 100644 (file)
@@ -180,7 +180,7 @@ fn traverse_successor(&mut self) {
         // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
         loop {
             let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
-                if let Some(&bb) = iter.next() {
+                if let Some(bb) = iter.next() {
                     bb
                 } else {
                     break;
index 0ef694a3c8543d52f4b402d2df5b8d0914f35175..6432c653f1ce72516f93f807cd2ace1bfe291e29 100644 (file)
         cache_on_disk_if { true }
     }
 
-    /// Convert an evaluated constant to a type level constant or
+    /// Evaluate a constant and convert it to a type level constant or
     /// return `None` if that is not possible.
-    query const_to_valtree(
-        key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>>
-    ) -> Option<ty::ValTree<'tcx>> {
-        desc { "destructure constant" }
+    query eval_to_valtree(
+        key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
+    ) -> EvalToValTreeResult<'tcx> {
+        desc { "evaluate type-level constant" }
         remap_env_constness
     }
 
     /// field values or return `None` if constant is invalid.
     ///
     /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
-    query try_destructure_const(
-        key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
-    ) -> Option<mir::DestructuredConst<'tcx>> {
-        desc { "destructure constant" }
+    query try_destructure_const(key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>) -> Option<mir::DestructuredConst<'tcx>> {
+        desc { "destructure type level constant"}
+    }
+
+    /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
+    /// and its field values.
+    query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
+        desc { "destructure mir constant"}
         remap_env_constness
     }
 
         remap_env_constness
     }
 
+    /// Dereference a constant reference or raw pointer and turn the result into a constant
+    /// again.
+    query deref_mir_constant(
+        key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+    ) -> mir::ConstantKind<'tcx> {
+        desc { "deref constant" }
+        remap_env_constness
+    }
+
     query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
         desc { "get a &core::panic::Location referring to a span" }
     }
         desc { "converting literal to const" }
     }
 
+    query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> {
+        desc { "converting literal to mir constant" }
+    }
+
     query check_match(key: DefId) {
         desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
     }
 
+    /// Returns the attributes on the item at `def_id`.
+    ///
+    /// Do not use this directly, use `tcx.get_attrs` instead.
     query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
         desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
+    /// Whether the function is an intrinsic
+    query is_intrinsic(def_id: DefId) -> bool {
+        desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
     /// Returns the lang items defined in another crate by loading it from metadata.
     query get_lang_items(_: ()) -> LanguageItems {
         storage(ArenaCacheSelector<'tcx>)
index fdf5ecfdaf7ef25f599a228886b759f19d11f918..26e070af76406a046c6bfb996379a1c98a89ba1e 100644 (file)
@@ -662,7 +662,7 @@ pub enum PatKind<'tcx> {
     /// * Opaque constants, that must not be matched structurally. So anything that does not derive
     ///   `PartialEq` and `Eq`.
     Constant {
-        value: ty::Const<'tcx>,
+        value: mir::ConstantKind<'tcx>,
     },
 
     Range(PatRange<'tcx>),
@@ -692,8 +692,8 @@ pub enum PatKind<'tcx> {
 
 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
-    pub lo: ty::Const<'tcx>,
-    pub hi: ty::Const<'tcx>,
+    pub lo: mir::ConstantKind<'tcx>,
+    pub hi: mir::ConstantKind<'tcx>,
     pub end: RangeEnd,
 }
 
index 8c660e38a7fbe4786695edbc43c059d2cb83f614..4d30c0e35e4726d42ba46517da1ff58350a2d41d 100644 (file)
@@ -61,6 +61,9 @@ pub enum Reveal {
     ///     let x: <() as Assoc>::Output = true;
     /// }
     /// ```
+    ///
+    /// We also do not reveal the hidden type of opaque types during
+    /// type-checking.
     UserFacing,
 
     /// At codegen time, all monomorphic projections will succeed.
@@ -97,9 +100,7 @@ pub struct ObligationCause<'tcx> {
     /// information.
     pub body_id: hir::HirId,
 
-    /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
-    /// the time). `Some` otherwise.
-    code: Option<Lrc<ObligationCauseCode<'tcx>>>,
+    code: InternedObligationCauseCode<'tcx>,
 }
 
 // This custom hash function speeds up hashing for `Obligation` deduplication
@@ -123,11 +124,7 @@ pub fn new(
         body_id: hir::HirId,
         code: ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
-        ObligationCause {
-            span,
-            body_id,
-            code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) },
-        }
+        ObligationCause { span, body_id, code: code.into() }
     }
 
     pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
@@ -136,15 +133,12 @@ pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
 
     #[inline(always)]
     pub fn dummy() -> ObligationCause<'tcx> {
-        ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None }
+        ObligationCause::dummy_with_span(DUMMY_SP)
     }
 
+    #[inline(always)]
     pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None }
-    }
-
-    pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> {
-        Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE)))
+        ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() }
     }
 
     pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
@@ -164,14 +158,37 @@ pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
 
     #[inline]
     pub fn code(&self) -> &ObligationCauseCode<'tcx> {
-        self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE)
+        &self.code
     }
 
-    pub fn clone_code(&self) -> Lrc<ObligationCauseCode<'tcx>> {
-        match &self.code {
-            Some(code) => code.clone(),
-            None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE),
-        }
+    pub fn map_code(
+        &mut self,
+        f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) {
+        self.code = f(std::mem::take(&mut self.code)).into();
+    }
+
+    pub fn derived_cause(
+        mut self,
+        parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        /*!
+         * Creates a cause for obligations that are derived from
+         * `obligation` by a recursive search (e.g., for a builtin
+         * bound, or eventually a `auto trait Foo`). If `obligation`
+         * is itself a derived obligation, this is just a clone, but
+         * otherwise we create a "derived obligation" cause so as to
+         * keep track of the original root obligation for error
+         * reporting.
+         */
+
+        // NOTE(flaper87): As of now, it keeps track of the whole error
+        // chain. Ideally, we should have a way to configure this either
+        // by using -Z verbose or just a CLI argument.
+        self.code =
+            variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
+        self
     }
 }
 
@@ -182,6 +199,30 @@ pub struct UnifyReceiverContext<'tcx> {
     pub substs: SubstsRef<'tcx>,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)]
+pub struct InternedObligationCauseCode<'tcx> {
+    /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
+    /// the time). `Some` otherwise.
+    code: Option<Lrc<ObligationCauseCode<'tcx>>>,
+}
+
+impl<'tcx> ObligationCauseCode<'tcx> {
+    #[inline(always)]
+    fn into(self) -> InternedObligationCauseCode<'tcx> {
+        InternedObligationCauseCode {
+            code: if let MISC_OBLIGATION_CAUSE_CODE = self { None } else { Some(Lrc::new(self)) },
+        }
+    }
+}
+
+impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
+    type Target = ObligationCauseCode<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE)
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
@@ -269,7 +310,7 @@ pub enum ObligationCauseCode<'tcx> {
         /// The node of the function call.
         call_hir_id: hir::HirId,
         /// The obligation introduced by this argument.
-        parent_code: Lrc<ObligationCauseCode<'tcx>>,
+        parent_code: InternedObligationCauseCode<'tcx>,
     },
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
@@ -404,25 +445,27 @@ pub struct ImplDerivedObligationCause<'tcx> {
     pub span: Span,
 }
 
-impl ObligationCauseCode<'_> {
+impl<'tcx> ObligationCauseCode<'tcx> {
     // Return the base obligation, ignoring derived obligations.
     pub fn peel_derives(&self) -> &Self {
         let mut base_cause = self;
-        loop {
-            match base_cause {
-                BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
-                | DerivedObligation(DerivedObligationCause { parent_code, .. })
-                | FunctionArgumentObligation { parent_code, .. } => {
-                    base_cause = &parent_code;
-                }
-                ImplDerivedObligation(obligation_cause) => {
-                    base_cause = &*obligation_cause.derived.parent_code;
-                }
-                _ => break,
-            }
+        while let Some((parent_code, _)) = base_cause.parent() {
+            base_cause = parent_code;
         }
         base_cause
     }
+
+    pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
+        match self {
+            FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)),
+            BuiltinDerivedObligation(derived)
+            | DerivedObligation(derived)
+            | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => {
+                Some((&derived.parent_code, Some(derived.parent_trait_pred)))
+            }
+            _ => None,
+        }
+    }
 }
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -472,7 +515,7 @@ pub struct DerivedObligationCause<'tcx> {
     pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
 
     /// The parent trait had this cause.
-    pub parent_code: Lrc<ObligationCauseCode<'tcx>>,
+    pub parent_code: InternedObligationCauseCode<'tcx>,
 }
 
 #[derive(Clone, Debug, TypeFoldable, Lift)]
index 2e4c16e39eb9671ed0de6557b1bb12f3fbb03f05..bf7cb610a9097fa3186ca16bd4c40162800ec2c9 100644 (file)
@@ -230,8 +230,7 @@ pub(super) fn new(
             flags |= AdtFlags::HAS_CTOR;
         }
 
-        let attrs = tcx.get_attrs(did);
-        if tcx.sess.contains_name(&attrs, sym::fundamental) {
+        if tcx.has_attr(did, sym::fundamental) {
             flags |= AdtFlags::IS_FUNDAMENTAL;
         }
         if Some(did) == tcx.lang_items().phantom_data() {
index 9d3d509eb216beca26e858efd1b759f209f67966..1616b753433a83c0e47415865ca3e67836870677 100644 (file)
@@ -1148,9 +1148,8 @@ pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
     /// `rustc_layout_scalar_valid_range` attribute.
     // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
     pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
-        let attrs = self.get_attrs(def_id);
         let get = |name| {
-            let Some(attr) = attrs.iter().find(|a| a.has_name(name)) else {
+            let Some(attr) = self.get_attr(def_id, name) else {
                 return Bound::Unbounded;
             };
             debug!("layout_scalar_valid_range: attr={:?}", attr);
@@ -1604,7 +1603,7 @@ pub fn has_strict_asm_symbol_naming(self) -> bool {
     pub fn caller_location_ty(self) -> Ty<'tcx> {
         self.mk_imm_ref(
             self.lifetimes.re_static,
-            self.type_of(self.require_lang_item(LangItem::PanicLocation, None))
+            self.bound_type_of(self.require_lang_item(LangItem::PanicLocation, None))
                 .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())),
         )
     }
@@ -2333,7 +2332,7 @@ fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
                         ty_param.into()
                     } else {
                         assert!(has_default);
-                        self.type_of(param.def_id).subst(self, substs).into()
+                        self.bound_type_of(param.def_id).subst(self, substs).into()
                     }
                 }
             });
index da0934b67c5df70d0c87e5245fad7957c0c586c2..a0fe632f11a07f21b3cf37f5649226c318d399bf 100644 (file)
@@ -568,11 +568,8 @@ fn foo(&self, x: T) -> T { x }
                 }
             }
             TargetFeatureCast(def_id) => {
-                let attrs = self.get_attrs(*def_id);
-                let target_spans = attrs
-                    .iter()
-                    .filter(|attr| attr.has_name(sym::target_feature))
-                    .map(|attr| attr.span);
+                let target_spans =
+                    self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span);
                 diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
index 0bd96f8f865fcaa33f4882a1c1f5535802300765..d9b82ee0a76801e57e0ba70ee34328231489b40d 100644 (file)
@@ -1,6 +1,7 @@
 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
 use crate::ty;
 use crate::ty::subst::{Subst, SubstsRef};
+use crate::ty::EarlyBinder;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
@@ -229,7 +230,11 @@ pub fn instantiate_own(
         substs: SubstsRef<'tcx>,
     ) -> InstantiatedPredicates<'tcx> {
         InstantiatedPredicates {
-            predicates: self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)).collect(),
+            predicates: self
+                .predicates
+                .iter()
+                .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))
+                .collect(),
             spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
         }
     }
@@ -243,7 +248,9 @@ fn instantiate_into(
         if let Some(def_id) = self.parent {
             tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs);
         }
-        instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)));
+        instantiated
+            .predicates
+            .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs)));
         instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp));
     }
 
index 7cf7f8973475d26a766e9577848442e6cb2dab4c..f088db00d02a18212ff5d9be135e32484a8dd82f 100644 (file)
@@ -1,13 +1,14 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_macros::HashStable;
 use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
+use rustc_span::Symbol;
 
 use std::fmt;
 
@@ -185,8 +186,8 @@ pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
     }
 
     #[inline]
-    pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
-        tcx.get_attrs(self.def_id())
+    pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> {
+        tcx.get_attrs(self.def_id(), attr)
     }
 
     /// Returns `true` if the LLVM version of this instance is unconditionally
@@ -557,7 +558,11 @@ pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
     where
         T: TypeFoldable<'tcx> + Copy,
     {
-        if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v }
+        if let Some(substs) = self.substs_for_mir_body() {
+            EarlyBinder(*v).subst(tcx, substs)
+        } else {
+            *v
+        }
     }
 
     #[inline(always)]
index c8055100d30968a5c1c9f0df09fa9d5400b72f38..a7488fd44cd1c31d0ca78989507c148e6ea4a08a 100644 (file)
@@ -2,7 +2,7 @@
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::subst::Subst;
-use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeFoldable};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_hir as hir;
@@ -1706,7 +1706,7 @@ fn generator_layout(
     ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
         use SavedLocalEligibility::*;
         let tcx = self.tcx;
-        let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
+        let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs);
 
         let Some(info) = tcx.generator_layout(def_id) else {
             return Err(LayoutError::Unknown(ty));
@@ -2750,7 +2750,7 @@ fn fn_sig_for_fn_abi(
                 // track of a polymorphization `ParamEnv` to allow normalizing later.
                 let mut sig = match *ty.kind() {
                     ty::FnDef(def_id, substs) => tcx
-                        .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
+                        .normalize_erasing_regions(tcx.param_env(def_id), tcx.bound_fn_sig(def_id))
                         .subst(tcx, substs),
                     _ => unreachable!(),
                 };
@@ -2888,6 +2888,14 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: Spe
             return false;
         }
 
+        // With `-C panic=abort`, all non-FFI functions are required to not unwind.
+        //
+        // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
+        // function defined in Rust is also required to abort.
+        if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
+            return false;
+        }
+
         // With -Z panic-in-drop=abort, drop_in_place never unwinds.
         //
         // This is not part of `codegen_fn_attrs` as it can differ between crates
index d847068b5bfb3e99cefaabc82dc3ab3dd51403e0..91eea01bfb9b936648f7ca8ea139ee6bcd02bded 100644 (file)
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
 pub use self::Variance::*;
-pub use adt::*;
-pub use assoc::*;
-pub use generics::*;
-use rustc_data_structures::fingerprint::Fingerprint;
-pub use vtable::*;
-
 use crate::metadata::ModChild;
 use crate::middle::privacy::AccessLevels;
 use crate::mir::{Body, GeneratorLayout};
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::Discr;
+pub use adt::*;
+pub use assoc::*;
+pub use generics::*;
 use rustc_ast as ast;
 use rustc_attr as attr;
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -44,6 +42,7 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::Align;
+pub use vtable::*;
 
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -78,7 +77,7 @@
 pub use self::sty::TyKind::*;
 pub use self::sty::{
     Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
-    CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
+    CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBinder, EarlyBoundRegion,
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
     GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
     ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
@@ -736,7 +735,7 @@ pub fn subst_supertrait(
         let shifted_pred =
             tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder());
         // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1>
-        let new = shifted_pred.subst(tcx, trait_ref.skip_binder().substs);
+        let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs);
         // 3) ['x] + ['b] -> ['x, 'b]
         let bound_vars =
             tcx.mk_bound_variable_kinds(trait_bound_vars.iter().chain(pred_bound_vars));
@@ -1818,8 +1817,8 @@ pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
             field_shuffle_seed ^= user_seed;
         }
 
-        for attr in tcx.get_attrs(did).iter() {
-            for r in attr::find_repr_attrs(&tcx.sess, attr) {
+        for attr in tcx.get_attrs(did, sym::repr) {
+            for r in attr::parse_repr_attr(&tcx.sess, attr) {
                 flags.insert(match r {
                     attr::ReprC => ReprFlags::IS_C,
                     attr::ReprPacked(pack) => {
@@ -1932,7 +1931,7 @@ impl<'tcx> FieldDef {
     /// Returns the type of this field. The resulting type is not normalized. The `subst` is
     /// typically obtained via the second field of [`TyKind::Adt`].
     pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
-        tcx.type_of(self.did).subst(tcx, subst)
+        tcx.bound_type_of(self.did).subst(tcx, subst)
     }
 
     /// Computes the `Ident` of this variant by looking up the `Span`
@@ -1941,8 +1940,7 @@ pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
     }
 }
 
-pub type Attributes<'tcx> = &'tcx [ast::Attribute];
-
+pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>;
 #[derive(Debug, PartialEq, Eq)]
 pub enum ImplOverlapKind {
     /// These impls are always allowed to overlap.
@@ -1996,7 +1994,8 @@ pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'
             .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
     }
 
-    fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
+    /// Look up the name of a definition across crates. This does not look at HIR.
+    pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
         if let Some(cnum) = def_id.as_crate_root() {
             Some(self.crate_name(cnum))
         } else {
@@ -2016,16 +2015,11 @@ fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
 
     /// Look up the name of a definition across crates. This does not look at HIR.
     ///
-    /// When possible, this function should be used for cross-crate lookups over
-    /// [`opt_item_name`] to avoid invalidating the incremental cache. If you
-    /// need to handle items without a name, or HIR items that will not be
-    /// serialized cross-crate, or if you need the span of the item, use
+    /// This method will ICE if the corresponding item does not have a name.  In these cases, use
     /// [`opt_item_name`] instead.
     ///
     /// [`opt_item_name`]: Self::opt_item_name
     pub fn item_name(self, id: DefId) -> Symbol {
-        // Look at cross-crate items first to avoid invalidating the incremental cache
-        // unless we have to.
         self.opt_item_name(id).unwrap_or_else(|| {
             bug!("item_name: no name for {:?}", self.def_path(id));
         })
@@ -2186,8 +2180,8 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         }
     }
 
-    /// Gets the attributes of a definition.
-    pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> {
+    // FIXME(@lcnr): Remove this function.
+    pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] {
         if let Some(did) = did.as_local() {
             self.hir().attrs(self.hir().local_def_id_to_hir_id(did))
         } else {
@@ -2195,9 +2189,29 @@ pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> {
         }
     }
 
+    /// Gets all attributes with the given name.
+    pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> {
+        let filter_fn = move |a: &&ast::Attribute| a.has_name(attr);
+        if let Some(did) = did.as_local() {
+            self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+        } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) {
+            bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
+        } else {
+            self.item_attrs(did).iter().filter(filter_fn)
+        }
+    }
+
+    pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
+        self.get_attrs(did, attr).next()
+    }
+
     /// Determines whether an item is annotated with an attribute.
     pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
-        self.sess.contains_name(&self.get_attrs(did), attr)
+        if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) {
+            bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
+        } else {
+            self.get_attrs(did, attr).next().is_some()
+        }
     }
 
     /// Returns `true` if this is an `auto trait`.
index 808be446b2af66920b70c439e15329ad18549863..9bbbd7e2f7c5ee58fb8b78a60c087aca4a94357f 100644 (file)
@@ -11,7 +11,7 @@
 use crate::traits::query::NoSolution;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
 use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, EarlyBinder, Ty, TyCtxt};
 
 #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
 pub enum NormalizationError<'tcx> {
@@ -133,7 +133,7 @@ pub fn subst_and_normalize_erasing_regions<T>(
              param_env={:?})",
             param_substs, value, param_env,
         );
-        let substituted = value.subst(self, param_substs);
+        let substituted = EarlyBinder(value).subst(self, param_substs);
         self.normalize_erasing_regions(param_env, substituted)
     }
 
@@ -157,7 +157,7 @@ pub fn try_subst_and_normalize_erasing_regions<T>(
              param_env={:?})",
             param_substs, value, param_env,
         );
-        let substituted = value.subst(self, param_substs);
+        let substituted = EarlyBinder(value).subst(self, param_substs);
         self.try_normalize_erasing_regions(param_env, substituted)
     }
 }
index a1d1b6b3a785bcc6e522d6e7363140e4a4fcdb90..9d8124eb25db15e34a42059b0e0b77ca612cf892 100644 (file)
@@ -115,12 +115,16 @@ fn default_print_def_path(
 
             DefPathData::Impl => {
                 let generics = self.tcx().generics_of(def_id);
-                let mut self_ty = self.tcx().type_of(def_id);
-                let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id);
-                if substs.len() >= generics.count() {
-                    self_ty = self_ty.subst(self.tcx(), substs);
-                    impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs);
-                }
+                let self_ty = self.tcx().bound_type_of(def_id);
+                let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id);
+                let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() {
+                    (
+                        self_ty.subst(self.tcx(), substs),
+                        impl_trait_ref.map(|i| i.subst(self.tcx(), substs)),
+                    )
+                } else {
+                    (self_ty.0, impl_trait_ref.map(|i| i.0))
+                };
                 self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
             }
 
@@ -203,7 +207,7 @@ fn generic_args_to_print(
                     has_default
                         && substs[param.index as usize]
                             == GenericArg::from(
-                                self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
+                                self.tcx().bound_type_of(param.def_id).subst(self.tcx(), substs),
                             )
                 }
                 ty::GenericParamDefKind::Const { has_default } => {
index eed90337c0a5057aac25794491bc6ebbc54fe594..4c0bc2e4337c712ffd96f09cc6d90f744c4abf20 100644 (file)
@@ -587,7 +587,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 p!(")")
             }
             ty::FnDef(def_id, substs) => {
-                let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
+                let sig = self.tcx().bound_fn_sig(def_id).subst(self.tcx(), substs);
                 p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
@@ -774,13 +774,13 @@ fn pretty_print_opaque_impl_type(
 
         // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
         // by looking up the projections associated with the def_id.
-        let bounds = self.tcx().explicit_item_bounds(def_id);
+        let bounds = self.tcx().bound_explicit_item_bounds(def_id);
 
         let mut traits = BTreeMap::new();
         let mut fn_traits = BTreeMap::new();
         let mut is_sized = false;
 
-        for (predicate, _) in bounds {
+        for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
             let predicate = predicate.subst(self.tcx(), substs);
             let bound_predicate = predicate.kind();
 
index fb937ded65af12d43ae2d29813f139df4dad83a4..0398a83e22020006ec3e3eef2bebb543c7bfed16 100644 (file)
 use crate::middle::stability::{self, DeprecationEntry};
 use crate::mir;
 use crate::mir::interpret::GlobalId;
-use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput};
-use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
+use crate::mir::interpret::{
+    ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+};
+use crate::mir::interpret::{LitToConstError, LitToConstInput};
 use crate::mir::mono::CodegenUnit;
 use crate::thir;
 use crate::traits::query::{
index 4c1160e21fec2bf715d8257f46082faba65f2916..8677405eebedac5aa8443288f05734b56e0865b0 100644 (file)
@@ -159,7 +159,8 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
         let variance = variances[i];
         let variance_info = if variance == ty::Invariant {
-            let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+            let ty =
+                *cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst));
             ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
         } else {
             ty::VarianceDiagInfo::default()
index 4ef6ff1835ffd022ccddc0a098c3c2496aec2640..2c8cd4f933d0444a1b527ad4df6ade630b6f46a7 100644 (file)
@@ -860,6 +860,27 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
     }
 }
 
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> {
+    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        self.try_map_bound(|ty| ty.try_fold_with(folder))
+    }
+
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_map_bound(|ty| ty.try_fold_with(folder))
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.as_ref().0.visit_with(visitor)
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.as_ref().0.visit_with(visitor)
+    }
+}
+
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
index 7969e7aa151df46a5f6c262db7e0c00f193ede40..a973a5c9b5053d6c311f371121f973db49315efc 100644 (file)
@@ -713,7 +713,9 @@ pub fn state_tys(
     ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
         let layout = tcx.generator_layout(def_id).unwrap();
         layout.variant_fields.iter().map(move |variant| {
-            variant.iter().map(move |field| layout.field_tys[*field].subst(tcx, self.substs))
+            variant
+                .iter()
+                .map(move |field| EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs))
         })
     }
 
@@ -1068,6 +1070,69 @@ pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTrai
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable)]
+pub struct EarlyBinder<T>(pub T);
+
+impl<T> EarlyBinder<T> {
+    pub fn as_ref(&self) -> EarlyBinder<&T> {
+        EarlyBinder(&self.0)
+    }
+
+    pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
+    where
+        F: FnOnce(&T) -> U,
+    {
+        self.as_ref().map_bound(f)
+    }
+
+    pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
+    where
+        F: FnOnce(T) -> U,
+    {
+        let value = f(self.0);
+        EarlyBinder(value)
+    }
+
+    pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
+    where
+        F: FnOnce(T) -> Result<U, E>,
+    {
+        let value = f(self.0)?;
+        Ok(EarlyBinder(value))
+    }
+}
+
+impl<T> EarlyBinder<Option<T>> {
+    pub fn transpose(self) -> Option<EarlyBinder<T>> {
+        self.0.map(|v| EarlyBinder(v))
+    }
+}
+
+impl<T, U> EarlyBinder<(T, U)> {
+    pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) {
+        (EarlyBinder(self.0.0), EarlyBinder(self.0.1))
+    }
+}
+
+pub struct EarlyBinderIter<T> {
+    t: T,
+}
+
+impl<T: IntoIterator> EarlyBinder<T> {
+    pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
+        EarlyBinderIter { t: self.0.into_iter() }
+    }
+}
+
+impl<T: Iterator> Iterator for EarlyBinderIter<T> {
+    type Item = EarlyBinder<T::Item>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.t.next().map(|i| EarlyBinder(i))
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum BoundVariableKind {
@@ -2139,7 +2204,7 @@ pub fn builtin_index(self) -> Option<Ty<'tcx>> {
 
     pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
         match self.kind() {
-            FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs),
+            FnDef(def_id, substs) => tcx.bound_fn_sig(*def_id).subst(tcx, substs),
             FnPtr(f) => *f,
             Error(_) => {
                 // ignore errors (#54954)
@@ -2306,7 +2371,7 @@ pub fn ptr_metadata_ty(
             ty::Str | ty::Slice(_) => (tcx.types.usize, false),
             ty::Dynamic(..) => {
                 let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
-                (tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
+                (tcx.bound_type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
             },
 
             // type parameters only have unit metadata if they're sized, so return true
index 5b1fb70872988c0787dc2bfe4d49ab0167c65969..48c71113d50329e1ffd10e18b1e0de330d031bc7 100644 (file)
@@ -4,7 +4,7 @@
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
-use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+use crate::ty::{self, EarlyBinder, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
@@ -499,14 +499,19 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
 }
 
 // Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
+#[rustc_on_unimplemented(message = "Calling `subst` must now be done through an `EarlyBinder`")]
 pub trait Subst<'tcx>: Sized {
-    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self;
+    type Inner;
+
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner;
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
-    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
+impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for EarlyBinder<T> {
+    type Inner = T;
+
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner {
         let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
-        self.fold_with(&mut folder)
+        self.0.fold_with(&mut folder)
     }
 }
 
index 1c8af13ce9ca1f980d4f6a99894c5029fa9c60a7..55f08b5678aa32728acd9907a281b656fa38ad59 100644 (file)
@@ -6,7 +6,8 @@
 use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
 use crate::ty::{
-    self, Const, DebruijnIndex, DefIdTree, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, TypeFoldable,
+    self, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*,
+    TypeFoldable,
 };
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
@@ -20,6 +21,7 @@
 use rustc_macros::HashStable;
 use rustc_span::{sym, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
+use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
 use std::{fmt, iter};
 
@@ -591,6 +593,32 @@ pub fn try_expand_impl_trait_type(
         trace!(?expanded_type);
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
+
+    pub fn bound_type_of(self, def_id: DefId) -> EarlyBinder<Ty<'tcx>> {
+        EarlyBinder(self.type_of(def_id))
+    }
+
+    pub fn bound_fn_sig(self, def_id: DefId) -> EarlyBinder<ty::PolyFnSig<'tcx>> {
+        EarlyBinder(self.fn_sig(def_id))
+    }
+
+    pub fn bound_impl_trait_ref(self, def_id: DefId) -> Option<EarlyBinder<ty::TraitRef<'tcx>>> {
+        self.impl_trait_ref(def_id).map(|i| EarlyBinder(i))
+    }
+
+    pub fn bound_explicit_item_bounds(
+        self,
+        def_id: DefId,
+    ) -> EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
+        EarlyBinder(self.explicit_item_bounds(def_id))
+    }
+
+    pub fn bound_item_bounds(
+        self,
+        def_id: DefId,
+    ) -> EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
+        EarlyBinder(self.item_bounds(def_id))
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
@@ -622,7 +650,7 @@ fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option
             let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
                 Some(expanded_ty) => *expanded_ty,
                 None => {
-                    let generic_ty = self.tcx.type_of(def_id);
+                    let generic_ty = self.tcx.bound_type_of(def_id);
                     let concrete_ty = generic_ty.subst(self.tcx, substs);
                     let expanded_ty = self.fold_ty(concrete_ty);
                     self.expanded_cache.insert((def_id, substs), expanded_ty);
@@ -662,7 +690,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
 impl<'tcx> Ty<'tcx> {
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
+    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -677,12 +705,13 @@ pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
             }),
             _ => None,
         };
-        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
+    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -696,7 +725,8 @@ pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
             }),
             _ => None,
         };
-        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Checks whether values of this type `T` are *moved* or *copied*
@@ -1163,12 +1193,17 @@ pub fn normalize_opaque_types<'tcx>(
 
 /// Determines whether an item is annotated with `doc(hidden)`.
 pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    tcx.get_attrs(def_id)
-        .iter()
-        .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None })
+    tcx.get_attrs(def_id, sym::doc)
+        .filter_map(|attr| attr.meta_item_list())
         .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
 }
 
+/// Determines whether an item is an intrinsic by Abi.
+pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { normalize_opaque_types, is_doc_hidden, ..*providers }
+    *providers =
+        ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
 }
index 3a6e59db90b91d08cd492268ebf3ebf934210cbc..25ba5d570b83b11083a853a0d0e3a0cb5cf8a5b0 100644 (file)
@@ -1,16 +1,12 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::Builder;
-use crate::thir::constant::parse_float;
-use rustc_ast as ast;
+use crate::build::{lit_to_mir_constant, Builder};
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::interpret::Allocation;
 use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
-use rustc_target::abi::Size;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
@@ -88,54 +84,3 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 }
-
-#[instrument(skip(tcx, lit_input))]
-fn lit_to_mir_constant<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    lit_input: LitToConstInput<'tcx>,
-) -> Result<ConstantKind<'tcx>, LitToConstError> {
-    let LitToConstInput { lit, ty, neg } = lit_input;
-    let trunc = |n| {
-        let param_ty = ty::ParamEnv::reveal_all().and(ty);
-        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
-        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
-        let result = width.truncate(n);
-        trace!("trunc result: {}", result);
-        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
-    };
-
-    let value = match (lit, &ty.kind()) {
-        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
-            let s = s.as_str();
-            let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
-            let allocation = tcx.intern_const_alloc(allocation);
-            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
-        }
-        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
-            if matches!(inner_ty.kind(), ty::Slice(_)) =>
-        {
-            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
-            let allocation = tcx.intern_const_alloc(allocation);
-            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
-        }
-        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
-            let id = tcx.allocate_bytes(data);
-            ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
-        }
-        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
-            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
-        }
-        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
-            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
-        }
-        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
-            parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
-        }
-        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
-        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
-        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
-        _ => return Err(LitToConstError::TypeError),
-    };
-
-    Ok(ConstantKind::Val(value, ty))
-}
index fa5ec22926efcf4d5a161ac12438d92a8775c3fc..05b1342cf8c0783c3e7036500f0e6dc80d69a813 100644 (file)
@@ -966,13 +966,13 @@ enum TestKind<'tcx> {
         ///
         /// For `bool` we always generate two edges, one for `true` and one for
         /// `false`.
-        options: FxIndexMap<ty::Const<'tcx>, u128>,
+        options: FxIndexMap<ConstantKind<'tcx>, u128>,
     },
 
     /// Test for equality with value, possibly after an unsizing coercion to
     /// `ty`,
     Eq {
-        value: ty::Const<'tcx>,
+        value: ConstantKind<'tcx>,
         // Integer types are handled by `SwitchInt`, and constants with ADT
         // types are converted back into patterns, so this can only be `&str`,
         // `&[T]`, `f32` or `f64`.
index 7f53d9dd70502ad10b0f567efdd81d9e77a9f3fa..895df5808dbe16c6eb0cbb2abbeecab6d35c9598 100644 (file)
@@ -228,9 +228,7 @@ fn simplify_match_pair<'pat>(
                     _ => (None, 0),
                 };
                 if let Some((min, max, sz)) = range {
-                    if let (Some(lo), Some(hi)) =
-                        (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz))
-                    {
+                    if let (Some(lo), Some(hi)) = (lo.try_to_bits(sz), hi.try_to_bits(sz)) {
                         // We want to compare ranges numerically, but the order of the bitwise
                         // representation of signed integers does not match their numeric order.
                         // Thus, to correct the ordering, we need to shift the range of signed
index 0e9e98693766084ec18e95d4d1f10904dbd7c2ee..565345595d5002d7092886d64295b32aa6331588 100644 (file)
@@ -86,7 +86,7 @@ pub(super) fn add_cases_to_switch<'pat>(
         test_place: &PlaceBuilder<'tcx>,
         candidate: &Candidate<'pat, 'tcx>,
         switch_ty: Ty<'tcx>,
-        options: &mut FxIndexMap<ty::Const<'tcx>, u128>,
+        options: &mut FxIndexMap<ConstantKind<'tcx>, u128>,
     ) -> bool {
         let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else {
             return false;
@@ -366,7 +366,7 @@ fn non_scalar_compare(
         block: BasicBlock,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
         source_info: SourceInfo,
-        value: ty::Const<'tcx>,
+        value: ConstantKind<'tcx>,
         place: Place<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
@@ -760,7 +760,11 @@ fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> !
         span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
     }
 
-    fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option<bool> {
+    fn const_range_contains(
+        &self,
+        range: PatRange<'tcx>,
+        value: ConstantKind<'tcx>,
+    ) -> Option<bool> {
         use std::cmp::Ordering::*;
 
         let tcx = self.tcx;
@@ -777,7 +781,7 @@ fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) ->
     fn values_not_contained_in_range(
         &self,
         range: PatRange<'tcx>,
-        options: &FxIndexMap<ty::Const<'tcx>, u128>,
+        options: &FxIndexMap<ConstantKind<'tcx>, u128>,
     ) -> Option<bool> {
         for &val in options.keys() {
             if self.const_range_contains(range, val)? {
@@ -834,7 +838,7 @@ fn trait_method<'tcx>(
         .find(|item| item.kind == ty::AssocKind::Fn)
         .expect("trait method not found");
 
-    let method_ty = tcx.type_of(item.def_id);
+    let method_ty = tcx.bound_type_of(item.def_id);
     let method_ty = method_ty.subst(tcx, substs);
 
     ConstantKind::zero_sized(method_ty)
index 84762d602f8db5030f46e9c4046ed9f3000bf833..8b1ab482ee8be109c1aa2eb8727f1eec592631b9 100644 (file)
@@ -3,7 +3,6 @@
 
 use crate::build::Builder;
 
-use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, DUMMY_SP};
@@ -26,11 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     /// Convenience function for creating a literal operand, one
     /// without any user type annotation.
-    crate fn literal_operand(
-        &mut self,
-        span: Span,
-        literal: mir::ConstantKind<'tcx>,
-    ) -> Operand<'tcx> {
+    crate fn literal_operand(&mut self, span: Span, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
         let constant = Box::new(Constant { span, user_ty: None, literal });
         Operand::Constant(constant)
     }
index ce57e5fe846eb7e37323ae80451bbb544716658c..1cbe8c5a68af4120367de86ed94a3417f8d3d737 100644 (file)
@@ -1,7 +1,9 @@
 use crate::build;
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
+use crate::thir::constant::parse_float;
 use crate::thir::pattern::pat_from_hir;
+use rustc_ast as ast;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
 use super::lints;
@@ -177,7 +182,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
                 let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
                     let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(arg.span));
 
-                    tcx.type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()])
+                    tcx.bound_type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()])
                 } else {
                     fn_sig.inputs()[index]
                 };
@@ -260,6 +265,57 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     })
 }
 
+#[instrument(skip(tcx, lit_input))]
+pub(crate) fn lit_to_mir_constant<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    lit_input: LitToConstInput<'tcx>,
+) -> Result<ConstantKind<'tcx>, LitToConstError> {
+    let LitToConstInput { lit, ty, neg } = lit_input;
+    let trunc = |n| {
+        let param_ty = ty::ParamEnv::reveal_all().and(ty);
+        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
+        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
+        let result = width.truncate(n);
+        trace!("trunc result: {}", result);
+        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
+    };
+
+    let value = match (lit, &ty.kind()) {
+        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
+            let s = s.as_str();
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
+            let allocation = tcx.intern_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
+        }
+        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
+            if matches!(inner_ty.kind(), ty::Slice(_)) =>
+        {
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+            let allocation = tcx.intern_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+        }
+        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
+            let id = tcx.allocate_bytes(data);
+            ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
+        }
+        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
+            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
+        }
+        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
+            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
+        }
+        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
+            parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
+        }
+        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
+        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
+        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
+        _ => return Err(LitToConstError::TypeError),
+    };
+
+    Ok(ConstantKind::Val(value, ty))
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
 
@@ -679,7 +735,6 @@ fn construct_fn<'tcx, A>(
     } else {
         None
     };
-    debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id()));
 
     let mut body = builder.finish();
     body.spread_arg = spread_arg;
index 4ffee59a962749db407cac266a8ec0a098f2b1f4..4f0402bfa8bc791ec75de7e6400cc0f59b51a086 100644 (file)
@@ -27,6 +27,7 @@
 pub fn provide(providers: &mut Providers) {
     providers.check_match = thir::pattern::check_match;
     providers.lit_to_const = thir::constant::lit_to_const;
+    providers.lit_to_mir_constant = build::lit_to_mir_constant;
     providers.mir_built = build::mir_built;
     providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
index 147c136e651dd6ccf15dea84b0b5ab315c78e630..8f5ad6b1a07a0e44f41111614e873e7c1be19049 100644 (file)
@@ -798,8 +798,8 @@ fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
             pattern: self.pattern_from_hir(&arm.pat),
             guard: arm.guard.as_ref().map(|g| match g {
                 hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)),
-                hir::Guard::IfLet(ref pat, ref e) => {
-                    Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(e))
+                hir::Guard::IfLet(ref l) => {
+                    Guard::IfLet(self.pattern_from_hir(l.pat), self.mirror_expr(l.init))
                 }
             }),
             body: self.mirror_expr(arm.body),
index f17fe38b292cbca5b6234856f23d40f293f68f17..aafc368d3fdaaded6bbf3cd778ab358ced8dad78 100644 (file)
@@ -5,6 +5,7 @@
 use crate::thir::pattern::pat_from_hir;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
+use rustc_ast as ast;
 use rustc_data_structures::steal::Steal;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_hir::Node;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::ConstantKind;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 
 crate fn thir_body<'tcx>(
@@ -75,6 +78,24 @@ fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
+    crate fn const_eval_literal(
+        &mut self,
+        lit: &'tcx ast::LitKind,
+        ty: Ty<'tcx>,
+        sp: Span,
+        neg: bool,
+    ) -> ConstantKind<'tcx> {
+        match self.tcx.at(sp).lit_to_mir_constant(LitToConstInput { lit, ty, neg }) {
+            Ok(c) => c,
+            Err(LitToConstError::Reported) => {
+                // create a dummy value and continue compiling
+                ConstantKind::Ty(self.tcx.const_error(ty))
+            }
+            Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"),
+        }
+    }
+
     crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
         let p = match self.tcx.hir().get(p.hir_id) {
             Node::Pat(p) | Node::Binding(p) => p,
index 58e484e413dab4d5a1a4d4ca14f40479ec059328..f86899021e38808fc3878900c660a7820c04e977 100644 (file)
@@ -173,10 +173,10 @@ fn check_match(
         for arm in hir_arms {
             // Check the arm for some things unrelated to exhaustiveness.
             self.check_patterns(&arm.pat, Refutable);
-            if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
-                self.check_patterns(pat, Refutable);
-                let tpat = self.lower_pattern(&mut cx, pat, &mut false);
-                self.check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span());
+            if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard {
+                self.check_patterns(let_expr.pat, Refutable);
+                let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false);
+                self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span());
             }
         }
 
@@ -1108,9 +1108,9 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
 
     match parent_node {
         hir::Node::Arm(hir::Arm {
-            guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
+            guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })),
             ..
-        }) if Some(hir_id) == pat_id => {
+        }) if Some(*hir_id) == pat_id => {
             return LetSource::IfLetGuard;
         }
         hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
index 2298cc7cddf47a26a220a27576e0094586e93bf3..880f86aff5d01acdf4b8f807dba494c351861275 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_middle::mir::Field;
+use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
@@ -22,7 +22,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     pub(super) fn const_to_pat(
         &self,
-        cv: ty::Const<'tcx>,
+        cv: mir::ConstantKind<'tcx>,
         id: hir::HirId,
         span: Span,
         mir_structural_match_violation: bool,
@@ -152,7 +152,11 @@ fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> {
+    fn to_pat(
+        &mut self,
+        cv: mir::ConstantKind<'tcx>,
+        mir_structural_match_violation: bool,
+    ) -> Pat<'tcx> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -246,7 +250,7 @@ fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
 
     fn field_pats(
         &self,
-        vals: impl Iterator<Item = ty::Const<'tcx>>,
+        vals: impl Iterator<Item = mir::ConstantKind<'tcx>>,
     ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
         vals.enumerate()
             .map(|(idx, val)| {
@@ -257,9 +261,10 @@ fn field_pats(
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
+    #[instrument(skip(self), level = "debug")]
     fn recur(
         &self,
-        cv: ty::Const<'tcx>,
+        cv: mir::ConstantKind<'tcx>,
         mir_structural_match_violation: bool,
     ) -> Result<Pat<'tcx>, FallbackToConstRef> {
         let id = self.id;
@@ -365,7 +370,7 @@ fn recur(
                 PatKind::Wild
             }
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_mir_constant(param_env, cv);
                 PatKind::Variant {
                     adt_def: *adt_def,
                     substs,
@@ -376,12 +381,12 @@ fn recur(
                 }
             }
             ty::Tuple(_) | ty::Adt(_, _) => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_mir_constant(param_env, cv);
                 PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
             }
             ty::Array(..) => PatKind::Array {
                 prefix: tcx
-                    .destructure_const(param_env.and(cv))
+                    .destructure_mir_constant(param_env, cv)
                     .fields
                     .iter()
                     .map(|val| self.recur(*val, false))
@@ -412,12 +417,12 @@ fn recur(
                 // arrays.
                 ty::Array(..) if !self.treat_byte_string_as_slice => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Array {
                                 prefix: tcx
-                                    .destructure_const(param_env.and(array))
+                                    .destructure_mir_constant(param_env, array)
                                     .fields
                                     .iter()
                                     .map(|val| self.recur(*val, false))
@@ -438,12 +443,12 @@ fn recur(
                 // pattern.
                 ty::Slice(elem_ty) => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Slice {
                                 prefix: tcx
-                                    .destructure_const(param_env.and(array))
+                                    .destructure_mir_constant(param_env, array)
                                     .fields
                                     .iter()
                                     .map(|val| self.recur(*val, false))
@@ -512,7 +517,7 @@ fn recur(
                         // we fall back to a const pattern. If we do not do this, we may end up with
                         // a !structural-match constant that is not of reference type, which makes it
                         // very hard to invoke `PartialEq::eq` on it as a fallback.
-                        let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
+                        let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
                             Ok(subpattern) => PatKind::Deref { subpattern },
                             Err(_) => PatKind::Constant { value: cv },
                         };
index 60eead69a1b05445f80c696832b7dcb682fa22bb..b7de3f28872e5f100cb1cdaedcd5c1ec0bc44050 100644 (file)
@@ -52,7 +52,7 @@
 use rustc_index::vec::Idx;
 
 use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::Field;
+use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
@@ -133,23 +133,35 @@ fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u
     }
 
     #[inline]
-    fn from_const<'tcx>(
+    fn from_constant<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: ty::Const<'tcx>,
+        value: mir::ConstantKind<'tcx>,
     ) -> Option<IntRange> {
         let ty = value.ty();
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
             let val = (|| {
-                if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = 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 fall through, which
-                    // is more general but much slower.)
-                    if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size).unwrap() {
-                        return Some(bits);
+                match value {
+                    mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => {
+                        // 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 fall through, which
+                        // is more general but much slower.)
+                        if let Ok(Ok(bits)) = scalar.to_bits_or_ptr_internal(target_size) {
+                            return Some(bits);
+                        } else {
+                            return None;
+                        }
                     }
+                    mir::ConstantKind::Ty(c) => match c.val() {
+                        ty::ConstKind::Value(_) => bug!(
+                            "encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"
+                        ),
+                        _ => {}
+                    },
+                    _ => {}
                 }
+
                 // This is a more general form of the previous case.
                 value.try_eval_bits(tcx, param_env, ty)
             })()?;
@@ -234,8 +246,8 @@ fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
         let (lo, hi) = (lo ^ bias, hi ^ bias);
 
         let env = ty::ParamEnv::empty().and(ty);
-        let lo_const = ty::Const::from_bits(tcx, lo, env);
-        let hi_const = ty::Const::from_bits(tcx, hi, env);
+        let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
+        let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
 
         let kind = if lo == hi {
             PatKind::Constant { value: lo_const }
@@ -635,9 +647,9 @@ pub(super) enum Constructor<'tcx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd),
+    FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
-    Str(ty::Const<'tcx>),
+    Str(mir::ConstantKind<'tcx>),
     /// Array and slice patterns.
     Slice(Slice),
     /// Constants that must not be matched structurally. They are treated as black
@@ -1376,7 +1388,7 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                 }
             }
             PatKind::Constant { value } => {
-                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) {
+                if let Some(int_range) = IntRange::from_constant(cx.tcx, cx.param_env, *value) {
                     ctor = IntRange(int_range);
                     fields = Fields::empty();
                 } else {
index 5b0aa4309a8ed9918141507e8ae3e08153b0d75b..55d84782c485eb62f47c595bf35832d81965abff 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_index::vec::Idx;
 use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
 use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
-use rustc_middle::mir::UserTypeProjection;
+use rustc_middle::mir::{self, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
 use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
@@ -121,8 +121,8 @@ fn lower_range_expr(
     fn lower_pattern_range(
         &mut self,
         ty: Ty<'tcx>,
-        lo: ty::Const<'tcx>,
-        hi: ty::Const<'tcx>,
+        lo: mir::ConstantKind<'tcx>,
+        hi: mir::ConstantKind<'tcx>,
         end: RangeEnd,
         span: Span,
     ) -> PatKind<'tcx> {
@@ -177,16 +177,18 @@ fn normalize_range_pattern_ends(
         ty: Ty<'tcx>,
         lo: Option<&PatKind<'tcx>>,
         hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> {
+    ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
         match (lo, hi) {
             (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
                 Some((*lo, *hi))
             }
             (Some(PatKind::Constant { value: lo }), None) => {
-                Some((*lo, ty.numeric_max_val(self.tcx)?))
+                let hi = ty.numeric_max_val(self.tcx)?;
+                Some((*lo, hi.into()))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
-                Some((ty.numeric_min_val(self.tcx)?, *hi))
+                let lo = ty.numeric_min_val(self.tcx)?;
+                Some((lo.into(), *hi))
             }
             _ => None,
         }
@@ -446,6 +448,7 @@ fn lower_variant_or_leaf(
     /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
     /// it to `const_to_pat`. Any other path (like enum variants without fields)
     /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
+    #[instrument(skip(self), level = "debug")]
     fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
         let ty = self.typeck_results.node_type(id);
         let res = self.typeck_results.qpath_res(qpath, id);
@@ -487,8 +490,8 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
         debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
 
         match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
-            Ok(value) => {
-                let const_ = ty::Const::from_value(self.tcx, value, ty);
+            Ok(literal) => {
+                let const_ = mir::ConstantKind::Val(literal, ty);
                 let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
 
                 if !is_associated_const {
@@ -537,25 +540,30 @@ fn lower_inline_const(
         span: Span,
     ) -> PatKind<'tcx> {
         let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-        let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
+        let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const_def_id);
 
         // Evaluate early like we do in `lower_path`.
         let value = value.eval(self.tcx, self.param_env);
 
-        match value.val() {
-            ConstKind::Param(_) => {
-                self.errors.push(PatternError::ConstParamInPattern(span));
-                return PatKind::Wild;
-            }
-            ConstKind::Unevaluated(_) => {
-                // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
-                return PatKind::Wild;
+        match value {
+            mir::ConstantKind::Ty(c) => {
+                match c.val() {
+                    ConstKind::Param(_) => {
+                        self.errors.push(PatternError::ConstParamInPattern(span));
+                        return PatKind::Wild;
+                    }
+                    ConstKind::Unevaluated(_) => {
+                        // If we land here it means the const can't be evaluated because it's `TooGeneric`.
+                        self.tcx
+                            .sess
+                            .span_err(span, "constant pattern depends on a generic parameter");
+                        return PatKind::Wild;
+                    }
+                    _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"),
+                }
             }
-            _ => (),
+            mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind,
         }
-
-        *self.const_to_pat(value, id, span, false).kind
     }
 
     /// Converts literals, paths and negation of literals to patterns.
@@ -582,7 +590,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
 
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
-        match self.tcx.at(expr.span).lit_to_const(lit_input) {
+        match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
             Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
             Err(LitToConstError::Reported) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
@@ -740,8 +748,8 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
 #[instrument(skip(tcx), level = "debug")]
 crate fn compare_const_vals<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
+    a: mir::ConstantKind<'tcx>,
+    b: mir::ConstantKind<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ordering> {
@@ -754,9 +762,7 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         return fallback();
     }
 
-    // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
-    // are just integer addresses).
-    if a.val() == b.val() {
+    if a == b {
         return from_bool(true);
     }
 
@@ -788,9 +794,9 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     }
 
     if let ty::Str = ty.kind() && let (
-        ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
-        ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
-    ) = (a.val(), b.val())
+        Some(a_val @ ConstValue::Slice { .. }),
+        Some(b_val @ ConstValue::Slice { .. }),
+    ) = (a.try_val(), b.try_val())
     {
         let a_bytes = get_slice_bytes(&tcx, a_val);
         let b_bytes = get_slice_bytes(&tcx, b_val);
index 88ed0128a1fd360d2ed4825b29927b60c853a15e..50efb4c1dc42a4a9750bc3bccc468530cb3c1f70 100644 (file)
@@ -333,14 +333,11 @@ struct RustcMirAttrs {
 
 impl RustcMirAttrs {
     fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
-        let attrs = tcx.get_attrs(def_id);
-
         let mut result = Ok(());
         let mut ret = RustcMirAttrs::default();
 
-        let rustc_mir_attrs = attrs
-            .iter()
-            .filter(|attr| attr.has_name(sym::rustc_mir))
+        let rustc_mir_attrs = tcx
+            .get_attrs(def_id, sym::rustc_mir)
             .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
 
         for attr in rustc_mir_attrs {
index 599b4087c78e4b94f5e20d7d0b615e397d86a4bd..c6a85bc43f458a0e4a22f3038b3c9662ded28a9c 100644 (file)
@@ -125,7 +125,7 @@ fn source(&self, edge: &Self::Edge) -> Self::Node {
     }
 
     fn target(&self, edge: &Self::Edge) -> Self::Node {
-        self.body[edge.source].terminator().successors().nth(edge.index).copied().unwrap()
+        self.body[edge.source].terminator().successors().nth(edge.index).unwrap()
     }
 }
 
index d0837bcf754e4acef09baf674fe2bb882257fe85..c1124a533bf2ba277c9d90689756e2cbb9243f2c 100644 (file)
@@ -14,9 +14,9 @@
 #[macro_use]
 extern crate rustc_middle;
 
-use rustc_ast::{self as ast, MetaItem};
-use rustc_middle::ty;
-use rustc_session::Session;
+use rustc_ast::MetaItem;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
 pub use self::drop_flag_effects::{
@@ -49,19 +49,13 @@ pub struct MoveDataParamEnv<'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
 }
 
-pub fn has_rustc_mir_with(
-    _sess: &Session,
-    attrs: &[ast::Attribute],
-    name: Symbol,
-) -> Option<MetaItem> {
-    for attr in attrs {
-        if attr.has_name(sym::rustc_mir) {
-            let items = attr.meta_item_list();
-            for item in items.iter().flat_map(|l| l.iter()) {
-                match item.meta_item() {
-                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
-                    _ => continue,
-                }
+pub fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
+    for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
+        let items = attr.meta_item_list();
+        for item in items.iter().flat_map(|l| l.iter()) {
+            match item.meta_item() {
+                Some(mi) if mi.has_name(name) => return Some(mi.clone()),
+                _ => continue,
             }
         }
     }
index 51ab5b43bff0a3753c1ee20952a8e46a772e52dd..2f884887ad9feeb69a0b50343ec886bb0bc9dbd8 100644 (file)
@@ -1,7 +1,5 @@
-use rustc_ast::ast;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::MirPass;
@@ -31,43 +29,41 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
         }
 
-        let attributes = tcx.get_attrs(def_id);
         let param_env = tcx.param_env(def_id);
         let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
         let mdpe = MoveDataParamEnv { move_data, param_env };
-        let sess = &tcx.sess;
 
-        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() {
+        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
             let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits);
+            sanity_check_via_rustc_peek(tcx, body, &flow_inits);
         }
 
-        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() {
+        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
             let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits);
+            sanity_check_via_rustc_peek(tcx, body, &flow_uninits);
         }
 
-        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() {
+        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
             let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
+            sanity_check_via_rustc_peek(tcx, body, &flow_def_inits);
         }
 
-        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
+        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
             let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness);
+            sanity_check_via_rustc_peek(tcx, body, &flow_liveness);
         }
 
-        if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() {
+        if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
             tcx.sess.fatal("stop_after_dataflow ended compilation");
         }
     }
@@ -92,7 +88,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 pub fn sanity_check_via_rustc_peek<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    _attributes: &[ast::Attribute],
     results: &Results<'tcx, A>,
 ) where
     A: RustcPeekAt<'tcx>,
@@ -197,9 +192,8 @@ fn from_terminator<'tcx>(
             &terminator.kind
         {
             if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() {
-                let sig = tcx.fn_sig(def_id);
                 let name = tcx.item_name(def_id);
-                if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek {
+                if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
                     return None;
                 }
 
index f7535d338da40dd05caa6e7a8e037498d2e94257..54c3cc46b265f62cff50af3751e46e3473d32a9f 100644 (file)
@@ -18,7 +18,9 @@
 };
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi;
@@ -28,7 +30,8 @@
 use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
     ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
-    Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
+    Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
+    StackPopUnwind,
 };
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -285,6 +288,14 @@ fn before_access_global(
         Ok(())
     }
 
+    #[inline(always)]
+    fn expose_ptr(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _ptr: Pointer<AllocId>,
+    ) -> InterpResult<'tcx> {
+        throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
+    }
+
     #[inline(always)]
     fn init_frame_extra(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -374,7 +385,7 @@ fn new(
         );
 
         let ret = ecx
-            .layout_of(body.return_ty().subst(tcx, substs))
+            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for ZST types which have no values
             // or for large values.
index aa898cfd3ba5ef3e5f14529e1cb3973599378348..6c0df98bc27131947bb7e67928eb55c3ad65c1c3 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
+    self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_session::lint;
 use rustc_span::{def_id::DefId, Span};
@@ -30,8 +30,8 @@
 use rustc_const_eval::const_eval::ConstEvalErr;
 use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
-    LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Scalar,
-    ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
+    LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
+    Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
 };
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -280,6 +280,14 @@ fn before_access_global(
         Ok(())
     }
 
+    #[inline(always)]
+    fn expose_ptr(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _ptr: Pointer<AllocId>,
+    ) -> InterpResult<'tcx> {
+        throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
+    }
+
     #[inline(always)]
     fn init_frame_extra(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -370,7 +378,7 @@ fn new(
         );
 
         let ret = ecx
-            .layout_of(body.return_ty().subst(tcx, substs))
+            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for ZST types which have no values
             // or for large values.
index 8e28ed2426bbb0fa99083e079c9cc1fd8889eb1a..434bf9d849e5a1fab81092de16c0e9a7f9fa8f2b 100644 (file)
@@ -701,7 +701,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
         edge_labels.retain(|label| label != "unreachable");
         let edge_counters = from_terminator
             .successors()
-            .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
+            .map(|successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
         iter::zip(&edge_labels, edge_counters)
             .map(|(label, some_counter)| {
                 if let Some(counter) = some_counter {
index 6bb7e676e851c6fa234c27c8768bbb4b963b798c..47190fa0d1ad9346125b52bc60f9f62659695d08 100644 (file)
@@ -484,17 +484,17 @@ fn bcb_filtered_successors<'a, 'tcx>(
     body: &'tcx &'a mir::Body<'tcx>,
     term_kind: &'tcx TerminatorKind<'tcx>,
 ) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
-    let mut successors = term_kind.successors();
     Box::new(
         match &term_kind {
             // SwitchInt successors are never unwind, and all of them should be traversed.
-            TerminatorKind::SwitchInt { .. } => successors,
+            TerminatorKind::SwitchInt { ref targets, .. } => {
+                None.into_iter().chain(targets.all_targets().into_iter().copied())
+            }
             // For all other kinds, return only the first successor, if any, and ignore unwinds.
             // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
             // `next().into_iter()`) into the `mir::Successors` aliased type.
-            _ => successors.next().into_iter().chain(&[]),
+            _ => term_kind.successors().next().into_iter().chain((&[]).into_iter().copied()),
         }
-        .copied()
         .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
     )
 }
index 2ed14b917781d695ffdbbd3da756119a70647801..1f9bd90d11f683808389bfd93d69cbf1bd04348d 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_middle::ty::{
     self,
     subst::{GenericArgKind, Subst, SubstsRef},
-    PredicateKind, Ty, TyCtxt,
+    EarlyBinder, PredicateKind, Ty, TyCtxt,
 };
 use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::{symbol::sym, Span};
@@ -90,7 +90,7 @@ fn check_bound_args(
                             // If the inner type matches the type bound by `Pointer`
                             if inner_ty == bound_ty {
                                 // Do a substitution using the parameters from the callsite
-                                let subst_ty = inner_ty.subst(self.tcx, substs_ref);
+                                let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref);
                                 if let Some((fn_id, fn_substs)) =
                                     FunctionItemRefChecker::is_fn_ref(subst_ty)
                                 {
index d5d4bfa255bd98fab46b686ab2fd8c896ac2d047..b7dec57b75768e0dac9f3489c1f6f82b1dd37803 100644 (file)
@@ -247,7 +247,7 @@ fn make_state(
         assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1);
         let ty = self
             .tcx
-            .type_of(self.state_adt_ref.variant(idx).fields[0].did)
+            .bound_type_of(self.state_adt_ref.variant(idx).fields[0].did)
             .subst(self.tcx, self.state_substs);
         expand_aggregate(
             Place::return_place(),
index 5e6dabeba6da2577498281561819211583d0a53e..a73fd13ce2d0ea13471570a4ef4f74c88ac76055 100644 (file)
@@ -260,7 +260,7 @@ fn resolve_callsite(
                     return None;
                 }
 
-                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
+                let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
 
                 return Some(CallSite {
                     callee,
@@ -418,8 +418,7 @@ fn check_mir_body(
                             }
                         }
                         // Don't give intrinsics the extra penalty for calls
-                        let f = tcx.fn_sig(def_id);
-                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
+                        if tcx.is_intrinsic(def_id) {
                             cost += INSTR_COST;
                         } else {
                             cost += CALL_PENALTY;
@@ -450,7 +449,7 @@ fn check_mir_body(
             }
 
             if !is_drop {
-                for &succ in term.successors() {
+                for succ in term.successors() {
                     work_list.push(succ);
                 }
             }
index ea1ec6249bca49bf9ee418c9f0f1b21fda25a05b..bee6aeebcf8452fb1fcc89eb1119eacc7142f7c0 100644 (file)
@@ -1,5 +1,4 @@
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sso::SsoHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir::TerminatorKind;
@@ -45,7 +44,10 @@ fn process<'tcx>(
     ) -> bool {
         trace!(%caller);
         for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
-            let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs);
+            let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(tcx, param_env, substs) else {
+                trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
+                continue;
+            };
             let Some(callee) = ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() else {
                 trace!(?callee, "cannot resolve, skipping");
                 continue;
@@ -150,7 +152,7 @@ fn process<'tcx>(
         // Functions from other crates and MIR shims
         _ => tcx.instance_mir(instance),
     };
-    let mut calls = SsoHashSet::new();
+    let mut calls = FxIndexSet::default();
     for bb_data in body.basic_blocks() {
         let terminator = bb_data.terminator();
         if let TerminatorKind::Call { func, .. } = &terminator.kind {
index 40cc6dafe6177c11aecc7e93df64baff07895c7d..d08382700a80ab9d3a8827a251691f0785008429 100644 (file)
@@ -170,7 +170,7 @@ fn visit_variant_data(
             intravisit::walk_struct_def(self, v)
         }
     }
-    tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
+    tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set });
 
     set
 }
index 684d988ee9ed2f2cfdd02a91e791db39477f1b88..d0d0e09d5255a9fb5d902fd7cb85235b591546a3 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
 
 pub struct LowerIntrinsics;
 
@@ -139,8 +138,7 @@ fn resolve_rust_intrinsic<'tcx>(
     func_ty: Ty<'tcx>,
 ) -> Option<(Symbol, SubstsRef<'tcx>)> {
     if let ty::FnDef(def_id, substs) = *func_ty.kind() {
-        let fn_sig = func_ty.fn_sig(tcx);
-        if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
+        if tcx.is_intrinsic(def_id) {
             return Some((tcx.item_name(def_id), substs));
         }
     }
index 4d214b0356ca7f1a56925c1344bbe7659226aa65..f925d13b2fb91223d334e6066993080f7f526808 100644 (file)
@@ -65,7 +65,7 @@ fn is_nop_landing_pad(
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. } => {
-                terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
+                terminator.successors().all(|succ| nop_landing_pads.contains(succ))
             }
             TerminatorKind::GeneratorDrop
             | TerminatorKind::Yield { .. }
index d10cac2ac7635f03d0c3668d9da12108a79179cd..016b3bc098073c68b11b6c9ece9b49614b403808 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
 
 use rustc_index::vec::{Idx, IndexVec};
@@ -70,7 +70,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             // of this function. Is this intentional?
             if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) {
                 let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
-                let body = body.clone().subst(tcx, substs);
+                let body = EarlyBinder(body.clone()).subst(tcx, substs);
                 debug!("make_shim({:?}) = {:?}", instance, body);
                 return body;
             }
@@ -151,7 +151,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     } else {
         InternalSubsts::identity_for_item(tcx, def_id)
     };
-    let sig = tcx.fn_sig(def_id).subst(tcx, substs);
+    let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
     let sig = tcx.erase_late_bound_regions(sig);
     let span = tcx.def_span(def_id);
 
@@ -343,7 +343,7 @@ fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
         // otherwise going to be TySelf and we can't index
         // or access fields of a Place of type TySelf.
         let substs = tcx.mk_substs_trait(self_ty, &[]);
-        let sig = tcx.fn_sig(def_id).subst(tcx, substs);
+        let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
         let sig = tcx.erase_late_bound_regions(sig);
         let span = tcx.def_span(def_id);
 
@@ -541,7 +541,7 @@ fn build_call_shim<'tcx>(
 
     assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
     if let Some(sig_substs) = sig_substs {
-        sig = sig.subst(tcx, sig_substs);
+        sig = EarlyBinder(sig).subst(tcx, sig_substs);
     }
 
     if let CallKind::Indirect(fnty) = call_kind {
index b42e3909cf386bc7b322383ac424dceaf4f28aec..72e083439257645100def7667498a5002519f08d 100644 (file)
@@ -81,7 +81,7 @@ pub fn new(body: &'a mut Body<'tcx>) -> Self {
 
         for (_, data) in traversal::preorder(body) {
             if let Some(ref term) = data.terminator {
-                for &tgt in term.successors() {
+                for tgt in term.successors() {
                     pred_count[tgt] += 1;
                 }
             }
@@ -235,8 +235,8 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
         };
 
         let first_succ = {
-            if let Some(&first_succ) = terminator.successors().next() {
-                if terminator.successors().all(|s| *s == first_succ) {
+            if let Some(first_succ) = terminator.successors().next() {
+                if terminator.successors().all(|s| s == first_succ) {
                     let count = terminator.successors().count();
                     self.pred_count[first_succ] -= (count - 1) as u32;
                     first_succ
index cf13c856a71c1434d6a007014d2973fbfcabab88..3cfd935d8b0ae1d41743eadccb7027c9abafbd1a 100644 (file)
@@ -197,7 +197,7 @@ fn emit_unused_generic_params_error<'tcx>(
     unused_parameters: &FiniteBitSet<u32>,
 ) {
     let base_def_id = tcx.typeck_root_def_id(def_id);
-    if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
+    if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
         return;
     }
 
index 369650edd57d0e4ccab84d313f6c0b03904dd8f3..3b2ce0de50915a57e2765fda165677da8caf3709 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_errors::{
     Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@@ -252,6 +252,40 @@ struct AmbiguousPlus {
     pub span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")]
+struct BadTypePlus<'a> {
+    pub ty: String,
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: BadTypePlusSub<'a>,
+}
+
+#[derive(SessionSubdiagnostic, Clone, Copy)]
+pub enum BadTypePlusSub<'a> {
+    #[suggestion(
+        slug = "parser-add-paren",
+        code = "{sum_with_parens}",
+        applicability = "machine-applicable"
+    )]
+    AddParen {
+        sum_with_parens: &'a str,
+        #[primary_span]
+        span: Span,
+    },
+    #[label(slug = "parser-forgot-paren")]
+    ForgotParen {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(slug = "parser-expect-path")]
+    ExpectPath {
+        #[primary_span]
+        span: Span,
+    },
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -1255,17 +1289,11 @@ pub(super) fn maybe_recover_from_bad_type_plus(
         let bounds = self.parse_generic_bounds(None)?;
         let sum_span = ty.span.to(self.prev_token.span);
 
-        let mut err = struct_span_err!(
-            self.sess.span_diagnostic,
-            sum_span,
-            E0178,
-            "expected a path on the left-hand side of `+`, not `{}`",
-            pprust::ty_to_string(ty)
-        );
+        let sum_with_parens: String;
 
-        match ty.kind {
+        let sub = match ty.kind {
             TyKind::Rptr(ref lifetime, ref mut_ty) => {
-                let sum_with_parens = pprust::to_string(|s| {
+                sum_with_parens = pprust::to_string(|s| {
                     s.s.word("&");
                     s.print_opt_lifetime(lifetime);
                     s.print_mutability(mut_ty.mutbl, false);
@@ -1274,21 +1302,15 @@ pub(super) fn maybe_recover_from_bad_type_plus(
                     s.print_type_bounds(" +", &bounds);
                     s.pclose()
                 });
-                err.span_suggestion(
-                    sum_span,
-                    "try adding parentheses",
-                    sum_with_parens,
-                    Applicability::MachineApplicable,
-                );
-            }
-            TyKind::Ptr(..) | TyKind::BareFn(..) => {
-                err.span_label(sum_span, "perhaps you forgot parentheses?");
-            }
-            _ => {
-                err.span_label(sum_span, "expected a path");
+
+                BadTypePlusSub::AddParen { sum_with_parens: &sum_with_parens, span: sum_span }
             }
-        }
-        err.emit();
+            TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
+            _ => BadTypePlusSub::ExpectPath { span: sum_span },
+        };
+
+        self.sess.emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
+
         Ok(())
     }
 
index 8d207e4e1a92489b1857b1bf0fb8a7f7610259ba..ab3319a1186aedc899cb6a583c8e3502d0cf5f8c 100644 (file)
@@ -23,6 +23,7 @@
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
 use std::collections::hash_map::Entry;
 
 pub(crate) fn target_from_impl_item<'tcx>(
@@ -1317,22 +1318,27 @@ fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target
 
     /// Checks if `#[link]` is applied to an item other than a foreign module.
     fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
-        match target {
-            Target::ForeignMod => {}
-            _ => {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    let mut diag = lint.build("attribute should be applied to an `extern` block");
-                    diag.warn(
-                        "this was previously accepted by the compiler but is \
-                         being phased out; it will become a hard error in \
-                         a future release!",
-                    );
+        if target == Target::ForeignMod
+            && let hir::Node::Item(item) = self.tcx.hir().get(hir_id)
+            && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
+            && !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+        {
+            return;
+        }
 
-                    diag.span_label(span, "not an `extern` block");
-                    diag.emit();
-                });
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            let mut diag =
+                lint.build("attribute should be applied to an `extern` block with non-Rust ABI");
+            diag.warn(
+                "this was previously accepted by the compiler but is \
+                 being phased out; it will become a hard error in \
+                 a future release!",
+            );
+            if target != Target::ForeignMod {
+                diag.span_label(span, "not an `extern` block");
             }
-        }
+            diag.emit();
+        });
     }
 
     /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
@@ -2384,7 +2390,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let check_attr_visitor = &mut CheckAttrVisitor { tcx };
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
index 9e352fa5cc6736f066c0df47cbb83266a3fd015a..04d6e9f205abd56b40cc5c9e8dedb7bcd78219bd 100644 (file)
@@ -57,89 +57,71 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
 
 fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let mut vis = CheckConstVisitor::new(tcx);
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_const_bodies, ..*providers };
 }
 
-struct CheckConstTraitVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> CheckConstTraitVisitor<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        CheckConstTraitVisitor { tcx }
-    }
-}
-
-impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
-    /// check for const trait impls, and errors if the impl uses provided/default functions
-    /// of the trait being implemented; as those provided functions can be non-const.
-    fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
-        let _: Option<_> = try {
-            if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
-                    let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
-                    let ancestors = self
-                        .tcx
-                        .trait_def(trait_def_id)
-                        .ancestors(self.tcx, item.def_id.to_def_id())
-                        .ok()?;
-                    let mut to_implement = Vec::new();
-
-                    for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
+fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
+    let _: Option<_> = try {
+        if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
+            let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
+            let ancestors = tcx
+                .trait_def(trait_def_id)
+                .ancestors(tcx, item.def_id.to_def_id())
+                .ok()?;
+            let mut to_implement = Vec::new();
+
+            for trait_item in tcx.associated_items(trait_def_id).in_definition_order()
+            {
+                if let ty::AssocItem {
+                    kind: ty::AssocKind::Fn,
+                    defaultness,
+                    def_id: trait_item_id,
+                    ..
+                } = *trait_item
+                {
+                    // we can ignore functions that do not have default bodies:
+                    // if those are unimplemented it will be caught by typeck.
+                    if !defaultness.has_value()
+                        || tcx
+                        .has_attr(trait_item_id, sym::default_method_body_is_const)
                     {
-                        if let ty::AssocItem {
-                            kind: ty::AssocKind::Fn,
-                            defaultness,
-                            def_id: trait_item_id,
-                            ..
-                        } = *trait_item
-                        {
-                            // we can ignore functions that do not have default bodies:
-                            // if those are unimplemented it will be caught by typeck.
-                            if !defaultness.has_value()
-                                || self
-                                    .tcx
-                                    .has_attr(trait_item_id, sym::default_method_body_is_const)
-                            {
-                                continue;
-                            }
-
-                            let is_implemented = ancestors
-                                .leaf_def(self.tcx, trait_item_id)
-                                .map(|node_item| !node_item.defining_node.is_from_trait())
-                                .unwrap_or(false);
-
-                            if !is_implemented {
-                                to_implement.push(self.tcx.item_name(trait_item_id).to_string());
-                            }
-                        }
+                        continue;
                     }
 
-                    // all nonconst trait functions (not marked with #[default_method_body_is_const])
-                    // must be implemented
-                    if !to_implement.is_empty() {
-                        self.tcx
-                            .sess
-                            .struct_span_err(
-                                item.span,
-                                "const trait implementations may not use non-const default functions",
-                            )
-                            .note(&format!("`{}` not implemented", to_implement.join("`, `")))
-                            .emit();
+                    let is_implemented = ancestors
+                        .leaf_def(tcx, trait_item_id)
+                        .map(|node_item| !node_item.defining_node.is_from_trait())
+                        .unwrap_or(false);
+
+                    if !is_implemented {
+                        to_implement.push(trait_item_id);
                     }
+                }
             }
-        };
-    }
-
-    fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
-
-    fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
 
-    fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
+            // all nonconst trait functions (not marked with #[default_method_body_is_const])
+            // must be implemented
+            if !to_implement.is_empty() {
+                let not_implemented = to_implement
+                    .into_iter()
+                    .map(|did| tcx.item_name(did).to_string())
+                    .collect::<Vec<_>>()
+                    .join("`, `");
+                tcx
+                    .sess
+                    .struct_span_err(
+                        item.span,
+                        "const trait implementations may not use non-const default functions",
+                    )
+                    .note(&format!("`{}` not implemented", not_implemented))
+                    .emit();
+            }
+        }
+    };
 }
 
 #[derive(Copy, Clone)]
@@ -170,7 +152,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
 
             // If `def_id` is `None`, we don't need to consider stability attributes.
             let def_id = match def_id {
-                Some(x) => x.to_def_id(),
+                Some(x) => x,
                 None => return true,
             };
 
@@ -182,14 +164,16 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
 
             // If this crate is not using stability attributes, or this function is not claiming to be a
             // stable `const fn`, that is all that is required.
-            if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+            if !tcx.features().staged_api
+                || tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable)
+            {
                 return true;
             }
 
             // However, we cannot allow stable `const fn`s to use unstable features without an explicit
             // opt-in via `rustc_allow_const_fn_unstable`.
-            attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id))
-                .any(|name| name == feature_gate)
+            let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
+            attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
         };
 
         match required_gates {
@@ -268,6 +252,11 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.tcx.hir()
     }
 
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        intravisit::walk_item(self, item);
+        check_item(self.tcx, item);
+    }
+
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
         let kind = Some(hir::ConstContext::Const);
         self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
index df28ea4d444baafe6327d90277ef7cd8963182d9..e78d9a59982842b92879b36d5bc9928dd901970c 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -468,7 +467,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
 }
 
-// This visitor seeds items that
+// These check_* functions 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
@@ -481,82 +480,95 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 //   or
 //   2) We are not sure to be live or not
 //     * Implementations of traits and trait methods
-struct LifeSeeder<'tcx> {
-    worklist: Vec<LocalDefId>,
+fn check_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    // see `MarkSymbolVisitor::struct_constructors`
-    struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
-        if allow_dead_code {
-            self.worklist.push(item.def_id);
-        }
-        match item.kind {
-            hir::ItemKind::Enum(ref enum_def, _) => {
-                let hir = self.tcx.hir();
+    worklist: &mut Vec<LocalDefId>,
+    struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>,
+    id: hir::ItemId,
+) {
+    let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
+    if allow_dead_code {
+        worklist.push(id.def_id);
+    }
+
+    match tcx.def_kind(id.def_id) {
+        DefKind::Enum => {
+            let item = tcx.hir().item(id);
+            if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
+                let hir = tcx.hir();
                 if allow_dead_code {
-                    self.worklist.extend(
+                    worklist.extend(
                         enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
                     );
                 }
 
                 for variant in enum_def.variants {
                     if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-                        self.struct_constructors
+                        struct_constructors
                             .insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
                     }
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
-                if of_trait.is_some() {
-                    self.worklist.push(item.def_id);
-                }
-                for impl_item_ref in *items {
-                    let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
-                    if of_trait.is_some()
-                        || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
-                    {
-                        self.worklist.push(impl_item_ref.id.def_id);
-                    }
+        }
+        DefKind::Impl => {
+            let of_trait = tcx.impl_trait_ref(id.def_id);
+
+            if of_trait.is_some() {
+                worklist.push(id.def_id);
+            }
+
+            // get DefIds from another query
+            let local_def_ids = tcx
+                .associated_item_def_ids(id.def_id)
+                .iter()
+                .filter_map(|def_id| def_id.as_local());
+
+            // And we access the Map here to get HirId from LocalDefId
+            for id in local_def_ids {
+                if of_trait.is_some()
+                    || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id))
+                {
+                    worklist.push(id);
                 }
             }
-            hir::ItemKind::Struct(ref variant_data, _) => {
+        }
+        DefKind::Struct => {
+            let item = tcx.hir().item(id);
+            if let hir::ItemKind::Struct(ref variant_data, _) = item.kind {
                 if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
-                    self.struct_constructors
-                        .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
+                    struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
                 }
             }
-            hir::ItemKind::GlobalAsm(_) => {
-                // global_asm! is always live.
-                self.worklist.push(item.def_id);
-            }
-            _ => (),
         }
+        DefKind::GlobalAsm => {
+            // global_asm! is always live.
+            worklist.push(id.def_id);
+        }
+        _ => {}
     }
+}
 
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
-        use hir::TraitItemKind::{Const, Fn};
+fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
+    use hir::TraitItemKind::{Const, Fn};
+    if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
+        let trait_item = tcx.hir().trait_item(id);
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
-            && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
+            && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
         {
-            self.worklist.push(trait_item.def_id);
+            worklist.push(trait_item.def_id);
         }
     }
+}
 
-    fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
-        // ignore: we are handling this in `visit_item` above
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
-        use hir::ForeignItemKind::{Fn, Static};
-        if matches!(foreign_item.kind, Static(..) | Fn(..))
-            && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
-        {
-            self.worklist.push(foreign_item.def_id);
-        }
+fn check_foreign_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    worklist: &mut Vec<LocalDefId>,
+    id: hir::ForeignItemId,
+) {
+    if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
+        && has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
+    {
+        worklist.push(id.def_id);
     }
 }
 
@@ -564,7 +576,9 @@ fn create_and_seed_worklist<'tcx>(
     tcx: TyCtxt<'tcx>,
 ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
     let access_levels = &tcx.privacy_access_levels(());
-    let worklist = access_levels
+    // see `MarkSymbolVisitor::struct_constructors`
+    let mut struct_constructors = Default::default();
+    let mut worklist = access_levels
         .map
         .iter()
         .filter_map(
@@ -576,11 +590,20 @@ fn create_and_seed_worklist<'tcx>(
         .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
         .collect::<Vec<_>>();
 
-    // Seed implemented trait items
-    let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
-    tcx.hir().visit_all_item_likes(&mut life_seeder);
+    let crate_items = tcx.hir_crate_items(());
+    for id in crate_items.items() {
+        check_item(tcx, &mut worklist, &mut struct_constructors, id);
+    }
+
+    for id in crate_items.trait_items() {
+        check_trait_item(tcx, &mut worklist, id);
+    }
+
+    for id in crate_items.foreign_items() {
+        check_foreign_item(tcx, &mut worklist, id);
+    }
 
-    (life_seeder.worklist, life_seeder.struct_constructors)
+    (worklist, struct_constructors)
 }
 
 fn live_symbols_and_ignored_derived_traits<'tcx>(
index f89092c57a37aeb9ce36e0e0779b4b86241e5fda..8305830bc988ff87d044d385f495140b76f714fb 100644 (file)
@@ -5,8 +5,7 @@
 use rustc_expand::base::resolve_path;
 use rustc_hir as hir;
 use rustc_hir::def_id::CrateNum;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{HirId, Target};
+use rustc_hir::HirId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LOCAL_CRATE;
 
 use std::sync::Arc;
 
-struct DebuggerVisualizerCollector<'tcx> {
-    debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
+fn check_for_debugger_visualizer<'tcx>(
     tcx: TyCtxt<'tcx>,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let target = Target::from_item(item);
-        match target {
-            Target::Mod => {
-                self.check_for_debugger_visualizer(item.hir_id());
-            }
-            _ => {}
-        }
-    }
-
-    fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
-
-    fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
-
-    fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
-}
-
-impl<'tcx> DebuggerVisualizerCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
-        DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
-    }
-
-    fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
-        let attrs = self.tcx.hir().attrs(hir_id);
-        for attr in attrs {
-            if attr.has_name(sym::debugger_visualizer) {
-                let list = match attr.meta_item_list() {
-                    Some(list) => list,
+    hir_id: HirId,
+    debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
+) {
+    let attrs = tcx.hir().attrs(hir_id);
+    for attr in attrs {
+        if attr.has_name(sym::debugger_visualizer) {
+            let list = match attr.meta_item_list() {
+                Some(list) => list,
+                _ => continue,
+            };
+
+            let meta_item = match list.len() {
+                1 => match list[0].meta_item() {
+                    Some(meta_item) => meta_item,
                     _ => continue,
-                };
-
-                let meta_item = match list.len() {
-                    1 => match list[0].meta_item() {
-                        Some(meta_item) => meta_item,
-                        _ => continue,
-                    },
-                    _ => continue,
-                };
-
-                let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
-                    (sym::natvis_file, Some(value)) => {
-                        match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
-                            Ok(file) => file,
-                            Err(mut err) => {
-                                err.emit();
-                                continue;
-                            }
+                },
+                _ => continue,
+            };
+
+            let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
+                (sym::natvis_file, Some(value)) => {
+                    match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
+                        Ok(file) => file,
+                        Err(mut err) => {
+                            err.emit();
+                            continue;
                         }
                     }
-                    (_, _) => continue,
+                }
+                (_, _) => continue,
+            };
+
+            if file.is_file() {
+                let contents = match std::fs::read(&file) {
+                    Ok(contents) => contents,
+                    Err(err) => {
+                        tcx.sess
+                            .struct_span_err(
+                                attr.span,
+                                &format!(
+                                    "Unable to read contents of file `{}`. {}",
+                                    file.display(),
+                                    err
+                                ),
+                            )
+                            .emit();
+                        continue;
+                    }
                 };
 
-                if file.is_file() {
-                    let contents = match std::fs::read(&file) {
-                        Ok(contents) => contents,
-                        Err(err) => {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    attr.span,
-                                    &format!(
-                                        "Unable to read contents of file `{}`. {}",
-                                        file.display(),
-                                        err
-                                    ),
-                                )
-                                .emit();
-                            continue;
-                        }
-                    };
-
-                    self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
-                        Arc::from(contents),
-                        DebuggerVisualizerType::Natvis,
-                    ));
-                } else {
-                    self.tcx
-                        .sess
-                        .struct_span_err(
-                            attr.span,
-                            &format!("{} is not a valid file", file.display()),
-                        )
-                        .emit();
-                }
+                debugger_visualizers.insert(DebuggerVisualizerFile::new(
+                    Arc::from(contents),
+                    DebuggerVisualizerType::Natvis,
+                ));
+            } else {
+                tcx.sess
+                    .struct_span_err(attr.span, &format!("{} is not a valid file", file.display()))
+                    .emit();
             }
         }
     }
@@ -114,17 +83,21 @@ fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<Debugger
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
-    let mut collector = DebuggerVisualizerCollector::new(tcx);
+    let mut debugger_visualizers = FxHashSet::default();
 
     // Collect debugger visualizers in this crate.
-    tcx.hir().visit_all_item_likes(&mut collector);
+    tcx.hir().for_each_module(|id| {
+        check_for_debugger_visualizer(
+            tcx,
+            tcx.hir().local_def_id_to_hir_id(id),
+            &mut debugger_visualizers,
+        )
+    });
 
     // Collect debugger visualizers on the crate attributes.
-    collector.check_for_debugger_visualizer(CRATE_HIR_ID);
+    check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
 
     // Extract out the found debugger_visualizer items.
-    let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
-
     let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
 
     // Sort the visualizers so we always get a deterministic query result.
index 9cbb7917e9a32de6a84ddda1d55c548480f27d57..e6b69d8986cf83e07e7e4622de0e1402699866d0 100644 (file)
 //! * Compiler internal types like `Ty` and `TyCtxt`
 
 use rustc_ast as ast;
-use rustc_hir as hir;
 use rustc_hir::diagnostic_items::DiagnosticItems;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
-struct DiagnosticItemCollector<'tcx> {
+fn observe_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    diagnostic_items: DiagnosticItems,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.observe_item(item.def_id);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
-        self.observe_item(trait_item.def_id);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
-        self.observe_item(impl_item.def_id);
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
-        self.observe_item(foreign_item.def_id);
-    }
-}
-
-impl<'tcx> DiagnosticItemCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
-        DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
-    }
-
-    fn observe_item(&mut self, def_id: LocalDefId) {
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        let attrs = self.tcx.hir().attrs(hir_id);
-        if let Some(name) = extract(attrs) {
-            // insert into our table
-            collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
-        }
+    diagnostic_items: &mut DiagnosticItems,
+    def_id: LocalDefId,
+) {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let attrs = tcx.hir().attrs(hir_id);
+    if let Some(name) = extract(attrs) {
+        // insert into our table
+        collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
     }
 }
 
@@ -83,7 +56,7 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
     }
 }
 
-/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p
+/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
 fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
     attrs.iter().find_map(|attr| {
         if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
@@ -95,12 +68,28 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
-    let mut collector = DiagnosticItemCollector::new(tcx);
+    let mut diagnostic_items = DiagnosticItems::default();
 
     // Collect diagnostic items in this crate.
-    tcx.hir().visit_all_item_likes(&mut collector);
+    let crate_items = tcx.hir_crate_items(());
+
+    for id in crate_items.items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.trait_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.impl_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.foreign_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
 
-    collector.diagnostic_items
+    diagnostic_items
 }
 
 /// Traverse and collect all the diagnostic items in all crates.
index f84b848e08d1ec1b9b2162ae4beb4ead3297a3e7..b90d44e2af57cd5de7b4cc78dcae000cb6f6e72e 100644 (file)
@@ -1,8 +1,8 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{CrateType, EntryFnType};
@@ -25,25 +25,6 @@ struct EntryContext<'tcx> {
     non_main_fns: Vec<Span>,
 }
 
-impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
-    fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
-        find_item(item, self, at_root);
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem<'tcx>) {
-        // Entry fn is never a trait item.
-    }
-
-    fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) {
-        // Entry fn is never a trait item.
-    }
-
-    fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
-        // Entry fn is never a foreign item.
-    }
-}
-
 fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
     let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
     if !any_exe {
@@ -59,28 +40,35 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
     let mut ctxt =
         EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
 
-    tcx.hir().visit_all_item_likes(&mut ctxt);
+    for id in tcx.hir().items() {
+        find_item(id, &mut ctxt);
+    }
 
     configure_main(tcx, &ctxt)
 }
 
 // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
 // (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
-    let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+// A small optimization was added so that hir::Item is fetched only when needed.
+// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
+fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
+    let attrs = ctxt.tcx.hir().attrs(id.hir_id());
     if ctxt.tcx.sess.contains_name(attrs, sym::start) {
         EntryPointType::Start
     } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_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 {
+        if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
+            && name == sym::main {
+            if at_root {
+                // This is a top-level function so can be `main`.
+                EntryPointType::MainNamed
+            } else {
+                EntryPointType::OtherMain
+            }
         } else {
-            EntryPointType::OtherMain
+            EntryPointType::None
         }
-    } else {
-        EntryPointType::None
     }
 }
 
@@ -89,11 +77,13 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
         .emit();
 }
 
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
-    match entry_point_type(ctxt, item, at_root) {
+fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
+    let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
+
+    match entry_point_type(ctxt, id, at_root) {
         EntryPointType::None => (),
-        _ if !matches!(item.kind, ItemKind::Fn(..)) => {
-            let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+        _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
+            let attrs = ctxt.tcx.hir().attrs(id.hir_id());
             if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
                 throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
             }
@@ -103,31 +93,39 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
-            ctxt.non_main_fns.push(item.span);
+            ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
         }
         EntryPointType::MainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((item.def_id, item.span));
+                ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
                 struct_span_err!(
                     ctxt.tcx.sess,
-                    item.span,
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
                     E0137,
                     "multiple functions with a `#[main]` attribute"
                 )
-                .span_label(item.span, "additional `#[main]` function")
+                .span_label(
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    "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.def_id, item.span));
+                ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
-                struct_span_err!(ctxt.tcx.sess, 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();
+                struct_span_err!(
+                    ctxt.tcx.sess,
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    E0138,
+                    "multiple `start` functions"
+                )
+                .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
+                .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
+                .emit();
             }
         }
     }
index 379a6827c8aac5d3d41075a5aa1998ee7d4cec24..23ff0a91159708ee0dfd0871a6e366c552c90f12 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -20,8 +19,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     let hir_map = tcx.hir();
 
     hir_map.par_for_each_module(|module_id| {
-        hir_map
-            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
+        let mut v = HirIdValidator {
+            hir_map,
+            owner: None,
+            hir_ids_seen: Default::default(),
+            errors: &errors,
+        };
+
+        tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v);
     });
 
     let errors = errors.into_inner();
@@ -39,13 +44,8 @@ struct HirIdValidator<'a, 'hir> {
     errors: &'a Lock<Vec<String>>,
 }
 
-struct OuterVisitor<'a, 'hir> {
-    hir_map: Map<'hir>,
-    errors: &'a Lock<Vec<String>>,
-}
-
-impl<'a, 'hir> OuterVisitor<'a, 'hir> {
-    fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
+impl<'a, 'hir> HirIdValidator<'a, 'hir> {
+    fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
         HirIdValidator {
             hir_map,
             owner: None,
@@ -53,31 +53,7 @@ fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
             errors: self.errors,
         }
     }
-}
-
-impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
-    fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
-    }
-
-    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
-    }
-
-    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
-    }
-
-    fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
-    }
-}
 
-impl<'a, 'hir> HirIdValidator<'a, 'hir> {
     #[cold]
     #[inline(never)]
     fn error(&self, f: impl FnOnce() -> String) {
@@ -146,6 +122,11 @@ fn nested_visit_map(&mut self) -> Self::Map {
         self.hir_map
     }
 
+    fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
+    }
+
     fn visit_id(&mut self, hir_id: HirId) {
         let owner = self.owner.expect("no owner");
 
@@ -163,17 +144,18 @@ fn visit_id(&mut self, hir_id: HirId) {
         self.hir_ids_seen.insert(hir_id.local_id);
     }
 
-    fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
-        // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
-        // values that actually belong to an ImplItem instead of the ItemKind::Impl
-        // we are currently in. So for those it's correct that they have a
-        // different owner.
+    fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
+    }
+
+    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
     }
 
-    fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) {
-        // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
-        // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
-        // we are currently in. So for those it's correct that they have a
-        // different owner.
+    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
     }
 }
index 7028fc4412648832b09dc57e90ae1aa1b8e35a29..9c840777bafc11b25611f1b870324e0883bdc07b 100644 (file)
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
 use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
-use rustc_target::spec::abi::Abi::RustIntrinsic;
 
 fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx });
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -63,8 +62,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
 
 impl<'tcx> 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
+        self.tcx.is_intrinsic(def_id) && self.tcx.item_name(def_id) == sym::transmute
     }
 
     fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
index 00e8eb5eb2b380d5b7b69fb5517e8fd7e63803eb..fd03f657111d99c62a30adf2407a5030773e28e4 100644 (file)
@@ -1,8 +1,6 @@
 use rustc_ast::Attribute;
-use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::ItemKind;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
-        tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
-    }
-}
-
-struct LayoutTest<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        match item.kind {
-            ItemKind::TyAlias(..)
-            | ItemKind::Enum(..)
-            | ItemKind::Struct(..)
-            | ItemKind::Union(..) => {
-                for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() {
-                    if attr.has_name(sym::rustc_layout) {
-                        self.dump_layout_of(item.def_id, item, attr);
-                    }
+        for id in tcx.hir().items() {
+            if matches!(
+                tcx.def_kind(id.def_id),
+                DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
+            ) {
+                for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
+                    dump_layout_of(tcx, id.def_id, attr);
                 }
             }
-            _ => {}
         }
     }
-
-    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
-    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
-    fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
 }
 
-impl<'tcx> LayoutTest<'tcx> {
-    fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
-        let tcx = self.tcx;
-        let param_env = self.tcx.param_env(item_def_id);
-        let ty = self.tcx.type_of(item_def_id);
-        match self.tcx.layout_of(param_env.and(ty)) {
-            Ok(ty_layout) => {
-                // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
-                // The `..` are the names of fields to dump.
-                let meta_items = attr.meta_item_list().unwrap_or_default();
-                for meta_item in meta_items {
-                    match meta_item.name_or_empty() {
-                        sym::abi => {
-                            self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
-                        }
+fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
+    let tcx = tcx;
+    let param_env = tcx.param_env(item_def_id);
+    let ty = tcx.type_of(item_def_id);
+    match tcx.layout_of(param_env.and(ty)) {
+        Ok(ty_layout) => {
+            // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
+            // The `..` are the names of fields to dump.
+            let meta_items = attr.meta_item_list().unwrap_or_default();
+            for meta_item in meta_items {
+                match meta_item.name_or_empty() {
+                    sym::abi => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("abi: {:?}", ty_layout.abi),
+                        );
+                    }
 
-                        sym::align => {
-                            self.tcx
-                                .sess
-                                .span_err(item.span, &format!("align: {:?}", ty_layout.align));
-                        }
+                    sym::align => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("align: {:?}", ty_layout.align),
+                        );
+                    }
 
-                        sym::size => {
-                            self.tcx
-                                .sess
-                                .span_err(item.span, &format!("size: {:?}", ty_layout.size));
-                        }
+                    sym::size => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("size: {:?}", ty_layout.size),
+                        );
+                    }
 
-                        sym::homogeneous_aggregate => {
-                            self.tcx.sess.span_err(
-                                item.span,
-                                &format!(
-                                    "homogeneous_aggregate: {:?}",
-                                    ty_layout
-                                        .homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
-                                ),
-                            );
-                        }
+                    sym::homogeneous_aggregate => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!(
+                                "homogeneous_aggregate: {:?}",
+                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+                            ),
+                        );
+                    }
 
-                        sym::debug => {
-                            let normalized_ty = self.tcx.normalize_erasing_regions(
-                                param_env.with_reveal_all_normalized(self.tcx),
-                                ty,
-                            );
-                            self.tcx.sess.span_err(
-                                item.span,
-                                &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
-                            );
-                        }
+                    sym::debug => {
+                        let normalized_ty = tcx.normalize_erasing_regions(
+                            param_env.with_reveal_all_normalized(tcx),
+                            ty,
+                        );
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+                        );
+                    }
 
-                        name => {
-                            self.tcx.sess.span_err(
-                                meta_item.span(),
-                                &format!("unrecognized field name `{}`", name),
-                            );
-                        }
+                    name => {
+                        tcx.sess.span_err(
+                            meta_item.span(),
+                            &format!("unrecognized field name `{}`", name),
+                        );
                     }
                 }
             }
+        }
 
-            Err(layout_error) => {
-                self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", layout_error));
-            }
+        Err(layout_error) => {
+            tcx.sess.span_err(
+                tcx.def_span(item_def_id.to_def_id()),
+                &format!("layout error: {:?}", layout_error),
+            );
         }
     }
 }
index 9eba7fb0811c6200eff5d4ac7333f4f2040a9a8e..b09d9831d43e39286b8e71a9dab498d9f77def34 100644 (file)
@@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
 }
 
 fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -373,8 +373,8 @@ fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
 
     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
         self.add_from_pat(&arm.pat);
-        if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
-            self.add_from_pat(pat);
+        if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard {
+            self.add_from_pat(let_expr.pat);
         }
         intravisit::walk_arm(self, arm);
     }
@@ -914,9 +914,9 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
 
                     let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g {
                         hir::Guard::If(e) => self.propagate_through_expr(e, body_succ),
-                        hir::Guard::IfLet(pat, e) => {
-                            let let_bind = self.define_bindings_in_pat(pat, body_succ);
-                            self.propagate_through_expr(e, let_bind)
+                        hir::Guard::IfLet(let_expr) => {
+                            let let_bind = self.define_bindings_in_pat(let_expr.pat, body_succ);
+                            self.propagate_through_expr(let_expr.init, let_bind)
                         }
                     });
                     let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
index 02b09daf0a41e443b012f19621971e0e685f23a8..e0dac09870df74637365e5d8c607241d66c05889 100644 (file)
@@ -31,9 +31,9 @@ struct CheckLoopVisitor<'a, 'hir> {
 }
 
 fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
+    tcx.hir().deep_visit_item_likes_in_module(
         module_def_id,
-        &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
+        &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
     );
 }
 
index e85720952da7a4dc81616ff3b19de86995708da4..5d7768c8240def357cffa30570cafbd93c2363e7 100644 (file)
 use rustc_target::spec::abi::Abi;
 
 fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut CheckNakedFunctions { tcx }.as_deep_visitor(),
-    );
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
 }
 
 crate fn provide(providers: &mut Providers) {
index a5133bfd9459cf10d7f92fb0285f85bdf05f4579..0ded6a421f57f30b20a2b948ee8c25db1dbba214 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::middle::privacy;
@@ -314,79 +313,60 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
     }
 }
 
-// Some methods from non-exported (completely private) trait impls still have to be
-// reachable if they are called from inlinable code. Generally, it's not known until
-// monomorphization if a specific trait impl item can be reachable or not. So, we
-// conservatively mark all of them as reachable.
-// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
-// items of non-exported traits (or maybe all local traits?) unless their respective
-// trait items are used from inlinable code through method call syntax or UFCS, or their
-// trait is a lang item.
-struct CollectPrivateImplItemsVisitor<'a, 'tcx> {
+fn check_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    access_levels: &'a privacy::AccessLevels,
-    worklist: &'a mut Vec<LocalDefId>,
-}
+    id: hir::ItemId,
+    worklist: &mut Vec<LocalDefId>,
+    access_levels: &privacy::AccessLevels,
+) {
+    if has_custom_linkage(tcx, id.def_id) {
+        worklist.push(id.def_id);
+    }
 
-impl CollectPrivateImplItemsVisitor<'_, '_> {
-    fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
-        // Anything which has custom linkage gets thrown on the worklist no
-        // matter where it is in the crate, along with "special std symbols"
-        // which are currently akin to allocator symbols.
-        if self.tcx.def_kind(def_id).has_codegen_attrs() {
-            let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
-            if codegen_attrs.contains_extern_indicator()
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
-                // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
-                // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
-                // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
-            {
-                self.worklist.push(def_id);
-            }
-        }
+    if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
+        return;
     }
-}
 
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.push_to_worklist_if_has_custom_linkage(item.def_id);
-
-        // We need only trait impls here, not inherent impls, and only non-exported ones
-        if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
-            item.kind
-        {
-            if !self.access_levels.is_reachable(item.def_id) {
-                // FIXME(#53488) remove `let`
-                let tcx = self.tcx;
-                self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
-
-                let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
-                    unreachable!();
-                };
+    // We need only trait impls here, not inherent impls, and only non-exported ones
+    let item = tcx.hir().item(id);
+    if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
+        item.kind
+    {
+        if !access_levels.is_reachable(item.def_id) {
+            // FIXME(#53488) remove `let`
+            let tcx = tcx;
+            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
 
-                if !trait_def_id.is_local() {
-                    return;
-                }
+            let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
+                unreachable!();
+            };
 
-                self.worklist.extend(
-                    tcx.provided_trait_methods(trait_def_id)
-                        .map(|assoc| assoc.def_id.expect_local()),
-                );
+            if !trait_def_id.is_local() {
+                return;
             }
-        }
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
 
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
-        self.push_to_worklist_if_has_custom_linkage(impl_item.def_id);
+            worklist.extend(
+                tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()),
+            );
+        }
     }
+}
 
-    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
-        // We never export foreign functions as they have no body to export.
+fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+    // Anything which has custom linkage gets thrown on the worklist no
+    // matter where it is in the crate, along with "special std symbols"
+    // which are currently akin to allocator symbols.
+    if !tcx.def_kind(def_id).has_codegen_attrs() {
+        return false;
     }
+    let codegen_attrs = tcx.codegen_fn_attrs(def_id);
+    codegen_attrs.contains_extern_indicator()
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+        // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+        // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+        // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
 }
 
 fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
@@ -418,12 +398,25 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
         }
     }
     {
-        let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
-            tcx,
-            access_levels,
-            worklist: &mut reachable_context.worklist,
-        };
-        tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
+        // Some methods from non-exported (completely private) trait impls still have to be
+        // reachable if they are called from inlinable code. Generally, it's not known until
+        // monomorphization if a specific trait impl item can be reachable or not. So, we
+        // conservatively mark all of them as reachable.
+        // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
+        // items of non-exported traits (or maybe all local traits?) unless their respective
+        // trait items are used from inlinable code through method call syntax or UFCS, or their
+        // trait is a lang item.
+        let crate_items = tcx.hir_crate_items(());
+
+        for id in crate_items.items() {
+            check_item(tcx, id, &mut reachable_context.worklist, access_levels);
+        }
+
+        for id in crate_items.impl_items() {
+            if has_custom_linkage(tcx, id.def_id) {
+                reachable_context.worklist.push(id.def_id);
+            }
+        }
     }
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
index 10dc587be6e48a9304ba5e18c746e7864b820b63..58195fce281975b5e0245c204214c6e5cbc955a0 100644 (file)
@@ -110,7 +110,7 @@ fn annotate<F>(
     ) where
         F: FnOnce(&mut Self),
     {
-        let attrs = self.tcx.get_attrs(def_id.to_def_id());
+        let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
 
         let depr = attr::find_deprecation(&self.tcx.sess, attrs);
@@ -661,7 +661,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -837,7 +837,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
         tcx.hir().walk_toplevel_module(&mut missing);
-        tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor());
+        tcx.hir().deep_visit_all_item_likes(&mut missing);
     }
 
     let declared_lang_features = &tcx.features().declared_lang_features;
index ee459d9c129d37d2126c6dcb5e499d1cca671a55..e6c7b4064fb09dc490409225506f6ec0c0e4de9c 100644 (file)
@@ -14,8 +14,8 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
-use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
@@ -775,7 +775,14 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.update(item.def_id, variant_level);
+                        self.reach(item.def_id, variant_level).ty();
+                    }
+                    if let Some(hir_id) = variant.data.ctor_hir_id() {
+                        let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
+                        let ctor_level = self.get(ctor_def_id);
+                        if ctor_level.is_some() {
+                            self.reach(item.def_id, ctor_level).ty();
+                        }
                     }
                 }
             }
@@ -803,6 +810,13 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                         }
                     }
                 }
+                if let Some(hir_id) = struct_def.ctor_hir_id() {
+                    let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
+                    let ctor_level = self.get(ctor_def_id);
+                    if ctor_level.is_some() {
+                        self.reach(item.def_id, ctor_level).ty();
+                    }
+                }
             }
         }
 
@@ -1802,12 +1816,12 @@ fn visit_def_id(
     }
 }
 
-struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
+struct PrivateItemsInPublicInterfacesChecker<'tcx> {
     tcx: TyCtxt<'tcx>,
     old_error_set_ancestry: LocalDefIdSet,
 }
 
-impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
+impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
     fn check(
         &self,
         def_id: LocalDefId,
@@ -1841,110 +1855,110 @@ fn check_assoc_item(
             check.ty();
         }
     }
-}
-
-impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+    pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(item.def_id);
+        let item_visibility = tcx.visibility(id.def_id);
+        let def_kind = tcx.def_kind(id.def_id);
 
-        match item.kind {
-            // Crates are always public.
-            hir::ItemKind::ExternCrate(..) => {}
-            // All nested items are checked by `visit_item`.
-            hir::ItemKind::Mod(..) => {}
-            // Checked in resolve.
-            hir::ItemKind::Use(..) => {}
-            // No subitems.
-            hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {}
-            // Subitems of these items have inherited publicity.
-            hir::ItemKind::Const(..)
-            | hir::ItemKind::Static(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::TyAlias(..) => {
-                self.check(item.def_id, item_visibility).generics().predicates().ty();
+        match def_kind {
+            DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
+                self.check(id.def_id, item_visibility).generics().predicates().ty();
             }
-            hir::ItemKind::OpaqueTy(..) => {
+            DefKind::OpaqueTy => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(item.def_id, item_visibility).generics().bounds();
+                self.check(id.def_id, item_visibility).generics().bounds();
             }
-            hir::ItemKind::Trait(.., trait_item_refs) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Trait => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for trait_item_ref in trait_item_refs {
-                    self.check_assoc_item(
-                        trait_item_ref.id.def_id,
-                        trait_item_ref.kind,
-                        trait_item_ref.defaultness,
-                        item_visibility,
-                    );
-
-                    if let AssocItemKind::Type = trait_item_ref.kind {
-                        self.check(trait_item_ref.id.def_id, item_visibility).bounds();
+                    for trait_item_ref in trait_item_refs {
+                        self.check_assoc_item(
+                            trait_item_ref.id.def_id,
+                            trait_item_ref.kind,
+                            trait_item_ref.defaultness,
+                            item_visibility,
+                        );
+
+                        if let AssocItemKind::Type = trait_item_ref.kind {
+                            self.check(trait_item_ref.id.def_id, item_visibility).bounds();
+                        }
                     }
                 }
             }
-            hir::ItemKind::TraitAlias(..) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::TraitAlias => {
+                self.check(id.def_id, item_visibility).generics().predicates();
             }
-            hir::ItemKind::Enum(ref def, _) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Enum => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Enum(ref def, _) = item.kind {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for variant in def.variants {
-                    for field in variant.data.fields() {
-                        self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
+                    for variant in def.variants {
+                        for field in variant.data.fields() {
+                            self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility)
+                                .ty();
+                        }
                     }
                 }
             }
             // Subitems of foreign modules have their own publicity.
-            hir::ItemKind::ForeignMod { items, .. } => {
-                for foreign_item in items {
-                    let vis = tcx.visibility(foreign_item.id.def_id);
-                    self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+            DefKind::ForeignMod => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
+                    for foreign_item in items {
+                        let vis = tcx.visibility(foreign_item.id.def_id);
+                        self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+                    }
                 }
             }
             // Subitems of structs and unions have their own publicity.
-            hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Struct | DefKind::Union => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Struct(ref struct_def, _)
+                | hir::ItemKind::Union(ref struct_def, _) = item.kind
+                {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for field in struct_def.fields() {
-                    let def_id = tcx.hir().local_def_id(field.hir_id);
-                    let field_visibility = tcx.visibility(def_id);
-                    self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
+                    for field in struct_def.fields() {
+                        let def_id = tcx.hir().local_def_id(field.hir_id);
+                        let field_visibility = tcx.visibility(def_id);
+                        self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
+                    }
                 }
             }
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity.
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
-            hir::ItemKind::Impl(ref impl_) => {
-                let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
-                // check that private components do not appear in the generics or predicates of inherent impls
-                // this check is intentionally NOT performed for impls of traits, per #90586
-                if impl_.of_trait.is_none() {
-                    self.check(item.def_id, impl_vis).generics().predicates();
-                }
-                for impl_item_ref in impl_.items {
-                    let impl_item_vis = if impl_.of_trait.is_none() {
-                        min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
-                    } else {
-                        impl_vis
-                    };
-                    self.check_assoc_item(
-                        impl_item_ref.id.def_id,
-                        impl_item_ref.kind,
-                        impl_item_ref.defaultness,
-                        impl_item_vis,
-                    );
+            DefKind::Impl => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Impl(ref impl_) = item.kind {
+                    let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
+                    // check that private components do not appear in the generics or predicates of inherent impls
+                    // this check is intentionally NOT performed for impls of traits, per #90586
+                    if impl_.of_trait.is_none() {
+                        self.check(item.def_id, impl_vis).generics().predicates();
+                    }
+                    for impl_item_ref in impl_.items {
+                        let impl_item_vis = if impl_.of_trait.is_none() {
+                            min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+                        } else {
+                            impl_vis
+                        };
+                        self.check_assoc_item(
+                            impl_item_ref.id.def_id,
+                            impl_item_ref.kind,
+                            impl_item_ref.defaultness,
+                            impl_item_vis,
+                        );
+                    }
                 }
             }
+            _ => {}
         }
     }
 }
@@ -2069,7 +2083,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     }
 
     // Check for private types and traits in public interfaces.
-    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+    let mut checker = PrivateItemsInPublicInterfacesChecker {
         tcx,
         // Only definition IDs are ever searched in `old_error_set_ancestry`,
         // so we can filter away all non-definition IDs at this point.
@@ -2078,5 +2092,8 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
             .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
             .collect(),
     };
-    tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
+
+    for id in tcx.hir().items() {
+        checker.check_item(id);
+    }
 }
index e68d6fdeea55b310321eae866438d87abe9bab24..dffec44ddbcc301b94e5f3cdea63fe78236bd4d9 100644 (file)
@@ -1268,7 +1268,6 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
-            self.r.all_macro_rules.insert(ident.name, res);
             if is_macro_export {
                 let module = self.r.graph_root;
                 self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
index 6503b97a1d31fbc8d57e1d298d4f42381387ca82..ec3b14ace4df21553bf957af963496708022c8ef 100644 (file)
@@ -315,21 +315,28 @@ impl Resolver<'_> {
                 "remove the unused import"
             };
 
-            let parent_module = visitor.r.get_nearest_non_block_module(
-                visitor.r.local_def_id(unused.use_tree_id).to_def_id(),
-            );
-            let test_module_span = match module_to_string(parent_module) {
-                Some(module)
-                    if module == "test"
-                        || module == "tests"
-                        || module.starts_with("test_")
-                        || module.starts_with("tests_")
-                        || module.ends_with("_test")
-                        || module.ends_with("_tests") =>
-                {
-                    Some(parent_module.span)
+            // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
+            // attribute; however, if not, suggest adding the attribute. There is no way to
+            // retrieve attributes here because we do not have a `TyCtxt` yet.
+            let test_module_span = if visitor.r.session.opts.test {
+                None
+            } else {
+                let parent_module = visitor.r.get_nearest_non_block_module(
+                    visitor.r.local_def_id(unused.use_tree_id).to_def_id(),
+                );
+                match module_to_string(parent_module) {
+                    Some(module)
+                        if module == "test"
+                            || module == "tests"
+                            || module.starts_with("test_")
+                            || module.starts_with("tests_")
+                            || module.ends_with("_test")
+                            || module.ends_with("_tests") =>
+                    {
+                        Some(parent_module.span)
+                    }
+                    _ => None,
                 }
-                _ => None,
             };
 
             visitor.r.lint_buffer.buffer_lint_with_diagnostic(
index 1e8cca6122c4c58724bad81648e96417624a6073..f0861103098d25f802cdd68e3e00c100d614421e 100644 (file)
@@ -109,7 +109,7 @@ fn visit_item(&mut self, i: &'a Item) {
                 visit::walk_item(self, i);
                 return self.visit_macro_invoc(i.id);
             }
-            ItemKind::GlobalAsm(..) => DefPathData::Misc,
+            ItemKind::GlobalAsm(..) => DefPathData::GlobalAsm,
             ItemKind::Use(..) => {
                 return visit::walk_item(self, i);
             }
@@ -160,11 +160,11 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
     }
 
     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
-        self.create_def(id, DefPathData::Misc, use_tree.span);
+        self.create_def(id, DefPathData::Use, use_tree.span);
         match use_tree.kind {
             UseTreeKind::Simple(_, id1, id2) => {
-                self.create_def(id1, DefPathData::Misc, use_tree.prefix.span);
-                self.create_def(id2, DefPathData::Misc, use_tree.prefix.span);
+                self.create_def(id1, DefPathData::Use, use_tree.prefix.span);
+                self.create_def(id2, DefPathData::Use, use_tree.prefix.span);
             }
             UseTreeKind::Glob => (),
             UseTreeKind::Nested(..) => {}
index baaab33d71f50feff18adcdf53f8b340e97c9ac4..7ac1bb441c68d04248a2eba6a064b622611c5de8 100644 (file)
@@ -1171,6 +1171,7 @@ fn validate_res_from_ribs(
                         | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
+                        | InlineAsmSymRibKind
                         | ForwardGenericParamBanRibKind => {
                             // Nothing to do. Continue.
                             continue;
@@ -1216,22 +1217,6 @@ fn validate_res_from_ribs(
                             }
                             return Res::Err;
                         }
-                        InlineAsmSymRibKind => {
-                            let features = self.session.features_untracked();
-                            if !features.generic_const_exprs {
-                                if let Some(span) = finalize {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst {
-                                            name: rib_ident.name,
-                                            is_type: true,
-                                        },
-                                    );
-                                }
-                                return Res::Err;
-                            }
-                            continue;
-                        }
                     };
 
                     if let Some(span) = finalize {
@@ -1262,6 +1247,7 @@ fn validate_res_from_ribs(
                         | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
+                        | InlineAsmSymRibKind
                         | ForwardGenericParamBanRibKind => continue,
 
                         ConstantItemRibKind(trivial, _) => {
@@ -1296,22 +1282,6 @@ fn validate_res_from_ribs(
                             }
                             return Res::Err;
                         }
-                        InlineAsmSymRibKind => {
-                            let features = self.session.features_untracked();
-                            if !features.generic_const_exprs {
-                                if let Some(span) = finalize {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst {
-                                            name: rib_ident.name,
-                                            is_type: false,
-                                        },
-                                    );
-                                }
-                                return Res::Err;
-                            }
-                            continue;
-                        }
                     };
 
                     // This was an attempt to use a const parameter outside its scope.
index 723e66e9ef61807d42ed927cdf72970d2157ecab..2712bfeb7b311da06aeb036f76bd954453349632 100644 (file)
@@ -918,6 +918,29 @@ fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         self.diagnostic_metadata.current_where_predicate = previous_value;
     }
 
+    fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
+        for (op, _) in &asm.operands {
+            match op {
+                InlineAsmOperand::In { expr, .. }
+                | InlineAsmOperand::Out { expr: Some(expr), .. }
+                | InlineAsmOperand::InOut { expr, .. } => self.visit_expr(expr),
+                InlineAsmOperand::Out { expr: None, .. } => {}
+                InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                    self.visit_expr(in_expr);
+                    if let Some(out_expr) = out_expr {
+                        self.visit_expr(out_expr);
+                    }
+                }
+                InlineAsmOperand::Const { anon_const, .. } => {
+                    // Although this is `DefKind::AnonConst`, it is allowed to reference outer
+                    // generic parameters like an inline const.
+                    self.resolve_inline_const(anon_const);
+                }
+                InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
+            }
+        }
+    }
+
     fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
         // This is similar to the code for AnonConst.
         self.with_rib(ValueNS, InlineAsmSymRibKind, |this| {
index 030c27af4447dcd47804da0890a48f8a6735284f..700d7c3bfb6fe1231cb0d6eb991f2cd097f98687 100644 (file)
@@ -1025,6 +1025,20 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         }
                         self.uninsert_lifetime_on_error(lifetime, def.unwrap());
                     }
+                    if let hir::Node::Item(hir::Item {
+                        kind: hir::ItemKind::OpaqueTy { .. }, ..
+                    }) = self.tcx.hir().get(parent_id)
+                    {
+                        if !self.trait_definition_only {
+                            let mut err = self.tcx.sess.struct_span_err(
+                                lifetime.span,
+                                "higher kinded lifetime bounds on nested opaque types are not supported yet",
+                            );
+                            err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
+                            err.emit();
+                        }
+                        self.uninsert_lifetime_on_error(lifetime, def.unwrap());
+                    }
                 }
 
                 // We want to start our early-bound indices at the end of the parent scope,
@@ -2002,12 +2016,7 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                         let parent_def_id = self.tcx.parent(def_id);
                         if let Some(def_id) = parent_def_id.as_local() {
                             // lifetimes in `derive` expansions don't count (Issue #53738)
-                            if self
-                                .tcx
-                                .get_attrs(def_id.to_def_id())
-                                .iter()
-                                .any(|attr| attr.has_name(sym::automatically_derived))
-                            {
+                            if self.tcx.has_attr(def_id.to_def_id(), sym::automatically_derived) {
                                 continue;
                             }
 
index 8d3c46c29a861a78063e4dda24e333db9f38c7ad..6c0148a17a1b828655d5cfc54356daa4ce5d9add 100644 (file)
@@ -59,7 +59,7 @@
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
-use std::{cmp, fmt, mem, ptr};
+use std::{cmp, fmt, ptr};
 use tracing::debug;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
@@ -966,8 +966,6 @@ pub struct Resolver<'a> {
     registered_attrs: FxHashSet<Ident>,
     registered_tools: RegisteredTools,
     macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
-    /// FIXME: The only user of this is a doc link resolution hack for rustdoc.
-    all_macro_rules: FxHashMap<Symbol, Res>,
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
     dummy_ext_bang: Lrc<SyntaxExtension>,
     dummy_ext_derive: Lrc<SyntaxExtension>,
@@ -1360,7 +1358,6 @@ pub fn new(
             registered_attrs,
             registered_tools,
             macro_use_prelude: FxHashMap::default(),
-            all_macro_rules: Default::default(),
             macro_map: FxHashMap::default(),
             dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
             dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
@@ -1912,11 +1909,6 @@ pub fn resolve_rustdoc_path(
         }
     }
 
-    // For rustdoc.
-    pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> {
-        mem::take(&mut self.all_macro_rules)
-    }
-
     /// For rustdoc.
     /// For local modules returns only reexports, for external modules returns all children.
     pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
@@ -1928,8 +1920,12 @@ pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
     }
 
     /// For rustdoc.
-    pub fn macro_rules_scope(&self, def_id: LocalDefId) -> MacroRulesScopeRef<'a> {
-        *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item")
+    pub fn macro_rules_scope(&self, def_id: LocalDefId) -> (MacroRulesScopeRef<'a>, Res) {
+        let scope = *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item");
+        match scope.get() {
+            MacroRulesScope::Binding(mb) => (scope, mb.binding.res()),
+            _ => unreachable!(),
+        }
     }
 
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
index e1c9ecc055f6ad52b11b30c0d03e75cccccb123a..fe417f45e88d972d16e2ddfdb35ffabee5ae37a6 100644 (file)
@@ -780,13 +780,18 @@ fn process_struct_lit(
         variant: &'tcx ty::VariantDef,
         rest: Option<&'tcx hir::Expr<'tcx>>,
     ) {
-        if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
+        if let Some(_ex_res_data) = self.save_ctxt.get_expr_data(ex) {
             if let hir::QPath::Resolved(_, path) = path {
                 self.write_sub_paths_truncated(path);
             }
-            down_cast_data!(struct_lit_data, RefData, ex.span);
+            // For MyEnum::MyVariant, get_expr_data gives us MyEnum, not MyVariant.
+            // For recording the span's ref id, we want MyVariant.
             if !generated_code(ex.span) {
-                self.dumper.dump_ref(struct_lit_data);
+                let sub_span = path.last_segment_span();
+                let span = self.save_ctxt.span_from_span(sub_span);
+                let reff =
+                    Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(variant.def_id) };
+                self.dumper.dump_ref(reff);
             }
 
             for field in fields {
index 530c1a06f8f47d451e0e843c12031366512acc3e..e1e398a06ed42c6f091505c5724cb13cfeef8016 100644 (file)
@@ -1937,33 +1937,27 @@ fn parse_native_lib_kind(
     };
 
     let kind = match kind {
-        "dylib" => NativeLibKind::Dylib { as_needed: None },
-        "framework" => NativeLibKind::Framework { as_needed: None },
         "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
         "static-nobundle" => {
             early_warn(
                 error_format,
                 "library kind `static-nobundle` has been superseded by specifying \
-                `-bundle` on library kind `static`. Try `static:-bundle`",
+                 modifier `-bundle` with library kind `static`. Try `static:-bundle`",
             );
-            if modifiers.is_some() {
-                early_error(
-                    error_format,
-                    "linking modifier can't be used with library kind `static-nobundle`",
-                )
-            }
             if !nightly_options::match_is_nightly_build(matches) {
                 early_error(
                     error_format,
-                    "library kind `static-nobundle` are currently unstable and only accepted on \
-                the nightly compiler",
+                    "library kind `static-nobundle` is unstable \
+                     and only accepted on the nightly compiler",
                 );
             }
             NativeLibKind::Static { bundle: Some(false), whole_archive: None }
         }
-        s => early_error(
+        "dylib" => NativeLibKind::Dylib { as_needed: None },
+        "framework" => NativeLibKind::Framework { as_needed: None },
+        _ => early_error(
             error_format,
-            &format!("unknown library kind `{s}`, expected one of dylib, framework, or static"),
+            &format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"),
         ),
     };
     match modifiers {
@@ -1978,21 +1972,6 @@ fn parse_native_lib_modifiers(
     error_format: ErrorOutputType,
     matches: &getopts::Matches,
 ) -> (NativeLibKind, Option<bool>) {
-    let report_unstable_modifier = |modifier| {
-        if !nightly_options::is_unstable_enabled(matches) {
-            let why = if nightly_options::match_is_nightly_build(matches) {
-                " and only accepted on the nightly compiler"
-            } else {
-                ", the `-Z unstable-options` flag must also be passed to use it"
-            };
-            early_error(
-                error_format,
-                &format!("{modifier} linking modifier is currently unstable{why}"),
-            )
-        }
-    };
-
-    let mut has_duplicate_modifiers = false;
     let mut verbatim = None;
     for modifier in modifiers.split(',') {
         let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
@@ -2000,56 +1979,63 @@ fn parse_native_lib_modifiers(
             None => early_error(
                 error_format,
                 "invalid linking modifier syntax, expected '+' or '-' prefix \
-                    before one of: bundle, verbatim, whole-archive, as-needed",
+                 before one of: bundle, verbatim, whole-archive, as-needed",
             ),
         };
 
+        let report_unstable_modifier = || {
+            if !nightly_options::is_unstable_enabled(matches) {
+                let why = if nightly_options::match_is_nightly_build(matches) {
+                    " and only accepted on the nightly compiler"
+                } else {
+                    ", the `-Z unstable-options` flag must also be passed to use it"
+                };
+                early_error(
+                    error_format,
+                    &format!("linking modifier `{modifier}` is unstable{why}"),
+                )
+            }
+        };
+        let assign_modifier = |dst: &mut Option<bool>| {
+            if dst.is_some() {
+                let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
+                early_error(error_format, &msg)
+            } else {
+                *dst = Some(value);
+            }
+        };
         match (modifier, &mut kind) {
             ("bundle", NativeLibKind::Static { bundle, .. }) => {
-                report_unstable_modifier(modifier);
-                if bundle.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *bundle = Some(value);
+                report_unstable_modifier();
+                assign_modifier(bundle)
             }
             ("bundle", _) => early_error(
                 error_format,
-                "bundle linking modifier is only compatible with \
-                    `static` linking kind",
+                "linking modifier `bundle` is only compatible with `static` linking kind",
             ),
 
             ("verbatim", _) => {
-                report_unstable_modifier(modifier);
-                if verbatim.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                verbatim = Some(value);
+                report_unstable_modifier();
+                assign_modifier(&mut verbatim)
             }
 
             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                if whole_archive.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *whole_archive = Some(value);
+                assign_modifier(whole_archive)
             }
             ("whole-archive", _) => early_error(
                 error_format,
-                "whole-archive linking modifier is only compatible with \
-                    `static` linking kind",
+                "linking modifier `whole-archive` is only compatible with `static` linking kind",
             ),
 
             ("as-needed", NativeLibKind::Dylib { as_needed })
             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                report_unstable_modifier(modifier);
-                if as_needed.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *as_needed = Some(value);
+                report_unstable_modifier();
+                assign_modifier(as_needed)
             }
             ("as-needed", _) => early_error(
                 error_format,
-                "as-needed linking modifier is only compatible with \
-                    `dylib` and `framework` linking kinds",
+                "linking modifier `as-needed` is only compatible with \
+                 `dylib` and `framework` linking kinds",
             ),
 
             // Note: this error also excludes the case with empty modifier
@@ -2057,15 +2043,12 @@ fn parse_native_lib_modifiers(
             _ => early_error(
                 error_format,
                 &format!(
-                    "unrecognized linking modifier `{modifier}`, expected one \
-                    of: bundle, verbatim, whole-archive, as-needed"
+                    "unknown linking modifier `{modifier}`, expected one \
+                     of: bundle, verbatim, whole-archive, as-needed"
                 ),
             ),
         }
     }
-    if has_duplicate_modifiers {
-        report_unstable_modifier("duplicating")
-    }
 
     (kind, verbatim)
 }
@@ -2093,6 +2076,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
                 None => (name, None),
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
+            if name.is_empty() {
+                early_error(error_format, "library name must not be empty");
+            }
             NativeLib { name, new_name, kind, verbatim }
         })
         .collect()
index 7357cebf62eb9dc67d20d49a9a566af1e8a13476..1f4578c08a3f2443d6eb02d8171318f2f9692d24 100644 (file)
@@ -335,8 +335,8 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
-impl FileNameDisplay<'_> {
-    pub fn to_string_lossy(&self) -> Cow<'_, str> {
+impl<'a> FileNameDisplay<'a> {
+    pub fn to_string_lossy(&self) -> Cow<'a, str> {
         match self.inner {
             FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
             _ => Cow::from(format!("{}", self)),
@@ -1153,7 +1153,7 @@ fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
 }
 
 /// The hash of the on-disk source file used for debug info.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct SourceFileHash {
     pub kind: SourceFileHashAlgorithm,
index 505c0af953af1e85e0921b636bb35ef799848162..020ae3ad0c78cf438c1f12f1571a7733c9afa5bf 100644 (file)
@@ -1098,28 +1098,45 @@ pub fn new(mapping: Vec<(PathBuf, PathBuf)>) -> FilePathMapping {
     /// The return value is the remapped path and a boolean indicating whether
     /// the path was affected by the mapping.
     pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
-        // NOTE: We are iterating over the mapping entries from last to first
-        //       because entries specified later on the command line should
-        //       take precedence.
-        for &(ref from, ref to) in self.mapping.iter().rev() {
-            if let Ok(rest) = path.strip_prefix(from) {
-                let remapped = if rest.as_os_str().is_empty() {
-                    // This is subtle, joining an empty path onto e.g. `foo/bar` will
-                    // result in `foo/bar/`, that is, there'll be an additional directory
-                    // separator at the end. This can lead to duplicated directory separators
-                    // in remapped paths down the line.
-                    // So, if we have an exact match, we just return that without a call
-                    // to `Path::join()`.
-                    to.clone()
-                } else {
-                    to.join(rest)
-                };
+        if path.as_os_str().is_empty() {
+            // Exit early if the path is empty and therefore there's nothing to remap.
+            // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
+            return (path, false);
+        }
 
-                return (remapped, true);
+        return remap_path_prefix(&self.mapping, path);
+
+        #[instrument(level = "debug", skip(mapping))]
+        fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
+            // NOTE: We are iterating over the mapping entries from last to first
+            //       because entries specified later on the command line should
+            //       take precedence.
+            for &(ref from, ref to) in mapping.iter().rev() {
+                debug!("Trying to apply {:?} => {:?}", from, to);
+
+                if let Ok(rest) = path.strip_prefix(from) {
+                    let remapped = if rest.as_os_str().is_empty() {
+                        // This is subtle, joining an empty path onto e.g. `foo/bar` will
+                        // result in `foo/bar/`, that is, there'll be an additional directory
+                        // separator at the end. This can lead to duplicated directory separators
+                        // in remapped paths down the line.
+                        // So, if we have an exact match, we just return that without a call
+                        // to `Path::join()`.
+                        to.clone()
+                    } else {
+                        to.join(rest)
+                    };
+                    debug!("Match - remapped {:?} => {:?}", path, remapped);
+
+                    return (remapped, true);
+                } else {
+                    debug!("No match - prefix {:?} does not match {:?}", from, path);
+                }
             }
-        }
 
-        (path, false)
+            debug!("Path {:?} was not remapped", path);
+            (path, false)
+        }
     }
 
     fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
@@ -1140,4 +1157,83 @@ fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
             other => (other.clone(), false),
         }
     }
+
+    /// Expand a relative path to an absolute path with remapping taken into account.
+    /// Use this when absolute paths are required (e.g. debuginfo or crate metadata).
+    ///
+    /// The resulting `RealFileName` will have its `local_path` portion erased if
+    /// possible (i.e. if there's also a remapped path).
+    pub fn to_embeddable_absolute_path(
+        &self,
+        file_path: RealFileName,
+        working_directory: &RealFileName,
+    ) -> RealFileName {
+        match file_path {
+            // Anything that's already remapped we don't modify, except for erasing
+            // the `local_path` portion.
+            RealFileName::Remapped { local_path: _, virtual_name } => {
+                RealFileName::Remapped {
+                    // We do not want any local path to be exported into metadata
+                    local_path: None,
+                    // We use the remapped name verbatim, even if it looks like a relative
+                    // path. The assumption is that the user doesn't want us to further
+                    // process paths that have gone through remapping.
+                    virtual_name,
+                }
+            }
+
+            RealFileName::LocalPath(unmapped_file_path) => {
+                // If no remapping has been applied yet, try to do so
+                let (new_path, was_remapped) = self.map_prefix(unmapped_file_path);
+                if was_remapped {
+                    // It was remapped, so don't modify further
+                    return RealFileName::Remapped { local_path: None, virtual_name: new_path };
+                }
+
+                if new_path.is_absolute() {
+                    // No remapping has applied to this path and it is absolute,
+                    // so the working directory cannot influence it either, so
+                    // we are done.
+                    return RealFileName::LocalPath(new_path);
+                }
+
+                debug_assert!(new_path.is_relative());
+                let unmapped_file_path_rel = new_path;
+
+                match working_directory {
+                    RealFileName::LocalPath(unmapped_working_dir_abs) => {
+                        let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel);
+
+                        // Although neither `working_directory` nor the file name were subject
+                        // to path remapping, the concatenation between the two may be. Hence
+                        // we need to do a remapping here.
+                        let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs);
+                        if was_remapped {
+                            RealFileName::Remapped {
+                                // Erase the actual path
+                                local_path: None,
+                                virtual_name: file_path_abs,
+                            }
+                        } else {
+                            // No kind of remapping applied to this path, so
+                            // we leave it as it is.
+                            RealFileName::LocalPath(file_path_abs)
+                        }
+                    }
+                    RealFileName::Remapped {
+                        local_path: _,
+                        virtual_name: remapped_working_dir_abs,
+                    } => {
+                        // If working_directory has been remapped, then we emit
+                        // Remapped variant as the expanded path won't be valid
+                        RealFileName::Remapped {
+                            local_path: None,
+                            virtual_name: Path::new(remapped_working_dir_abs)
+                                .join(unmapped_file_path_rel),
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
index 481e015c66c25ce3c6a8881974f93f2fc17cb1c2..be827cea8744b6f90f8ce9ffb487160a9d08f391 100644 (file)
@@ -313,82 +313,169 @@ fn span_substr(
     }
 }
 
-fn map_path_prefix(mapping: &FilePathMapping, path: &str) -> String {
+// Takes a unix-style path and returns a platform specific path.
+fn path(p: &str) -> PathBuf {
+    path_str(p).into()
+}
+
+// Takes a unix-style path and returns a platform specific path.
+fn path_str(p: &str) -> String {
+    #[cfg(not(windows))]
+    {
+        return p.into();
+    }
+
+    #[cfg(windows)]
+    {
+        let mut path = p.replace('/', "\\");
+        if let Some(rest) = path.strip_prefix('\\') {
+            path = ["X:\\", rest].concat();
+        }
+
+        path
+    }
+}
+
+fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String {
     // It's important that we convert to a string here because that's what
     // later stages do too (e.g. in the backend), and comparing `Path` values
     // won't catch some differences at the string level, e.g. "abc" and "abc/"
     // compare as equal.
-    mapping.map_prefix(path.into()).0.to_string_lossy().to_string()
+    mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
 }
 
-#[cfg(unix)]
 #[test]
 fn path_prefix_remapping() {
     // Relative to relative
     {
-        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("abc/def"), path("foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc/def"), "foo");
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "abc/def"), path_str("foo"));
     }
 
     // Relative to absolute
     {
-        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "/foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("abc/def"), path("/foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "/foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc/def"), "/foo");
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "abc/def"), path_str("/foo"));
     }
 
     // Absolute to relative
     {
-        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("/abc/def"), path("foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "/abc/def"), "foo");
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), path_str("foo"));
     }
 
     // Absolute to absolute
     {
-        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "/foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("/abc/def"), path("/foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "/foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "/abc/def"), "/foo");
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), path_str("/foo"));
     }
 }
 
-#[cfg(windows)]
 #[test]
-fn path_prefix_remapping_from_relative2() {
-    // Relative to relative
-    {
-        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "foo".into())]);
+fn path_prefix_remapping_expand_to_absolute() {
+    // "virtual" working directory is relative path
+    let mapping =
+        &FilePathMapping::new(vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))]);
+    let working_directory = path("/foo");
+    let working_directory = RealFileName::Remapped {
+        local_path: Some(working_directory.clone()),
+        virtual_name: mapping.map_prefix(working_directory).0,
+    };
+
+    assert_eq!(working_directory.remapped_path_if_available(), path("FOO"));
+
+    // Unmapped absolute path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/foo/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc\\def"), "foo");
-    }
+    // Unmapped absolute path with unrelated working directory
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/bar/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") }
+    );
 
-    // Relative to absolute
-    {
-        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "X:\\foo".into())]);
+    // Unmapped absolute path that does not match any prefix
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/quux/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::LocalPath(path("/quux/src/main.rs")),
+    );
 
-        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc\\def"), "X:\\foo");
-    }
+    // Unmapped relative path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-    // Absolute to relative
-    {
-        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "foo".into())]);
+    // Unmapped relative path with `./`
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("./src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "foo");
-    }
+    // Unmapped relative path that does not match any prefix
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("quux/src/main.rs")),
+            &RealFileName::LocalPath(path("/abc")),
+        ),
+        RealFileName::LocalPath(path("/abc/quux/src/main.rs")),
+    );
 
-    // Absolute to absolute
-    {
-        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "X:\\foo".into())]);
+    // Already remapped absolute path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped {
+                local_path: Some(path("/foo/src/main.rs")),
+                virtual_name: path("FOO/src/main.rs"),
+            },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "X:\\foo");
-    }
+    // Already remapped absolute path, with unrelated working directory
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped {
+                local_path: Some(path("/bar/src/main.rs")),
+                virtual_name: path("BAR/src/main.rs"),
+            },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") }
+    );
+
+    // Already remapped relative path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
+    );
 }
index 2cc6eb03585676c441a8bd369be1b85c446877c1..5c9c16350e469b3a96fa4d42de2f8b7fc0d4548a 100644 (file)
         thread_local_macro,
         thumb2,
         thumb_mode: "thumb-mode",
+        tmm_reg,
         todo_macro,
         tool_attributes,
         tool_lints,
index 37d1cffa2a52b9e1f6cc482a1208df1c52a53b4f..7249ce04c155ecac4c357fbd7af61220c096e75a 100644 (file)
@@ -49,27 +49,26 @@ struct SymbolNamesTest<'tcx> {
 impl SymbolNamesTest<'_> {
     fn process_attrs(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
-        for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
-            if attr.has_name(SYMBOL_NAME) {
-                let def_id = def_id.to_def_id();
-                let instance = Instance::new(
-                    def_id,
-                    tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
-                );
-                let mangled = tcx.symbol_name(instance);
-                tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
-                if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
-                    tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
-                    tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
-                }
-            } else if attr.has_name(DEF_PATH) {
-                let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id()));
-                tcx.sess.span_err(attr.span, &format!("def-path({})", path));
+        // The formatting of `tag({})` is chosen so that tests can elect
+        // to test the entirety of the string, if they choose, or else just
+        // some subset.
+        for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) {
+            let def_id = def_id.to_def_id();
+            let instance = Instance::new(
+                def_id,
+                tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
+            );
+            let mangled = tcx.symbol_name(instance);
+            tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
+            if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
+                tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
+                tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
             }
+        }
 
-            // (*) The formatting of `tag({})` is chosen so that tests can elect
-            // to test the entirety of the string, if they choose, or else just
-            // some subset.
+        for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) {
+            let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id()));
+            tcx.sess.span_err(attr.span, &format!("def-path({})", path));
         }
     }
 }
index c8fdf363f053eb24e81663977a63886908a24c34..dc1946bcdc2ebbf1b3a08dbaee4ede4030f6d35e 100644 (file)
@@ -9,7 +9,9 @@
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_middle::ty::{
+    self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy,
+};
 use rustc_span::symbol::kw;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Integer;
@@ -297,7 +299,7 @@ fn print_impl_path(
 
         let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
         if !substs.is_empty() {
-            param_env = param_env.subst(self.tcx, substs);
+            param_env = EarlyBinder(param_env).subst(self.tcx, substs);
         }
 
         match &mut impl_trait_ref {
@@ -788,7 +790,8 @@ fn path_append(
 
             // These should never show up as `path_append` arguments.
             DefPathData::CrateRoot
-            | DefPathData::Misc
+            | DefPathData::Use
+            | DefPathData::GlobalAsm
             | DefPathData::Impl
             | DefPathData::MacroNs(_)
             | DefPathData::LifetimeNs(_) => {
index 6bc807c7c4421649f89e81867da730d26a88b733..df8ccc42a77a33fe27629c09aa0eb2863e1a41ba 100644 (file)
@@ -912,6 +912,7 @@ macro_rules! clobbered_regs {
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
+                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
                 }
             },
             InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
@@ -931,6 +932,7 @@ macro_rules! clobbered_regs {
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
+                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
                 }
             },
             InlineAsmClobberAbi::AArch64 => clobbered_regs! {
index 854674c7f2fa7c98804c4ce6cc28bc9d5c483a9b..e35035fd25af6e52263aad4218d15b16a73d092b 100644 (file)
@@ -17,6 +17,7 @@
         kreg0,
         mmx_reg,
         x87_reg,
+        tmm_reg,
     }
 }
 
@@ -41,6 +42,7 @@ pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
             Self::kreg | Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
+            Self::tmm_reg => &[],
         }
     }
 
@@ -80,6 +82,7 @@ pub fn suggest_modifier(
             },
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
+            Self::tmm_reg => None,
         }
     }
 
@@ -98,6 +101,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
             Self::zmm_reg => Some(('z', "zmm0")),
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
+            Self::tmm_reg => None,
         }
     }
 
@@ -135,6 +139,7 @@ pub fn supported_types(
             },
             Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
+            Self::tmm_reg => &[],
         }
     }
 }
@@ -320,6 +325,14 @@ fn esi_reserved(
         st5: x87_reg = ["st(5)"],
         st6: x87_reg = ["st(6)"],
         st7: x87_reg = ["st(7)"],
+        tmm0: tmm_reg = ["tmm0"] % x86_64_only,
+        tmm1: tmm_reg = ["tmm1"] % x86_64_only,
+        tmm2: tmm_reg = ["tmm2"] % x86_64_only,
+        tmm3: tmm_reg = ["tmm3"] % x86_64_only,
+        tmm4: tmm_reg = ["tmm4"] % x86_64_only,
+        tmm5: tmm_reg = ["tmm5"] % x86_64_only,
+        tmm6: tmm_reg = ["tmm6"] % x86_64_only,
+        tmm7: tmm_reg = ["tmm7"] % x86_64_only,
         #error = ["bp", "bpl", "ebp", "rbp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "spl", "esp", "rsp"] =>
diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs
new file mode 100644 (file)
index 0000000..59c6a95
--- /dev/null
@@ -0,0 +1,16 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+    let mut base = super::windows_gnullvm_base::opts();
+    base.max_atomic_width = Some(64);
+    base.features = "+neon,+fp-armv8".into();
+    base.linker = Some("aarch64-w64-mingw32-clang".into());
+
+    Target {
+        llvm_target: "aarch64-pc-windows-gnu".into(),
+        pointer_width: 64,
+        data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: base,
+    }
+}
index 965a3c109832ba2cfa79b7a1075955f03a04bc7d..832eeec3e8b272bb7b9cf7d2c26719c7d530f93e 100644 (file)
@@ -82,6 +82,7 @@
 mod vxworks_base;
 mod wasm_base;
 mod windows_gnu_base;
+mod windows_gnullvm_base;
 mod windows_msvc_base;
 mod windows_uwp_gnu_base;
 mod windows_uwp_msvc_base;
@@ -939,6 +940,9 @@ fn $module() {
     ("i686-uwp-windows-gnu", i686_uwp_windows_gnu),
     ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),
 
+    ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm),
+    ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm),
+
     ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
     ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc),
     ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),
diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs
new file mode 100644 (file)
index 0000000..9f9f8be
--- /dev/null
@@ -0,0 +1,52 @@
+use crate::spec::{cvs, LinkArgs, LinkerFlavor, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    let pre_link_args = LinkArgs::from([(
+        LinkerFlavor::Gcc,
+        vec![
+            // We cannot use `-nodefaultlibs` because compiler-rt has to be passed
+            // as a path since it's not added to linker search path by the default.
+            // There were attemts to make it behave like libgcc (so one can just use -l<name>)
+            // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440
+            "-nolibc".into(),
+            "--unwindlib=none".into(),
+        ],
+    )]);
+    let late_link_args = LinkArgs::from([(
+        LinkerFlavor::Gcc,
+        // Order of `late_link_args*` does not matter with LLD.
+        vec![
+            "-lmingw32".into(),
+            "-lmingwex".into(),
+            "-lmsvcrt".into(),
+            "-lkernel32".into(),
+            "-luser32".into(),
+        ],
+    )]);
+
+    TargetOptions {
+        os: "windows".into(),
+        env: "gnu".into(),
+        vendor: "pc".into(),
+        abi: "llvm".into(),
+        linker: Some("clang".into()),
+        dynamic_linking: true,
+        executables: true,
+        dll_prefix: "".into(),
+        dll_suffix: ".dll".into(),
+        exe_suffix: ".exe".into(),
+        families: cvs!["windows"],
+        is_like_windows: true,
+        allows_weak_linkage: false,
+        pre_link_args,
+        late_link_args,
+        abi_return_struct_as_int: true,
+        emit_debug_gdb_scripts: false,
+        requires_uwtable: true,
+        eh_frame_header: false,
+        no_default_libraries: false,
+        has_thread_local: true,
+
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs
new file mode 100644 (file)
index 0000000..b5ff63e
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::spec::{LinkerFlavor, Target};
+
+pub fn target() -> Target {
+    let mut base = super::windows_gnullvm_base::opts();
+    base.cpu = "x86-64".into();
+    let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default();
+    gcc_pre_link_args.push("-m64".into());
+    base.max_atomic_width = Some(64);
+    base.linker = Some("x86_64-w64-mingw32-clang".into());
+
+    Target {
+        llvm_target: "x86_64-pc-windows-gnu".into(),
+        pointer_width: 64,
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .into(),
+        arch: "x86_64".into(),
+        options: base,
+    }
+}
index 74f5185d6723632d3356c2d0f03a6f7ea899e52c..238c6d9999075780d2fc29ba567f68514570b43d 100644 (file)
@@ -82,6 +82,15 @@ fn infer_opaque_definition_from_instantiation(
         ));
         debug!(?definition_ty);
 
+        if !check_opaque_type_parameter_valid(
+            self.tcx,
+            opaque_type_key,
+            origin,
+            instantiated_ty.span,
+        ) {
+            return self.tcx.ty_error();
+        }
+
         // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
         // on stable and we'd break that.
         if let OpaqueTyOrigin::TyAlias = origin {
@@ -148,6 +157,98 @@ fn infer_opaque_definition_from_instantiation(
     }
 }
 
+fn check_opaque_type_parameter_valid(
+    tcx: TyCtxt<'_>,
+    opaque_type_key: OpaqueTypeKey<'_>,
+    origin: OpaqueTyOrigin,
+    span: Span,
+) -> bool {
+    match origin {
+        // No need to check return position impl trait (RPIT)
+        // because for type and const parameters they are correct
+        // by construction: we convert
+        //
+        // fn foo<P0..Pn>() -> impl Trait
+        //
+        // into
+        //
+        // type Foo<P0...Pn>
+        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
+        //
+        // For lifetime parameters we convert
+        //
+        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+        //
+        // into
+        //
+        // type foo::<'p0..'pn>::Foo<'q0..'qm>
+        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+        //
+        // which would error here on all of the `'static` args.
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
+        // Check these
+        OpaqueTyOrigin::TyAlias => {}
+    }
+    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
+    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
+        let arg_is_param = match arg.unpack() {
+            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
+            GenericArgKind::Lifetime(lt) if lt.is_static() => {
+                tcx.sess
+                    .struct_span_err(span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
+                        "cannot use static lifetime; use a bound lifetime \
+                                    instead or remove the lifetime parameter from the \
+                                    opaque type",
+                    )
+                    .emit();
+                return false;
+            }
+            GenericArgKind::Lifetime(lt) => {
+                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+            }
+            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
+        };
+
+        if arg_is_param {
+            seen_params.entry(arg).or_default().push(i);
+        } else {
+            // Prevent `fn foo() -> Foo<u32>` from being defining.
+            let opaque_param = opaque_generics.param_at(i, tcx);
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(
+                    tcx.def_span(opaque_param.def_id),
+                    &format!(
+                        "used non-generic {} `{}` for generic parameter",
+                        opaque_param.kind.descr(),
+                        arg,
+                    ),
+                )
+                .emit();
+            return false;
+        }
+    }
+
+    for (_, indices) in seen_params {
+        if indices.len() > 1 {
+            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
+            let spans: Vec<_> = indices
+                .into_iter()
+                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
+                .collect();
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(spans, &format!("{} used multiple times", descr))
+                .emit();
+            return false;
+        }
+    }
+    true
+}
+
 struct ReverseMapper<'tcx> {
     tcx: TyCtxt<'tcx>,
 
index 24110d30a8456e0da2e9ba274d21542e4680c57f..e56173b2dc50f9013e14b1192d1f4ebcbc5c2137 100644 (file)
@@ -135,8 +135,8 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
 
     let header = ty::ImplHeader {
         impl_def_id,
-        self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs),
-        trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs),
+        self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
+        trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
         predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
     };
 
@@ -645,7 +645,7 @@ fn uncover_fundamental_ty<'tcx>(
                 .substs
                 .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|ty| ty_is_local_constructor(*ty, in_crate));
+                .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
 
             debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
 
@@ -677,7 +677,7 @@ fn contained_non_local_types<'tcx>(
     ty: Ty<'tcx>,
     in_crate: InCrate,
 ) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(ty, in_crate) {
+    if ty_is_local_constructor(tcx, ty, in_crate) {
         Vec::new()
     } else {
         match fundamental_ty_inner_tys(tcx, ty) {
@@ -730,7 +730,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
     }
 }
 
-fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
     debug!("ty_is_local_constructor({:?})", ty);
 
     match *ty.kind() {
@@ -789,11 +789,6 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
             false
         }
 
-        ty::Closure(..) => {
-            // Similar to the `Opaque` case (#83613).
-            false
-        }
-
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
                 def_id_is_local(principal.def_id(), in_crate)
@@ -804,8 +799,20 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
 
         ty::Error(_) => true,
 
-        ty::Generator(..) | ty::GeneratorWitness(..) => {
-            bug!("ty_is_local invoked on unexpected type: {:?}", ty)
+        // These variants should never appear during coherence checking because they
+        // cannot be named directly.
+        //
+        // They could be indirectly used through an opaque type. While using opaque types
+        // in impls causes an error, this path can still be hit afterwards.
+        //
+        // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
+        // could happens.
+        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            tcx.sess.delay_span_bug(
+                DUMMY_SP,
+                format!("ty_is_local invoked on closure or generator: {:?}", ty),
+            );
+            true
         }
     }
 }
index 5daa9796d12e4f615f6a0380b8dcfb7724123324..27ce08ea0453f184e7b84d9d1b6c8b32d47d5835 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_middle::thir;
 use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, DelaySpanBugEmitted, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
@@ -263,8 +263,10 @@ pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
     pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
         let node = self.inner.last().copied().unwrap();
         match node {
-            Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)),
-            Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)),
+            Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)),
+            Node::Cast(kind, operand, ty) => {
+                Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs))
+            }
             // Don't perform substitution on the following as they can't directly contain generic params
             Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
         }
index 7a3579eb1cc853193bbda3e3ecdb74c3c5d65cf6..266fcc777ef565738b1d83cdc3b6a6af4e76e7c8 100644 (file)
@@ -2,11 +2,10 @@
 pub mod suggestions;
 
 use super::{
-    DerivedObligationCause, EvaluationResult, FulfillmentContext, FulfillmentError,
-    FulfillmentErrorCode, ImplDerivedObligationCause, MismatchedProjectionTypes, Obligation,
-    ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote,
-    OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError,
-    TraitNotObjectSafe,
+    EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
+    MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+    OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
+    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -684,42 +683,12 @@ fn report_selection_error(
                                 let mut code = obligation.cause.code();
                                 let mut trait_pred = trait_predicate;
                                 let mut peeled = false;
-                                loop {
-                                    match &*code {
-                                        ObligationCauseCode::FunctionArgumentObligation {
-                                            parent_code,
-                                            ..
-                                        } => {
-                                            code = &parent_code;
-                                        }
-                                        ObligationCauseCode::ImplDerivedObligation(
-                                            box ImplDerivedObligationCause {
-                                                derived:
-                                                    DerivedObligationCause {
-                                                        parent_code,
-                                                        parent_trait_pred,
-                                                    },
-                                                ..
-                                            },
-                                        )
-                                        | ObligationCauseCode::BuiltinDerivedObligation(
-                                            DerivedObligationCause {
-                                                parent_code,
-                                                parent_trait_pred,
-                                            },
-                                        )
-                                        | ObligationCauseCode::DerivedObligation(
-                                            DerivedObligationCause {
-                                                parent_code,
-                                                parent_trait_pred,
-                                            },
-                                        ) => {
-                                            peeled = true;
-                                            code = &parent_code;
-                                            trait_pred = *parent_trait_pred;
-                                        }
-                                        _ => break,
-                                    };
+                                while let Some((parent_code, parent_trait_pred)) = code.parent() {
+                                    code = parent_code;
+                                    if let Some(parent_trait_pred) = parent_trait_pred {
+                                        trait_pred = parent_trait_pred;
+                                        peeled = true;
+                                    }
                                 }
                                 let def_id = trait_pred.def_id();
                                 // Mention *all* the `impl`s for the *top most* obligation, the
@@ -1415,8 +1384,7 @@ fn note_version_mismatch(
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx>;
 
     fn maybe_report_ambiguity(
@@ -1954,14 +1922,11 @@ fn note_version_mismatch(
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx> {
-        assert!(!new_self_ty.has_escaping_bound_vars());
-
-        let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
+        let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
             trait_ref: ty::TraitRef {
-                substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
+                substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
                 ..tr.trait_ref
             },
             ..*tr
index 9e9c230aebb85b2a597cf5dad201e09aa02eda42..4263a6fdf18415155c59ad8bb8ecc5dbb46baac9 100644 (file)
@@ -45,7 +45,7 @@ fn impl_similar_to(
 
         self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
             let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
-            let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+            let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
 
             let impl_self_ty = impl_trait_ref.self_ty();
 
index d20ba99ebc9b5b2434bd7f07fc24891823adf550..c3ee849d857165346ce33eeddb69f73c2da7d49e 100644 (file)
@@ -1,6 +1,6 @@
 use super::{
-    DerivedObligationCause, EvaluationResult, ImplDerivedObligationCause, Obligation,
-    ObligationCause, ObligationCauseCode, PredicateObligation, SelectionContext,
+    EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    SelectionContext,
 };
 
 use crate::autoderef::Autoderef;
@@ -623,39 +623,26 @@ fn suggest_dereferences(
         let span = obligation.cause.span;
         let mut real_trait_pred = trait_pred;
         let mut code = obligation.cause.code();
-        loop {
-            match &code {
-                ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
-                    code = &parent_code;
-                }
-                ObligationCauseCode::ImplDerivedObligation(box ImplDerivedObligationCause {
-                    derived: DerivedObligationCause { parent_code, parent_trait_pred },
-                    ..
-                })
-                | ObligationCauseCode::BuiltinDerivedObligation(DerivedObligationCause {
-                    parent_code,
-                    parent_trait_pred,
-                })
-                | ObligationCauseCode::DerivedObligation(DerivedObligationCause {
-                    parent_code,
-                    parent_trait_pred,
-                }) => {
-                    code = &parent_code;
-                    real_trait_pred = *parent_trait_pred;
-                }
-                _ => break,
-            };
-            let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
-                continue;
-            };
+        while let Some((parent_code, parent_trait_pred)) = code.parent() {
+            code = parent_code;
+            if let Some(parent_trait_pred) = parent_trait_pred {
+                real_trait_pred = parent_trait_pred;
+            }
+
+            // Skipping binder here, remapping below
+            let real_ty = real_trait_pred.self_ty().skip_binder();
 
             if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
                 let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
                 if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                     // Re-add the `&`
                     let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
-                    let obligation =
-                        self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+                    let obligation = self
+                        .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
                     Some(steps).filter(|_| self.predicate_may_hold(&obligation))
                 }) {
                     if steps > 0 {
@@ -676,10 +663,13 @@ fn suggest_dereferences(
                     }
                 } else if real_trait_pred != trait_pred {
                     // This branch addresses #87437.
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_base_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
                     let obligation = self.mk_trait_obligation_with_new_self_ty(
                         param_env,
-                        real_trait_pred,
-                        base_ty,
+                        real_trait_pred_and_base_ty,
                     );
                     if self.predicate_may_hold(&obligation) {
                         err.span_suggestion_verbose(
@@ -737,9 +727,8 @@ fn suggest_fn_call(
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
-            return false;
-        };
+        // Skipping binder here, remapping below
+        let self_ty = trait_pred.self_ty().skip_binder();
 
         let (def_id, output_ty, callable) = match *self_ty.kind() {
             ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
@@ -748,14 +737,15 @@ fn suggest_fn_call(
         };
         let msg = format!("use parentheses to call the {}", callable);
 
-        // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
-        // variables, so bail out if we have any.
-        let Some(output_ty) = output_ty.no_bound_vars() else {
-            return false;
-        };
+        // "We should really create a single list of bound vars from the combined vars
+        // from the predicate and function, but instead we just liberate the function bound vars"
+        let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+
+        // Remapping bound vars here
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
 
         let new_obligation =
-            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
 
         match self.evaluate_obligation(&new_obligation) {
             Ok(
@@ -859,96 +849,97 @@ fn suggest_add_reference_to_arg(
         let param_env = obligation.param_env;
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
-                                 blacklist: &[DefId]|
-         -> bool {
-            if blacklist.contains(&old_pred.def_id()) {
-                return false;
-            }
-
-            // This is a quick fix to resolve an ICE (#96223).
-            // This change should probably be deeper.
-            // As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
-            // instead of `Binder<Ty>` leading to some changes to its call places.
-            let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
-            let mk_result = |new_ty| {
-                let obligation =
-                    self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
-                self.predicate_must_hold_modulo_regions(&obligation)
-            };
-            let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
-            let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
-
-            if imm_result || mut_result {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    // We have a very specific type of error, where just borrowing this argument
-                    // might solve the problem. In cases like this, the important part is the
-                    // original type obligation, not the last one that failed, which is arbitrary.
-                    // Because of this, we modify the error to refer to the original obligation and
-                    // return early in the caller.
-
-                    let msg = format!(
-                        "the trait bound `{}: {}` is not satisfied",
-                        orig_ty,
-                        old_pred.print_modifiers_and_trait_path(),
-                    );
-                    if has_custom_message {
-                        err.note(&msg);
-                    } else {
-                        err.message =
-                            vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
-                    }
-                    if snippet.starts_with('&') {
-                        // This is already a literal borrow and the obligation is failing
-                        // somewhere else in the obligation chain. Do not suggest non-sense.
-                        return false;
-                    }
-                    err.span_label(
-                        span,
-                        &format!(
-                            "expected an implementor of trait `{}`",
-                            old_pred.print_modifiers_and_trait_path(),
-                        ),
-                    );
+        let mut try_borrowing =
+            |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
+                if blacklist.contains(&old_pred.def_id()) {
+                    return false;
+                }
+                // We map bounds to `&T` and `&mut T`
+                let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
+                let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
 
-                    // This if is to prevent a special edge-case
-                    if matches!(
-                        span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
-                    ) {
-                        // We don't want a borrowing suggestion on the fields in structs,
-                        // ```
-                        // struct Foo {
-                        //  the_foos: Vec<Foo>
-                        // }
-                        // ```
-
-                        if imm_result && mut_result {
-                            err.span_suggestions(
-                                span.shrink_to_lo(),
-                                "consider borrowing here",
-                                ["&".to_string(), "&mut ".to_string()].into_iter(),
-                                Applicability::MaybeIncorrect,
-                            );
+                let mk_result = |trait_pred_and_new_ty| {
+                    let obligation =
+                        self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+                    self.predicate_must_hold_modulo_regions(&obligation)
+                };
+                let imm_result = mk_result(trait_pred_and_imm_ref);
+                let mut_result = mk_result(trait_pred_and_mut_ref);
+
+                if imm_result || mut_result {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        // We have a very specific type of error, where just borrowing this argument
+                        // might solve the problem. In cases like this, the important part is the
+                        // original type obligation, not the last one that failed, which is arbitrary.
+                        // Because of this, we modify the error to refer to the original obligation and
+                        // return early in the caller.
+
+                        let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+                        if has_custom_message {
+                            err.note(&msg);
                         } else {
-                            err.span_suggestion_verbose(
-                                span.shrink_to_lo(),
-                                &format!(
-                                    "consider{} borrowing here",
-                                    if mut_result { " mutably" } else { "" }
-                                ),
-                                format!("&{}", if mut_result { "mut " } else { "" }),
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.message =
+                                vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
+                        }
+                        if snippet.starts_with('&') {
+                            // This is already a literal borrow and the obligation is failing
+                            // somewhere else in the obligation chain. Do not suggest non-sense.
+                            return false;
                         }
+                        err.span_label(
+                            span,
+                            &format!(
+                                "expected an implementor of trait `{}`",
+                                old_pred.print_modifiers_and_trait_path(),
+                            ),
+                        );
+
+                        // This if is to prevent a special edge-case
+                        if matches!(
+                            span.ctxt().outer_expn_data().kind,
+                            ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+                        ) {
+                            // We don't want a borrowing suggestion on the fields in structs,
+                            // ```
+                            // struct Foo {
+                            //  the_foos: Vec<Foo>
+                            // }
+                            // ```
+
+                            if imm_result && mut_result {
+                                err.span_suggestions(
+                                    span.shrink_to_lo(),
+                                    "consider borrowing here",
+                                    ["&".to_string(), "&mut ".to_string()].into_iter(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_suggestion_verbose(
+                                    span.shrink_to_lo(),
+                                    &format!(
+                                        "consider{} borrowing here",
+                                        if mut_result { " mutably" } else { "" }
+                                    ),
+                                    format!("&{}", if mut_result { "mut " } else { "" }),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                        return true;
                     }
-                    return true;
                 }
-            }
-            return false;
-        };
+                return false;
+            };
 
         if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
             try_borrowing(cause.derived.parent_trait_pred, &[])
@@ -1009,9 +1000,8 @@ fn suggest_remove_reference(
                 return false;
             }
 
-            let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
+            // Skipping binder here, remapping below
+            let mut suggested_ty = trait_pred.self_ty().skip_binder();
 
             for refs_remaining in 0..refs_number {
                 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
@@ -1019,10 +1009,13 @@ fn suggest_remove_reference(
                 };
                 suggested_ty = *inner_ty;
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
 
                 if self.predicate_may_hold(&new_obligation) {
@@ -1142,26 +1135,21 @@ fn suggest_change_mut(
                 return;
             }
 
+            // Skipping binder here, remapping below
             if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
             {
-                if region.is_late_bound() || t_type.has_escaping_bound_vars() {
-                    // Avoid debug assertion in `mk_obligation_for_def_id`.
-                    //
-                    // If the self type has escaping bound vars then it's not
-                    // going to be the type of an expression, so the suggestion
-                    // probably won't apply anyway.
-                    return;
-                }
-
                 let suggested_ty = match mutability {
                     hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
                     hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
                 };
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
                 let suggested_ty_would_satisfy_obligation = self
                     .evaluate_obligation_no_overflow(&new_obligation)
@@ -1212,7 +1200,9 @@ fn suggest_semicolon_removal(
             // Only suggest this if the expression behind the semicolon implements the predicate
             && let Some(typeck_results) = self.in_progress_typeck_results
             && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
-            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
+            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
+                obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
+            ))
         {
             err.span_label(
                 expr.span,
@@ -1669,7 +1659,7 @@ fn maybe_note_obligation_cause_for_async_await(
             debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
                 ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
-                    next_code = Some(parent_code.as_ref());
+                    next_code = Some(parent_code);
                 }
                 ObligationCauseCode::ImplDerivedObligation(cause) => {
                     let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
@@ -1700,7 +1690,7 @@ fn maybe_note_obligation_cause_for_async_await(
                         _ => {}
                     }
 
-                    next_code = Some(cause.derived.parent_code.as_ref());
+                    next_code = Some(&cause.derived.parent_code);
                 }
                 ObligationCauseCode::DerivedObligation(derived_obligation)
                 | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
@@ -1732,7 +1722,7 @@ fn maybe_note_obligation_cause_for_async_await(
                         _ => {}
                     }
 
-                    next_code = Some(derived_obligation.parent_code.as_ref());
+                    next_code = Some(&derived_obligation.parent_code);
                 }
                 _ => break,
             }
@@ -2382,8 +2372,7 @@ fn note_obligation_cause_code<T>(
                 let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
                     false
                 } else {
-                    if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
-                        *data.parent_code
+                    if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code
                     {
                         let parent_trait_ref =
                             self.resolve_vars_if_possible(data.parent_trait_pred);
@@ -2428,7 +2417,7 @@ fn note_obligation_cause_code<T>(
                             err,
                             &parent_predicate,
                             param_env,
-                            &cause_code.peel_derives(),
+                            cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
                         )
@@ -2745,8 +2734,7 @@ fn suggest_await_before_try(
                 );
                 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    normalized_ty.ty().unwrap(),
+                    trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())),
                 );
                 debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
                 if self.predicate_may_hold(&try_obligation)
index e1b6ed92269ca7b1833930bf2f9e95afa8c4a458..e3e384798d3010d3a5ded3b8d7850819aca7642c 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
@@ -531,7 +531,7 @@ fn receiver_for_self_ty<'tcx>(
         if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
     });
 
-    let result = receiver_ty.subst(tcx, substs);
+    let result = EarlyBinder(receiver_ty).subst(tcx, substs);
     debug!(
         "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
         receiver_ty, self_ty, method_def_id, result
index c266eec25aa6b9a68eb914b43978f417b65cb308..7d4181981953627e016b2cec5c236b2c866fc955 100644 (file)
@@ -175,9 +175,7 @@ fn parse(
     }
 
     pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
-        let attrs = tcx.get_attrs(item_def_id);
-
-        let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
+        let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
             return Ok(None);
         };
 
index be4d734b964b8fb45d35c70e4ebe87c21ddf3d02..beaa56e1c1ca7f3cb85da0982f7544b36607f8cb 100644 (file)
@@ -31,7 +31,7 @@
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
@@ -515,7 +515,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                         }
 
                         let substs = substs.super_fold_with(self);
-                        let generic_ty = self.tcx().type_of(def_id);
+                        let generic_ty = self.tcx().bound_type_of(def_id);
                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
                         self.depth += 1;
                         let folded_ty = self.fold_ty(concrete_ty);
@@ -1276,8 +1276,8 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
     let bounds = match *obligation.predicate.self_ty().kind() {
-        ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
-        ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
+        ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs),
+        ty::Opaque(def_id, substs) => tcx.bound_item_bounds(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -2032,7 +2032,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         Progress { term: err.into(), obligations: nested }
     } else {
         assoc_ty_own_obligations(selcx, obligation, &mut nested);
-        Progress { term: term.subst(tcx, substs), obligations: nested }
+        Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested }
     }
 }
 
index ed0ad5601aa400478afdf09db7e7e731ecab7c05..6a81a7764afd9143047b90f89a9496c4a8e51898 100644 (file)
@@ -217,7 +217,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
                             self.infcx.report_overflow_error(&obligation, true);
                         }
 
-                        let generic_ty = self.tcx().type_of(def_id);
+                        let generic_ty = self.tcx().bound_type_of(def_id);
                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
                         self.anon_depth += 1;
                         if concrete_ty == ty {
index 771a3072af5d94475aa29de59fbecdeb82a7f852..d607f4e7642b6aa83470369377dced37dacabb08 100644 (file)
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, Ty};
+use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty};
 use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
 use rustc_span::def_id::DefId;
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
-use crate::traits::select::TraitObligationExt;
 use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
 use crate::traits::{
-    BuiltinDerivedObligation, DerivedObligationCause, ImplDerivedObligation,
-    ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData,
-    ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData,
-    ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData,
-    ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
-    ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch,
-    PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation,
-    Unimplemented, VtblSegment,
+    BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
+    ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
+    ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
+    ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+    ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
+    Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
+    SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment,
 };
 
 use super::BuiltinImplConditions;
@@ -174,7 +172,8 @@ fn confirm_projection_candidate(
                 _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
             };
 
-            let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
+            let candidate_predicate =
+                tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
             let candidate = candidate_predicate
                 .to_opt_poly_trait_pred()
                 .expect("projection candidate is not a trait predicate")
@@ -500,7 +499,7 @@ fn confirm_object_candidate(
             // This maybe belongs in wf, but that can't (doesn't) handle
             // higher-ranked things.
             // Prevent, e.g., `dyn Iterator<Item = str>`.
-            for bound in self.tcx().item_bounds(assoc_type) {
+            for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() {
                 let subst_bound =
                     if defs.count() == 0 {
                         bound.subst(tcx, trait_predicate.trait_ref.substs)
@@ -509,9 +508,9 @@ fn confirm_object_candidate(
                         substs.extend(trait_predicate.trait_ref.substs.iter());
                         let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
                             smallvec::SmallVec::with_capacity(
-                                bound.kind().bound_vars().len() + defs.count(),
+                                bound.0.kind().bound_vars().len() + defs.count(),
                             );
-                        bound_vars.extend(bound.kind().bound_vars().into_iter());
+                        bound_vars.extend(bound.0.kind().bound_vars().into_iter());
                         InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param
                             .kind
                         {
@@ -558,7 +557,8 @@ fn confirm_object_candidate(
                         let assoc_ty_substs = tcx.intern_substs(&substs);
 
                         let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
-                        let bound = bound.kind().skip_binder().subst(tcx, assoc_ty_substs);
+                        let bound =
+                            EarlyBinder(bound.0.kind().skip_binder()).subst(tcx, assoc_ty_substs);
                         tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
                     };
                 let normalized_bound = normalize_with_depth_to(
@@ -1005,10 +1005,10 @@ fn confirm_builtin_unsize_candidate(
                 // The last field of the structure has to exist and contain type/const parameters.
                 let (tail_field, prefix_fields) =
                     def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
-                let tail_field_ty = tcx.type_of(tail_field.did);
+                let tail_field_ty = tcx.bound_type_of(tail_field.did);
 
                 let mut unsizing_params = GrowableBitSet::new_empty();
-                for arg in tail_field_ty.walk() {
+                for arg in tail_field_ty.0.walk() {
                     if let Some(i) = maybe_unsizing_param_idx(arg) {
                         unsizing_params.insert(i);
                     }
@@ -1126,21 +1126,13 @@ fn confirm_const_destruct_candidate(
                 let substs = self.rematch_impl(impl_def_id, &new_obligation);
                 debug!(?substs, "impl substs");
 
-                let derived = DerivedObligationCause {
-                    parent_trait_pred: obligation.predicate,
-                    parent_code: obligation.cause.clone_code(),
-                };
-                let derived_code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                    derived,
-                    impl_def_id,
-                    span: obligation.cause.span,
-                }));
-
-                let cause = ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    derived_code,
-                );
+                let cause = obligation.derived_cause(|derived| {
+                    ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                        derived,
+                        impl_def_id,
+                        span: obligation.cause.span,
+                    }))
+                });
                 ensure_sufficient_stack(|| {
                     self.vtable_impl(
                         impl_def_id,
index 6584d33032a463c88c49e2e87623132a9f64de11..57ded504b3c422527e03faea09fe9d52d7d713a2 100644 (file)
@@ -14,9 +14,9 @@
 use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
 use super::wf;
 use super::{
-    DerivedObligationCause, ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause,
-    Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, PredicateObligation,
-    Selection, SelectionError, SelectionResult, TraitObligation, TraitQueryMode,
+    ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
+    ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError,
+    SelectionResult, TraitObligation, TraitQueryMode,
 };
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -38,7 +38,7 @@
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
-use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::sym;
 
@@ -103,22 +103,31 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// require themselves.
     freshener: TypeFreshener<'cx, 'tcx>,
 
-    /// If `true`, indicates that the evaluation should be conservative
-    /// and consider the possibility of types outside this crate.
+    /// During coherence we have to assume that other crates may add
+    /// additional impls which we currently don't know about.
+    ///
+    /// To deal with this evaluation should be conservative
+    /// and consider the possibility of impls from outside this crate.
     /// This comes up primarily when resolving ambiguity. Imagine
     /// there is some trait reference `$0: Bar` where `$0` is an
     /// inference variable. If `intercrate` is true, then we can never
     /// say for sure that this reference is not implemented, even if
     /// there are *no impls at all for `Bar`*, because `$0` could be
     /// bound to some type that in a downstream crate that implements
-    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
-    /// though, we set this to false, because we are only interested
-    /// in types that the user could actually have written --- in
-    /// other words, we consider `$0: Bar` to be unimplemented if
+    /// `Bar`.
+    ///
+    /// Outside of coherence we set this to false because we are only
+    /// interested in types that the user could actually have written.
+    /// In other words, we consider `$0: Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
     intercrate: bool,
-
+    /// If `intercrate` is set, we remember predicates which were
+    /// considered ambiguous because of impls potentially added in other crates.
+    /// This is used in coherence to give improved diagnostics.
+    /// We don't do his until we detect a coherence error because it can
+    /// lead to false overflow results (#47139) and because always
+    /// computing it may negatively impact performance.
     intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
 
     /// The mode that trait queries run in, which informs our error handling
@@ -240,11 +249,8 @@ pub fn with_query_mode(
         }
     }
 
-    /// Enables tracking of intercrate ambiguity causes. These are
-    /// used in coherence to give improved diagnostics. We don't do
-    /// this until we detect a coherence error because it can lead to
-    /// false overflow results (#47139) and because it costs
-    /// computation time.
+    /// Enables tracking of intercrate ambiguity causes. See
+    /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
         assert!(self.intercrate);
         assert!(self.intercrate_ambiguity_causes.is_none());
@@ -1156,9 +1162,9 @@ fn filter_reservation_impls(
         if let ImplCandidate(def_id) = candidate {
             if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
                 if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
-                    let attrs = tcx.get_attrs(def_id);
-                    let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
-                    let value = attr.and_then(|a| a.value_str());
+                    let value = tcx
+                        .get_attr(def_id, sym::rustc_reservation_impl)
+                        .and_then(|a| a.value_str());
                     if let Some(value) = value {
                         debug!(
                             "filter_reservation_impls: \
@@ -1341,7 +1347,7 @@ fn match_projection_obligation_against_definition_bounds(
                 );
             }
         };
-        let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
+        let bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs);
 
         // The bounds returned by `item_bounds` may contain duplicates after
         // normalization, so try to deduplicate when possible to avoid
@@ -1795,11 +1801,9 @@ fn sized_conditions(
             ty::Adt(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
-                Where(
-                    obligation.predicate.rebind({
-                        sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
-                    }),
-                )
+                Where(obligation.predicate.rebind({
+                    sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect()
+                }))
             }
 
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
@@ -1962,7 +1966,7 @@ fn constituent_types_for_ty(
                 // We can resolve the `impl Trait` to its concrete type,
                 // which enforces a DAG between the functions requiring
                 // the auto trait bounds in question.
-                t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)])
+                t.rebind(vec![self.tcx().bound_type_of(def_id).subst(self.tcx(), substs)])
             }
         }
     }
@@ -2068,12 +2072,12 @@ fn match_impl(
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
-        let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
+        let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
 
         // Before we create the substitutions and everything, first
         // consider a "quick reject". This avoids creating more types
         // and so forth that we need to.
-        if self.fast_reject_trait_refs(obligation, &impl_trait_ref) {
+        if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
             return Err(());
         }
 
@@ -2316,23 +2320,21 @@ fn impl_or_trait_obligations(
         debug!(?predicates);
         assert_eq!(predicates.parent, None);
         let mut obligations = Vec::with_capacity(predicates.predicates.len());
-        let parent_code = cause.clone_code();
         for (predicate, span) in predicates.predicates {
             let span = *span;
-            let derived =
-                DerivedObligationCause { parent_trait_pred, parent_code: parent_code.clone() };
-            let code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                derived,
-                impl_def_id: def_id,
-                span,
-            }));
-            let cause = ObligationCause::new(cause.span, cause.body_id, code);
+            let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
+                ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                    derived,
+                    impl_def_id: def_id,
+                    span,
+                }))
+            });
             let predicate = normalize_with_depth_to(
                 self,
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                predicate.subst(tcx, substs),
+                EarlyBinder(*predicate).subst(tcx, substs),
                 &mut obligations,
             );
             obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
@@ -2342,42 +2344,6 @@ fn impl_or_trait_obligations(
     }
 }
 
-trait TraitObligationExt<'tcx> {
-    fn derived_cause(
-        &self,
-        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx>;
-}
-
-impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> {
-    fn derived_cause(
-        &self,
-        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx> {
-        /*!
-         * Creates a cause for obligations that are derived from
-         * `obligation` by a recursive search (e.g., for a builtin
-         * bound, or eventually a `auto trait Foo`). If `obligation`
-         * is itself a derived obligation, this is just a clone, but
-         * otherwise we create a "derived obligation" cause so as to
-         * keep track of the original root obligation for error
-         * reporting.
-         */
-
-        let obligation = self;
-
-        // NOTE(flaper87): As of now, it keeps track of the whole error
-        // chain. Ideally, we should have a way to configure this either
-        // by using -Z verbose or just a CLI argument.
-        let derived_cause = DerivedObligationCause {
-            parent_trait_pred: obligation.predicate,
-            parent_code: obligation.cause.clone_code(),
-        };
-        let derived_code = variant(derived_cause);
-        ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
-    }
-}
-
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
         TraitObligationStackList::with(self)
index 49c8c56083f0816f75d5fcdbdef13da6bdcb29d4..bca1d15ada90f85ec2e4703e0ceb872a64b1ade6 100644 (file)
@@ -85,7 +85,7 @@ pub fn translate_substs<'a, 'tcx>(
         param_env, source_impl, source_substs, target_node
     );
     let source_trait_ref =
-        infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
+        infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
 
     // translate the Self and Param parts of the substitution, since those
     // vary across impls
index d101f69096fe8e013572d2c605c99dc54a1d938b..f2e31c068a0d37eeba1dc284bf30044059698b4a 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
 pub use rustc_infer::traits::{self, util::*};
@@ -201,7 +201,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
     impl_substs: SubstsRef<'tcx>,
 ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
     let subject = selcx.tcx().impl_subject(impl_def_id);
-    let subject = subject.subst(selcx.tcx(), impl_substs);
+    let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs);
     let Normalized { value: subject, obligations: normalization_obligations1 } =
         super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
 
index de0ade64247dfa2638229bb92746f7ced70a8bf3..0379b16334cdc6f1ef64aa02d2889effa2ebe550 100644 (file)
@@ -294,30 +294,22 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
         let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
 
         debug!("compute_trait_ref obligations {:?}", obligations);
-        let cause = self.cause(traits::MiscObligation);
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
         let item = self.item;
 
-        let extend = |obligation: traits::PredicateObligation<'tcx>| {
-            let mut cause = cause.clone();
-            if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() {
-                let derived_cause = traits::DerivedObligationCause {
+        let extend = |traits::PredicateObligation { predicate, mut cause, .. }| {
+            if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() {
+                cause = cause.derived_cause(
                     parent_trait_pred,
-                    parent_code: obligation.cause.clone_code(),
-                };
-                *cause.make_mut_code() =
-                    traits::ObligationCauseCode::DerivedObligation(derived_cause);
+                    traits::ObligationCauseCode::DerivedObligation,
+                );
             }
             extend_cause_with_original_assoc_item_obligation(
-                tcx,
-                trait_ref,
-                item,
-                &mut cause,
-                obligation.predicate,
+                tcx, trait_ref, item, &mut cause, predicate,
             );
-            traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
+            traits::Obligation::with_depth(cause, depth, param_env, predicate)
         };
 
         if let Elaborate::All = elaborate {
@@ -339,17 +331,17 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
                 })
                 .filter(|(_, arg)| !arg.has_escaping_bound_vars())
                 .map(|(i, arg)| {
-                    let mut new_cause = cause.clone();
+                    let mut cause = traits::ObligationCause::misc(self.span, self.body_id);
                     // The first subst is the self ty - use the correct span for it.
                     if i == 0 {
                         if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) =
                             item.map(|i| &i.kind)
                         {
-                            new_cause.span = self_ty.span;
+                            cause.span = self_ty.span;
                         }
                     }
                     traits::Obligation::with_depth(
-                        new_cause,
+                        cause,
                         depth,
                         param_env,
                         ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
@@ -575,7 +567,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                     // generators don't take arguments.
                 }
 
-                ty::Closure(_, substs) => {
+                ty::Closure(did, substs) => {
                     // Only check the upvar types for WF, not the rest
                     // of the types within. This is needed because we
                     // capture the signature and it may not be WF
@@ -596,18 +588,26 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                     // probably always be WF, because it should be
                     // shorthand for something like `where(T: 'a) {
                     // fn(&'a T) }`, as discussed in #25860.
-                    //
-                    // Note that we are also skipping the generic
-                    // types. This is consistent with the `outlives`
-                    // code, but anyway doesn't matter: within the fn
+                    walker.skip_current_subtree(); // subtree handled below
+                    // FIXME(eddyb) add the type to `walker` instead of recursing.
+                    self.compute(substs.as_closure().tupled_upvars_ty().into());
+                    // Note that we cannot skip the generic types
+                    // types. Normally, within the fn
                     // body where they are created, the generics will
                     // always be WF, and outside of that fn body we
                     // are not directly inspecting closure types
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
-                    walker.skip_current_subtree(); // subtree handled below
-                    // FIXME(eddyb) add the type to `walker` instead of recursing.
-                    self.compute(substs.as_closure().tupled_upvars_ty().into());
+                    // But when a closure is part of a type-alias-impl-trait
+                    // then the function that created the defining site may
+                    // have had more bounds available than the type alias
+                    // specifies. This may cause us to have a closure in the
+                    // hidden type that is not actually well formed and
+                    // can cause compiler crashes when the user abuses unsafe
+                    // code to procure such a closure.
+                    // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
+                    let obligations = self.nominal_obligations(did, substs);
+                    self.out.extend(obligations);
                 }
 
                 ty::FnPtr(_) => {
index 6424b907478764ce6698c23112d3234732a1485d..5b5b84991918840fda33de19c17d8630c6347157 100644 (file)
@@ -8,7 +8,9 @@
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, AssocItemContainer, AssocKind, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable,
+};
 
 use rustc_ast::ast;
 use rustc_attr as attr;
@@ -41,7 +43,7 @@ fn where_clauses_for(
         let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
         predicates
             .iter()
-            .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
+            .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars))
             .filter_map(|wc| LowerInto::<
                     Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
                     >::lower_into(wc, self.interner)).collect()
@@ -55,7 +57,7 @@ fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
             .tcx
             .explicit_item_bounds(def_id)
             .iter()
-            .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
+            .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
             .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
             .collect()
     }
@@ -272,15 +274,17 @@ fn fn_def_datum(
         let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
             self.interner,
             self.interner.tcx,
-            sig.inputs_and_output().subst(self.interner.tcx, bound_vars),
+            EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars),
         );
 
         let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
             .iter()
-            .map(|t| t.subst(self.interner.tcx, &bound_vars).lower_into(self.interner))
+            .map(|t| {
+                EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)
+            })
             .collect();
 
-        let return_type = inputs_and_output[inputs_and_output.len() - 1]
+        let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1])
             .subst(self.interner.tcx, &bound_vars)
             .lower_into(self.interner);
 
@@ -306,7 +310,7 @@ fn impl_datum(
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(self.interner, bound_vars);
 
-        let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
+        let trait_ref = self.interner.tcx.bound_impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
@@ -348,10 +352,10 @@ fn impls_for_trait(
         let all_impls = self.interner.tcx.all_impls(def_id);
         let matched_impls = all_impls.filter(|impl_def_id| {
             use chalk_ir::could_match::CouldMatch;
-            let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap();
+            let trait_ref = self.interner.tcx.bound_impl_trait_ref(*impl_def_id).unwrap();
             let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id);
 
-            let self_ty = trait_ref.self_ty();
+            let self_ty = trait_ref.map_bound(|t| t.self_ty());
             let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
             let lowered_ty = self_ty.lower_into(self.interner);
 
@@ -463,7 +467,7 @@ fn associated_ty_value(
         let ty = self
             .interner
             .tcx
-            .type_of(def_id)
+            .bound_type_of(def_id)
             .subst(self.interner.tcx, bound_vars)
             .lower_into(self.interner);
 
@@ -506,7 +510,7 @@ fn opaque_ty_data(
                 .tcx
                 .explicit_item_bounds(opaque_ty_id.0)
                 .iter()
-                .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
+                .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
                 .map(|bound| {
                     bound.fold_with(&mut ReplaceOpaqueTyFolder {
                         tcx: self.interner.tcx,
index e4c22a354232b784704e1e1c1757469059d7c305..3fd0bb1814a65e1e6719a85f9b22431436bc1aba 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives;
 use rustc_trait_selection::traits::query::dropck_outlives::{
@@ -271,9 +271,15 @@ fn dtorck_constraint_for_ty<'tcx>(
                 tcx.at(span).adt_dtorck_constraint(def.did())?;
             // FIXME: we can try to recursively `dtorck_constraint_on_ty`
             // there, but that needs some way to handle cycles.
-            constraints.dtorck_types.extend(dtorck_types.iter().map(|t| t.subst(tcx, substs)));
-            constraints.outlives.extend(outlives.iter().map(|t| t.subst(tcx, substs)));
-            constraints.overflows.extend(overflows.iter().map(|t| t.subst(tcx, substs)));
+            constraints
+                .dtorck_types
+                .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
+            constraints
+                .outlives
+                .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
+            constraints
+                .overflows
+                .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
         }
 
         // Objects must be alive in order for their destructor
index 6fcac9fcdc622aa0fdedcfcff850a9d99854aee0..861d3bc564fca8ed903728434abbd09a8044bdfd 100644 (file)
@@ -6,7 +6,9 @@
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
-use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance};
+use rustc_middle::ty::{
+    self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance,
+};
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
@@ -115,7 +117,7 @@ fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        value.subst(self.tcx(), substs)
+        EarlyBinder(value).subst(self.tcx(), substs)
     }
 
     fn relate_mir_and_user_ty(
index 143081d61fb37bac2da9dabe7d9ff35b30adb450..17eac2bb2c9e937908c861a5e60c3cebd4c3bc58 100644 (file)
@@ -5,7 +5,6 @@
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::{sym, DUMMY_SP};
-use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
 
@@ -155,12 +154,7 @@ fn inner_resolve_instance<'tcx>(
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
 
         let def = match *item_type.kind() {
-            ty::FnDef(..)
-                if {
-                    let f = item_type.fn_sig(tcx);
-                    f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
-                } =>
-            {
+            ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => {
                 debug!(" => intrinsic");
                 ty::InstanceDef::Intrinsic(def.did)
             }
index c5fc4e4c6610562865eb132b3cf3114eb35ad49a..9ad44d14d61802e37e380508a1322cb3fbd5fcac 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
 use rustc_session::Limit;
 use rustc_span::{sym, DUMMY_SP};
 
@@ -204,7 +204,7 @@ fn with_query_cache<'tcx>(
             match subty.kind() {
                 ty::Adt(adt_id, subst) => {
                     for subty in tcx.adt_drop_tys(adt_id.did())? {
-                        vec.push(subty.subst(tcx, subst));
+                        vec.push(EarlyBinder(subty).subst(tcx, subst));
                     }
                 }
                 _ => vec.push(subty),
@@ -237,7 +237,7 @@ fn with_query_cache<'tcx>(
             Ok(Vec::new())
         } else {
             let field_tys = adt_def.all_fields().map(|field| {
-                let r = tcx.type_of(field.did).subst(tcx, substs);
+                let r = tcx.bound_type_of(field.did).subst(tcx, substs);
                 debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
                 r
             });
index 6ad71bdb48169bfdf5eb29751804f7b5d3b7186f..23700e653e36a23359a66ebc382dd11183ec01f6 100644 (file)
@@ -2,7 +2,9 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
+};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits;
 
@@ -33,7 +35,7 @@ fn sized_constraint_for_ty<'tcx>(
             debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
             adt_tys
                 .iter()
-                .map(|ty| ty.subst(tcx, substs))
+                .map(|ty| EarlyBinder(*ty).subst(tcx, substs))
                 .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
                 .collect()
         }
@@ -442,7 +444,7 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
             //     one uninhabited field.
             def.variants().iter().all(|var| {
                 var.fields.iter().any(|field| {
-                    let ty = tcx.type_of(field.did).subst(tcx, substs);
+                    let ty = tcx.bound_type_of(field.did).subst(tcx, substs);
                     tcx.conservative_is_privately_uninhabited(param_env.and(ty))
                 })
             })
index 38cc74a5e37348ccca400456140e43b9650d210b..8fe89c66389c266098f686cc18e71de125cbe29a 100644 (file)
@@ -1,4 +1,5 @@
 use crate::astconv::AstConv;
+use crate::errors::{ManualImplementation, MissingTypeParams};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -24,65 +25,13 @@ pub(crate) fn complain_about_missing_type_params(
         if missing_type_params.is_empty() {
             return;
         }
-        let display =
-            missing_type_params.iter().map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
-        let mut err = struct_span_err!(
-            self.tcx().sess,
+
+        self.tcx().sess.emit_err(MissingTypeParams {
             span,
-            E0393,
-            "the type parameter{} {} must be explicitly specified",
-            pluralize!(missing_type_params.len()),
-            display,
-        );
-        err.span_label(
-            self.tcx().def_span(def_id),
-            &format!(
-                "type parameter{} {} must be specified for this",
-                pluralize!(missing_type_params.len()),
-                display,
-            ),
-        );
-        let mut suggested = false;
-        if let (Ok(snippet), true) = (
-            self.tcx().sess.source_map().span_to_snippet(span),
-            // Don't suggest setting the type params if there are some already: the order is
-            // tricky to get right and the user will already know what the syntax is.
+            def_span: self.tcx().def_span(def_id),
+            missing_type_params,
             empty_generic_args,
-        ) {
-            if snippet.ends_with('>') {
-                // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
-                // we would have to preserve the right order. For now, as clearly the user is
-                // aware of the syntax, we do nothing.
-            } else {
-                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
-                // least we can clue them to the correct syntax `Iterator<Type>`.
-                err.span_suggestion(
-                    span,
-                    &format!(
-                        "set the type parameter{plural} to the desired type{plural}",
-                        plural = pluralize!(missing_type_params.len()),
-                    ),
-                    format!("{}<{}>", snippet, missing_type_params.join(", ")),
-                    Applicability::HasPlaceholders,
-                );
-                suggested = true;
-            }
-        }
-        if !suggested {
-            err.span_label(
-                span,
-                format!(
-                    "missing reference{} to {}",
-                    pluralize!(missing_type_params.len()),
-                    display,
-                ),
-            );
-        }
-        err.note(
-            "because of the default `Self` reference, type parameters must be \
-                  specified on object types",
-        );
-        err.emit();
+        });
     }
 
     /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
@@ -172,19 +121,7 @@ pub(crate) fn complain_about_internal_fn_trait(
 
         if is_impl {
             let trait_name = self.tcx().def_path_str(trait_def_id);
-            struct_span_err!(
-                self.tcx().sess,
-                span,
-                E0183,
-                "manual implementations of `{}` are experimental",
-                trait_name,
-            )
-            .span_label(
-                span,
-                format!("manual implementations of `{}` are experimental", trait_name),
-            )
-            .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
-            .emit();
+            self.tcx().sess.emit_err(ManualImplementation { span, trait_name });
         }
     }
 
index 38c29d3874c9e169fbe4828fe6eb712574ec4459..dc4bc8fb55a17fe280e48447d6a0f1c1c53cc072 100644 (file)
@@ -3,10 +3,7 @@
     AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, GenericArgPosition,
 };
-use crate::errors::{
-    AssocTypeBindingNotAllowed, ExplicitGenericArgsWithImplTrait,
-    ExplicitGenericArgsWithImplTraitFeature,
-};
+use crate::errors::{AssocTypeBindingNotAllowed, ExplicitGenericArgsWithImplTrait};
 use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
@@ -639,11 +636,10 @@ pub(crate) fn check_impl_trait(
                 })
                 .collect::<Vec<_>>();
 
-            let mut err = tcx.sess.create_err(ExplicitGenericArgsWithImplTrait { spans });
-            if tcx.sess.is_nightly_build() {
-                err.subdiagnostic(ExplicitGenericArgsWithImplTraitFeature);
-            }
-            err.emit();
+            tcx.sess.emit_err(ExplicitGenericArgsWithImplTrait {
+                spans,
+                is_nightly_build: tcx.sess.is_nightly_build().then_some(()),
+            });
         }
 
         impl_trait
index e940d065a999400e1819149f2a3893144f852f16..2ff32bdf9780502815a48fbfff71ae8146153826 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_hir::{GenericArg, GenericArgs};
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -523,7 +523,8 @@ fn inferred_kind(
                                 self.astconv
                                     .normalize_ty(
                                         self.span,
-                                        tcx.at(self.span).type_of(param.def_id).subst(tcx, substs),
+                                        EarlyBinder(tcx.at(self.span).type_of(param.def_id))
+                                            .subst(tcx, substs),
                                     )
                                     .into()
                             }
@@ -543,7 +544,9 @@ fn inferred_kind(
                     GenericParamDefKind::Const { has_default } => {
                         let ty = tcx.at(self.span).type_of(param.def_id);
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
+                            EarlyBinder(tcx.const_param_default(param.def_id))
+                                .subst(tcx, substs.unwrap())
+                                .into()
                         } else {
                             if infer_args {
                                 self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -1292,7 +1295,10 @@ fn ast_path_to_ty(
         item_segment: &hir::PathSegment<'_>,
     ) -> Ty<'tcx> {
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs))
+        self.normalize_ty(
+            span,
+            EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs),
+        )
     }
 
     fn conv_object_ty_poly_trait_ref(
@@ -2441,7 +2447,8 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                     true,
                     None,
                 );
-                self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
+                EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
+                    .subst(tcx, substs)
             }
             hir::TyKind::Array(ref ty, ref length) => {
                 let length = match length {
@@ -2684,7 +2691,7 @@ fn suggest_trait_fn_ty_for_impl_fn_infer(
             trait_ref.def_id,
         )?;
 
-        let fn_sig = tcx.fn_sig(assoc.def_id).subst(
+        let fn_sig = tcx.bound_fn_sig(assoc.def_id).subst(
             tcx,
             trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
         );
index 1c7e7c935c4a1c4ee378394a29ab4dbf8239681a..9aff854c8030591125c44406a76868a7e0771619 100644 (file)
@@ -82,13 +82,8 @@ pub fn check_match(
                     hir::Guard::If(e) => {
                         self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
                     }
-                    hir::Guard::IfLet(pat, e) => {
-                        let scrutinee_ty = self.demand_scrutinee_type(
-                            e,
-                            pat.contains_explicit_ref_binding(),
-                            false,
-                        );
-                        self.check_pat_top(&pat, scrutinee_ty, None, true);
+                    hir::Guard::IfLet(l) => {
+                        self.check_expr_let(l);
                     }
                 };
             }
index 90b59df472cadf0f32d8fa2893c28b2174e7b915..0a84d41b4f31caa0cf99b50ecd5fb750761dd27a 100644 (file)
@@ -339,7 +339,7 @@ fn confirm_builtin_call(
     ) -> Ty<'tcx> {
         let (fn_sig, def_id) = match *callee_ty.kind() {
             ty::FnDef(def_id, subst) => {
-                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
+                let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, subst);
 
                 // Unit testing: function items annotated with
                 // `#[rustc_evaluate_where_clauses]` trigger special output
index 4627b58c9bcd3854c40799be62d62b33c90fb2c9..3e76738cc5d9e65367125e0d3e92ec4162fb0675 100644 (file)
@@ -171,7 +171,7 @@ pub(super) fn check_fn<'a, 'tcx>(
         let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
         let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
 
-        Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
+        Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
     } else {
         None
     };
@@ -655,7 +655,7 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
-    let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+    let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let defining_use_anchor = match *origin {
@@ -1056,9 +1056,7 @@ fn check_impl_items_against_trait<'tcx>(
         if let Some(missing_items) = must_implement_one_of {
             let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
             let attr_span = tcx
-                .get_attrs(impl_trait_ref.def_id)
-                .iter()
-                .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+                .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
                 .map(|attr| attr.span);
 
             missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
@@ -1158,20 +1156,20 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
 pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
     let repr = def.repr();
     if repr.packed() {
-        for attr in tcx.get_attrs(def.did()).iter() {
-            for r in attr::find_repr_attrs(&tcx.sess, attr) {
+        for attr in tcx.get_attrs(def.did(), sym::repr) {
+            for r in attr::parse_repr_attr(&tcx.sess, attr) {
                 if let attr::ReprPacked(pack) = r
-                    && let Some(repr_pack) = repr.pack
-                    && pack as u64 != repr_pack.bytes()
-                {
-                            struct_span_err!(
-                                tcx.sess,
-                                sp,
-                                E0634,
-                                "type has conflicting packed representation hints"
-                            )
-                            .emit();
-                }
+                && let Some(repr_pack) = repr.pack
+                && pack as u64 != repr_pack.bytes()
+            {
+                        struct_span_err!(
+                            tcx.sess,
+                            sp,
+                            E0634,
+                            "type has conflicting packed representation hints"
+                        )
+                        .emit();
+            }
             }
         }
         if repr.align.is_some() {
@@ -1321,8 +1319,7 @@ fn check_enum<'tcx>(
     def.destructor(tcx); // force the destructor to be evaluated
 
     if vs.is_empty() {
-        let attributes = tcx.get_attrs(def_id.to_def_id());
-        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
+        if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) {
             struct_span_err!(
                 tcx.sess,
                 attr.span,
index 50e55bdc4af30c5ac9e9823f27509c051248e409..c8fe046873603ec260af644723ce7a29595a0143 100644 (file)
@@ -175,19 +175,25 @@ fn deduce_expectations_from_expected_type(
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
         match *expected_ty.kind() {
             ty::Opaque(def_id, substs) => {
-                let bounds = self.tcx.explicit_item_bounds(def_id);
-                let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
-                    ty::PredicateKind::Projection(proj_predicate) => self
-                        .deduce_sig_from_projection(
-                            Some(*span),
-                            pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
-                        ),
-                    _ => None,
-                });
+                let bounds = self.tcx.bound_explicit_item_bounds(def_id);
+                let sig = bounds
+                    .transpose_iter()
+                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+                    .find_map(|(pred, span)| match pred.0.kind().skip_binder() {
+                        ty::PredicateKind::Projection(proj_predicate) => self
+                            .deduce_sig_from_projection(
+                                Some(span.0),
+                                pred.0.kind().rebind(
+                                    pred.map_bound(|_| proj_predicate).subst(self.tcx, substs),
+                                ),
+                            ),
+                        _ => None,
+                    });
 
                 let kind = bounds
-                    .iter()
-                    .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+                    .transpose_iter()
+                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+                    .filter_map(|(pred, _)| match pred.0.kind().skip_binder() {
                         ty::PredicateKind::Trait(tp) => {
                             self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
                         }
@@ -668,7 +674,7 @@ fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty
             ),
         };
 
-        let item_bounds = self.tcx.explicit_item_bounds(def_id);
+        let item_bounds = self.tcx.bound_explicit_item_bounds(def_id);
 
         // Search for a pending obligation like
         //
@@ -676,17 +682,21 @@ fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty
         //
         // where R is the return type we are expecting. This type `T`
         // will be our output.
-        let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
-            let bound_predicate = predicate.subst(self.tcx, substs).kind();
-            if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
-                self.deduce_future_output_from_projection(
-                    span,
-                    bound_predicate.rebind(proj_predicate),
-                )
-            } else {
-                None
-            }
-        });
+        let output_ty = item_bounds
+            .transpose_iter()
+            .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+            .find_map(|(predicate, span)| {
+                let bound_predicate = predicate.subst(self.tcx, substs).kind();
+                if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
+                {
+                    self.deduce_future_output_from_projection(
+                        span.0,
+                        bound_predicate.rebind(proj_predicate),
+                    )
+                } else {
+                    None
+                }
+            });
 
         debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
         output_ty
index c563d57ed96bbc7c988c3c579b177b0c1bb81aed..71957a2d1b07649cdaa8f7e406993da1dd59cfdf 100644 (file)
@@ -58,7 +58,8 @@
 use rustc_span::symbol::sym;
 use rustc_span::{self, BytePos, DesugaringKind, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use smallvec::{smallvec, SmallVec};
@@ -615,7 +616,7 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
         )];
 
         let mut has_unsized_tuple_coercion = false;
-        let mut has_trait_upcasting_coercion = false;
+        let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -635,7 +636,7 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
                             && data_a.principal_def_id() != data_b.principal_def_id()
                         {
                             debug!("coerce_unsized: found trait upcasting coercion");
-                            has_trait_upcasting_coercion = true;
+                            has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
                         }
                         if let ty::Tuple(..) = unsize_ty.kind() {
                             debug!("coerce_unsized: found unsized tuple coercion");
@@ -706,14 +707,19 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
             .emit();
         }
 
-        if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
-            feature_err(
+        if let Some((sub, sup)) = has_trait_upcasting_coercion
+            && !self.tcx().features().trait_upcasting
+        {
+            // Renders better when we erase regions, since they're not really the point here.
+            let (sub, sup) = self.tcx.erase_regions((sub, sup));
+            let mut err = feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::trait_upcasting,
                 self.cause.span,
-                "trait upcasting coercion is experimental",
-            )
-            .emit();
+                &format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+            );
+            err.note(&format!("required when coercing `{source}` into `{target}`"));
+            err.emit();
         }
 
         Ok(coercion)
@@ -775,17 +781,19 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
         match b.kind() {
             ty::FnPtr(b_sig) => {
                 let a_sig = a.fn_sig(self.tcx);
-                // Intrinsics are not coercible to function pointers
-                if a_sig.abi() == Abi::RustIntrinsic || a_sig.abi() == Abi::PlatformIntrinsic {
-                    return Err(TypeError::IntrinsicCast);
-                }
+                if let ty::FnDef(def_id, _) = *a.kind() {
+                    // Intrinsics are not coercible to function pointers
+                    if self.tcx.is_intrinsic(def_id) {
+                        return Err(TypeError::IntrinsicCast);
+                    }
 
-                // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
-                if let ty::FnDef(def_id, _) = *a.kind()
-                    && b_sig.unsafety() == hir::Unsafety::Normal
-                    && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
-                {
-                    return Err(TypeError::TargetFeatureCast(def_id));
+                    // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
+
+                    if b_sig.unsafety() == hir::Unsafety::Normal
+                        && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                    {
+                        return Err(TypeError::TargetFeatureCast(def_id));
+                    }
                 }
 
                 let InferOk { value: a_sig, obligations: o1 } =
@@ -960,6 +968,26 @@ pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize>
             .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
     }
 
+    /// Given a type, this function will calculate and return the type given
+    /// for `<Ty as Deref>::Target` only if `Ty` also implements `DerefMut`.
+    ///
+    /// This function is for diagnostics only, since it does not register
+    /// trait or region sub-obligations. (presumably we could, but it's not
+    /// particularly important for diagnostics...)
+    pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
+            self.infcx
+                .type_implements_trait(
+                    self.infcx.tcx.lang_items().deref_mut_trait()?,
+                    expr_ty,
+                    ty::List::empty(),
+                    self.param_env,
+                )
+                .may_apply()
+                .then(|| deref_ty)
+        })
+    }
+
     /// Given some expressions, their known unified type and another expression,
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
index a83924d4636c59f4f57791c2eb4107591a0dccf4..b857679520b8935b935291e0bf0be9918c190f01 100644 (file)
@@ -265,9 +265,8 @@ fn compare_predicate_entailment<'tcx>(
         let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
-        // First liberate late bound regions and subst placeholders
-        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
-        let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
+        let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+        let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
         let trait_sig =
             inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
         // Add the resulting inputs and output as well-formed.
@@ -1066,7 +1065,7 @@ fn compare_generic_param_kinds<'tcx>(
 
         // Compute placeholder form of impl and trait const tys.
         let impl_ty = tcx.type_of(impl_c.def_id);
-        let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
+        let trait_ty = tcx.bound_type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
         let mut cause = ObligationCause::new(
             impl_c_span,
             impl_c_hir_id,
@@ -1452,14 +1451,15 @@ pub fn check_type_bounds<'tcx>(
         };
 
         let obligations = tcx
-            .explicit_item_bounds(trait_ty.def_id)
-            .iter()
-            .map(|&(bound, span)| {
+            .bound_explicit_item_bounds(trait_ty.def_id)
+            .transpose_iter()
+            .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+            .map(|(bound, span)| {
                 debug!(?bound);
                 let concrete_ty_bound = bound.subst(tcx, rebased_substs);
                 debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
 
-                traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+                traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
             })
             .collect();
         debug!("check_type_bounds: item_bounds={:?}", obligations);
index bfd2c32fd7e3c9bbae62bca713eed7cdd6e867a2..ede2180a8e9e73cf811ae198f9934e32e6280c4a 100644 (file)
@@ -407,8 +407,6 @@ pub fn get_conversion_methods(
             self.has_only_self_parameter(m)
                 && self
                     .tcx
-                    .get_attrs(m.def_id)
-                    .iter()
                     // This special internal attribute is used to permit
                     // "identity-like" conversion methods to be suggested here.
                     //
@@ -419,7 +417,7 @@ pub fn get_conversion_methods(
                     //
                     // FIXME? Other potential candidate methods: `as_ref` and
                     // `as_mut`?
-                    .any(|a| a.has_name(sym::rustc_conversion_suggestion))
+                    .has_attr(m.def_id, sym::rustc_conversion_suggestion)
         });
 
         methods
@@ -698,28 +696,13 @@ pub fn check_ref(
                         };
 
                         if let Some(hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Assign(left_expr, ..),
+                            kind: hir::ExprKind::Assign(..),
                             ..
                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                         {
                             if mutability == hir::Mutability::Mut {
-                                // Found the following case:
-                                // fn foo(opt: &mut Option<String>){ opt = None }
-                                //                                   ---   ^^^^
-                                //                                   |     |
-                                //    consider dereferencing here: `*opt`  |
-                                // expected mutable reference, found enum `Option`
-                                if sm.span_to_snippet(left_expr.span).is_ok() {
-                                    return Some((
-                                        left_expr.span.shrink_to_lo(),
-                                        "consider dereferencing here to assign to the mutable \
-                                         borrowed piece of memory"
-                                            .to_string(),
-                                        "*".to_string(),
-                                        Applicability::MachineApplicable,
-                                        true,
-                                    ));
-                                }
+                                // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+                                return None;
                             }
                         }
 
index 3bc92166543d4a2ece577248c035d740abc0bc1e..9caa4a40df71f838fd2b035f177b8edbf8d1ceae 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Predicate, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::query::dropck_outlives::AtExt;
@@ -84,7 +84,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
         let drop_impl_span = tcx.def_span(drop_impl_did);
         let fresh_impl_substs =
             infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did.to_def_id());
-        let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
+        let fresh_impl_self_ty = EarlyBinder(drop_impl_ty).subst(tcx, fresh_impl_substs);
 
         let cause = &ObligationCause::misc(drop_impl_span, drop_impl_hir_id);
         match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
index f3a5b9f13dd1bac3c123a487f1b366e178bfa2bf..151df84ca316969d5f138a3c9659b77d0d108fcf 100644 (file)
@@ -51,6 +51,7 @@
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -836,6 +837,7 @@ pub(crate) fn check_lhs_assignable(
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
+        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -858,6 +860,8 @@ pub(crate) fn check_lhs_assignable(
             );
         });
 
+        adjust_err(&mut err);
+
         err.emit();
     }
 
@@ -1050,10 +1054,47 @@ fn check_expr_assign(
             return self.tcx.ty_error();
         }
 
-        self.check_lhs_assignable(lhs, "E0070", span);
-
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
-        let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
+
+        let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+                                   rhs_ty: Ty<'tcx>| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                // Can only assign if the type is sized, so if `DerefMut` yields a type that is
+                // unsized, do not suggest dereferencing it.
+                let lhs_deref_ty_is_sized = self
+                    .infcx
+                    .type_implements_trait(
+                        self.tcx.lang_items().sized_trait().unwrap(),
+                        lhs_deref_ty,
+                        ty::List::empty(),
+                        self.param_env,
+                    )
+                    .may_apply();
+                if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
+                    err.span_suggestion_verbose(
+                        lhs.span.shrink_to_lo(),
+                        "consider dereferencing here to assign to the mutably borrowed value",
+                        "*".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        };
+
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            let rhs_ty = self.check_expr(&rhs);
+            suggest_deref_binop(err, rhs_ty);
+        });
+
+        // This is (basically) inlined `check_expr_coercable_to_type`, but we want
+        // to suggest an additional fixup here in `suggest_deref_binop`.
+        let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
+        if let (_, Some(mut diag)) =
+            self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No)
+        {
+            suggest_deref_binop(&mut diag, rhs_ty);
+            diag.emit();
+        }
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
@@ -1064,7 +1105,7 @@ fn check_expr_assign(
         }
     }
 
-    fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
+    pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
         // for let statements, this is done in check_stmt
         let init = let_expr.init;
         self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
@@ -2600,10 +2641,10 @@ fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
                         self.check_expr_asm_operand(out_expr, false);
                     }
                 }
-                hir::InlineAsmOperand::Const { anon_const }
-                | hir::InlineAsmOperand::SymFn { anon_const } => {
-                    self.to_const(anon_const);
-                }
+                // `AnonConst`s have their own body and is type-checked separately.
+                // As they don't flow into the type system we don't need them to
+                // be well-formed.
+                hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
                 hir::InlineAsmOperand::SymStatic { .. } => {}
             }
         }
index d824c1d7cf252a6b2da48ff43a9165876817b89d..501ce31557ddab1a2ff30364fd5dc3389484b1ab 100644 (file)
@@ -23,8 +23,8 @@
     self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
 };
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
-    Ty, UserType,
+    self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
+    ToPredicate, Ty, UserType,
 };
 use rustc_session::lint;
 use rustc_span::hygiene::DesugaringKind;
@@ -347,7 +347,7 @@ fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value:
         T: TypeFoldable<'tcx>,
     {
         debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs);
-        let value = value.subst(self.tcx, substs);
+        let value = EarlyBinder(value).subst(self.tcx, substs);
         let result = self.normalize_associated_types_in(span, value);
         debug!("instantiate_type_scheme = {:?}", result);
         result
@@ -838,9 +838,9 @@ pub(in super::super) fn resolve_lang_item_path(
         let def_kind = self.tcx.def_kind(def_id);
 
         let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id))
+            self.tcx.bound_type_of(self.tcx.parent(def_id))
         } else {
-            self.tcx.type_of(def_id)
+            self.tcx.bound_type_of(def_id)
         };
         let substs = self.infcx.fresh_substs_for_item(span, def_id);
         let ty = item_ty.subst(self.tcx, substs);
@@ -1044,8 +1044,8 @@ pub(in super::super) fn note_need_for_fn_pointer(
     ) {
         let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
             (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2);
                 if sig1 != sig2 {
                     return;
                 }
@@ -1056,7 +1056,7 @@ pub(in super::super) fn note_need_for_fn_pointer(
                 (sig1, *did1, substs1)
             }
             (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                let sig1 = self.tcx.bound_fn_sig(*did).subst(self.tcx, substs);
                 if sig1 != *sig2 {
                     return;
                 }
@@ -1401,7 +1401,7 @@ fn inferred_kind(
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.
-                            let default = tcx.type_of(param.def_id);
+                            let default = tcx.bound_type_of(param.def_id);
                             self.fcx
                                 .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
                                 .into()
@@ -1415,7 +1415,9 @@ fn inferred_kind(
                     }
                     GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
+                            EarlyBinder(tcx.const_param_default(param.def_id))
+                                .subst(tcx, substs.unwrap())
+                                .into()
                         } else {
                             self.fcx.var_for_def(self.span, param)
                         }
index 847c2c32dba293f6487091932015837559d34954..54003654db010260560eaf7535ba958579333e79 100644 (file)
@@ -12,7 +12,6 @@
 use crate::structured_errors::StructuredDiagnostic;
 
 use rustc_ast as ast;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -1596,24 +1595,21 @@ fn point_at_arg_instead_of_call_if_possible(
             // Peel derived obligation, because it's the type that originally
             // started this inference chain that matters, not the one we wound
             // up with at the end.
-            fn unpeel_to_top(
-                mut code: Lrc<ObligationCauseCode<'_>>,
-            ) -> Lrc<ObligationCauseCode<'_>> {
-                let mut result_code = code.clone();
+            fn unpeel_to_top<'a, 'tcx>(
+                mut code: &'a ObligationCauseCode<'tcx>,
+            ) -> &'a ObligationCauseCode<'tcx> {
+                let mut result_code = code;
                 loop {
-                    let parent = match &*code {
-                        ObligationCauseCode::ImplDerivedObligation(c) => {
-                            c.derived.parent_code.clone()
-                        }
+                    let parent = match code {
+                        ObligationCauseCode::ImplDerivedObligation(c) => &c.derived.parent_code,
                         ObligationCauseCode::BuiltinDerivedObligation(c)
-                        | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
-                        _ => break,
+                        | ObligationCauseCode::DerivedObligation(c) => &c.parent_code,
+                        _ => break result_code,
                     };
-                    result_code = std::mem::replace(&mut code, parent);
+                    (result_code, code) = (code, parent);
                 }
-                result_code
             }
-            let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) {
+            let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) {
                 ObligationCauseCode::BuiltinDerivedObligation(code) |
                 ObligationCauseCode::DerivedObligation(code) => {
                     code.parent_trait_pred.self_ty().skip_binder().into()
@@ -1663,13 +1659,13 @@ fn unpeel_to_top(
                 // We make sure that only *one* argument matches the obligation failure
                 // and we assign the obligation's span to its expression's.
                 error.obligation.cause.span = args[ref_in].span;
-                let parent_code = error.obligation.cause.clone_code();
-                *error.obligation.cause.make_mut_code() =
+                error.obligation.cause.map_code(|parent_code| {
                     ObligationCauseCode::FunctionArgumentObligation {
                         arg_hir_id: args[ref_in].hir_id,
                         call_hir_id: expr.hir_id,
                         parent_code,
-                    };
+                    }
+                });
             } else if error.obligation.cause.span == call_sp {
                 // Make function calls point at the callee, not the whole thing.
                 if let hir::ExprKind::Call(callee, _) = expr.kind {
index 15edc11a4974d53e26a4c42b9e8a3f90868f70ec..92a2584a6de4d3deef9f645b165b763974578c58 100644 (file)
@@ -298,9 +298,8 @@ fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
                 Guard::If(ref e) => {
                     self.visit_expr(e);
                 }
-                Guard::IfLet(ref pat, ref e) => {
-                    self.visit_pat(pat);
-                    self.visit_expr(e);
+                Guard::IfLet(ref l) => {
+                    self.visit_let_expr(l);
                 }
             }
 
@@ -609,44 +608,43 @@ fn check_must_not_suspend_def(
     hir_id: HirId,
     data: SuspendCheckData<'_, '_>,
 ) -> bool {
-    for attr in tcx.get_attrs(def_id).iter() {
-        if attr.has_name(sym::must_not_suspend) {
-            tcx.struct_span_lint_hir(
-                rustc_session::lint::builtin::MUST_NOT_SUSPEND,
-                hir_id,
-                data.source_span,
-                |lint| {
-                    let msg = format!(
-                        "{}`{}`{} held across a suspend point, but should not be",
-                        data.descr_pre,
-                        tcx.def_path_str(def_id),
-                        data.descr_post,
-                    );
-                    let mut err = lint.build(&msg);
+    if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
+        tcx.struct_span_lint_hir(
+            rustc_session::lint::builtin::MUST_NOT_SUSPEND,
+            hir_id,
+            data.source_span,
+            |lint| {
+                let msg = format!(
+                    "{}`{}`{} held across a suspend point, but should not be",
+                    data.descr_pre,
+                    tcx.def_path_str(def_id),
+                    data.descr_post,
+                );
+                let mut err = lint.build(&msg);
 
-                    // add span pointing to the offending yield/await
-                    err.span_label(data.yield_span, "the value is held across this suspend point");
+                // add span pointing to the offending yield/await
+                err.span_label(data.yield_span, "the value is held across this suspend point");
 
-                    // Add optional reason note
-                    if let Some(note) = attr.value_str() {
-                        // FIXME(guswynn): consider formatting this better
-                        err.span_note(data.source_span, note.as_str());
-                    }
+                // Add optional reason note
+                if let Some(note) = attr.value_str() {
+                    // FIXME(guswynn): consider formatting this better
+                    err.span_note(data.source_span, note.as_str());
+                }
 
-                    // Add some quick suggestions on what to do
-                    // FIXME: can `drop` work as a suggestion here as well?
-                    err.span_help(
-                        data.source_span,
-                        "consider using a block (`{ ... }`) \
-                        to shrink the value's scope, ending before the suspend point",
-                    );
+                // Add some quick suggestions on what to do
+                // FIXME: can `drop` work as a suggestion here as well?
+                err.span_help(
+                    data.source_span,
+                    "consider using a block (`{ ... }`) \
+                    to shrink the value's scope, ending before the suspend point",
+                );
 
-                    err.emit();
-                },
-            );
+                err.emit();
+            },
+        );
 
-            return true;
-        }
+        true
+    } else {
+        false
     }
-    false
 }
index df8db0da6448259d24591d2afa036d52c38f5026..417778cc57d80fba6384c76d52ae0d073ed24a40 100644 (file)
@@ -344,9 +344,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                         // B -> C and E -> F are added implicitly due to the traversal order.
                         match guard {
                             Some(Guard::If(expr)) => self.visit_expr(expr),
-                            Some(Guard::IfLet(pat, expr)) => {
-                                self.visit_pat(pat);
-                                self.visit_expr(expr);
+                            Some(Guard::IfLet(let_expr)) => {
+                                self.visit_let_expr(let_expr);
                             }
                             None => (),
                         }
index 928daba0a7b3937db6eebaee61d693a122571e9f..e89a8961996158f24c2eb9517ac1f52dd90c8239 100644 (file)
@@ -180,6 +180,15 @@ fn mutate(
         diag_expr_id: HirId,
     ) {
         debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}");
+
+        if assignee_place.place.base == PlaceBase::Rvalue
+            && assignee_place.place.projections.is_empty()
+        {
+            // Assigning to an Rvalue is illegal unless done through a dereference. We would have
+            // already gotten a type error, so we will just return here.
+            return;
+        }
+
         // If the type being assigned needs dropped, then the mutation counts as a borrow
         // since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
         if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
index b67185e52116d9a004acb90dd6b864948cf4c1b0..7fe710cf8f4f2e160abf807b6fe32d7ed34a1735 100644 (file)
@@ -129,7 +129,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ty::INNERMOST,
                 ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv },
             ));
-            let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]);
+            let va_list_ty = tcx.bound_type_of(did).subst(tcx, &[region.into()]);
             (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty)
         })
     };
index 1b619776b857c3f4e0208d776d322c0d7d02b8b4..7992460f5464eef6073ae7005dc3123d0d59304a 100644 (file)
@@ -460,7 +460,7 @@ fn instantiate_method_sig(
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
-        let sig = self.tcx.fn_sig(def_id);
+        let sig = self.tcx.bound_fn_sig(def_id);
 
         let sig = sig.subst(self.tcx, all_substs);
         debug!("type scheme substituted, sig={:?}", sig);
index 1dd5e45fdc174026066730f9671bb4246dc4f00a..cb359434fdb9a864ddeaaa92c2d5c37573241895 100644 (file)
@@ -460,7 +460,7 @@ fn construct_obligation_for_trait(
         // N.B., instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let fn_sig = tcx.fn_sig(def_id);
+        let fn_sig = tcx.bound_fn_sig(def_id);
         let fn_sig = fn_sig.subst(self.tcx, substs);
         let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
 
index c28ab9fa1ee40cfae6c0292a68fcf5661dd67bd2..0861d121a1f0e75cfad3fd2c386bb5b8d2a8dc9c 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{
@@ -711,7 +711,7 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) {
             }
 
             let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
-            let impl_ty = impl_ty.subst(self.tcx, impl_substs);
+            let impl_ty = EarlyBinder(impl_ty).subst(self.tcx, impl_substs);
 
             debug!("impl_ty: {:?}", impl_ty);
 
@@ -901,7 +901,7 @@ pub fn matches_return_type(
     ) -> bool {
         match method.kind {
             ty::AssocKind::Fn => {
-                let fty = self.tcx.fn_sig(method.def_id);
+                let fty = self.tcx.bound_fn_sig(method.def_id);
                 self.probe(|_| {
                     let substs = self.fresh_substs_for_item(self.span, method.def_id);
                     let fty = fty.subst(self.tcx, substs);
@@ -1771,7 +1771,7 @@ fn xform_self_ty(
 
     #[instrument(level = "debug", skip(self))]
     fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
-        let fn_sig = self.tcx.fn_sig(method);
+        let fn_sig = self.tcx.bound_fn_sig(method);
         debug!(?fn_sig);
 
         assert!(!substs.has_escaping_bound_vars());
index 1ae53a77adc566589bc4a489c78903e9a54549ef..c99d9d8f9230d2824b2f1e944076f53c5ffffd8c 100644 (file)
@@ -41,7 +41,23 @@ pub fn check_binop_assign(
                 return_ty
             };
 
-        self.check_lhs_assignable(lhs, "E0067", op.span);
+        self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                if self
+                    .lookup_op_method(
+                        lhs_deref_ty,
+                        Some(rhs_ty),
+                        Some(rhs),
+                        Op::Binary(op, IsAssign::Yes),
+                    )
+                    .is_ok()
+                {
+                    // Suppress this error, since we already emitted
+                    // a deref suggestion in check_overloaded_binop
+                    err.delay_as_bug();
+                }
+            }
+        });
 
         ty
     }
@@ -404,16 +420,16 @@ fn check_overloaded_binop(
                         (err, missing_trait, use_output)
                     }
                 };
-                if let Ref(_, rty, _) = lhs_ty.kind() {
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
-                        && self
-                            .lookup_op_method(
-                                *rty,
-                                Some(rhs_ty),
-                                Some(rhs_expr),
-                                Op::Binary(op, is_assign),
-                            )
-                            .is_ok()
+
+                let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
+                    if self
+                        .lookup_op_method(
+                            lhs_deref_ty,
+                            Some(rhs_ty),
+                            Some(rhs_expr),
+                            Op::Binary(op, is_assign),
+                        )
+                        .is_ok()
                     {
                         if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
                             let msg = &format!(
@@ -423,7 +439,7 @@ fn check_overloaded_binop(
                                     IsAssign::Yes => "=",
                                     IsAssign::No => "",
                                 },
-                                rty.peel_refs(),
+                                lhs_deref_ty.peel_refs(),
                                 lstring,
                             );
                             err.span_suggestion_verbose(
@@ -434,6 +450,18 @@ fn check_overloaded_binop(
                             );
                         }
                     }
+                };
+
+                // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
+                // `a += b` => `*a += b` if a is a mut ref.
+                if is_assign == IsAssign::Yes
+                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                        suggest_deref_binop(lhs_deref_ty);
+                } else if is_assign == IsAssign::No
+                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
+                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+                        suggest_deref_binop(*lhs_deref_ty);
+                    }
                 }
                 if let Some(missing_trait) = missing_trait {
                     let mut visitor = TypeParamVisitor(vec![]);
index 829485367e0a4ee9481a7fdca20fec61cb987f2c..50966868ec7d968a04c78325a00123192484ceef 100644 (file)
@@ -21,7 +21,8 @@
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+    self, AdtKind, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -1388,7 +1389,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = pred.subst(tcx, substs);
+            let substituted_pred = EarlyBinder(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_param_types_or_consts()
index 1310467aeb9683196021fccf5f44671fe3460c7b..00f0d1e6f02a9744bd014ce2ab7e243789138e41 100644 (file)
@@ -128,7 +128,8 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
                 tcx.struct_span_lint_hir(lint, id, span, |lint| {
                     // Removal suggestion span needs to include attributes (Issue #54400)
                     let span_with_attrs = tcx
-                        .get_attrs(extern_crate.def_id)
+                        .hir()
+                        .attrs(id)
                         .iter()
                         .map(|attr| attr.span)
                         .fold(span, |acc, attr_span| acc.to(attr_span));
@@ -166,13 +167,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
             continue;
         }
 
+        let id = tcx.hir().local_def_id_to_hir_id(def_id);
         // If the extern crate has any attributes, they may have funky
         // semantics we can't faithfully represent using `use` (most
         // notably `#[macro_use]`). Ignore it.
-        if !tcx.get_attrs(extern_crate.def_id).is_empty() {
+        if !tcx.hir().attrs(id).is_empty() {
             continue;
         }
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
         tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
             // Otherwise, we can convert it into a `use` of some kind.
             let base_replacement = match extern_crate.orig_name {
index 2e0e026631b5191bd3d5514e32f509d437ccdef9..7f43f96c9a2b14583bb495441bd8eec7412209cb 100644 (file)
 // Main entry point
 
 fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
-    );
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -1200,9 +1197,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         ty::trait_def::TraitSpecializationKind::None
     };
     let must_implement_one_of = tcx
-        .get_attrs(def_id)
-        .iter()
-        .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+        .get_attr(def_id, sym::rustc_must_implement_one_of)
         // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
         // and that they are all identifiers
         .and_then(|attr| match attr.meta_item_list() {
@@ -1561,6 +1556,18 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
                         Some(tcx.typeck_root_def_id(def_id))
                     }
+                    // Exclude `GlobalAsm` here which cannot have generics.
+                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+                        if asm.operands.iter().any(|(op, _op_sp)| match op {
+                            hir::InlineAsmOperand::Const { anon_const }
+                            | hir::InlineAsmOperand::SymFn { anon_const } => {
+                                anon_const.hir_id == hir_id
+                            }
+                            _ => false,
+                        }) =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
                     _ => None,
                 }
             }
index 81d4c9135ef243695b6b515a277805ec46579919..cd3813ca4f5b536db118ef918e15c26ab2ed47cc 100644 (file)
@@ -1,7 +1,10 @@
 //! Errors emitted by typeck.
-use rustc_errors::Applicability;
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
+};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_middle::ty::Ty;
+use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -247,8 +250,83 @@ pub struct ExplicitGenericArgsWithImplTrait {
     #[primary_span]
     #[label]
     pub spans: Vec<Span>,
+    #[help]
+    pub is_nightly_build: Option<()>,
 }
 
-#[derive(SessionSubdiagnostic)]
-#[help(slug = "typeck-explicit-generic-args-with-impl-trait-feature")]
-pub struct ExplicitGenericArgsWithImplTraitFeature;
+pub struct MissingTypeParams {
+    pub span: Span,
+    pub def_span: Span,
+    pub missing_type_params: Vec<String>,
+    pub empty_generic_args: bool,
+}
+
+// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`.
+impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
+    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        static SLUG: &'static str = "typeck-missing-type-params";
+        let mut err = sess.span_diagnostic.struct_span_err_with_code(
+            self.span,
+            DiagnosticMessage::fluent(SLUG),
+            error_code!(E0393),
+        );
+        err.set_arg("parameterCount", self.missing_type_params.len());
+        err.set_arg(
+            "parameters",
+            self.missing_type_params
+                .iter()
+                .map(|n| format!("`{}`", n))
+                .collect::<Vec<_>>()
+                .join(", "),
+        );
+
+        err.span_label(self.def_span, DiagnosticMessage::fluent_attr(SLUG, "label"));
+
+        let mut suggested = false;
+        if let (Ok(snippet), true) = (
+            sess.source_map().span_to_snippet(self.span),
+            // Don't suggest setting the type params if there are some already: the order is
+            // tricky to get right and the user will already know what the syntax is.
+            self.empty_generic_args,
+        ) {
+            if snippet.ends_with('>') {
+                // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
+                // we would have to preserve the right order. For now, as clearly the user is
+                // aware of the syntax, we do nothing.
+            } else {
+                // The user wrote `Iterator`, so we don't have a type we can suggest, but at
+                // least we can clue them to the correct syntax `Iterator<Type>`.
+                err.span_suggestion(
+                    self.span,
+                    DiagnosticMessage::fluent_attr(SLUG, "suggestion"),
+                    format!("{}<{}>", snippet, self.missing_type_params.join(", ")),
+                    Applicability::HasPlaceholders,
+                );
+                suggested = true;
+            }
+        }
+        if !suggested {
+            err.span_label(self.span, DiagnosticMessage::fluent_attr(SLUG, "no-suggestion-label"));
+        }
+
+        err.note(DiagnosticMessage::fluent_attr(SLUG, "note"));
+        err
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0183", slug = "typeck-manual-implementation")]
+#[help]
+pub struct ManualImplementation {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub trait_name: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "typeck-substs-on-overridden-impl")]
+pub struct SubstsOnOverriddenImpl {
+    #[primary_span]
+    pub span: Span,
+}
index e69ba99dcef4266b8ced208ef4f1806b83115111..6de6b6ee4798de8fe4ecb170b30eb9410eb21d4d 100644 (file)
@@ -625,8 +625,8 @@ fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
 
         if let Some(hir::Guard::If(e)) = arm.guard {
             self.consume_expr(e)
-        } else if let Some(hir::Guard::IfLet(_, ref e)) = arm.guard {
-            self.consume_expr(e)
+        } else if let Some(hir::Guard::IfLet(ref l)) = arm.guard {
+            self.consume_expr(l.init)
         }
 
         self.consume_expr(arm.body);
index 22db15f4d4e8e77ceb058aaa75fed098fa1aac9f..bb97d00be32ccf41af60926b0944753c4e5b7284 100644 (file)
@@ -66,6 +66,7 @@
 //! on traits with methods can.
 
 use crate::constrained_generic_params as cgp;
+use crate::errors::SubstsOnOverriddenImpl;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -165,7 +166,7 @@ fn get_impl_substs<'tcx>(
     let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
     infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
-        tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit();
+        tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
         return None;
     };
     Some((impl1_substs, impl2_substs))
index fe285820ba6df50ad091b32c1f5d7b8106b2929f..67c6e791bfe584bd4902f98e6926b5065bfaf6aa 100644 (file)
@@ -298,17 +298,12 @@ fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         error = true;
     }
 
-    for attr in tcx.get_attrs(main_def_id) {
-        if attr.has_name(sym::track_caller) {
-            tcx.sess
-                .struct_span_err(
-                    attr.span,
-                    "`main` function is not allowed to be `#[track_caller]`",
-                )
-                .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
-                .emit();
-            error = true;
-        }
+    for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
+        tcx.sess
+            .struct_span_err(attr.span, "`main` function is not allowed to be `#[track_caller]`")
+            .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
+            .emit();
+        error = true;
     }
 
     if error {
index 13d22b13ed4f199748b4e6719dc3b0f37d87a77f..52f9e386441a434e5595e2f49e9af0206487f821 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
 use rustc_span::Span;
 
 use super::explicit::ExplicitPredicatesMap;
@@ -137,7 +137,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                         // `unsubstituted_predicate` is `U: 'b` in the
                         // example above.  So apply the substitution to
                         // get `T: 'a` (or `predicate`):
-                        let predicate = unsubstituted_predicate.subst(tcx, substs);
+                        let predicate = EarlyBinder(*unsubstituted_predicate).subst(tcx, substs);
                         insert_outlives_predicate(
                             tcx,
                             predicate.0,
@@ -287,7 +287,7 @@ pub fn check_explicit_predicates<'tcx>(
             continue;
         }
 
-        let predicate = outlives_predicate.subst(tcx, substs);
+        let predicate = EarlyBinder(*outlives_predicate).subst(tcx, substs);
         debug!("predicate = {:?}", &predicate);
         insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
     }
index 39f8f1d5a0ec758812568ad6e4d9c4c974147dff..6162b5c6d4c9308fa379f9ab9567e57f22ba02a5 100644 (file)
@@ -387,7 +387,7 @@ fn rt_error(layout: Layout) -> ! {
 #[cfg(all(not(no_global_oom_handling), test))]
 pub use std::alloc::handle_alloc_error;
 
-#[cfg(all(not(no_global_oom_handling), not(any(target_os = "hermit", test))))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
index 9dbac3c36ffb2871ce5e93f30dc3aef1fa94b9c3..4be5f6cf9ca514773cf8857dce2058e43c46b5fd 100644 (file)
@@ -118,7 +118,6 @@ impl<T, A: Allocator> RawVec<T, A> {
 
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn new_in(alloc: A) -> Self {
         // `cap: 0` means "unallocated". zero-sized types are ignored.
         Self { ptr: Unique::dangling(), cap: 0, alloc }
index 8839a69d119afae4ad20a47be0504cb137043b89..887246c600144801dc4d7e7d48229e800cc7a5aa 100644 (file)
@@ -208,11 +208,9 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
     ///
     /// If this returns a non-null pointer, then ownership of the memory block
     /// referenced by `ptr` has been transferred to this allocator.
-    /// The memory may or may not have been deallocated,
-    /// and should be considered unusable (unless of course it was
-    /// transferred back to the caller again via the return value of
-    /// this method). The new memory block is allocated with `layout`, but
-    /// with the `size` updated to `new_size`. This new layout should be
+    /// The memory may or may not have been deallocated, and should be
+    /// considered unusable. The new memory block is allocated with `layout`,
+    /// but with the `size` updated to `new_size`. This new layout should be
     /// used when deallocating the new memory block with `dealloc`. The range
     /// `0..min(layout.size(), new_size)` of the new memory block is
     /// guaranteed to have the same values as the original block.
index a034562d13ab7ad968f5e535e8251d097a53ebdb..6cc6e359e65b6029bc413a070289a5ae30eaad2c 100644 (file)
@@ -161,8 +161,7 @@ fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
     ///
     /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
     /// transferred to this allocator. The memory may or may not have been freed, and should be
-    /// considered unusable unless it was transferred back to the caller again via the return value
-    /// of this method.
+    /// considered unusable.
     ///
     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
     /// this allocator, and the contents of the memory block are unaltered.
@@ -288,8 +287,7 @@ unsafe fn grow_zeroed(
     ///
     /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
     /// transferred to this allocator. The memory may or may not have been freed, and should be
-    /// considered unusable unless it was transferred back to the caller again via the return value
-    /// of this method.
+    /// considered unusable.
     ///
     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
     /// this allocator, and the contents of the memory block are unaltered.
index 5cecc4086d8f3ac6e538fbcfff0e5add75059614..f4885ed9ffbb67c676e8550574702483666664cd 100644 (file)
@@ -266,7 +266,7 @@ fn fold<Acc, Fold>(mut self, init: Acc, mut fold: Fold) -> Acc
         Fold: FnMut(Acc, Self::Item) -> Acc,
     {
         let data = &mut self.data;
-        self.alive.by_ref().fold(init, |acc, idx| {
+        iter::ByRefSized(&mut self.alive).fold(init, |acc, idx| {
             // SAFETY: idx is obtained by folding over the `alive` range, which implies the
             // value is currently considered alive but as the range is being consumed each value
             // we read here will only be read once and then considered dead.
@@ -323,6 +323,20 @@ fn next_back(&mut self) -> Option<Self::Item> {
         })
     }
 
+    #[inline]
+    fn rfold<Acc, Fold>(mut self, init: Acc, mut rfold: Fold) -> Acc
+    where
+        Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let data = &mut self.data;
+        iter::ByRefSized(&mut self.alive).rfold(init, |acc, idx| {
+            // SAFETY: idx is obtained by folding over the `alive` range, which implies the
+            // value is currently considered alive but as the range is being consumed each value
+            // we read here will only be read once and then considered dead.
+            rfold(acc, unsafe { data.get_unchecked(idx).assume_init_read() })
+        })
+    }
+
     fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
         let len = self.len();
 
index 58ea109c735b67afbde616c0d21cb46ce1890ca0..7ae1bfd4f351a1331d8fd14ddadaa2cefcd12ec9 100644 (file)
@@ -5,27 +5,78 @@
 
 use crate::intrinsics;
 
-/// Informs the compiler that this point in the code is not reachable, enabling
-/// further optimizations.
+/// Informs the compiler that the site which is calling this function is not
+/// reachable, possibly enabling further optimizations.
 ///
 /// # Safety
 ///
-/// Reaching this function is completely *undefined behavior* (UB). In
-/// particular, the compiler assumes that all UB must never happen, and
-/// therefore will eliminate all branches that reach to a call to
-/// `unreachable_unchecked()`.
+/// Reaching this function is *Undefined Behavior*.
 ///
-/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
-/// `unreachable_unchecked()` call is actually reachable among all possible
-/// control flow, the compiler will apply the wrong optimization strategy, and
-/// may sometimes even corrupt seemingly unrelated code, causing
-/// difficult-to-debug problems.
+/// As the compiler assumes that all forms of Undefined Behavior can never
+/// happen, it will eliminate all branches in the surrounding code that it can
+/// determine will invariably lead to a call to `unreachable_unchecked()`.
 ///
-/// Use this function only when you can prove that the code will never call it.
-/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
-/// optimizations but will panic when executed.
+/// If the assumptions embedded in using this function turn out to be wrong -
+/// that is, if the site which is calling `unreachable_unchecked()` is actually
+/// reachable at runtime - the compiler may have generated nonsensical machine
+/// instructions for this situation, including in seemingly unrelated code,
+/// causing difficult-to-debug problems.
 ///
-/// # Example
+/// Use this function sparingly. Consider using the [`unreachable!`] macro,
+/// which may prevent some optimizations but will safely panic in case it is
+/// actually reached at runtime. Benchmark your code to find out if using
+/// `unreachable_unchecked()` comes with a performance benefit.
+///
+/// # Examples
+///
+/// `unreachable_unchecked()` can be used in situations where the compiler
+/// can't prove invariants that were previously established. Such situations
+/// have a higher chance of occuring if those invariants are upheld by
+/// external code that the compiler can't analyze.
+/// ```
+/// fn prepare_inputs(divisors: &mut Vec<u32>) {
+///     // Note to future-self when making changes: The invariant established
+///     // here is NOT checked in `do_computation()`; if this changes, you HAVE
+///     // to change `do_computation()`.
+///     divisors.retain(|divisor| *divisor != 0)
+/// }
+///
+/// /// # Safety
+/// /// All elements of `divisor` must be non-zero.
+/// unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 {
+///     divisors.iter().fold(i, |acc, divisor| {
+///         // Convince the compiler that a division by zero can't happen here
+///         // and a check is not needed below.
+///         if *divisor == 0 {
+///             // Safety: `divisor` can't be zero because of `prepare_inputs`,
+///             // but the compiler does not know about this. We *promise*
+///             // that we always call `prepare_inputs`.
+///             std::hint::unreachable_unchecked()
+///         }
+///         // The compiler would normally introduce a check here that prevents
+///         // a division by zero. However, if `divisor` was zero, the branch
+///         // above would reach what we explicitly marked as unreachable.
+///         // The compiler concludes that `divisor` can't be zero at this point
+///         // and removes the - now proven useless - check.
+///         acc / divisor
+///     })
+/// }
+///
+/// let mut divisors = vec![2, 0, 4];
+/// prepare_inputs(&mut divisors);
+/// let result = unsafe {
+///     // Safety: prepare_inputs() guarantees that divisors is non-zero
+///     do_computation(100, &divisors)
+/// };
+/// assert_eq!(result, 12);
+///
+/// ```
+///
+/// While using `unreachable_unchecked()` is perfectly sound in the following
+/// example, the compiler is able to prove that a division by zero is not
+/// possible. Benchmarking reveals that `unreachable_unchecked()` provides
+/// no benefit over using [`unreachable!`], while the latter does not introduce
+/// the possibility of Undefined Behavior.
 ///
 /// ```
 /// fn div_1(a: u32, b: u32) -> u32 {
index 0b5e2a89ef3dedfe43fd6f6b95e638ba14ecb3cd..bf2e3e182e2a3234c3417cadb477be7d862e92a8 100644 (file)
@@ -9,22 +9,27 @@
 impl<I: Iterator> Iterator for ByRefSized<'_, I> {
     type Item = I::Item;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.0.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.0.size_hint()
     }
 
+    #[inline]
     fn advance_by(&mut self, n: usize) -> Result<(), usize> {
         self.0.advance_by(n)
     }
 
+    #[inline]
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
         self.0.nth(n)
     }
 
+    #[inline]
     fn fold<B, F>(self, init: B, f: F) -> B
     where
         F: FnMut(B, Self::Item) -> B,
@@ -32,6 +37,7 @@ fn fold<B, F>(self, init: B, f: F) -> B
         self.0.fold(init, f)
     }
 
+    #[inline]
     fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
     where
         F: FnMut(B, Self::Item) -> R,
@@ -40,3 +46,37 @@ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
         self.0.try_fold(init, f)
     }
 }
+
+impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
+    #[inline]
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.0.next_back()
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        self.0.advance_back_by(n)
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.0.nth_back(n)
+    }
+
+    #[inline]
+    fn rfold<B, F>(self, init: B, f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.0.rfold(init, f)
+    }
+
+    #[inline]
+    fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        self.0.try_rfold(init, f)
+    }
+}
index 247123737df423e445f399efd80584cce70960ba..17957d7e770484ea63d745441a60430e1a4d564d 100644 (file)
@@ -36,7 +36,7 @@ fn first_isdigit(&self) -> bool {
     }
 
     /// Check if self starts with u with a case-insensitive comparison.
-    fn eq_ignore_case(&self, u: &[u8]) -> bool {
+    fn starts_with_ignore_case(&self, u: &[u8]) -> bool {
         debug_assert!(self.as_ref().len() >= u.len());
         let iter = self.as_ref().iter().zip(u.iter());
         let d = iter.fold(0, |i, (&x, &y)| i | (x ^ y));
index fa677bf5123959820054064cf58abb580dcfd3f1..1a90e0d206fd7f4e041fb97e63eb7d8c2739f3ec 100644 (file)
@@ -207,12 +207,12 @@ pub fn parse_number(s: &[u8], negative: bool) -> Option<Number> {
 /// Parse a partial representation of a special, non-finite float.
 fn parse_partial_inf_nan<F: RawFloat>(s: &[u8]) -> Option<(F, usize)> {
     fn parse_inf_rest(s: &[u8]) -> usize {
-        if s.len() >= 8 && s[3..].as_ref().eq_ignore_case(b"inity") { 8 } else { 3 }
+        if s.len() >= 8 && s[3..].as_ref().starts_with_ignore_case(b"inity") { 8 } else { 3 }
     }
     if s.len() >= 3 {
-        if s.eq_ignore_case(b"nan") {
+        if s.starts_with_ignore_case(b"nan") {
             return Some((F::NAN, 3));
-        } else if s.eq_ignore_case(b"inf") {
+        } else if s.starts_with_ignore_case(b"inf") {
             return Some((F::INFINITY, parse_inf_rest(s)));
         }
     }
index a98b5d787f10ac3372b9540b9af136dd9bd6d2db..70969edd6eaf7019ad371f50336ef1a0a0a1a38d 100644 (file)
@@ -52,7 +52,6 @@ impl $Ty {
                 #[$const_new_unchecked_stability]
                 #[must_use]
                 #[inline]
-                #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] // required by assert_unsafe_precondition
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
                     // SAFETY: this is guaranteed to be safe by the caller.
                     unsafe {
index f339b076dd7d083a961a64dae88b806774ff7cc4..d0746698f40131940c281155cfafd0daa7de16f1 100644 (file)
@@ -1486,7 +1486,6 @@ pub const fn get_or_insert_default(&mut self) -> &mut T
     where
         T: ~const Default,
     {
-        #[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
         const fn default<T: ~const Default>() -> T {
             T::default()
         }
index 27af227a1f27f0804b305945dacd1abd7b56924d..413fe7e6cc40f7303f48673b1f083ae0b7c3a1d5 100644 (file)
@@ -147,7 +147,6 @@ impl RawWakerVTable {
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
     #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
-    #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
index a778779c0fd88e6b910bba1af853dde9b69928c9..ee7ff012ec1c12e4ab64aeb3f76f3a34f72dc470 100644 (file)
@@ -668,3 +668,35 @@ fn array_mixed_equality_nans() {
     assert!(!(mut3 == array3));
     assert!(mut3 != array3);
 }
+
+#[test]
+fn array_into_iter_fold() {
+    // Strings to help MIRI catch if we double-free or something
+    let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()];
+    let mut s = "s".to_string();
+    a.into_iter().for_each(|b| s += &b);
+    assert_eq!(s, "sAaBbCc");
+
+    let a = [1, 2, 3, 4, 5, 6];
+    let mut it = a.into_iter();
+    it.advance_by(1).unwrap();
+    it.advance_back_by(2).unwrap();
+    let s = it.fold(10, |a, b| 10 * a + b);
+    assert_eq!(s, 10234);
+}
+
+#[test]
+fn array_into_iter_rfold() {
+    // Strings to help MIRI catch if we double-free or something
+    let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()];
+    let mut s = "s".to_string();
+    a.into_iter().rev().for_each(|b| s += &b);
+    assert_eq!(s, "sCcBbAa");
+
+    let a = [1, 2, 3, 4, 5, 6];
+    let mut it = a.into_iter();
+    it.advance_by(1).unwrap();
+    it.advance_back_by(2).unwrap();
+    let s = it.rfold(10, |a, b| 10 * a + b);
+    assert_eq!(s, 10432);
+}
index cf51d8da16db5afd3136797712fcb56230b751d9..cdb2bac2607572c8ffce7f7d1e5d254b9eb89b84 100644 (file)
@@ -416,7 +416,6 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
 }
 
 impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
         extern "C" fn run(
             bridge: Bridge<'_>,
@@ -429,7 +428,6 @@ extern "C" fn run(
 }
 
 impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn expand2(
         f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
     ) -> Self {
@@ -474,7 +472,6 @@ pub fn name(&self) -> &'static str {
         }
     }
 
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn custom_derive(
         trait_name: &'static str,
         attributes: &'static [&'static str],
@@ -483,7 +480,6 @@ pub const fn custom_derive(
         ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
     }
 
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn attr(
         name: &'static str,
         expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
@@ -491,7 +487,6 @@ pub const fn attr(
         ProcMacro::Attr { name, client: Client::expand2(expand) }
     }
 
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn bang(
         name: &'static str,
         expand: fn(crate::TokenStream) -> crate::TokenStream,
index e1307856175b1406c06e11f91b7cac39b4ea8711..2cde1f65adf9c484ab0aee45fe6c978fda30cbb9 100644 (file)
@@ -35,7 +35,6 @@ fn deref_mut(&mut self) -> &mut Self::Target {
 pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>);
 
 impl<T: LambdaL> ScopedCell<T> {
-    #[rustc_allow_const_fn_unstable(const_fn)]
     pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self {
         ScopedCell(Cell::new(value))
     }
index bfc5ce0156415cf7c7f4ecd5efa88b248995e82b..53433823fbd3bce4ca837cf328432682e7b2f9d9 100644 (file)
@@ -32,6 +32,7 @@
 // 32-bit c_int. Below is -2, in two's complement, but that only works out
 // because c_int is 32 bits.
 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct BorrowedFd<'fd> {
     fd: RawFd,
@@ -52,6 +53,7 @@ pub struct BorrowedFd<'fd> {
 // 32-bit c_int. Below is -2, in two's complement, but that only works out
 // because c_int is 32 bits.
 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct OwnedFd {
     fd: RawFd,
index 26ef93e3d7110a1f5d9020fd95ef69597b175534..b39863644f1161e85ecb91045b8c0a10aee97c1e 100644 (file)
@@ -32,3 +32,22 @@ fn test_fd() {
     assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd);
     assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd);
 }
+
+#[cfg(any(unix, target_os = "wasi"))]
+#[test]
+fn test_niche_optimizations() {
+    use crate::mem::size_of;
+    #[cfg(unix)]
+    use crate::os::unix::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+    #[cfg(target_os = "wasi")]
+    use crate::os::wasi::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+
+    assert_eq!(size_of::<Option<OwnedFd>>(), size_of::<RawFd>());
+    assert_eq!(size_of::<Option<BorrowedFd<'static>>>(), size_of::<RawFd>());
+    unsafe {
+        assert_eq!(OwnedFd::from_raw_fd(RawFd::MIN).into_raw_fd(), RawFd::MIN);
+        assert_eq!(OwnedFd::from_raw_fd(RawFd::MAX).into_raw_fd(), RawFd::MAX);
+        assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MIN)).unwrap().into_raw_fd(), RawFd::MIN);
+        assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MAX)).unwrap().into_raw_fd(), RawFd::MAX);
+    }
+}
index 290b7f0d08a72c430f9a1d84a6799918ef95974f..0ecac6b447570503f17951036dc032077824f97d 100644 (file)
 /// so it can be used in FFI in places where a handle is passed as an argument,
 /// it is not captured or consumed.
 ///
-/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
-/// sometimes a valid handle value. See [here] for the full story.
+/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
 ///
 /// And, it *may* have the value `NULL` (0), which can occur when consoles are
 /// detached from processes, or when `windows_subsystem` is used.
@@ -33,6 +35,7 @@
 /// handle, which is then borrowed under the same lifetime.
 ///
 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
 #[derive(Copy, Clone)]
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
@@ -45,8 +48,10 @@ pub struct BorrowedHandle<'handle> {
 ///
 /// This closes the handle on drop.
 ///
-/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
-/// sometimes a valid handle value. See [here] for the full story.
+/// Note that it *may* have the value `-1`, which in `OwnedHandle` always
+/// represents a valid handle value, such as [the current process handle], and
+/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See
+/// [here] for the full story.
 ///
 /// And, it *may* have the value `NULL` (0), which can occur when consoles are
 /// detached from processes, or when `windows_subsystem` is used.
@@ -59,6 +64,7 @@ pub struct BorrowedHandle<'handle> {
 /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
 ///
 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct OwnedHandle {
@@ -75,11 +81,13 @@ pub struct OwnedHandle {
 /// `NULL`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `NULL` first.
 ///
-/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
-/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
-/// as special.
+/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when
+/// it holds `-1`, that value is interpreted as a valid handle value, such as
+/// [the current process handle], and not `INVALID_HANDLE_VALUE`.
 ///
-/// If this holds a valid handle, it will close the handle on drop.
+/// If this holds a non-null handle, it will close the handle on drop.
+///
+/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 #[derive(Debug)]
@@ -95,11 +103,10 @@ pub struct OwnedHandle {
 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `INVALID_HANDLE_VALUE` first.
 ///
-/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
-/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
-/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
+/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds
+/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`.
 ///
-/// If this holds a valid handle, it will close the handle on drop.
+/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop.
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 #[derive(Debug)]
@@ -199,6 +206,7 @@ pub(crate) fn duplicate(
     }
 
     /// Allow child processes to inherit the handle.
+    #[cfg(not(target_vendor = "uwp"))]
     pub(crate) fn set_inheritable(&self) -> io::Result<()> {
         cvt(unsafe {
             c::SetHandleInformation(
index 2f6f0769548091ac6f74e1ee771e1bee3047cbfd..3325688e661ef7e25c12695b327becdddbee3009 100644 (file)
@@ -54,3 +54,6 @@
 pub use raw::*;
 #[unstable(feature = "io_safety", issue = "87074")]
 pub use socket::*;
+
+#[cfg(test)]
+mod tests;
index 68fa8918a56a08a4fc3ad0aef8fcedfb03387ad1..49e4f304f5dba6363992bc248d7eb2ca274ca096 100644 (file)
@@ -32,8 +32,15 @@ pub trait AsRawHandle {
     /// raw handle to the caller, and the handle is only guaranteed
     /// to be valid while the original object has not yet been destroyed.
     ///
+    /// This function may return null, such as when called on [`Stdin`],
+    /// [`Stdout`], or [`Stderr`] when the console is detached.
+    ///
     /// However, borrowing is not strictly required. See [`AsHandle::as_handle`]
     /// for an API which strictly borrows a handle.
+    ///
+    /// [`Stdin`]: io::Stdin
+    /// [`Stdout`]: io::Stdout
+    /// [`Stderr`]: io::Stderr
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_raw_handle(&self) -> RawHandle;
 }
index c14a1d6192fa2b9a465a05f548248569438a40b3..e23e1cf8ceed6b8c0c055de94af998be00135cf5 100644 (file)
@@ -10,6 +10,7 @@
 use crate::mem::forget;
 use crate::sys;
 use crate::sys::c;
+#[cfg(not(target_vendor = "uwp"))]
 use crate::sys::cvt;
 
 /// A borrowed socket.
@@ -34,6 +35,7 @@
     target_pointer_width = "64",
     rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
 )]
+#[rustc_nonnull_optimization_guaranteed]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct BorrowedSocket<'socket> {
     socket: RawSocket,
@@ -56,6 +58,7 @@ pub struct BorrowedSocket<'socket> {
     target_pointer_width = "64",
     rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
 )]
+#[rustc_nonnull_optimization_guaranteed]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct OwnedSocket {
     socket: RawSocket,
diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs
new file mode 100644 (file)
index 0000000..41734e5
--- /dev/null
@@ -0,0 +1,21 @@
+#[test]
+fn test_niche_optimizations_socket() {
+    use crate::mem::size_of;
+    use crate::os::windows::io::{
+        BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
+    };
+
+    assert_eq!(size_of::<Option<OwnedSocket>>(), size_of::<RawSocket>());
+    assert_eq!(size_of::<Option<BorrowedSocket<'static>>>(), size_of::<RawSocket>(),);
+    unsafe {
+        #[cfg(target_pointer_width = "32")]
+        let (min, max) = (i32::MIN as u32, i32::MAX as u32);
+        #[cfg(target_pointer_width = "64")]
+        let (min, max) = (i64::MIN as u64, i64::MAX as u64);
+
+        assert_eq!(OwnedSocket::from_raw_socket(min).into_raw_socket(), min);
+        assert_eq!(OwnedSocket::from_raw_socket(max).into_raw_socket(), max);
+        assert_eq!(Some(OwnedSocket::from_raw_socket(min)).unwrap().into_raw_socket(), min);
+        assert_eq!(Some(OwnedSocket::from_raw_socket(max)).unwrap().into_raw_socket(), max);
+    }
+}
index 0d8ea29c2be759b1580f2b36f20560d5d2b6ecb7..351cf698810f1faeb162150d4f586e3651b880fd 100644 (file)
@@ -7,6 +7,7 @@
 use crate::sync::Arc;
 use core::hint::black_box;
 
+#[allow(unknown_lints, unused_macro_rules)]
 macro_rules! t (
     ($path:expr, iter: $iter:expr) => (
         {
index 771461a59089b6d7b3e91de1c1a5f31b66c26e26..e253f46406fb78c595f592610f60b8e35146b9a6 100644 (file)
@@ -1725,6 +1725,49 @@ impl ExitCode {
     /// return the same codes (but will also `eprintln!` the error).
     #[stable(feature = "process_exitcode", since = "1.61.0")]
     pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
+
+    /// Exit the current process with the given `ExitCode`.
+    ///
+    /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function
+    /// terminates the process immediately, so no destructors on the current stack or any other
+    /// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply
+    /// return this ExitCode from the `main` function, as demonstrated in the [type
+    /// documentation](#examples).
+    ///
+    /// # Differences from `process::exit()`
+    ///
+    /// `process::exit()` accepts any `i32` value as the exit code for the process; however, there
+    /// are platforms that only use a subset of that value (see [`process::exit` platform-specific
+    /// behavior][exit#platform-specific-behavior]). `ExitCode` exists because of this; only
+    /// `ExitCode`s that are supported by a majority of our platforms can be created, so those
+    /// problems don't exist (as much) with this method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(exitcode_exit_method)]
+    /// # use std::process::ExitCode;
+    /// # use std::fmt;
+    /// # enum UhOhError { GenericProblem, Specific, WithCode { exit_code: ExitCode, _x: () } }
+    /// # impl fmt::Display for UhOhError {
+    /// #     fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { unimplemented!() }
+    /// # }
+    /// // there's no way to gracefully recover from an UhOhError, so we just
+    /// // print a message and exit
+    /// fn handle_unrecoverable_error(err: UhOhError) -> ! {
+    ///     eprintln!("UH OH! {err}");
+    ///     let code = match err {
+    ///         UhOhError::GenericProblem => ExitCode::FAILURE,
+    ///         UhOhError::Specific => ExitCode::from(3),
+    ///         UhOhError::WithCode { exit_code, .. } => exit_code,
+    ///     };
+    ///     code.exit_process()
+    /// }
+    /// ```
+    #[unstable(feature = "exitcode_exit_method", issue = "97100")]
+    pub fn exit_process(self) -> ! {
+        exit(self.to_i32())
+    }
 }
 
 impl ExitCode {
@@ -1944,7 +1987,17 @@ pub fn wait_with_output(mut self) -> io::Result<Output> {
 /// process, no destructors on the current stack or any other thread's stack
 /// will be run. If a clean shutdown is needed it is recommended to only call
 /// this function at a known point where there are no more destructors left
-/// to run.
+/// to run; or, preferably, simply return a type implementing [`Termination`]
+/// (such as [`ExitCode`] or `Result`) from the `main` function and avoid this
+/// function altogether:
+///
+/// ```
+/// # use std::io::Error as MyError;
+/// fn main() -> Result<(), MyError> {
+///     // ...
+///     Ok(())
+/// }
+/// ```
 ///
 /// ## Platform-specific behavior
 ///
@@ -1952,39 +2005,14 @@ pub fn wait_with_output(mut self) -> io::Result<Output> {
 /// will be visible to a parent process inspecting the exit code. On most
 /// Unix-like platforms, only the eight least-significant bits are considered.
 ///
-/// # Examples
-///
-/// Due to this function’s behavior regarding destructors, a conventional way
-/// to use the function is to extract the actual computation to another
-/// function and compute the exit code from its return value:
-///
-/// ```
-/// fn run_app() -> Result<(), ()> {
-///     // Application logic here
-///     Ok(())
-/// }
-///
-/// fn main() {
-///     std::process::exit(match run_app() {
-///         Ok(_) => 0,
-///         Err(err) => {
-///             eprintln!("error: {err:?}");
-///             1
-///         }
-///     });
-/// }
-/// ```
-///
-/// Due to [platform-specific behavior], the exit code for this example will be
-/// `0` on Linux, but `256` on Windows:
+/// For example, the exit code for this example will be `0` on Linux, but `256`
+/// on Windows:
 ///
 /// ```no_run
 /// use std::process;
 ///
 /// process::exit(0x0100);
 /// ```
-///
-/// [platform-specific behavior]: #platform-specific-behavior
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn exit(code: i32) -> ! {
     crate::rt::cleanup();
index 8d5ad18997d07859a03e5d1778f878458cf72f52..8d05cb44b94794acb5309abbb467c7b55a0828c8 100644 (file)
@@ -25,7 +25,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     //
     // Overflows are rounded up to an infinite timeout (None).
     let timespec = timeout
-        .and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?))
+        .and_then(|d| Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d))
         .and_then(|t| t.to_timespec());
 
     loop {
@@ -136,15 +136,13 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 
 #[cfg(target_os = "openbsd")]
 pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    use super::time::Timespec;
     use crate::ptr::{null, null_mut};
-    let timespec = timeout.and_then(|d| {
-        Some(libc::timespec {
-            // Sleep forever if the timeout is longer than fits in a timespec.
-            tv_sec: d.as_secs().try_into().ok()?,
-            // This conversion never truncates, as subsec_nanos is always <1e9.
-            tv_nsec: d.subsec_nanos() as _,
-        })
-    });
+
+    // Overflows are rounded up to an infinite timeout (None).
+    let timespec = timeout
+        .and_then(|d| Timespec::zero().checked_add_duration(&d))
+        .and_then(|t| t.to_timespec());
 
     let r = unsafe {
         libc::futex(
index 333182bdad4de809d7313d430f8ebc4209952a95..f99c453a3a85b88cd3f3eb66582cc716962c382b 100644 (file)
@@ -51,7 +51,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 impl Timespec {
-    const fn zero() -> Timespec {
+    pub const fn zero() -> Timespec {
         Timespec { tv_sec: 0, tv_nsec: 0 }
     }
 
@@ -125,6 +125,7 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         Some(Timespec::new(secs, nsec as i64))
     }
 
+    #[allow(dead_code)]
     pub fn to_timespec(&self) -> Option<libc::timespec> {
         Some(libc::timespec {
             tv_sec: self.tv_sec.try_into().ok()?,
index 0692da1d795192d0e5358e7f2c5dc291293e7545..0bb6fee60c92eba5c22cd55910c7a6783da1b215 100644 (file)
@@ -788,6 +788,10 @@ pub struct BY_HANDLE_FILE_INFORMATION {
 
     #[link(name = "advapi32")]
     extern "system" {
+        // Forbidden when targeting UWP
+        #[link_name = "SystemFunction036"]
+        pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
+
         // Allowed but unused by UWP
         pub fn OpenProcessToken(
             ProcessHandle: HANDLE,
index 3b609825a79da94d435213f249ccc0332a3f3c38..c319cb28630f553ee956fe5f570e289edc98cf07 100644 (file)
@@ -221,6 +221,7 @@ pub fn duplicate(
         Ok(Self(self.0.duplicate(access, inherit, options)?))
     }
 
+    #[cfg(not(target_vendor = "uwp"))]
     pub(crate) fn set_inheritable(&self) -> io::Result<()> {
         self.0.set_inheritable()
     }
index 928bf2439c3e1e1ac6f99b90046dc0f31557a7d8..2c586f1abe4335977286efbcbd5363f9f425a6d3 100644 (file)
@@ -57,10 +57,21 @@ pub fn new_synchronous(
             } else {
                 let (ours, theirs) = if ours_readable { (read, write) } else { (write, read) };
                 let ours = Handle::from_raw_handle(ours);
+                #[cfg(not(target_vendor = "uwp"))]
                 let theirs = Handle::from_raw_handle(theirs);
+                #[cfg(target_vendor = "uwp")]
+                let mut theirs = Handle::from_raw_handle(theirs);
 
                 if their_handle_inheritable {
-                    theirs.set_inheritable()?;
+                    #[cfg(not(target_vendor = "uwp"))]
+                    {
+                        theirs.set_inheritable()?;
+                    }
+
+                    #[cfg(target_vendor = "uwp")]
+                    {
+                        theirs = theirs.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?;
+                    }
                 }
 
                 Ok(Pipes { ours: AnonPipe::Sync(ours), theirs: AnonPipe::Sync(theirs) })
index de73e9154b45e1aac371cb4683a003540b6fb7ae..22e024d8552ec25f85d0c0acc47ce19cc3cd71ed 100644 (file)
@@ -1,8 +1,60 @@
 use crate::io;
+use crate::lazy;
 use crate::mem;
 use crate::sys::c;
 
+/// The kinds of HashMap RNG that may be available
+#[derive(Clone, Copy, Debug, PartialEq)]
+enum HashMapRng {
+    Preferred,
+    Fallback,
+}
+
 pub fn hashmap_random_keys() -> (u64, u64) {
+    match get_hashmap_rng() {
+        HashMapRng::Preferred => {
+            preferred_rng().expect("couldn't generate random bytes with preferred RNG")
+        }
+        HashMapRng::Fallback => {
+            fallback_rng().expect("couldn't generate random bytes with fallback RNG")
+        }
+    }
+}
+
+/// Returns the HashMap RNG that should be used
+///
+/// Panics if they are both broken
+fn get_hashmap_rng() -> HashMapRng {
+    // Assume that if the preferred RNG is broken the first time we use it, it likely means
+    // that: the DLL has failed to load, there is no point to calling it over-and-over again,
+    // and we should cache the result
+    static VALUE: lazy::SyncOnceCell<HashMapRng> = lazy::SyncOnceCell::new();
+    *VALUE.get_or_init(choose_hashmap_rng)
+}
+
+/// Test whether we should use the preferred or fallback RNG
+///
+/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
+/// we choose that
+///
+/// Panics if both the preferred and the fallback RNG are both non-functional
+fn choose_hashmap_rng() -> HashMapRng {
+    let preferred_error = match preferred_rng() {
+        Ok(_) => return HashMapRng::Preferred,
+        Err(e) => e,
+    };
+
+    match fallback_rng() {
+        Ok(_) => return HashMapRng::Fallback,
+        Err(fallback_error) => panic!(
+            "preferred RNG broken: `{}`, fallback RNG broken: `{}`",
+            preferred_error, fallback_error
+        ),
+    }
+}
+
+/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
+fn preferred_rng() -> Result<(u64, u64), io::Error> {
     use crate::ptr;
 
     let mut v = (0, 0);
@@ -14,8 +66,22 @@ pub fn hashmap_random_keys() -> (u64, u64) {
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
     };
-    if ret != 0 {
-        panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
-    }
-    return v;
+
+    if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+}
+
+/// Generate random numbers using the fallback RNG function (RtlGenRandom)
+#[cfg(not(target_vendor = "uwp"))]
+fn fallback_rng() -> Result<(u64, u64), io::Error> {
+    let mut v = (0, 0);
+    let ret =
+        unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
+
+    if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+}
+
+/// We can't use RtlGenRandom with UWP, so there is no fallback
+#[cfg(target_vendor = "uwp")]
+fn fallback_rng() -> Result<(u64, u64), io::Error> {
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
 }
index 61d3f45ca6523bd003cd97a391cbe6072034daf1..f88e6a924b5f04ef9bb756b5192f722c018f551f 100644 (file)
@@ -36,7 +36,7 @@ fn main() {
         println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("dragonfly") {
         println!("cargo:rustc-link-lib=gcc_pic");
-    } else if target.contains("pc-windows-gnu") {
+    } else if target.ends_with("pc-windows-gnu") {
         // This is handled in the target spec with late_link_args_[static|dynamic]
     } else if target.contains("uwp-windows-gnu") {
         println!("cargo:rustc-link-lib=unwind");
index a01b56004c456953eccde85536d39e562cecf646..c92a7d310f309db0cc1a6fc0f08333434568346b 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(c_unwind)]
+#![feature(cfg_target_abi)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 
 cfg_if::cfg_if! {
@@ -85,3 +86,7 @@
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
 #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
 extern "C" {}
+
+#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))]
+#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
+extern "C" {}
index ab4338e1c85ef1bad52b1d165350e73edd795a36..d36344ece4ea3d113bca3e8eb64012fd3fed1977 100644 (file)
@@ -110,29 +110,42 @@ def download(path, url, probably_big, verbose, help_on_error=None):
 
 
 def _download(path, url, probably_big, verbose, exception, help_on_error=None):
+    # Try to use curl (potentially available on win32
+    #    https://devblogs.microsoft.com/commandline/tar-and-curl-come-to-windows/)
+    # If an error occurs:
+    #  - If we are on win32 fallback to powershell
+    #  - Otherwise raise the error if appropriate
     if probably_big or verbose:
         print("downloading {}".format(url))
-    # see https://serverfault.com/questions/301128/how-to-download
-    if sys.platform == 'win32':
-        run(["PowerShell.exe", "/nologo", "-Command",
-             "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
-             "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)],
-            verbose=verbose,
-            exception=exception)
-    else:
+
+    platform_is_win32 = sys.platform == 'win32'
+    try:
         if probably_big or verbose:
             option = "-#"
         else:
             option = "-s"
-        require(["curl", "--version"])
+        # If curl is not present on Win32, we shoud not sys.exit
+        #   but raise `CalledProcessError` or `OSError` instead
+        require(["curl", "--version"], exception=platform_is_win32)
         run(["curl", option,
              "-L", # Follow redirect.
              "-y", "30", "-Y", "10",    # timeout if speed is < 10 bytes/sec for > 30 seconds
              "--connect-timeout", "30",  # timeout if cannot connect within 30 seconds
              "--retry", "3", "-Sf", "-o", path, url],
             verbose=verbose,
-            exception=exception,
+            exception=True, # Will raise RuntimeError on failure
             help_on_error=help_on_error)
+    except (subprocess.CalledProcessError, OSError, RuntimeError):
+        # see http://serverfault.com/questions/301128/how-to-download
+        if platform_is_win32:
+            run(["PowerShell.exe", "/nologo", "-Command",
+                 "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+                 "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)],
+                verbose=verbose,
+                exception=exception)
+        # Check if the RuntimeError raised by run(curl) should be silenced
+        elif verbose or exception:
+            raise
 
 
 def verify(path, expected, verbose):
@@ -198,19 +211,23 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error=
             sys.exit(err)
 
 
-def require(cmd, exit=True):
+def require(cmd, exit=True, exception=False):
     '''Run a command, returning its output.
     On error,
-        If `exit` is `True`, exit the process.
-        Otherwise, return None.'''
+        If `exception` is `True`, raise the error
+        Otherwise If `exit` is `True`, exit the process
+        Else return None.'''
     try:
         return subprocess.check_output(cmd).strip()
     except (subprocess.CalledProcessError, OSError) as exc:
-        if not exit:
-            return None
-        print("error: unable to run `{}`: {}".format(' '.join(cmd), exc))
-        print("Please make sure it's installed and in the path.")
-        sys.exit(1)
+        if exception:
+            raise
+        elif exit:
+            print("error: unable to run `{}`: {}".format(' '.join(cmd), exc))
+            print("Please make sure it's installed and in the path.")
+            sys.exit(1)
+        return None
+
 
 
 def format_build_time(duration):
index 7d838c0a61d22f521012c1a787564949d1c6a715..894d74fb269a1bab7cc3f1244c9aa9b4504963d1 100644 (file)
@@ -1154,9 +1154,13 @@ pub fn cargo(
             // backtrace, core_simd, std_float, ...), those dependencies have their own features
             // but cargo isn't involved in the #[path] and so cannot pass the complete list of
             // features, so for that reason we don't enable checking of features for std.
-            if mode != Mode::Std {
-                cargo.arg("-Zcheck-cfg-features");
-            }
+            //
+            // FIXME: Re-enable this after the beta bump as apperently rustc-perf doesn't use the
+            // beta cargo. See https://github.com/rust-lang/rust/pull/96984#issuecomment-1126678773
+            // #[cfg(not(bootstrap))]
+            // if mode != Mode::Std {
+            //     cargo.arg("-Zcheck-cfg-features"); // -Zcheck-cfg=features after bump
+            // }
 
             // Enable cfg checking of well known names/values
             rustflags
index d3e91c75837a0dd8a9d6b665b7c08c77fde0ce71..4ab502e90526fad6549987df50b2bb7262f1df33 100644 (file)
@@ -507,6 +507,7 @@ fn test_with_no_doc_stage0() {
         config.stage = 0;
         config.cmd = Subcommand::Test {
             paths: vec!["library/std".into()],
+            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
@@ -577,6 +578,7 @@ fn test_docs() {
         let mut config = configure(&["A"], &["A"]);
         config.cmd = Subcommand::Test {
             paths: vec![],
+            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
index 53933e4cd7d200299444a550d6fc2e0d6951fda4..7a8c7fee5f5499e637488ca8eeda8d77949135f4 100644 (file)
@@ -175,6 +175,7 @@ fn copy_third_party_objects(
     }
 
     if target == "x86_64-fortanix-unknown-sgx"
+        || target.contains("pc-windows-gnullvm")
         || builder.config.llvm_libunwind == LlvmLibunwind::InTree
             && (target.contains("linux") || target.contains("fuchsia"))
     {
@@ -246,7 +247,7 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
-    } else if target.contains("windows-gnu") {
+    } else if target.ends_with("windows-gnu") {
         for obj in ["crt2.o", "dllcrt2.o"].iter() {
             let src = compiler_file(builder, builder.cc(target), target, CLang::C, obj);
             let target = libdir_self_contained.join(obj);
@@ -477,7 +478,7 @@ fn make_run(run: RunConfig<'_>) {
     fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
-        if !target.contains("windows-gnu") {
+        if !target.ends_with("windows-gnu") {
             return vec![];
         }
 
index d37a59426f895f69f7a37b9a84f1027b800823b7..16727f4398dff5c425fe9aaff6472beca5a0b0c2 100644 (file)
@@ -285,7 +285,7 @@ fn make_run(run: RunConfig<'_>) {
     /// without any extra installed software (e.g., we bundle gcc, libraries, etc).
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let host = self.host;
-        if !host.contains("pc-windows-gnu") {
+        if !host.ends_with("pc-windows-gnu") {
             return None;
         }
 
@@ -341,7 +341,7 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
         // anything requiring us to distribute a license, but it's likely the
         // install will *also* include the rust-mingw package, which also needs
         // licenses, so to be safe we just include it here in all MinGW packages.
-        if host.contains("pc-windows-gnu") {
+        if host.ends_with("pc-windows-gnu") {
             make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder);
             tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
         }
@@ -1352,7 +1352,7 @@ macro_rules! add_component {
         tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) }));
         tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std"));
 
-        if target.contains("windows-gnu") {
+        if target.ends_with("windows-gnu") {
             tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw"));
         }
 
@@ -1522,7 +1522,7 @@ fn filter(contents: &str, marker: &str) -> String {
                     prepare(tool);
                 }
             }
-            if target.contains("windows-gnu") {
+            if target.ends_with("windows-gnu") {
                 prepare("rust-mingw");
             }
 
@@ -1711,7 +1711,7 @@ fn filter(contents: &str, marker: &str) -> String {
                     .arg("-t")
                     .arg(etc.join("msi/remove-duplicates.xsl")),
             );
-            if target.contains("windows-gnu") {
+            if target.ends_with("windows-gnu") {
                 builder.run(
                     Command::new(&heat)
                         .current_dir(&exe)
@@ -1760,7 +1760,7 @@ fn filter(contents: &str, marker: &str) -> String {
                 if built_tools.contains("miri") {
                     cmd.arg("-dMiriDir=miri");
                 }
-                if target.contains("windows-gnu") {
+                if target.ends_with("windows-gnu") {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
                 builder.run(&mut cmd);
@@ -1787,7 +1787,7 @@ fn filter(contents: &str, marker: &str) -> String {
             }
             candle("AnalysisGroup.wxs".as_ref());
 
-            if target.contains("windows-gnu") {
+            if target.ends_with("windows-gnu") {
                 candle("GccGroup.wxs".as_ref());
             }
 
@@ -1829,7 +1829,7 @@ fn filter(contents: &str, marker: &str) -> String {
                 cmd.arg("MiriGroup.wixobj");
             }
 
-            if target.contains("windows-gnu") {
+            if target.ends_with("windows-gnu") {
                 cmd.arg("GccGroup.wixobj");
             }
             // ICE57 wrongly complains about the shortcuts
@@ -1859,7 +1859,9 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
         .env("CFG_BUILD", target.triple)
         .env("CFG_CHANNEL", &builder.config.channel);
 
-    if target.contains("windows-gnu") {
+    if target.contains("windows-gnullvm") {
+        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
+    } else if target.contains("windows-gnu") {
         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
     } else {
         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
@@ -2045,6 +2047,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
             "llvm-cov",
             "llvm-dwp",
             "llvm-nm",
+            "llvm-dwarfdump",
         ] {
             tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
         }
index 58571ea129c1940b68766ae64f5b78c9a78a19a7..4cd835ade6421128f0efe6d463c2f092bf65442b 100644 (file)
@@ -111,6 +111,7 @@ pub enum Subcommand {
         compare_mode: Option<String>,
         pass: Option<String>,
         run: Option<String>,
+        skip: Vec<String>,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -261,6 +262,7 @@ pub fn parse(args: &[String]) -> Flags {
         match subcommand {
             Kind::Test => {
                 opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
+                opts.optmulti("", "skip", "skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times", "SUBSTRING");
                 opts.optmulti(
                     "",
                     "test-args",
@@ -545,6 +547,7 @@ pub fn parse(args: &[String]) -> Flags {
                 compare_mode: matches.opt_str("compare-mode"),
                 pass: matches.opt_str("pass"),
                 run: matches.opt_str("run"),
+                skip: matches.opt_strs("skip"),
                 test_args: matches.opt_strs("test-args"),
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
@@ -689,12 +692,26 @@ pub fn kind(&self) -> Kind {
     }
 
     pub fn test_args(&self) -> Vec<&str> {
+        let mut args = vec![];
+
+        match *self {
+            Subcommand::Test { ref skip, .. } => {
+                for s in skip {
+                    args.push("--skip");
+                    args.push(s.as_str());
+                }
+            }
+            _ => (),
+        };
+
         match *self {
             Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
-                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
+                args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
             }
-            _ => Vec::new(),
+            _ => (),
         }
+
+        args
     }
 
     pub fn rustc_args(&self) -> Vec<&str> {
index 5d32b4f801a183fb22247e16f7bffcb99aab1d36..a4e35bf6d475b64919072f4bd42686250e9de746 100644 (file)
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
 use crate::util::{
-    exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, CiEnv,
+    check_run, exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed,
+    CiEnv,
 };
 
 mod builder;
@@ -961,6 +962,17 @@ fn try_run_quiet(&self, cmd: &mut Command) -> bool {
         try_run_suppressed(cmd)
     }
 
+    /// Runs a command, printing out nice contextual information if it fails.
+    /// Returns false if do not execute at all, otherwise returns its
+    /// `status.success()`.
+    fn check_run(&self, cmd: &mut Command) -> bool {
+        if self.config.dry_run {
+            return true;
+        }
+        self.verbose(&format!("running: {:?}", cmd));
+        check_run(cmd, self.is_verbose())
+    }
+
     pub fn is_verbose(&self) -> bool {
         self.verbosity > 0
     }
index 64e25f803b27f68141cda943297c4de7a7a67c49..09b8cbe9014d4bd6c99645200c9b0cab64c4820c 100644 (file)
@@ -156,7 +156,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
         let llvm_lib = llvm_root.join("lib");
         for entry in t!(fs::read_dir(&llvm_lib)) {
             let lib = t!(entry).path();
-            if lib.ends_with(".so") {
+            if lib.extension().map_or(false, |ext| ext == "so") {
                 fix_bin_or_dylib(builder, &lib);
             }
         }
@@ -284,7 +284,7 @@ fn fix_bin_or_dylib(builder: &Builder<'_>, fname: &Path) {
         entries
     };
     patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
-    if !fname.ends_with(".so") {
+    if !fname.extension().map_or(false, |ext| ext == "so") {
         // Finally, set the corret .interp for binaries
         let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
         // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
@@ -306,39 +306,40 @@ fn download_component(builder: &Builder<'_>, base: &str, url: &str, dest_path: &
 
 fn download_with_retries(builder: &Builder<'_>, tempfile: &str, url: &str) {
     println!("downloading {}", url);
-
-    // FIXME: check if curl is installed instead of skipping straight to powershell
-    if builder.build.build.contains("windows-msvc") {
-        for _ in 0..3 {
-            if builder.try_run(Command::new("PowerShell.exe").args(&[
-                "/nologo",
-                "-Command",
-                "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
-                &format!(
-                    "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
-                    url, tempfile
-                ),
-            ])) {
-                return;
+    // Try curl. If that fails and we are on windows, fallback to PowerShell.
+    if !builder.check_run(Command::new("curl").args(&[
+        "-#",
+        "-y",
+        "30",
+        "-Y",
+        "10", // timeout if speed is < 10 bytes/sec for > 30 seconds
+        "--connect-timeout",
+        "30", // timeout if cannot connect within 30 seconds
+        "--retry",
+        "3",
+        "-Sf",
+        "-o",
+        tempfile,
+        url,
+    ])) {
+        if builder.build.build.contains("windows-msvc") {
+            println!("Fallback to PowerShell");
+            for _ in 0..3 {
+                if builder.try_run(Command::new("PowerShell.exe").args(&[
+                    "/nologo",
+                    "-Command",
+                    "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
+                    &format!(
+                        "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
+                        url, tempfile
+                    ),
+                ])) {
+                    return;
+                }
+                println!("\nspurious failure, trying again");
             }
-            println!("\nspurious failure, trying again");
         }
-    } else {
-        builder.run(Command::new("curl").args(&[
-            "-#",
-            "-y",
-            "30",
-            "-Y",
-            "10", // timeout if speed is < 10 bytes/sec for > 30 seconds
-            "--connect-timeout",
-            "30", // timeout if cannot connect within 30 seconds
-            "--retry",
-            "3",
-            "-Sf",
-            "-o",
-            tempfile,
-            url,
-        ]));
+        std::process::exit(1);
     }
 }
 
@@ -1372,6 +1373,10 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
                 cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
                 cfg.define("NDEBUG", None);
             }
+            if self.target.contains("windows") {
+                cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
+                cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
+            }
         }
 
         cc_cfg.compiler(builder.cc(self.target));
index b78ca3712bd452116fefe36eedc2bbcf608c4ec5..710b3588b845bf9b874e6ca6003cead1252be4e9 100644 (file)
@@ -346,6 +346,24 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
     status.success()
 }
 
+pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
+    let status = match cmd.status() {
+        Ok(status) => status,
+        Err(e) => {
+            println!("failed to execute command: {:?}\nerror: {}", cmd, e);
+            return false;
+        }
+    };
+    if !status.success() && print_cmd_on_fail {
+        println!(
+            "\n\ncommand did not execute successfully: {:?}\n\
+             expected success, got: {}\n\n",
+            cmd, status
+        );
+    }
+    status.success()
+}
+
 pub fn run_suppressed(cmd: &mut Command) {
     if !try_run_suppressed(cmd) {
         std::process::exit(1);
index 9bd56394eafc6add71473ce3f2f914811d22a051..36c94458da7bd422c307f8008239bff6bfffc18d 100755 (executable)
@@ -2,16 +2,21 @@
 
 set -ex
 
-# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz
-curl https://ci-mirrors.rust-lang.org/rustc/2021-01-14-clang%2Bllvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | \
+# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz
+curl https://ci-mirrors.rust-lang.org/rustc/2022-05-10-clang%2Bllvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \
   tar xJf -
-export PATH=`pwd`/clang+llvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04/bin:$PATH
+bin="$PWD/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04/bin"
 
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard ad5133410f66b93a2381db5b542aad5e0964db96
-make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
+git reset --hard 9886d3d6200fcc3726329966860fc058707406cd
+make -j$(nproc) \
+    CC="$bin/clang" \
+    NM="$bin/llvm-nm" \
+    AR="$bin/llvm-ar" \
+    INSTALL_DIR=/wasm32-wasi \
+    install
 
 cd ..
 rm -rf wasi-libc
index 899f24fc754a14b89617093824d258aaa3aa2943..f76f9131742ee389211cdafc141553a15268098f 100644 (file)
@@ -1 +1 @@
-0.9.0
\ No newline at end of file
+0.9.2
\ No newline at end of file
index 691d1282cf499ceae3f17bc288c0d44a77c83c23..aedfe98bdea11108b56ba30addbb780a2c89c5d4 100755 (executable)
@@ -82,7 +82,11 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
 
 # Here we're profiling the `rustc` frontend, so we also include `Check`.
 # The benchmark set includes various stress tests that put the frontend under pressure.
-gather_profiles "Check,Debug,Opt" "All" \
+# The profile data is written into a single filepath that is being repeatedly merged when each
+# rustc invocation ends. Empirically, this can result in some profiling data being lost.
+# That's why we override the profile path to include the PID. This will produce many more profiling
+# files, but the resulting profile will produce a slightly faster rustc binary.
+LLVM_PROFILE_FILE=/tmp/rustc-pgo/default_%m_%p.profraw gather_profiles "Check,Debug,Opt" "All" \
   "externs,ctfe-stress-4,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress"
 
 # Merge the profile data we gathered
index 952d8ef48fe57d15cb61e613aa3cad12e802b88b..c2d44ac0e4dce55c99f0f88f754755e4dc34792b 100644 (file)
 - [Platform Support](platform-support.md)
     - [Template for target-specific documentation](platform-support/TEMPLATE.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
-    - [aarch64-unknown-none-hermitkernel](platform-support/aarch64-unknown-none-hermitkernel.md)
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
     - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
+    - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
+    - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
index 0d02fa7bd6b3e996422d3b6fa9ac652f302365af..d80e4f2086995725f9e6f03cd4efcda13d2c649d 100644 (file)
@@ -52,7 +52,8 @@ where `KIND` may be one of:
 If the kind is specified, then linking modifiers can be attached to it.
 Modifiers are specified as a comma-delimited string with each modifier prefixed with
 either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively.
-The last boolean value specified for a given modifier wins. \
+Specifying multiple `modifiers` arguments in a single `link` attribute,
+or multiple identical modifiers in the same `modifiers` argument is not currently supported. \
 Example: `-l static:+whole-archive=mylib`.
 
 The kind of library and the modifiers can also be specified in a [`#[link]`
index 12ac575210aa3df68522649f598ec1be30253273..ab98651a1ec3a204d107c0991b06ee1e6a5c92a7 100644 (file)
@@ -208,6 +208,7 @@ target | std | host | notes
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
+[`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
 `aarch64-unknown-uefi` | * |  | ARM64 UEFI
@@ -288,6 +289,7 @@ target | std | host | notes
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 `x86_64-apple-tvos` | * | | x86 64-bit tvOS
+[`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
 `x86_64-pc-windows-msvc` | * |  | 64-bit Windows XP support
 `x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md
new file mode 100644 (file)
index 0000000..1af1410
--- /dev/null
@@ -0,0 +1,58 @@
+# `nvptx64-nvidia-cuda`
+
+**Tier: 2**
+
+This is the target meant for deploying code for Nvidia® accelerators based on their CUDA
+platform.
+
+## Target maintainers
+
+- Riccardo D'Ambrosio, https://github.com/RDambrosio016
+- Kjetil Kjeka, https://github.com/kjetilkjeka
+
+<!-- FIXME: fill this out
+
+## Requirements
+
+Does the target support host tools, or only cross-compilation? Does the target
+support std, or alloc (either with a default allocator, or if the user supplies
+an allocator)?
+
+Document the expectations of binaries built for the target. Do they assume
+specific minimum features beyond the baseline of the CPU/environment/etc? What
+version of the OS or environment do they expect?
+
+Are there notable `#[target_feature(...)]` or `-C target-feature=` values that
+programs may wish to use?
+
+What calling convention does `extern "C"` use on the target?
+
+What format do binaries use by default? ELF, PE, something else?
+
+## Building the target
+
+If Rust doesn't build the target by default, how can users build it? Can users
+just add it to the `target` list in `config.toml`?
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Does the target support running binaries, or do binaries have varying
+expectations that prevent having a standard way to run them? If users can run
+binaries, can they do so in some common emulator, or do they need native
+hardware? Does the target support running the Rust testsuite?
+
+## Cross-compilation toolchains and C code
+
+Does the target support C code? If so, what toolchain target should users use
+to build compatible C code? (This may match the target triple, or it may be a
+toolchain for a different target triple, potentially with specific options or
+caveats.)
+
+-->
diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md
new file mode 100644 (file)
index 0000000..96ae065
--- /dev/null
@@ -0,0 +1,48 @@
+# \*-pc-windows-gnullvm
+
+**Tier: 3**
+
+Windows targets similar to `*-pc-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils.
+
+Target triples avaiable so far:
+- `aarch64-pc-windows-gnullvm`
+- `x86_64-pc-windows-gnullvm`
+
+## Target maintainers
+
+- [@mati865](https://github.com/mati865)
+
+## Requirements
+
+The easiest way to obtain these targets is cross-compilation but native build from `x86_64-pc-windows-gnu` is possible with few hacks which I don't recommend.
+Std support is expected to be on pair with `*-pc-windows-gnu`.
+
+Binaries for this target should be at least on pair with `*-pc-windows-gnu` in terms of requirements and functionality.
+
+Those targets follow Windows calling convention for `extern "C"`.
+
+Like with any other Windows target created binaries are in PE format.
+
+## Building the target
+
+For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors.
+Native bootstrapping builds require rather fragile hacks until host artifacts are avaiable so I won't describe them here.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Created binaries work fine on Windows or Wine using native hardware. Testing AArch64 on x86_64 is problematic though and requires spending some time with QEMU.
+Once these targets bootstrap themselves on native hardware they should pass Rust testsuite.
+
+## Cross-compilation toolchains and C code
+
+Compatible C code can be built with Clang's `aarch64-pc-windows-gnu` and `x86_64-pc-windows-gnu` targets as long as LLVM based C toolchains are used.
+Those include:
+- [llvm-mingw](https://github.com/mstorsjo/llvm-mingw)
+- [MSYS2 with CLANG* environment](https://www.msys2.org/docs/environments)
index 098bc1879b56f6c9a3f3f6006ba6d176e534681d..d666d54b31579ef04cca3382a428495578c67d6b 100644 (file)
@@ -59,15 +59,8 @@ or the current item whose documentation is being displayed.
 ## The Theme Picker and Search Interface
 
 When viewing `rustdoc`'s output in a browser with JavaScript enabled,
-a dynamic interface appears at the top of the page.
-To the left is the theme picker, denoted with a paint-brush icon,
-and the search interface, help screen, and options appear to the right of that.
-
-### The Theme Picker
-
-Clicking on the theme picker provides a list of themes -
-by default `ayu`, `light`, and `dark` -
-which are available for viewing.
+a dynamic interface appears at the top of the page composed of the search
+interface, help screen, and options.
 
 ### The Search Interface
 
@@ -91,12 +84,16 @@ When typing in the search bar, you can prefix your search term with a type
 followed by a colon (such as `mod:`) to restrict the results to just that
 kind of item. (The available items are listed in the help popup.)
 
+### Changing displayed theme
+
+You can change the displayed theme by opening the settings menu (the gear
+icon in the upper right) and then pick a new one from there.
+
 ### Shortcuts
 
 Pressing `S` while focused elsewhere on the page will move focus to the
 search bar, and pressing `?` shows the help screen,
 which includes all these shortcuts and more.
-Pressing `T` focuses the theme picker.
 
 When the search results are focused,
 the left and right arrows move between tabs and the up and down arrows move
index 35e6ccbc388078cdad1d41e45a18751119f3c6d9..e1e09aa4a8ada7111713b67ea6ed0999de559026 100644 (file)
@@ -109,8 +109,9 @@ rustdoc --extend-css custom.css src/lib.rs
 
 A good example of using this feature to create a dark theme is documented [on
 this blog].  Just remember, dark theme is already included in the rustdoc output
-by clicking on the paintbrush.  Adding additional options to the themes are
-as easy as creating a custom theme `.css` file and using the following syntax:
+by clicking on the gear icon in the upper right. Adding additional options to the
+themes are as easy as creating a custom theme `.css` file and using the following
+syntax:
 
 ```bash
 rustdoc --theme awesome.css src/lib.rs
index 3f60caffef5b703a73bdcfba17db3989e483edf1..e83c4d98cc7a4cad6edd2bfb4b4d5e442e03c391 100644 (file)
@@ -22,7 +22,10 @@ This feature allows for use of one of following sanitizers:
 
 To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
 `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
-`-Zsanitizer=memtag`, or `-Zsanitizer=thread`.
+`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example:
+```shell
+$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
+```
 
 # AddressSanitizer
 
index 21efd040663b8aa9e848aa6ff3456f1fa864fa89..0495cd97dc229f3adde1b0cfc5437e699eb1410e 100644 (file)
@@ -12,7 +12,6 @@ askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
 pulldown-cmark = { version = "0.9", default-features = false }
 minifier = "0.0.43"
-rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.6.1"
@@ -29,6 +28,9 @@ version = "0.3.3"
 default-features = false
 features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
 
+[target.'cfg(windows)'.dependencies]
+rayon = "1.5.1"
+
 [dev-dependencies]
 expect-test = "1.0"
 
index f0d87f7ce4cd582908f9a7211ea4b520f5fff928..805cc5c71d83a40c29d21424bcec1a05ff66eec9 100644 (file)
 impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
     crate fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
         let param_env = self.cx.tcx.param_env(item_def_id);
-        let ty = self.cx.tcx.type_of(item_def_id);
+        let ty = self.cx.tcx.bound_type_of(item_def_id);
 
         trace!("get_blanket_impls({:?})", ty);
         let mut impls = Vec::new();
         self.cx.with_all_traits(|cx, all_traits| {
             for &trait_def_id in all_traits {
                 if !cx.cache.access_levels.is_public(trait_def_id)
-                    || cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
+                    || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
                 {
                     continue;
                 }
@@ -34,12 +34,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                         trait_def_id,
                         impl_def_id
                     );
-                    let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
-                    let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
+                    let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+                    let is_param = matches!(trait_ref.0.self_ty().kind(), ty::Param(_));
                     let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
                         let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
                         let ty = ty.subst(infcx.tcx, substs);
-                        let param_env = param_env.subst(infcx.tcx, substs);
+                        let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
 
                         let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
                         let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
@@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                         continue;
                     }
 
-                    cx.generated_synthetics.insert((ty, trait_def_id));
+                    cx.generated_synthetics.insert((ty.0, trait_def_id));
 
                     impls.push(Item {
                         name: None,
@@ -115,15 +115,15 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             ),
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
-                            trait_: Some(trait_ref.clean(cx)),
-                            for_: ty.clean(cx),
+                            trait_: Some(trait_ref.0.clean(cx)),
+                            for_: ty.0.clean(cx),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
                                 .in_definition_order()
                                 .map(|x| x.clean(cx))
                                 .collect::<Vec<_>>(),
                             polarity: ty::ImplPolarity::Positive,
-                            kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
+                            kind: ImplKind::Blanket(box trait_ref.0.self_ty().clean(cx)),
                         }),
                         cfg: None,
                     });
index 261eb39bf723d3aaf22da9a1c3238fe3dab8dbdf..9a579cb5311642487251b5697021af5532b4dba3 100644 (file)
@@ -22,7 +22,7 @@
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
-type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
+type Attrs<'hir> = &'hir [ast::Attribute];
 
 /// Attempt to inline a definition into this AST.
 ///
 }
 
 crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
-    cx.tcx.get_attrs(did)
+    cx.tcx.get_attrs_unchecked(did)
 }
 
 /// Record an external fully qualified name in the external_paths cache.
@@ -691,7 +691,7 @@ fn separate_supertrait_bounds(
 
     let trait_ = clean::TraitWithExtraInfo {
         trait_,
-        is_notable: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::notable_trait),
+        is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait),
     };
     cx.external_traits.borrow_mut().insert(did, trait_);
     cx.active_extern_traits.remove(&did);
index 7cc96183d6da48cb4eb6bc41b946023b29a66133..6e18f381c59a441f6abf3304dcd38930e8e5e795 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, AdtKind, DefIdTree, Lift, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Lift, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1634,7 +1634,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                     .tcx
                     .explicit_item_bounds(def_id)
                     .iter()
-                    .map(|(bound, _)| bound.subst(cx.tcx, substs))
+                    .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
                     .collect::<Vec<_>>();
                 let mut regions = vec![];
                 let mut has_sized = false;
index 2b65b8f910c7069b74c23d24c4847a5240898dc8..456d860f12559d4832c5df65e9d0121bafa127d1 100644 (file)
@@ -211,8 +211,8 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
         // Failing that, see if there's an attribute specifying where to find this
         // external crate
         let did = self.crate_num.as_def_id();
-        tcx.get_attrs(did)
-            .lists(sym::doc)
+        tcx.get_attrs(did, sym::doc)
+            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
             .filter(|a| a.has_name(sym::html_root_url))
             .filter_map(|a| a.value_str())
             .map(to_remote)
@@ -226,11 +226,13 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
 
         let as_keyword = |res: Res<!>| {
             if let Res::Def(DefKind::Mod, def_id) = res {
-                let attrs = tcx.get_attrs(def_id);
                 let mut keyword = None;
-                for attr in attrs.lists(sym::doc) {
-                    if attr.has_name(sym::keyword) {
-                        if let Some(v) = attr.value_str() {
+                let meta_items = tcx
+                    .get_attrs(def_id, sym::doc)
+                    .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
+                for meta in meta_items {
+                    if meta.has_name(sym::keyword) {
+                        if let Some(v) = meta.value_str() {
                             keyword = Some(v);
                             break;
                         }
@@ -288,11 +290,13 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
         // rendering by delegating everything to a hash map.
         let as_primitive = |res: Res<!>| {
             if let Res::Def(DefKind::Mod, def_id) = res {
-                let attrs = tcx.get_attrs(def_id);
                 let mut prim = None;
-                for attr in attrs.lists(sym::doc) {
-                    if let Some(v) = attr.value_str() {
-                        if attr.has_name(sym::primitive) {
+                let meta_items = tcx
+                    .get_attrs(def_id, sym::doc)
+                    .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
+                for meta in meta_items {
+                    if let Some(v) = meta.value_str() {
+                        if meta.has_name(sym::primitive) {
                             prim = PrimitiveType::from_symbol(v);
                             if prim.is_some() {
                                 break;
@@ -413,7 +417,10 @@ impl Item {
     }
 
     crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
-        self.item_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
+        self.item_id
+            .as_def_id()
+            .map(|did| tcx.get_attrs_unchecked(did).inner_docs())
+            .unwrap_or(false)
     }
 
     crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -464,7 +471,7 @@ impl Item {
         kind: ItemKind,
         cx: &mut DocContext<'_>,
     ) -> Item {
-        let ast_attrs = cx.tcx.get_attrs(def_id);
+        let ast_attrs = cx.tcx.get_attrs_unchecked(def_id);
 
         Self::from_def_id_and_attrs_and_parts(
             def_id,
index 3a2f24d719c937b2221efd169472d7a0b53dccfd..c67b92df6431f72eb610b2529375e74729382cb8 100644 (file)
@@ -474,10 +474,9 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> S
 ///
 /// This function exists because it runs on `hir::Attributes` whereas the other is a
 /// `clean::Attributes` method.
-crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool {
-    attrs.iter().any(|attr| {
-        attr.has_name(sym::doc)
-            && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
+crate fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
+    tcx.get_attrs(did, sym::doc).any(|attr| {
+        attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
     })
 }
 
index d59273db08b4f9f50fe7155816a55340893f3ed2..8dd8eb23df2706fe5f60beffe8d6200d5e06f81c 100644 (file)
@@ -54,7 +54,8 @@ impl DocFS {
     where
         E: PathError,
     {
-        if !self.sync_only && cfg!(windows) {
+        #[cfg(windows)]
+        if !self.sync_only {
             // A possible future enhancement after more detailed profiling would
             // be to create the file sync so errors are reported eagerly.
             let sender = self.errors.clone().expect("can't write after closing");
@@ -68,6 +69,10 @@ impl DocFS {
         } else {
             fs::write(&path, contents).map_err(|e| E::new(e, path))?;
         }
+
+        #[cfg(not(windows))]
+        fs::write(&path, contents).map_err(|e| E::new(e, path))?;
+
         Ok(())
     }
 }
index 56a085c2982508b3f50c988d5188f787413e0708..5ba3bdc12eda6ffe8a826989f3e96be296d1197b 100644 (file)
@@ -1448,8 +1448,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     // used in tera template files).
     map.insert("mainThemeStyle".into(), 1);
     map.insert("themeStyle".into(), 1);
-    map.insert("theme-picker".into(), 1);
-    map.insert("theme-choices".into(), 1);
     map.insert("settings-menu".into(), 1);
     map.insert("help-button".into(), 1);
     map.insert("main-content".into(), 1);
index a30c533aa48c8f04bfd64e9155e6bc368c2dc1e7..528180288de6a5175eeb2af2b5c923846fb086a1 100644 (file)
@@ -596,9 +596,11 @@ fn after_krate(&mut self) -> Result<(), Error> {
             |buf: &mut Buffer| {
                 write!(
                     buf,
-                    "<script defer src=\"{}settings{}.js\"></script>",
-                    page.static_root_path.unwrap_or(""),
-                    page.resource_suffix
+                    "<link rel=\"stylesheet\" type=\"text/css\" \
+                        href=\"{root_path}settings{suffix}.css\">\
+                    <script defer src=\"{root_path}settings{suffix}.js\"></script>",
+                    root_path = page.static_root_path.unwrap_or(""),
+                    suffix = page.resource_suffix,
                 )
             },
             &self.shared.style_files,
index fbb3d3e45845ba5db751ee8bdbcce9750fb913ba..4951cd83af207a3635d1aa4c6c7a10d0bce8663b 100644 (file)
@@ -323,7 +323,7 @@ fn cmp(
 
             clean::ImportItem(ref import) => {
                 let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
-                    let ast_attrs = cx.tcx().get_attrs(import_def_id);
+                    let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
                     let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None));
 
                     // Just need an item with the correct def_id and attrs
index e8e5fa17993337ddbaf0b0684de78e8d34cad61f..ece659284d177ed3043fdb1728b37f1f5cd9f6ef 100644 (file)
@@ -238,7 +238,6 @@ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
         write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?;
         write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?;
     }
-    write_toolchain("brush.svg", static_files::BRUSH_SVG)?;
     write_toolchain("wheel.svg", static_files::WHEEL_SVG)?;
     write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?;
     write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
@@ -417,7 +416,7 @@ fn to_json_string(&self) -> String {
             ));
             all_sources.sort();
             Ok(format!(
-                "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
+                "var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
                 all_sources.join("\n")
             )
             .into_bytes())
@@ -439,7 +438,13 @@ fn to_json_string(&self) -> String {
     write_crate("search-index.js", &|| {
         let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
         v.push_str(&all_indexes.join(",\\\n"));
-        v.push_str("\\\n}');\nif (window.initSearch) {window.initSearch(searchIndex)};");
+        v.push_str(
+            r#"\
+}');
+if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)};
+if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
+"#,
+        );
         Ok(v.into_bytes())
     })?;
 
index 52577b228aa1399e59057e451cb0b599d26d6804..7634a15b9bd19ed6993f84e0c985424747fd42fa 100644 (file)
@@ -29,5 +29,10 @@ module.exports = {
         "no-var": ["error"],
         "prefer-const": ["error"],
         "prefer-arrow-callback": ["error"],
+        "brace-style": [
+            "error",
+            "1tbs",
+            { "allowSingleLine": false }
+        ],
     }
 };
index e35358c56499398581bb215cb3542f0244f7a033..0a19a99abf05407474c63fee7dad22e6b259486d 100644 (file)
@@ -18,7 +18,3 @@ rules.
        /* The search bar and related controls don't work without JS */
        display: none;
 }
-
-#theme-picker {
-       display: none;
-}
index 0f4d842f4336d98a2e5c02248b984ce54d3ed12e..4eb8029ee2db6e4dc3cb947e0d93a0aeaac6d6e8 100644 (file)
@@ -897,7 +897,7 @@ table,
        margin-left: 0.25em;
        padding-left: 0.3125em;
        padding-right: 23px;
-       border: 0;
+       border: 1px solid;
        border-radius: 4px;
        outline: none;
        cursor: pointer;
@@ -1379,31 +1379,30 @@ pre.rust {
        margin-bottom: 6px;
 }
 
-.theme-picker {
-       position: absolute;
-       left: -38px;
-       top: 4px;
-}
-
-.theme-picker button {
-       outline: none;
-}
-
 #settings-menu, #help-button {
        margin-left: 4px;
        outline: none;
 }
 
-#theme-picker, #copy-path {
+#copy-path {
        height: 34px;
 }
-#theme-picker, #settings-menu, #help-button, #copy-path {
+#settings-menu > a, #help-button, #copy-path {
        padding: 5px;
        width: 33px;
        border: 1px solid;
        border-radius: 2px;
        cursor: pointer;
 }
+#settings-menu {
+       padding: 0;
+}
+#settings-menu > a {
+       padding: 5px;
+       width: 100%;
+       height: 100%;
+       display: block;
+}
 
 @keyframes rotating {
        from {
@@ -1413,9 +1412,33 @@ pre.rust {
                transform: rotate(360deg);
        }
 }
-#settings-menu.rotate img {
+#settings-menu.rotate > a img {
        animation: rotating 2s linear infinite;
 }
+#settings-menu #settings {
+       position: absolute;
+       right: 0;
+       z-index: 1;
+       display: block;
+       margin-top: 7px;
+       border-radius: 3px;
+       border: 1px solid;
+}
+#settings-menu #settings .setting-line {
+       margin: 0.6em;
+}
+/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */
+#settings-menu #settings::before {
+       content: '';
+       position: absolute;
+       right: 11px;
+       border: solid;
+       border-width: 1px 1px 0 0;
+       display: inline-block;
+       padding: 4px;
+       transform: rotate(-45deg);
+       top: -5px;
+}
 
 #help-button {
        font-family: "Fira Sans", Arial, sans-serif;
@@ -1838,12 +1861,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                margin-left: 32px;
        }
 
-       /* Space is at a premium on mobile, so remove the theme-picker icon. */
-       #theme-picker {
-               display: none;
-               width: 0;
-       }
-
        .content {
                margin-left: 0px;
        }
@@ -1993,7 +2010,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 
        #crate-search {
                border-radius: 4px;
-               border: 0;
        }
 
        .docblock {
index 7b337c2bc7a3356b4ba78835ba8305b8aded84c3..07588748ad68ef814251ca5ba30d5b43198b4f94 100644 (file)
        position: absolute;
 }
 
-.select-wrapper {
-       float: right;
-       position: relative;
-       height: 27px;
-       min-width: 25%;
-}
-
-.select-wrapper select {
-       appearance: none;
-       -moz-appearance: none;
-       -webkit-appearance: none;
-       background: none;
-       border: 2px solid #ccc;
-       padding-right: 28px;
-       width: 100%;
-}
-
-.select-wrapper img {
-       pointer-events: none;
-       position: absolute;
-       right: 0;
-       bottom: 0;
-       background: #ccc;
-       height: 100%;
-       width: 28px;
-       padding: 0px 4px;
-}
-
-.select-wrapper select option {
-       color: initial;
-}
-
 .slider {
        position: absolute;
        cursor: pointer;
@@ -96,7 +64,6 @@
        right: 0;
        bottom: 0;
        background-color: #ccc;
-       -webkit-transition: .3s;
        transition: .3s;
 }
 
        left: 4px;
        bottom: 4px;
        background-color: white;
-       -webkit-transition: .3s;
        transition: .3s;
 }
 
@@ -121,8 +87,6 @@ input:focus + .slider {
 }
 
 input:checked + .slider:before {
-       -webkit-transform: translateX(19px);
-       -ms-transform: translateX(19px);
        transform: translateX(19px);
 }
 
index b1bf06c1865c7eacb21de75947fcfbfd77d8015a..d32bb4cf22d6e665823f6e565cb49d7e86438b6c 100644 (file)
@@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 
 /* General structure and fonts */
 
-body {
+body, #settings-menu #settings, #settings-menu #settings::before {
        background-color: #0f1419;
        color: #c5c5c5;
 }
@@ -236,8 +236,8 @@ details.undocumented > summary::before {
 
 #crate-search, .search-input {
        background-color: #141920;
-       border-color: #424c57;
-       color: #c5c5c5;
+       /* Without the `!important`, the border-color is ignored for `<select>`... */
+       border-color: #424c57 !important;
 }
 
 .search-input {
@@ -531,16 +531,20 @@ kbd {
        box-shadow: inset 0 -1px 0 #5c6773;
 }
 
-#theme-picker, #settings-menu, #help-button {
+#settings-menu > a, #help-button {
        border-color: #5c6773;
        background-color: #0f1419;
        color: #fff;
 }
 
-#theme-picker > img, #settings-menu > img {
+#settings-menu > a img {
        filter: invert(100);
 }
 
+#settings-menu #settings, #settings-menu #settings::before {
+       border-color: #5c6773;
+}
+
 #copy-path {
        color: #fff;
 }
@@ -551,8 +555,7 @@ kbd {
        filter: invert(100%);
 }
 
-#theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus,
+#settings-menu > a:hover, #settings-menu > a:focus,
 #help-button:hover, #help-button:focus {
        border-color: #e0e0e0;
 }
@@ -570,12 +573,6 @@ kbd {
        background-color: rgba(110, 110, 110, 0.33);
 }
 
-@media (max-width: 700px) {
-       #theme-picker {
-               background: #0f1419;
-       }
-}
-
 .search-results .result-name span.alias {
        color: #c5c5c5;
 }
index 236304ccc9f1be49f0809f9487c09edcdd50962b..4957f25bcf358a3e46bb85215104c9c4d1f80227 100644 (file)
@@ -1,4 +1,4 @@
-body {
+body, #settings-menu #settings, #settings-menu #settings::before {
        background-color: #353535;
        color: #ddd;
 }
@@ -217,7 +217,8 @@ details.undocumented > summary::before {
 #crate-search, .search-input {
        color: #111;
        background-color: #f0f0f0;
-       border-color: #000;
+       /* Without the `!important`, the border-color is ignored for `<select>`... */
+       border-color: #f0f0f0 !important;
 }
 
 .search-input {
@@ -408,18 +409,21 @@ kbd {
        box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#theme-picker, #settings-menu, #help-button {
+#settings-menu > a, #help-button {
        border-color: #e0e0e0;
        background: #f0f0f0;
        color: #000;
 }
 
-#theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus,
+#settings-menu > a:hover, #settings-menu > a:focus,
 #help-button:hover, #help-button:focus {
        border-color: #ffb900;
 }
 
+#settings-menu #settings, #settings-menu #settings::before {
+       border-color: #d2d2d2;
+}
+
 #copy-path {
        color: #999;
 }
@@ -443,12 +447,6 @@ kbd {
        background-color: #4e4e4e;
 }
 
-@media (max-width: 700px) {
-       #theme-picker {
-               background: #f0f0f0;
-       }
-}
-
 .search-results .result-name span.alias {
        color: #fff;
 }
index c923902aba2d312de59830a51b201ccd9770d8fd..7d4acc6c61181901b2aa5c1736e8c6932f0634a6 100644 (file)
@@ -1,6 +1,6 @@
 /* General structure and fonts */
 
-body {
+body, #settings-menu #settings, #settings-menu #settings::before {
        background-color: white;
        color: black;
 }
@@ -209,9 +209,9 @@ details.undocumented > summary::before {
 }
 
 #crate-search, .search-input {
-       color: #555;
        background-color: white;
-       border-color: #e0e0e0;
+       /* Without the `!important`, the border-color is ignored for `<select>`... */
+       border-color: #e0e0e0 !important;
 }
 
 .search-input:focus {
@@ -394,17 +394,20 @@ kbd {
        box-shadow: inset 0 -1px 0 #c6cbd1;
 }
 
-#theme-picker, #settings-menu, #help-button {
+#settings-menu > a, #help-button {
        border-color: #e0e0e0;
        background-color: #fff;
 }
 
-#theme-picker:hover, #theme-picker:focus,
-#settings-menu:hover, #settings-menu:focus,
+#settings-menu > a:hover, #settings-menu > a:focus,
 #help-button:hover, #help-button:focus {
        border-color: #717171;
 }
 
+#settings-menu #settings, #settings-menu #settings::before {
+       border-color: #DDDDDD;
+}
+
 #copy-path {
        color: #999;
 }
@@ -428,12 +431,6 @@ kbd {
        background-color: #eee;
 }
 
-@media (max-width: 700px) {
-       #theme-picker {
-               background: #fff;
-       }
-}
-
 .search-results .result-name span.alias {
        color: #000;
 }
index 336223ad28f329b02fc32cbad6ad895bf546d7e3..454c7f557b9bcf8512590bdb5d83ad760407f374 100644 (file)
@@ -1,7 +1,6 @@
 // Local js definitions:
 /* global addClass, getSettingValue, hasClass, searchState */
 /* global onEach, onEachLazy, removeClass */
-/* global switchTheme, useSystemTheme */
 
 "use strict";
 
@@ -109,21 +108,11 @@ function getVirtualKey(ev) {
     return String.fromCharCode(c);
 }
 
-const THEME_PICKER_ELEMENT_ID = "theme-picker";
-const THEMES_ELEMENT_ID = "theme-choices";
 const MAIN_ID = "main-content";
 const SETTINGS_BUTTON_ID = "settings-menu";
 const ALTERNATIVE_DISPLAY_ID = "alternative-display";
 const NOT_DISPLAYED_ID = "not-displayed";
 
-function getThemesElement() {
-    return document.getElementById(THEMES_ELEMENT_ID);
-}
-
-function getThemePickerElement() {
-    return document.getElementById(THEME_PICKER_ELEMENT_ID);
-}
-
 function getSettingsButton() {
     return document.getElementById(SETTINGS_BUTTON_ID);
 }
@@ -133,74 +122,10 @@ function getNakedUrl() {
     return window.location.href.split("?")[0].split("#")[0];
 }
 
-function showThemeButtonState() {
-    const themePicker = getThemePickerElement();
-    const themeChoices = getThemesElement();
-
-    themeChoices.style.display = "block";
-    themePicker.style.borderBottomRightRadius = "0";
-    themePicker.style.borderBottomLeftRadius = "0";
-}
-
-function hideThemeButtonState() {
-    const themePicker = getThemePickerElement();
-    const themeChoices = getThemesElement();
-
-    themeChoices.style.display = "none";
-    themePicker.style.borderBottomRightRadius = "3px";
-    themePicker.style.borderBottomLeftRadius = "3px";
-}
-
 window.hideSettings = () => {
     // Does nothing by default.
 };
 
-// Set up the theme picker list.
-(function () {
-    if (!document.location.href.startsWith("file:///")) {
-        return;
-    }
-    const themeChoices = getThemesElement();
-    const themePicker = getThemePickerElement();
-    const availableThemes = getVar("themes").split(",");
-
-    removeClass(themeChoices.parentElement, "hidden");
-
-    function switchThemeButtonState() {
-        if (themeChoices.style.display === "block") {
-            hideThemeButtonState();
-        } else {
-            showThemeButtonState();
-        }
-    }
-
-    function handleThemeButtonsBlur(e) {
-        const active = document.activeElement;
-        const related = e.relatedTarget;
-
-        if (active.id !== THEME_PICKER_ELEMENT_ID &&
-            (!active.parentNode || active.parentNode.id !== THEMES_ELEMENT_ID) &&
-            (!related ||
-             (related.id !== THEME_PICKER_ELEMENT_ID &&
-              (!related.parentNode || related.parentNode.id !== THEMES_ELEMENT_ID)))) {
-            hideThemeButtonState();
-        }
-    }
-
-    themePicker.onclick = switchThemeButtonState;
-    themePicker.onblur = handleThemeButtonsBlur;
-    availableThemes.forEach(item => {
-        const but = document.createElement("button");
-        but.textContent = item;
-        but.onclick = () => {
-            switchTheme(window.currentTheme, window.mainTheme, item, true);
-            useSystemTheme(false);
-        };
-        but.onblur = handleThemeButtonsBlur;
-        themeChoices.appendChild(but);
-    });
-}());
-
 /**
  * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
  * doesn't have a parent node.
@@ -512,7 +437,7 @@ function loadCss(cssFileName) {
             ev.preventDefault();
         }
         searchState.defocus();
-        hideThemeButtonState();
+        window.hideSettings();
     }
 
     const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
@@ -522,8 +447,6 @@ function loadCss(cssFileName) {
             return;
         }
 
-        let themePicker;
-
         if (document.activeElement.tagName === "INPUT") {
             switch (getVirtualKey(ev)) {
             case "Escape":
@@ -553,64 +476,9 @@ function loadCss(cssFileName) {
                 displayHelp(true, ev);
                 break;
 
-            case "t":
-            case "T":
-                displayHelp(false, ev);
-                ev.preventDefault();
-                themePicker = getThemePickerElement();
-                themePicker.click();
-                themePicker.focus();
-                break;
-
             default:
-                if (getThemePickerElement().parentNode.contains(ev.target)) {
-                    handleThemeKeyDown(ev);
-                }
-            }
-        }
-    }
-
-    function handleThemeKeyDown(ev) {
-        const active = document.activeElement;
-        const themes = getThemesElement();
-        switch (getVirtualKey(ev)) {
-        case "ArrowUp":
-            ev.preventDefault();
-            if (active.previousElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) {
-                active.previousElementSibling.focus();
-            } else {
-                showThemeButtonState();
-                themes.lastElementChild.focus();
-            }
-            break;
-        case "ArrowDown":
-            ev.preventDefault();
-            if (active.nextElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) {
-                active.nextElementSibling.focus();
-            } else {
-                showThemeButtonState();
-                themes.firstElementChild.focus();
-            }
-            break;
-        case "Enter":
-        case "Return":
-        case "Space":
-            if (ev.target.id === THEME_PICKER_ELEMENT_ID && themes.style.display === "none") {
-                ev.preventDefault();
-                showThemeButtonState();
-                themes.firstElementChild.focus();
+                break;
             }
-            break;
-        case "Home":
-            ev.preventDefault();
-            themes.firstElementChild.focus();
-            break;
-        case "End":
-            ev.preventDefault();
-            themes.lastElementChild.focus();
-            break;
-        // The escape key is handled in handleEscape, not here,
-        // so that pressing escape will close the menu even if it isn't focused
         }
     }
 
@@ -841,8 +709,8 @@ function loadCss(cssFileName) {
             onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => {
                 if (e.parentNode.id !== "implementations-list" ||
                     (!hasClass(e, "implementors-toggle") &&
-                     !hasClass(e, "type-contents-toggle")))
-                {
+                     !hasClass(e, "type-contents-toggle"))
+                {
                     e.open = false;
                 }
             });
@@ -1006,7 +874,6 @@ function loadCss(cssFileName) {
         const shortcuts = [
             ["?", "Show this help dialog"],
             ["S", "Focus the search field"],
-            ["T", "Focus the theme picker menu"],
             ["↑", "Move up in search results"],
             ["↓", "Move down in search results"],
             ["← / →", "Switch result tab (when results focused)"],
index 408b7e19feadd0cd09d72aa63e64c636200c5aca..7b9d86a851b1983039b8166979c64a0afb616319 100644 (file)
@@ -98,7 +98,9 @@
             // visible. This is necessary since updateScrapedExample calls scrollToLoc which
             // depends on offsetHeight, a property that requires an element to be visible to
             // compute correctly.
-            setTimeout(() => { onEachLazy(moreExamples, updateScrapedExample); });
+            setTimeout(() => {
+                onEachLazy(moreExamples, updateScrapedExample);
+            });
         }, {once: true});
     });
 })();
index 7754d626e209ef179ef6ced58973c4af34eb1538..c784d69dcd66f1003b83c539ee64f3808085ef52 100644 (file)
@@ -1,5 +1,5 @@
-/* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
-/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */
+/* global addClass, getNakedUrl, getSettingValue */
+/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
 
 "use strict";
 
@@ -38,6 +38,11 @@ const itemTypes = [
 // used for special search precedence
 const TY_PRIMITIVE = itemTypes.indexOf("primitive");
 const TY_KEYWORD = itemTypes.indexOf("keyword");
+const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
+
+function hasOwnPropertyRustdoc(obj, property) {
+    return Object.prototype.hasOwnProperty.call(obj, property);
+}
 
 // In the search display, allows to switch between tabs.
 function printTab(nb) {
@@ -106,7 +111,7 @@ function levenshtein(s1, s2) {
     return s1_len + s2_len;
 }
 
-window.initSearch = rawSearchIndex => {
+function initSearch(rawSearchIndex) {
     const MAX_LEV_DISTANCE = 3;
     const MAX_RESULTS = 200;
     const GENERICS_DATA = 2;
@@ -119,16 +124,7 @@ window.initSearch = rawSearchIndex => {
      */
     let searchIndex;
     let currentResults;
-    const ALIASES = {};
-    const params = searchState.getQueryStringParams();
-
-    // Populate search bar with query string search term when provided,
-    // but only if the input bar is empty. This avoid the obnoxious issue
-    // where you start trying to do a search, and the index loads, and
-    // suddenly your search is gone!
-    if (searchState.input.value === "") {
-        searchState.input.value = params.search || "";
-    }
+    const ALIASES = Object.create(null);
 
     function isWhitespace(c) {
         return " \t\n\r".indexOf(c) !== -1;
@@ -320,8 +316,8 @@ window.initSearch = rawSearchIndex => {
                     if (foundExclamation) {
                         throw new Error("Cannot have more than one `!` in an ident");
                     } else if (parserState.pos + 1 < parserState.length &&
-                        isIdentCharacter(parserState.userQuery[parserState.pos + 1]))
-                    {
+                        isIdentCharacter(parserState.userQuery[parserState.pos + 1])
+                    {
                         throw new Error("`!` can only be at the end of an ident");
                     }
                     foundExclamation = true;
@@ -330,12 +326,10 @@ window.initSearch = rawSearchIndex => {
                 } else if (
                     isStopCharacter(c) ||
                     isSpecialStartCharacter(c) ||
-                    isSeparatorCharacter(c))
-                {
+                    isSeparatorCharacter(c)
+                {
                     break;
-                }
-                // If we allow paths ("str::string" for example).
-                else if (c === ":") {
+                } else if (c === ":") { // If we allow paths ("str::string" for example).
                     if (!isPathStart(parserState)) {
                         break;
                     }
@@ -372,8 +366,8 @@ window.initSearch = rawSearchIndex => {
             end = getIdentEndPosition(parserState);
         }
         if (parserState.pos < parserState.length &&
-            parserState.userQuery[parserState.pos] === "<")
-        {
+            parserState.userQuery[parserState.pos] === "<"
+        {
             if (isInGenerics) {
                 throw new Error("Unexpected `<` after `<`");
             } else if (start >= end) {
@@ -592,8 +586,8 @@ window.initSearch = rawSearchIndex => {
 
         if (elem &&
             elem.value !== "All crates" &&
-            hasOwnPropertyRustdoc(rawSearchIndex, elem.value))
-        {
+            hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
+        {
             return elem.value;
         }
         return null;
@@ -728,10 +722,11 @@ window.initSearch = rawSearchIndex => {
      * @param  {ParsedQuery} parsedQuery - The parsed user query
      * @param  {Object} searchWords      - The list of search words to query against
      * @param  {Object} [filterCrates]   - Crate to search in if defined
+     * @param  {Object} [currentCrate]   - Current crate, to rank results from this crate higher
      *
      * @return {ResultsTable}
      */
-    function execQuery(parsedQuery, searchWords, filterCrates) {
+    function execQuery(parsedQuery, searchWords, filterCrates, currentCrate) {
         const results_others = {}, results_in_args = {}, results_returned = {};
 
         function transformResults(results) {
@@ -763,7 +758,7 @@ window.initSearch = rawSearchIndex => {
             return out;
         }
 
-        function sortResults(results, isType) {
+        function sortResults(results, isType, preferredCrate) {
             const userQuery = parsedQuery.userQuery;
             const ar = [];
             for (const entry in results) {
@@ -786,37 +781,51 @@ window.initSearch = rawSearchIndex => {
                 // sort by exact match with regard to the last word (mismatch goes later)
                 a = (aaa.word !== userQuery);
                 b = (bbb.word !== userQuery);
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // Sort by non levenshtein results and then levenshtein results by the distance
                 // (less changes required to match means higher rankings)
                 a = (aaa.lev);
                 b = (bbb.lev);
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
-                // sort by crate (non-current crate goes later)
-                a = (aaa.item.crate !== window.currentCrate);
-                b = (bbb.item.crate !== window.currentCrate);
-                if (a !== b) { return a - b; }
+                // sort by crate (current crate comes first)
+                a = (aaa.item.crate !== preferredCrate);
+                b = (bbb.item.crate !== preferredCrate);
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // sort by item name length (longer goes later)
                 a = aaa.word.length;
                 b = bbb.word.length;
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // sort by item name (lexicographically larger goes later)
                 a = aaa.word;
                 b = bbb.word;
-                if (a !== b) { return (a > b ? +1 : -1); }
+                if (a !== b) {
+                    return (a > b ? +1 : -1);
+                }
 
                 // sort by index of keyword in item name (no literal occurrence goes later)
                 a = (aaa.index < 0);
                 b = (bbb.index < 0);
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
                 // (later literal occurrence, if any, goes later)
                 a = aaa.index;
                 b = bbb.index;
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // special precedence for primitive and keyword pages
                 if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
@@ -831,17 +840,23 @@ window.initSearch = rawSearchIndex => {
                 // sort by description (no description goes later)
                 a = (aaa.item.desc === "");
                 b = (bbb.item.desc === "");
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // sort by type (later occurrence in `itemTypes` goes later)
                 a = aaa.item.ty;
                 b = bbb.item.ty;
-                if (a !== b) { return a - b; }
+                if (a !== b) {
+                    return a - b;
+                }
 
                 // sort by path (lexicographically larger goes later)
                 a = aaa.item.path;
                 b = bbb.item.path;
-                if (a !== b) { return (a > b ? +1 : -1); }
+                if (a !== b) {
+                    return (a > b ? +1 : -1);
+                }
 
                 // que sera, sera
                 return 0;
@@ -1160,7 +1175,7 @@ window.initSearch = rawSearchIndex => {
             };
         }
 
-        function handleAliases(ret, query, filterCrates) {
+        function handleAliases(ret, query, filterCrates, currentCrate) {
             const lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
@@ -1176,7 +1191,7 @@ window.initSearch = rawSearchIndex => {
             } else {
                 Object.keys(ALIASES).forEach(crate => {
                     if (ALIASES[crate][lowerQuery]) {
-                        const pushTo = crate === window.currentCrate ? crateAliases : aliases;
+                        const pushTo = crate === currentCrate ? crateAliases : aliases;
                         const query_aliases = ALIASES[crate][lowerQuery];
                         for (const alias of query_aliases) {
                             pushTo.push(createAliasFromItem(searchIndex[alias]));
@@ -1208,8 +1223,9 @@ window.initSearch = rawSearchIndex => {
                     ret.others.pop();
                 }
             };
-            onEach(aliases, pushFunc);
-            onEach(crateAliases, pushFunc);
+
+            aliases.forEach(pushFunc);
+            crateAliases.forEach(pushFunc);
         }
 
         /**
@@ -1315,16 +1331,15 @@ window.initSearch = rawSearchIndex => {
             }
 
             if (searchWord.indexOf(elem.pathLast) > -1 ||
-                row.normalizedName.indexOf(elem.pathLast) > -1)
-            {
+                row.normalizedName.indexOf(elem.pathLast) > -1
+            {
                 // filter type: ... queries
                 if (!results_others[fullId] !== undefined) {
                     index = row.normalizedName.indexOf(elem.pathLast);
                 }
             }
             lev = levenshtein(searchWord, elem.pathLast);
-            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
-            {
+            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) {
                 if (elem.pathLast.length < 6) {
                     lev = 1;
                 } else {
@@ -1427,11 +1442,11 @@ window.initSearch = rawSearchIndex => {
         }
 
         const ret = createQueryResults(
-            sortResults(results_in_args, true),
-            sortResults(results_returned, true),
-            sortResults(results_others, false),
+            sortResults(results_in_args, true, currentCrate),
+            sortResults(results_returned, true, currentCrate),
+            sortResults(results_others, false, currentCrate),
             parsedQuery);
-        handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
+        handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
         if (parsedQuery.error !== null && ret.others.length !== 0) {
             // It means some doc aliases were found so let's "remove" the error!
             ret.query.error = null;
@@ -1504,18 +1519,18 @@ window.initSearch = rawSearchIndex => {
 
         if (type === "mod") {
             displayPath = path + "::";
-            href = window.rootPath + path.replace(/::/g, "/") + "/" +
-                   name + "/index.html";
+            href = ROOT_PATH + path.replace(/::/g, "/") + "/" +
+                name + "/index.html";
         } else if (type === "import") {
             displayPath = item.path + "::";
-            href = window.rootPath + item.path.replace(/::/g, "/") + "/index.html#reexport." + name;
+            href = ROOT_PATH + item.path.replace(/::/g, "/") + "/index.html#reexport." + name;
         } else if (type === "primitive" || type === "keyword") {
             displayPath = "";
-            href = window.rootPath + path.replace(/::/g, "/") +
-                   "/" + type + "." + name + ".html";
+            href = ROOT_PATH + path.replace(/::/g, "/") +
+                "/" + type + "." + name + ".html";
         } else if (type === "externcrate") {
             displayPath = "";
-            href = window.rootPath + name + "/index.html";
+            href = ROOT_PATH + name + "/index.html";
         } else if (item.parent !== undefined) {
             const myparent = item.parent;
             let anchor = "#" + type + "." + name;
@@ -1538,14 +1553,14 @@ window.initSearch = rawSearchIndex => {
             } else {
                 displayPath = path + "::" + myparent.name + "::";
             }
-            href = window.rootPath + path.replace(/::/g, "/") +
-                   "/" + pageType +
-                   "." + pageName +
-                   ".html" + anchor;
+            href = ROOT_PATH + path.replace(/::/g, "/") +
+                "/" + pageType +
+                "." + pageName +
+                ".html" + anchor;
         } else {
             displayPath = item.path + "::";
-            href = window.rootPath + item.path.replace(/::/g, "/") +
-                   "/" + type + "." + name + ".html";
+            href = ROOT_PATH + item.path.replace(/::/g, "/") +
+                "/" + type + "." + name + ".html";
         }
         return [displayPath, href];
     }
@@ -1670,8 +1685,8 @@ window.initSearch = rawSearchIndex => {
             // By default, the search DOM element is "empty" (meaning it has no children not
             // text content). Once a search has been run, it won't be empty, even if you press
             // ESC or empty the search input (which also "cancels" the search).
-            && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)))
-        {
+            && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText))
+        {
             const elem = document.createElement("a");
             elem.href = results.others[0].href;
             removeClass(elem, "active");
@@ -1723,7 +1738,7 @@ window.initSearch = rawSearchIndex => {
 
         let output = "<div id=\"search-settings\">" +
             `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
-            `${typeFilter}</h1> in ${crates} </div>`;
+            `${typeFilter}</h1>${crates}</div>`;
         if (results.query.error !== null) {
             output += `<h3>Query parser error: "${results.query.error}".</h3>`;
             output += "<div id=\"titles\">" +
@@ -1766,7 +1781,7 @@ window.initSearch = rawSearchIndex => {
         let i = 0;
         for (const elem of elems) {
             const j = i;
-            elem.onclick = () => { printTab(j); };
+            elem.onclick = () => printTab(j);
             searchState.focusedByTab.push(null);
             i += 1;
         }
@@ -1818,7 +1833,7 @@ window.initSearch = rawSearchIndex => {
         }
 
         showResults(
-            execQuery(query, searchWords, filterCrates),
+            execQuery(query, searchWords, filterCrates, window.currentCrate),
             params.go_to_first,
             filterCrates);
     }
@@ -1953,7 +1968,7 @@ window.initSearch = rawSearchIndex => {
             }
 
             if (aliases) {
-                ALIASES[crate] = {};
+                ALIASES[crate] = Object.create(null);
                 for (const alias_name in aliases) {
                     if (!hasOwnPropertyRustdoc(aliases, alias_name)) {
                         continue;
@@ -1998,6 +2013,16 @@ window.initSearch = rawSearchIndex => {
     }
 
     function registerSearchEvents() {
+        const params = searchState.getQueryStringParams();
+
+        // Populate search bar with query string search term when provided,
+        // but only if the input bar is empty. This avoid the obnoxious issue
+        // where you start trying to do a search, and the index loads, and
+        // suddenly your search is gone!
+        if (searchState.input.value === "") {
+            searchState.input.value = params.search || "";
+        }
+
         const searchAfter500ms = () => {
             searchState.clearInputTimeout();
             if (searchState.input.value.length === 0) {
@@ -2150,20 +2175,32 @@ window.initSearch = rawSearchIndex => {
      *  @type {Array<string>}
      */
     const searchWords = buildIndex(rawSearchIndex);
-    registerSearchEvents();
-
-    function runSearchIfNeeded() {
+    if (typeof window !== "undefined") {
+        registerSearchEvents();
         // If there's a search term in the URL, execute the search now.
-        if (searchState.getQueryStringParams().search) {
+        if (window.searchState.getQueryStringParams().search) {
             search();
         }
     }
 
-    runSearchIfNeeded();
-};
+    if (typeof exports !== "undefined") {
+        exports.initSearch = initSearch;
+        exports.execQuery = execQuery;
+        exports.parseQuery = parseQuery;
+    }
+    return searchWords;
+}
 
-if (window.searchIndex !== undefined) {
-    initSearch(window.searchIndex);
+if (typeof window !== "undefined") {
+    window.initSearch = initSearch;
+    if (window.searchIndex !== undefined) {
+        initSearch(window.searchIndex);
+    }
+} else {
+    // Running in Node, not a browser. Run initSearch just to produce the
+    // exports.
+    initSearch({});
 }
 
+
 })();
index ad32a193893896a6be5ea62162f6b863fde22544..2e2305029cdddb723021748d5cd48624f57ad49c 100644 (file)
@@ -1,7 +1,7 @@
 // Local js definitions:
 /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
-/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */
-/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */
+/* global addClass, removeClass, onEach, onEachLazy */
+/* global MAIN_ID, getVar, getSettingsButton */
 
 "use strict";
 
         ];
 
         // Then we build the DOM.
-        const el = document.createElement("section");
-        el.id = "settings";
-        let innerHTML = `
-            <div class="main-heading">
+        let innerHTML = "";
+        let elementKind = "div";
+
+        if (isSettingsPage) {
+            elementKind = "section";
+            innerHTML = `<div class="main-heading">
                 <h1 class="fqn">
                     <span class="in-band">Rustdoc settings</span>
                 </h1>
-                <span class="out-of-band">`;
-
-        if (isSettingsPage) {
-            innerHTML +=
-                "<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">Back</a>";
-        } else {
-            innerHTML += "<a id=\"back\" href=\"javascript:void(0)\" " +
-                "onclick=\"switchDisplayedElement(null);\">Back</a>";
+                <span class="out-of-band">
+                    <a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>
+                </span>
+                </div>`;
         }
-        innerHTML += `</span>
-            </div>
-            <div class="settings">${buildSettingsPageSections(settings)}</div>`;
+        innerHTML += `<div class="settings">${buildSettingsPageSections(settings)}</div>`;
 
+        const el = document.createElement(elementKind);
+        el.id = "settings";
         el.innerHTML = innerHTML;
 
         if (isSettingsPage) {
             document.getElementById(MAIN_ID).appendChild(el);
         } else {
-            getNotDisplayedElem().appendChild(el);
+            el.setAttribute("tabindex", "-1");
+            getSettingsButton().appendChild(el);
         }
         return el;
     }
 
     const settingsMenu = buildSettingsPage();
 
+    function displaySettings() {
+        settingsMenu.style.display = "";
+    }
+
+    function elemIsInParent(elem, parent) {
+        while (elem && elem !== document.body) {
+            if (elem === parent) {
+                return true;
+            }
+            elem = elem.parentElement;
+        }
+        return false;
+    }
+
+    function blurHandler(event) {
+        const settingsButton = getSettingsButton();
+        if (!elemIsInParent(document.activeElement, settingsButton) &&
+            !elemIsInParent(event.relatedTarget, settingsButton)
+        ) {
+            window.hideSettings();
+        }
+    }
+
     if (isSettingsPage) {
         // We replace the existing "onclick" callback to do nothing if clicked.
         getSettingsButton().onclick = function(event) {
     } else {
         // We replace the existing "onclick" callback.
         const settingsButton = getSettingsButton();
+        const settingsMenu = document.getElementById("settings");
+        window.hideSettings = function() {
+            settingsMenu.style.display = "none";
+        };
         settingsButton.onclick = function(event) {
+            if (elemIsInParent(event.target, settingsMenu)) {
+                return;
+            }
             event.preventDefault();
-            if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) {
-                switchDisplayedElement(settingsMenu);
-            } else {
+            if (settingsMenu.style.display !== "none") {
                 window.hideSettings();
+            } else {
+                displaySettings();
             }
         };
-        window.hideSettings = function() {
-            switchDisplayedElement(null);
-        };
+        settingsButton.onblur = blurHandler;
+        settingsButton.querySelector("a").onblur = blurHandler;
+        onEachLazy(settingsMenu.querySelectorAll("input"), el => {
+            el.onblur = blurHandler;
+        });
+        settingsMenu.onblur = blurHandler;
     }
 
     // We now wait a bit for the web browser to end re-computing the DOM...
         setEvents(settingsMenu);
         // The setting menu is already displayed if we're on the settings page.
         if (!isSettingsPage) {
-            switchDisplayedElement(settingsMenu);
+            displaySettings();
         }
         removeClass(getSettingsButton(), "rotate");
     }, 0);
index 21de7d77d64e7f60a3b449051e1758539d64e337..948885cd30a598d601724e25be322525206654bf 100644 (file)
@@ -100,11 +100,6 @@ function onEachLazy(lazyArray, func, reversed) {
         reversed);
 }
 
-// eslint-disable-next-line no-unused-vars
-function hasOwnPropertyRustdoc(obj, property) {
-    return Object.prototype.hasOwnProperty.call(obj, property);
-}
-
 function updateLocalStorage(name, value) {
     try {
         window.localStorage.setItem("rustdoc-" + name, value);
index bec5c083fed225b7f3afd6fbd55ca5866f2c6a10..85ca8431d90da1b38706e220aa41d1c2da33f474 100644 (file)
@@ -41,9 +41,6 @@
 
 crate static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
 
-/// The file contents of `brush.svg`, the icon used for the theme-switch button.
-crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
-
 /// The file contents of `wheel.svg`, the icon used for the settings button.
 crate static WHEEL_SVG: &[u8] = include_bytes!("static/images/wheel.svg");
 
index 470cce93a5020fca5d4c8ea410e48b830eaa168f..cd672aadd7e93c680da74aa89aa0a4c5845d6f42 100644 (file)
                     {%- endif -%}
                 </a> {#- -#}
                 <nav class="sub"> {#- -#}
-                    <div class="theme-picker hidden"> {#- -#}
-                        <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
-                            <img width="22" height="22" alt="Pick another theme!" {# -#}
-                             src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
-                        </button> {#- -#}
-                        <div id="theme-choices" role="menu"></div> {#- -#}
-                    </div> {#- -#}
                     <form class="search-form"> {#- -#}
                         <div class="search-container"> {#- -#}
                             <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
                                 placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
                                 type="search"> {#- -#}
                             <button type="button" id="help-button" title="help">?</button> {#- -#}
-                            <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
-                                <img width="22" height="22" alt="Change settings" {# -#}
+                            <div id="settings-menu" tabindex="-1">
+                                <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+                                    <img width="22" height="22" alt="Change settings" {# -#}
                                      src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
-                            </a> {#- -#}
+                                </a> {#- -#}
+                            </div>
                         </div> {#- -#}
                     </form> {#- -#}
                 </nav> {#- -#}
index 56b02cd848041236e30fab13cfc70fa0de4f62ff..412387313dc1719343e3809eaa3714472daf6cd5 100644 (file)
@@ -350,10 +350,16 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
     fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
         use clean::WherePredicate::*;
         match predicate {
-            BoundPredicate { ty, bounds, .. } => WherePredicate::BoundPredicate {
+            BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
                 type_: ty.into_tcx(tcx),
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-                // FIXME: add `bound_params` to rustdoc-json-params?
+                generic_params: bound_params
+                    .into_iter()
+                    .map(|x| GenericParamDef {
+                        name: x.0.to_string(),
+                        kind: GenericParamDefKind::Lifetime { outlives: vec![] },
+                    })
+                    .collect(),
             },
             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
                 lifetime: lifetime.0.to_string(),
index 22b2f8c0c8ec36df99af16f79dec42097f2dd987..95ba4ce5b06b9e834b1b4ebeb10a54dfb42113a3 100644 (file)
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::Mutability;
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
-use rustc_middle::{bug, span_bug, ty};
+use rustc_middle::{bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{BytePos, DUMMY_SP};
+use rustc_span::BytePos;
 use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
@@ -48,18 +48,6 @@ fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
     krate
 }
 
-/// Top-level errors emitted by this pass.
-enum ErrorKind<'a> {
-    Resolve(Box<ResolutionFailure<'a>>),
-    AnchorFailure(AnchorFailure),
-}
-
-impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
-    fn from(err: ResolutionFailure<'a>) -> Self {
-        ErrorKind::Resolve(box err)
-    }
-}
-
 #[derive(Copy, Clone, Debug, Hash)]
 enum Res {
     Def(DefKind, DefId),
@@ -97,12 +85,8 @@ fn def_id(self, tcx: TyCtxt<'_>) -> DefId {
         }
     }
 
-    fn as_hir_res(self) -> Option<rustc_hir::def::Res> {
-        match self {
-            Res::Def(kind, id) => Some(rustc_hir::def::Res::Def(kind, id)),
-            // FIXME: maybe this should handle the subset of PrimitiveType that fits into hir::PrimTy?
-            Res::Primitive(_) => None,
-        }
+    fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Res {
+        Res::Def(tcx.def_kind(def_id), def_id)
     }
 
     /// Used for error reporting.
@@ -160,8 +144,25 @@ fn try_from(res: ResolveRes) -> Result<Self, ()> {
     }
 }
 
-/// A link failed to resolve.
-#[derive(Clone, Debug)]
+/// The link failed to resolve. [`resolution_failure`] should look to see if there's
+/// a more helpful error that can be given.
+#[derive(Debug)]
+struct UnresolvedPath<'a> {
+    /// Item on which the link is resolved, used for resolving `Self`.
+    item_id: ItemId,
+    /// The scope the link was resolved in.
+    module_id: DefId,
+    /// If part of the link resolved, this has the `Res`.
+    ///
+    /// In `[std::io::Error::x]`, `std::io::Error` would be a partial resolution.
+    partial_res: Option<Res>,
+    /// The remaining unresolved path segments.
+    ///
+    /// In `[std::io::Error::x]`, `x` would be unresolved.
+    unresolved: Cow<'a, str>,
+}
+
+#[derive(Debug)]
 enum ResolutionFailure<'a> {
     /// This resolved, but with the wrong namespace.
     WrongNamespace {
@@ -173,35 +174,10 @@ enum ResolutionFailure<'a> {
         /// even though `Result`'s actual namespace is [`Namespace::TypeNS`].
         expected_ns: Namespace,
     },
-    /// The link failed to resolve. [`resolution_failure`] should look to see if there's
-    /// a more helpful error that can be given.
-    NotResolved {
-        /// Item on which the link is resolved, used for resolving `Self`.
-        item_id: ItemId,
-        /// The scope the link was resolved in.
-        module_id: DefId,
-        /// If part of the link resolved, this has the `Res`.
-        ///
-        /// In `[std::io::Error::x]`, `std::io::Error` would be a partial resolution.
-        partial_res: Option<Res>,
-        /// The remaining unresolved path segments.
-        ///
-        /// In `[std::io::Error::x]`, `x` would be unresolved.
-        unresolved: Cow<'a, str>,
-    },
-    /// This happens when rustdoc can't determine the parent scope for an item.
-    /// It is always a bug in rustdoc.
-    NoParentItem,
-    /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced.
-    MalformedGenerics(MalformedGenerics),
-    /// Used to communicate that this should be ignored, but shouldn't be reported to the user.
-    ///
-    /// This happens when there is no disambiguator and one of the namespaces
-    /// failed to resolve.
-    Dummy,
+    NotResolved(UnresolvedPath<'a>),
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
 enum MalformedGenerics {
     /// This link has unbalanced angle brackets.
     ///
@@ -242,35 +218,6 @@ enum MalformedGenerics {
     EmptyAngleBrackets,
 }
 
-impl ResolutionFailure<'_> {
-    /// This resolved fully (not just partially) but is erroneous for some other reason
-    ///
-    /// Returns the full resolution of the link, if present.
-    fn full_res(&self) -> Option<Res> {
-        match self {
-            Self::WrongNamespace { res, expected_ns: _ } => Some(*res),
-            _ => None,
-        }
-    }
-}
-
-#[derive(Clone, Copy)]
-enum AnchorFailure {
-    /// User error: `[std#x#y]` is not valid
-    MultipleAnchors,
-    /// The anchor provided by the user conflicts with Rustdoc's generated anchor.
-    ///
-    /// This is an unfortunate state of affairs. Not every item that can be
-    /// linked to has its own page; sometimes it is a subheading within a page,
-    /// like for associated items. In those cases, rustdoc uses an anchor to
-    /// link to the subheading. Since you can't have two anchors for the same
-    /// link, Rustdoc disallows having a user-specified anchor.
-    ///
-    /// Most of the time this is fine, because you can just link to the page of
-    /// the item if you want to provide your own anchor.
-    RustdocAnchorConflict(Res),
-}
-
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 crate enum UrlFragment {
     Item(ItemFragment),
@@ -302,24 +249,32 @@ impl UrlFragment {
     VariantField,
 }
 
-impl ItemFragment {
-    /// Create a fragment for an associated item.
-    #[instrument(level = "debug")]
-    fn from_assoc_item(item: &ty::AssocItem) -> Self {
-        let def_id = item.def_id;
-        match item.kind {
-            ty::AssocKind::Fn => {
-                if item.defaultness.has_value() {
-                    ItemFragment(FragmentKind::Method, def_id)
+impl FragmentKind {
+    fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> FragmentKind {
+        match tcx.def_kind(def_id) {
+            DefKind::AssocFn => {
+                if tcx.associated_item(def_id).defaultness.has_value() {
+                    FragmentKind::Method
+                } else {
+                    FragmentKind::TyMethod
+                }
+            }
+            DefKind::AssocConst => FragmentKind::AssociatedConstant,
+            DefKind::AssocTy => FragmentKind::AssociatedType,
+            DefKind::Variant => FragmentKind::Variant,
+            DefKind::Field => {
+                if tcx.def_kind(tcx.parent(def_id)) == DefKind::Variant {
+                    FragmentKind::VariantField
                 } else {
-                    ItemFragment(FragmentKind::TyMethod, def_id)
+                    FragmentKind::StructField
                 }
             }
-            ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id),
-            ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id),
+            kind => bug!("unexpected associated item kind: {:?}", kind),
         }
     }
+}
 
+impl ItemFragment {
     /// Render the fragment, including the leading `#`.
     crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
         write!(s, "#")?;
@@ -389,9 +344,9 @@ fn variant_field<'path>(
         path_str: &'path str,
         item_id: ItemId,
         module_id: DefId,
-    ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
+    ) -> Result<(Res, DefId), UnresolvedPath<'path>> {
         let tcx = self.cx.tcx;
-        let no_res = || ResolutionFailure::NotResolved {
+        let no_res = || UnresolvedPath {
             item_id,
             module_id,
             partial_res: None,
@@ -418,42 +373,27 @@ fn variant_field<'path>(
         let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
 
         match ty_res {
-            Res::Def(DefKind::Enum, did) => {
-                if tcx
-                    .inherent_impls(did)
-                    .iter()
-                    .flat_map(|imp| tcx.associated_items(*imp).in_definition_order())
-                    .any(|item| item.name == variant_name)
-                {
-                    // This is just to let `fold_item` know that this shouldn't be considered;
-                    // it's a bug for the error to make it to the user
-                    return Err(ResolutionFailure::Dummy.into());
-                }
-                match tcx.type_of(did).kind() {
-                    ty::Adt(def, _) if def.is_enum() => {
-                        if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name)
-                        {
-                            Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
-                        } else {
-                            Err(ResolutionFailure::NotResolved {
-                                item_id,
-                                module_id,
-                                partial_res: Some(Res::Def(DefKind::Enum, def.did())),
-                                unresolved: variant_field_name.to_string().into(),
-                            }
-                            .into())
-                        }
+            Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() {
+                ty::Adt(def, _) if def.is_enum() => {
+                    if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) {
+                        Ok((ty_res, field.did))
+                    } else {
+                        Err(UnresolvedPath {
+                            item_id,
+                            module_id,
+                            partial_res: Some(Res::Def(DefKind::Enum, def.did())),
+                            unresolved: variant_field_name.to_string().into(),
+                        })
                     }
-                    _ => unreachable!(),
                 }
-            }
-            _ => Err(ResolutionFailure::NotResolved {
+                _ => unreachable!(),
+            },
+            _ => Err(UnresolvedPath {
                 item_id,
                 module_id,
                 partial_res: Some(ty_res),
                 unresolved: variant_name.to_string().into(),
-            }
-            .into()),
+            }),
         }
     }
 
@@ -463,35 +403,13 @@ fn resolve_primitive_associated_item(
         prim_ty: PrimitiveType,
         ns: Namespace,
         item_name: Symbol,
-    ) -> Option<(Res, ItemFragment)> {
+    ) -> Option<(Res, DefId)> {
         let tcx = self.cx.tcx;
 
         prim_ty.impls(tcx).find_map(|impl_| {
             tcx.associated_items(impl_)
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
-                .map(|item| {
-                    let fragment = ItemFragment::from_assoc_item(item);
-                    (Res::Primitive(prim_ty), fragment)
-                })
-        })
-    }
-
-    /// Resolves a string as a macro.
-    ///
-    /// FIXME(jynelson): Can this be unified with `resolve()`?
-    fn resolve_macro(
-        &self,
-        path_str: &'a str,
-        item_id: ItemId,
-        module_id: DefId,
-    ) -> Result<Res, ResolutionFailure<'a>> {
-        self.resolve_path(path_str, MacroNS, item_id, module_id).ok_or_else(|| {
-            ResolutionFailure::NotResolved {
-                item_id,
-                module_id,
-                partial_res: None,
-                unresolved: path_str.into(),
-            }
+                .map(|item| (Res::Primitive(prim_ty), item.def_id))
         })
     }
 
@@ -525,21 +443,6 @@ fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Opt
             })
     }
 
-    /// HACK: Try to search the macro name in the list of all `macro_rules` items in the crate.
-    /// Used when nothing else works, may often give an incorrect result.
-    fn resolve_macro_rules(&self, path_str: &str, ns: Namespace) -> Option<Res> {
-        if ns != MacroNS {
-            return None;
-        }
-
-        self.cx
-            .resolver_caches
-            .all_macro_rules
-            .get(&Symbol::intern(path_str))
-            .copied()
-            .and_then(|res| res.try_into().ok())
-    }
-
     /// Convenience wrapper around `resolve_rustdoc_path`.
     ///
     /// This also handles resolving `true` and `false` as booleans.
@@ -571,8 +474,7 @@ fn resolve_path(
                 })
             })
             .and_then(|res| res.try_into().ok())
-            .or_else(|| resolve_primitive(path_str, ns))
-            .or_else(|| self.resolve_macro_rules(path_str, ns));
+            .or_else(|| resolve_primitive(path_str, ns));
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
         result
     }
@@ -585,43 +487,22 @@ fn resolve<'path>(
         ns: Namespace,
         item_id: ItemId,
         module_id: DefId,
-        user_fragment: &Option<String>,
-    ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
-        let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, item_id, module_id)?;
-        let chosen_fragment = match (user_fragment, rustdoc_fragment) {
-            (Some(_), Some(r_frag)) => {
-                let diag_res = match r_frag {
-                    ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did),
-                };
-                let failure = AnchorFailure::RustdocAnchorConflict(diag_res);
-                return Err(ErrorKind::AnchorFailure(failure));
-            }
-            (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())),
-            (None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)),
-            (None, None) => None,
-        };
-        Ok((res, chosen_fragment))
-    }
-
-    fn resolve_inner<'path>(
-        &mut self,
-        path_str: &'path str,
-        ns: Namespace,
-        item_id: ItemId,
-        module_id: DefId,
-    ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
+    ) -> Result<(Res, Option<DefId>), UnresolvedPath<'path>> {
         if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) {
-            match res {
-                // FIXME(#76467): make this fallthrough to lookup the associated
-                // item a separate function.
-                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS),
-                Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS),
-                Res::Def(DefKind::Variant, _) => {
-                    return handle_variant(self.cx, res);
-                }
-                // Not a trait item; just return what we found.
-                _ => return Ok((res, None)),
-            }
+            return Ok(match res {
+                Res::Def(
+                    DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Variant,
+                    def_id,
+                ) => (Res::from_def_id(self.cx.tcx, self.cx.tcx.parent(def_id)), Some(def_id)),
+                _ => ((res, None)),
+            });
+        } else if ns == MacroNS {
+            return Err(UnresolvedPath {
+                item_id,
+                module_id,
+                partial_res: None,
+                unresolved: path_str.into(),
+            });
         }
 
         // Try looking for methods and associated items.
@@ -637,7 +518,7 @@ fn resolve_inner<'path>(
             // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
             .ok_or_else(|| {
                 debug!("found no `::`, assumming {} was correctly not in scope", item_name);
-                ResolutionFailure::NotResolved {
+                UnresolvedPath {
                     item_id,
                     module_id,
                     partial_res: None,
@@ -652,24 +533,21 @@ fn resolve_inner<'path>(
         resolve_primitive(&path_root, TypeNS)
             .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
             .and_then(|ty_res| {
-                let (res, fragment) =
-                    self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
-
-                Some(Ok((res, Some(fragment))))
+                self.resolve_associated_item(ty_res, item_name, ns, module_id).map(Ok)
             })
             .unwrap_or_else(|| {
                 if ns == Namespace::ValueNS {
                     self.variant_field(path_str, item_id, module_id)
                 } else {
-                    Err(ResolutionFailure::NotResolved {
+                    Err(UnresolvedPath {
                         item_id,
                         module_id,
                         partial_res: None,
                         unresolved: path_root.into(),
-                    }
-                    .into())
+                    })
                 }
             })
+            .map(|(res, def_id)| (res, Some(def_id)))
     }
 
     /// Convert a DefId to a Res, where possible.
@@ -694,7 +572,7 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
             ty::FnPtr(_) => Res::Primitive(Fn),
             ty::Never => Res::Primitive(Never),
             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => {
-                Res::Def(self.cx.tcx.def_kind(did), did)
+                Res::from_def_id(self.cx.tcx, did)
             }
             ty::Projection(_)
             | ty::Closure(..)
@@ -751,23 +629,18 @@ fn resolve_associated_item(
         item_name: Symbol,
         ns: Namespace,
         module_id: DefId,
-    ) -> Option<(Res, ItemFragment)> {
+    ) -> Option<(Res, DefId)> {
         let tcx = self.cx.tcx;
 
         match root_res {
             Res::Primitive(prim) => {
                 self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| {
-                    let assoc_item = self
-                        .primitive_type_to_ty(prim)
+                    self.primitive_type_to_ty(prim)
                         .map(|ty| {
                             resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
                         })
-                        .flatten();
-
-                    assoc_item.map(|item| {
-                        let fragment = ItemFragment::from_assoc_item(&item);
-                        (root_res, fragment)
-                    })
+                        .flatten()
+                        .map(|item| (root_res, item.def_id))
                 })
             }
             Res::Def(DefKind::TyAlias, did) => {
@@ -788,10 +661,7 @@ fn resolve_associated_item(
                         ty::Adt(adt_def, _) => {
                             for variant in adt_def.variants() {
                                 if variant.name == item_name {
-                                    return Some((
-                                        root_res,
-                                        ItemFragment(FragmentKind::Variant, variant.def_id),
-                                    ));
+                                    return Some((root_res, variant.def_id));
                                 }
                             }
                         }
@@ -832,8 +702,7 @@ fn resolve_associated_item(
                 debug!("got associated item {:?}", assoc_item);
 
                 if let Some(item) = assoc_item {
-                    let fragment = ItemFragment::from_assoc_item(&item);
-                    return Some((root_res, fragment));
+                    return Some((root_res, item.def_id));
                 }
 
                 if ns != Namespace::ValueNS {
@@ -861,59 +730,22 @@ fn resolve_associated_item(
                 };
                 let field =
                     def.non_enum_variant().fields.iter().find(|item| item.name == item_name)?;
-                Some((root_res, ItemFragment(FragmentKind::StructField, field.did)))
+                Some((root_res, field.did))
             }
             Res::Def(DefKind::Trait, did) => tcx
                 .associated_items(did)
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
                 .map(|item| {
-                    let fragment = ItemFragment::from_assoc_item(item);
                     let res = Res::Def(item.kind.as_def_kind(), item.def_id);
-                    (res, fragment)
+                    (res, item.def_id)
                 }),
             _ => None,
         }
     }
+}
 
-    /// Used for reporting better errors.
-    ///
-    /// Returns whether the link resolved 'fully' in another namespace.
-    /// 'fully' here means that all parts of the link resolved, not just some path segments.
-    /// This returns the `Res` even if it was erroneous for some reason
-    /// (such as having invalid URL fragments or being in the wrong namespace).
-    fn check_full_res(
-        &mut self,
-        ns: Namespace,
-        path_str: &str,
-        item_id: ItemId,
-        module_id: DefId,
-        extra_fragment: &Option<String>,
-    ) -> Option<Res> {
-        // resolve() can't be used for macro namespace
-        let result = match ns {
-            Namespace::MacroNS => self
-                .resolve_macro(path_str, item_id, module_id)
-                .map(|res| (res, None))
-                .map_err(ErrorKind::from),
-            Namespace::TypeNS | Namespace::ValueNS => {
-                self.resolve(path_str, ns, item_id, module_id, extra_fragment)
-            }
-        };
-
-        let res = match result {
-            Ok((res, frag)) => {
-                if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag {
-                    Some(Res::Def(self.cx.tcx.def_kind(id), id))
-                } else {
-                    Some(res)
-                }
-            }
-            Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
-            Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res),
-            Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
-        };
-        res
-    }
+fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option<DefId>)) -> Res {
+    assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id))
 }
 
 /// Look to see if a resolved item has an associated item named `item_name`.
@@ -1093,14 +925,23 @@ fn visit_item(&mut self, item: &Item) {
 }
 
 enum PreprocessingError {
-    Anchor(AnchorFailure),
+    /// User error: `[std#x#y]` is not valid
+    MultipleAnchors,
     Disambiguator(Range<usize>, String),
-    Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>),
+    MalformedGenerics(MalformedGenerics, String),
 }
 
-impl From<AnchorFailure> for PreprocessingError {
-    fn from(err: AnchorFailure) -> Self {
-        Self::Anchor(err)
+impl PreprocessingError {
+    fn report(&self, cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) {
+        match self {
+            PreprocessingError::MultipleAnchors => report_multiple_anchors(cx, diag_info),
+            PreprocessingError::Disambiguator(range, msg) => {
+                disambiguator_error(cx, diag_info, range.clone(), msg)
+            }
+            PreprocessingError::MalformedGenerics(err, path_str) => {
+                report_malformed_generics(cx, diag_info, *err, path_str)
+            }
+        }
     }
 }
 
@@ -1145,7 +986,7 @@ fn preprocess_link(
     let extra_fragment = parts.next();
     if parts.next().is_some() {
         // A valid link can't have multiple #'s
-        return Some(Err(AnchorFailure::MultipleAnchors.into()));
+        return Some(Err(PreprocessingError::MultipleAnchors));
     }
 
     // Parse and strip the disambiguator from the link, if present.
@@ -1173,13 +1014,9 @@ fn preprocess_link(
     let path_str = if path_str.contains(['<', '>'].as_slice()) {
         match strip_generics_from_path(path_str) {
             Ok(path) => path,
-            Err(err_kind) => {
+            Err(err) => {
                 debug!("link has malformed generics: {}", path_str);
-                return Some(Err(PreprocessingError::Resolution(
-                    err_kind,
-                    path_str.to_owned(),
-                    disambiguator,
-                )));
+                return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned())));
             }
         }
     } else {
@@ -1229,32 +1066,10 @@ fn resolve_link(
             link_range: ori_link.range.clone(),
         };
 
-        let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link
-        {
-            Ok(x) => x,
-            Err(err) => {
-                match err {
-                    PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err),
-                    PreprocessingError::Disambiguator(range, msg) => {
-                        disambiguator_error(self.cx, diag_info, range.clone(), msg)
-                    }
-                    PreprocessingError::Resolution(err, path_str, disambiguator) => {
-                        resolution_failure(
-                            self,
-                            diag_info,
-                            path_str,
-                            *disambiguator,
-                            smallvec![err.clone()],
-                        );
-                    }
-                }
-                return None;
-            }
-        };
+        let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
+            pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
         let disambiguator = *disambiguator;
 
-        let inner_docs = item.inner_docs(self.cx.tcx);
-
         // In order to correctly resolve intra-doc links we need to
         // pick a base AST node to work from.  If the documentation for
         // this module came from an inner comment (//!) then we anchor
@@ -1266,21 +1081,10 @@ fn resolve_link(
         // we've already pushed this node onto the resolution stack but
         // for outer comments we explicitly try and resolve against the
         // parent_node first.
+        let inner_docs = item.inner_docs(self.cx.tcx);
         let base_node =
             if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node };
-
-        let Some(module_id) = base_node else {
-            // This is a bug.
-            debug!("attempting to resolve item without parent module: {}", path_str);
-            resolution_failure(
-                self,
-                diag_info,
-                path_str,
-                disambiguator,
-                smallvec![ResolutionFailure::NoParentItem],
-            );
-            return None;
-        };
+        let module_id = base_node.expect("doc link without parent module");
 
         let (mut res, fragment) = self.resolve_with_disambiguator_cached(
             ResolutionInfo {
@@ -1504,7 +1308,21 @@ fn resolve_with_disambiguator_cached(
             }
         }
 
-        let res = self.resolve_with_disambiguator(&key, diag);
+        let res = self.resolve_with_disambiguator(&key, diag.clone()).and_then(|(res, def_id)| {
+            let fragment = match (&key.extra_fragment, def_id) {
+                (Some(_), Some(def_id)) => {
+                    report_anchor_conflict(self.cx, diag, Res::from_def_id(self.cx.tcx, def_id));
+                    return None;
+                }
+                (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())),
+                (None, Some(def_id)) => Some(UrlFragment::Item(ItemFragment(
+                    FragmentKind::from_def_id(self.cx.tcx, def_id),
+                    def_id,
+                ))),
+                (None, None) => None,
+            };
+            Some((res, fragment))
+        });
 
         // Cache only if resolved successfully - don't silence duplicate errors
         if let Some(res) = res {
@@ -1529,103 +1347,55 @@ fn resolve_with_disambiguator(
         &mut self,
         key: &ResolutionInfo,
         diag: DiagnosticInfo<'_>,
-    ) -> Option<(Res, Option<UrlFragment>)> {
+    ) -> Option<(Res, Option<DefId>)> {
         let disambiguator = key.dis;
         let path_str = &key.path_str;
         let item_id = key.item_id;
         let base_node = key.module_id;
-        let extra_fragment = &key.extra_fragment;
 
         match disambiguator.map(Disambiguator::ns) {
-            Some(expected_ns @ (ValueNS | TypeNS)) => {
-                match self.resolve(path_str, expected_ns, item_id, base_node, extra_fragment) {
+            Some(expected_ns) => {
+                match self.resolve(path_str, expected_ns, item_id, base_node) {
                     Ok(res) => Some(res),
-                    Err(ErrorKind::Resolve(box mut kind)) => {
+                    Err(err) => {
                         // We only looked in one namespace. Try to give a better error if possible.
-                        if kind.full_res().is_none() {
-                            let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS };
-                            // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
-                            // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
-                            for new_ns in [other_ns, MacroNS] {
-                                if let Some(res) = self.check_full_res(
-                                    new_ns,
-                                    path_str,
-                                    item_id,
-                                    base_node,
-                                    extra_fragment,
-                                ) {
-                                    kind = ResolutionFailure::WrongNamespace { res, expected_ns };
+                        // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`.
+                        // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach.
+                        let mut err = ResolutionFailure::NotResolved(err);
+                        for other_ns in [TypeNS, ValueNS, MacroNS] {
+                            if other_ns != expected_ns {
+                                if let Ok(res) =
+                                    self.resolve(path_str, other_ns, item_id, base_node)
+                                {
+                                    err = ResolutionFailure::WrongNamespace {
+                                        res: full_res(self.cx.tcx, res),
+                                        expected_ns,
+                                    };
                                     break;
                                 }
                             }
                         }
-                        resolution_failure(self, diag, path_str, disambiguator, smallvec![kind]);
-                        // This could just be a normal link or a broken link
-                        // we could potentially check if something is
-                        // "intra-doc-link-like" and warn in that case.
-                        None
-                    }
-                    Err(ErrorKind::AnchorFailure(msg)) => {
-                        anchor_failure(self.cx, diag, msg);
-                        None
+                        resolution_failure(self, diag, path_str, disambiguator, smallvec![err])
                     }
                 }
             }
             None => {
                 // Try everything!
-                let mut candidates = PerNS {
-                    macro_ns: self
-                        .resolve_macro(path_str, item_id, base_node)
-                        .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
-                    type_ns: match self.resolve(
-                        path_str,
-                        TypeNS,
-                        item_id,
-                        base_node,
-                        extra_fragment,
-                    ) {
-                        Ok(res) => {
-                            debug!("got res in TypeNS: {:?}", res);
-                            Ok(res)
-                        }
-                        Err(ErrorKind::AnchorFailure(msg)) => {
-                            anchor_failure(self.cx, diag, msg);
-                            return None;
-                        }
-                        Err(ErrorKind::Resolve(box kind)) => Err(kind),
-                    },
-                    value_ns: match self.resolve(
-                        path_str,
-                        ValueNS,
-                        item_id,
-                        base_node,
-                        extra_fragment,
-                    ) {
-                        Ok(res) => Ok(res),
-                        Err(ErrorKind::AnchorFailure(msg)) => {
-                            anchor_failure(self.cx, diag, msg);
-                            return None;
-                        }
-                        Err(ErrorKind::Resolve(box kind)) => Err(kind),
-                    }
-                    .and_then(|(res, fragment)| {
-                        // Constructors are picked up in the type namespace.
+                let mut candidate = |ns| {
+                    self.resolve(path_str, ns, item_id, base_node)
+                        .map_err(ResolutionFailure::NotResolved)
+                };
+
+                let candidates = PerNS {
+                    macro_ns: candidate(MacroNS),
+                    type_ns: candidate(TypeNS),
+                    value_ns: candidate(ValueNS).and_then(|(res, def_id)| {
                         match res {
+                            // Constructors are picked up in the type namespace.
                             Res::Def(DefKind::Ctor(..), _) => {
                                 Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS })
                             }
-                            _ => {
-                                match (fragment, extra_fragment.clone()) {
-                                    (Some(fragment), Some(_)) => {
-                                        // Shouldn't happen but who knows?
-                                        Ok((res, Some(fragment)))
-                                    }
-                                    (fragment, None) => Ok((res, fragment)),
-                                    (None, fragment) => {
-                                        Ok((res, fragment.map(UrlFragment::UserWritten)))
-                                    }
-                                }
-                            }
+                            _ => Ok((res, def_id)),
                         }
                     }),
                 };
@@ -1633,15 +1403,13 @@ fn resolve_with_disambiguator(
                 let len = candidates.iter().filter(|res| res.is_ok()).count();
 
                 if len == 0 {
-                    resolution_failure(
+                    return resolution_failure(
                         self,
                         diag,
                         path_str,
                         disambiguator,
                         candidates.into_iter().filter_map(|res| res.err()).collect(),
                     );
-                    // this could just be a normal link
-                    return None;
                 }
 
                 if len == 1 {
@@ -1649,38 +1417,17 @@ fn resolve_with_disambiguator(
                 } else if len == 2 && is_derive_trait_collision(&candidates) {
                     Some(candidates.type_ns.unwrap())
                 } else {
-                    if is_derive_trait_collision(&candidates) {
-                        candidates.macro_ns = Err(ResolutionFailure::Dummy);
-                    }
+                    let ignore_macro = is_derive_trait_collision(&candidates);
                     // If we're reporting an ambiguity, don't mention the namespaces that failed
-                    let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
+                    let mut candidates =
+                        candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
+                    if ignore_macro {
+                        candidates.macro_ns = None;
+                    }
                     ambiguity_error(self.cx, diag, path_str, candidates.present_items().collect());
                     None
                 }
             }
-            Some(MacroNS) => {
-                match self.resolve_macro(path_str, item_id, base_node) {
-                    Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
-                    Err(mut kind) => {
-                        // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
-                        for ns in [TypeNS, ValueNS] {
-                            if let Some(res) = self.check_full_res(
-                                ns,
-                                path_str,
-                                item_id,
-                                base_node,
-                                extra_fragment,
-                            ) {
-                                kind =
-                                    ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
-                                break;
-                            }
-                        }
-                        resolution_failure(self, diag, path_str, disambiguator, smallvec![kind]);
-                        None
-                    }
-                }
-            }
         }
     }
 }
@@ -1968,8 +1715,9 @@ fn resolution_failure(
     path_str: &str,
     disambiguator: Option<Disambiguator>,
     kinds: SmallVec<[ResolutionFailure<'_>; 3]>,
-) {
+) -> Option<(Res, Option<DefId>)> {
     let tcx = collector.cx.tcx;
+    let mut recovered_res = None;
     report_diagnostic(
         tcx,
         BROKEN_INTRA_DOC_LINKS,
@@ -1995,12 +1743,12 @@ fn resolution_failure(
                 }
                 variants_seen.push(variant);
 
-                if let ResolutionFailure::NotResolved {
+                if let ResolutionFailure::NotResolved(UnresolvedPath {
                     item_id,
                     module_id,
                     partial_res,
                     unresolved,
-                } = &mut failure
+                }) = &mut failure
                 {
                     use DefKind::*;
 
@@ -2026,11 +1774,9 @@ fn split(path: &str) -> Option<(&str, &str)> {
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Some(res) =
-                                collector.check_full_res(ns, start, item_id, module_id, &None)
-                            {
+                            if let Ok(res) = collector.resolve(start, ns, item_id, module_id) {
                                 debug!("found partial_res={:?}", res);
-                                *partial_res = Some(res);
+                                *partial_res = Some(full_res(collector.cx.tcx, res));
                                 *unresolved = end.into();
                                 break 'outer;
                             }
@@ -2059,11 +1805,22 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             diag.note(&note);
                         }
 
-                        // If the link has `::` in it, assume it was meant to be an intra-doc link.
-                        // Otherwise, the `[]` might be unrelated.
-                        // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links
                         if !path_str.contains("::") {
-                            diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
+                            if disambiguator.map_or(true, |d| d.ns() == MacroNS)
+                                && let Some(&res) = collector.cx.resolver_caches.all_macro_rules
+                                                             .get(&Symbol::intern(path_str))
+                            {
+                                diag.note(format!(
+                                    "`macro_rules` named `{path_str}` exists in this crate, \
+                                     but it is not in scope at this link's location"
+                                ));
+                                recovered_res = res.try_into().ok().map(|res| (res, None));
+                            } else {
+                                // If the link has `::` in it, assume it was meant to be an
+                                // intra-doc link. Otherwise, the `[]` might be unrelated.
+                                diag.help("to escape `[` and `]` characters, \
+                                           add '\\' before them like `\\[` or `\\]`");
+                            }
                         }
 
                         continue;
@@ -2130,7 +1887,6 @@ fn split(path: &str) -> Option<(&str, &str)> {
                 }
                 let note = match failure {
                     ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
-                    ResolutionFailure::Dummy => continue,
                     ResolutionFailure::WrongNamespace { res, expected_ns } => {
                         suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
 
@@ -2140,38 +1896,6 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             expected_ns.descr()
                         )
                     }
-                    ResolutionFailure::NoParentItem => {
-                        // FIXME(eddyb) this doesn't belong here, whatever made
-                        // the `ResolutionFailure::NoParentItem` should emit an
-                        // immediate or delayed `span_bug` about the issue.
-                        tcx.sess.delay_span_bug(
-                            sp.unwrap_or(DUMMY_SP),
-                            "intra-doc link missing parent item",
-                        );
-
-                        "BUG: all intra-doc links should have a parent item".to_owned()
-                    }
-                    ResolutionFailure::MalformedGenerics(variant) => match variant {
-                        MalformedGenerics::UnbalancedAngleBrackets => {
-                            String::from("unbalanced angle brackets")
-                        }
-                        MalformedGenerics::MissingType => {
-                            String::from("missing type for generic parameters")
-                        }
-                        MalformedGenerics::HasFullyQualifiedSyntax => {
-                            diag.note("see https://github.com/rust-lang/rust/issues/74563 for more information");
-                            String::from("fully-qualified syntax is unsupported")
-                        }
-                        MalformedGenerics::InvalidPathSeparator => {
-                            String::from("has invalid path separator")
-                        }
-                        MalformedGenerics::TooManyAngleBrackets => {
-                            String::from("too many angle brackets")
-                        }
-                        MalformedGenerics::EmptyAngleBrackets => {
-                            String::from("empty angle brackets")
-                        }
-                    },
                 };
                 if let Some(span) = sp {
                     diag.span_label(span, &note);
@@ -2181,24 +1905,28 @@ fn split(path: &str) -> Option<(&str, &str)> {
             }
         },
     );
+
+    recovered_res
 }
 
-/// Report an anchor failure.
-fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: AnchorFailure) {
-    let (msg, anchor_idx) = match failure {
-        AnchorFailure::MultipleAnchors => {
-            (format!("`{}` contains multiple anchors", diag_info.ori_link), 1)
-        }
-        AnchorFailure::RustdocAnchorConflict(res) => (
-            format!(
-                "`{}` contains an anchor, but links to {kind}s are already anchored",
-                diag_info.ori_link,
-                kind = res.descr(),
-            ),
-            0,
-        ),
-    };
+fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) {
+    let msg = format!("`{}` contains multiple anchors", diag_info.ori_link);
+    anchor_failure(cx, diag_info, &msg, 1)
+}
 
+fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, res: Res) {
+    let (link, kind) = (diag_info.ori_link, res.descr());
+    let msg = format!("`{link}` contains an anchor, but links to {kind}s are already anchored");
+    anchor_failure(cx, diag_info, &msg, 0)
+}
+
+/// Report an anchor failure.
+fn anchor_failure(
+    cx: &DocContext<'_>,
+    diag_info: DiagnosticInfo<'_>,
+    msg: &str,
+    anchor_idx: usize,
+) {
     report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, |diag, sp| {
         if let Some(mut sp) = sp {
             if let Some((fragment_offset, _)) =
@@ -2208,13 +1936,6 @@ fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: A
             }
             diag.span_label(sp, "invalid anchor");
         }
-        if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure {
-            if let Some(sp) = sp {
-                span_bug!(sp, "anchors should be allowed now");
-            } else {
-                bug!("anchors should be allowed now");
-            }
-        }
     });
 }
 
@@ -2235,6 +1956,40 @@ fn disambiguator_error(
     });
 }
 
+fn report_malformed_generics(
+    cx: &DocContext<'_>,
+    diag_info: DiagnosticInfo<'_>,
+    err: MalformedGenerics,
+    path_str: &str,
+) {
+    report_diagnostic(
+        cx.tcx,
+        BROKEN_INTRA_DOC_LINKS,
+        &format!("unresolved link to `{}`", path_str),
+        &diag_info,
+        |diag, sp| {
+            let note = match err {
+                MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets",
+                MalformedGenerics::MissingType => "missing type for generic parameters",
+                MalformedGenerics::HasFullyQualifiedSyntax => {
+                    diag.note(
+                        "see https://github.com/rust-lang/rust/issues/74563 for more information",
+                    );
+                    "fully-qualified syntax is unsupported"
+                }
+                MalformedGenerics::InvalidPathSeparator => "has invalid path separator",
+                MalformedGenerics::TooManyAngleBrackets => "too many angle brackets",
+                MalformedGenerics::EmptyAngleBrackets => "empty angle brackets",
+            };
+            if let Some(span) = sp {
+                diag.span_label(span, note);
+            } else {
+                diag.note(note);
+            }
+        },
+    );
+}
+
 /// Report an ambiguity error, where there were multiple possible resolutions.
 fn ambiguity_error(
     cx: &DocContext<'_>,
@@ -2331,17 +2086,6 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
     });
 }
 
-/// Given an enum variant's res, return the res of its enum and the associated fragment.
-fn handle_variant(
-    cx: &DocContext<'_>,
-    res: Res,
-) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
-    let parent = cx.tcx.parent(res.def_id(cx.tcx));
-    let parent_def = Res::Def(DefKind::Enum, parent);
-    let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
-    Ok((parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id))))
-}
-
 /// Resolve a primitive type or value.
 fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
     if ns != TypeNS {
@@ -2381,7 +2125,7 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
     Some(Res::Primitive(prim))
 }
 
-fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
+fn strip_generics_from_path(path_str: &str) -> Result<String, MalformedGenerics> {
     let mut stripped_segments = vec![];
     let mut path = path_str.chars().peekable();
     let mut segment = Vec::new();
@@ -2396,9 +2140,7 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<
                         stripped_segments.push(stripped_segment);
                     }
                 } else {
-                    return Err(ResolutionFailure::MalformedGenerics(
-                        MalformedGenerics::InvalidPathSeparator,
-                    ));
+                    return Err(MalformedGenerics::InvalidPathSeparator);
                 }
             }
             '<' => {
@@ -2406,14 +2148,10 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<
 
                 match path.next() {
                     Some('<') => {
-                        return Err(ResolutionFailure::MalformedGenerics(
-                            MalformedGenerics::TooManyAngleBrackets,
-                        ));
+                        return Err(MalformedGenerics::TooManyAngleBrackets);
                     }
                     Some('>') => {
-                        return Err(ResolutionFailure::MalformedGenerics(
-                            MalformedGenerics::EmptyAngleBrackets,
-                        ));
+                        return Err(MalformedGenerics::EmptyAngleBrackets);
                     }
                     Some(chr) => {
                         segment.push(chr);
@@ -2441,16 +2179,10 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<
 
     let stripped_path = stripped_segments.join("::");
 
-    if !stripped_path.is_empty() {
-        Ok(stripped_path)
-    } else {
-        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::MissingType))
-    }
+    if !stripped_path.is_empty() { Ok(stripped_path) } else { Err(MalformedGenerics::MissingType) }
 }
 
-fn strip_generics_from_path_segment(
-    segment: Vec<char>,
-) -> Result<String, ResolutionFailure<'static>> {
+fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> {
     let mut stripped_segment = String::new();
     let mut param_depth = 0;
 
@@ -2465,9 +2197,7 @@ fn strip_generics_from_path_segment(
             if latest_generics_chunk.contains(" as ") {
                 // The segment tries to use fully-qualified syntax, which is currently unsupported.
                 // Give a helpful error message instead of completely ignoring the angle brackets.
-                return Err(ResolutionFailure::MalformedGenerics(
-                    MalformedGenerics::HasFullyQualifiedSyntax,
-                ));
+                return Err(MalformedGenerics::HasFullyQualifiedSyntax);
             }
         } else {
             if param_depth == 0 {
@@ -2482,6 +2212,6 @@ fn strip_generics_from_path_segment(
         Ok(stripped_segment)
     } else {
         // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
-        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::UnbalancedAngleBrackets))
+        Err(MalformedGenerics::UnbalancedAngleBrackets)
     }
 }
index 07d05cab1d1d7bbfa719c3cca89ca7a8bb0ccde3..6f9912e71c506ec06f1232be667573e06e3bcb3c 100644 (file)
@@ -40,6 +40,7 @@
         traits_in_scope: Default::default(),
         all_traits: Default::default(),
         all_trait_impls: Default::default(),
+        all_macro_rules: Default::default(),
         document_private_items,
     };
 
@@ -64,7 +65,7 @@
         traits_in_scope: link_resolver.traits_in_scope,
         all_traits: Some(link_resolver.all_traits),
         all_trait_impls: Some(link_resolver.all_trait_impls),
-        all_macro_rules: link_resolver.resolver.take_all_macro_rules(),
+        all_macro_rules: link_resolver.all_macro_rules,
     }
 }
 
@@ -82,6 +83,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_traits: Vec<DefId>,
     all_trait_impls: Vec<DefId>,
+    all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
     document_private_items: bool,
 }
 
@@ -134,24 +136,21 @@ fn process_extern_impls(&mut self) {
                 // using privacy, private traits and impls from other crates are never documented in
                 // the current crate, and links in their doc comments are not resolved.
                 for &def_id in &all_traits {
-                    if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
+                    if self.resolver.cstore().visibility_untracked(def_id).is_public() {
                         self.resolve_doc_links_extern_impl(def_id, false);
                     }
                 }
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
-                    if self.resolver.cstore().visibility_untracked(trait_def_id)
-                        == Visibility::Public
+                    if self.resolver.cstore().visibility_untracked(trait_def_id).is_public()
                         && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| {
-                            self.resolver.cstore().visibility_untracked(ty_def_id)
-                                == Visibility::Public
+                            self.resolver.cstore().visibility_untracked(ty_def_id).is_public()
                         })
                     {
                         self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
                 }
                 for (ty_def_id, impl_def_id) in all_inherent_impls {
-                    if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
-                    {
+                    if self.resolver.cstore().visibility_untracked(ty_def_id).is_public() {
                         self.resolve_doc_links_extern_impl(impl_def_id, true);
                     }
                 }
@@ -173,35 +172,50 @@ fn process_extern_impls(&mut self) {
     }
 
     fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
-        self.resolve_doc_links_extern_outer(def_id, def_id);
+        self.resolve_doc_links_extern_outer_fixme(def_id, def_id);
         let assoc_item_def_ids = Vec::from_iter(
             self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
         );
         for assoc_def_id in assoc_item_def_ids {
-            if !is_inherent
-                || self.resolver.cstore().visibility_untracked(assoc_def_id) == Visibility::Public
+            if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public()
             {
-                self.resolve_doc_links_extern_outer(assoc_def_id, def_id);
+                self.resolve_doc_links_extern_outer_fixme(assoc_def_id, def_id);
             }
         }
     }
 
-    fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
+    // FIXME: replace all uses with `resolve_doc_links_extern_outer` to actually resolve links, not
+    // just add traits in scope. This may be expensive and require benchmarking and optimization.
+    fn resolve_doc_links_extern_outer_fixme(&mut self, def_id: DefId, scope_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        // FIXME: actually resolve links, not just add traits in scope.
         if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
             self.add_traits_in_scope(parent_id);
         }
     }
 
+    fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+            return;
+        }
+        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let parent_scope = ParentScope::module(
+            self.resolver.get_nearest_non_block_module(
+                self.resolver.opt_parent(scope_id).unwrap_or(scope_id),
+            ),
+            self.resolver,
+        );
+        self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
+    }
+
     fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        // FIXME: actually resolve links, not just add traits in scope.
-        self.add_traits_in_scope(def_id);
+        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver);
+        self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
     }
 
     fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
@@ -255,9 +269,16 @@ fn resolve_doc_links(&mut self, attrs: Attributes, parent_scope: ParentScope<'ra
                         }
                     }
 
-                    // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics.
-                    if (need_assoc || !any_resolved) && pinfo.path_str.contains("::") {
-                        need_traits_in_scope = true;
+                    // Resolve all prefixes for type-relative resolution or for diagnostics.
+                    if need_assoc || !any_resolved {
+                        let mut path = &pinfo.path_str[..];
+                        while let Some(idx) = path.rfind("::") {
+                            path = &path[..idx];
+                            need_traits_in_scope = true;
+                            for ns in [TypeNS, ValueNS, MacroNS] {
+                                self.resolve_and_cache(path, ns, &parent_scope);
+                            }
+                        }
                     }
                 }
             }
@@ -279,7 +300,7 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
 
         for child in self.resolver.module_children_or_reexports(module_id) {
             // This condition should give a superset of `denied` from `fn clean_use_statement`.
-            if child.vis == Visibility::Public
+            if child.vis.is_public()
                 || self.document_private_items
                     && child.vis != Visibility::Restricted(module_id)
                     && module_id.is_local()
@@ -343,8 +364,10 @@ fn visit_item(&mut self, item: &ast::Item) {
                     self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
                 }
                 ItemKind::MacroDef(macro_def) if macro_def.macro_rules => {
-                    self.parent_scope.macro_rules =
+                    let (macro_rules_scope, res) =
                         self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id));
+                    self.parent_scope.macro_rules = macro_rules_scope;
+                    self.all_macro_rules.insert(item.ident.name, res);
                 }
                 _ => {}
             }
index d245c3750ec08d64e153f08e16bdadbf5aed33fa..3b7ca7dc3c5193bd2551f33ba1a34bddd00bf961 100644 (file)
@@ -53,9 +53,7 @@
             while let Some(did) = parent {
                 attr_buf.extend(
                     cx.tcx
-                        .get_attrs(did)
-                        .iter()
-                        .filter(|attr| attr.has_name(sym::doc))
+                        .get_attrs(did, sym::doc)
                         .filter(|attr| {
                             if let Some([attr]) = attr.meta_item_list().as_deref() {
                                 attr.has_name(sym::cfg)
index 0da490f3cd6c8a3b14b9662f09eacff2978c2395..e0aed1e1ed434cf228db4581906b8a68737093ac 100644 (file)
@@ -303,7 +303,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         // Run call-finder on all items
         let mut calls = FxHashMap::default();
         let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
-        tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+        tcx.hir().deep_visit_all_item_likes(&mut finder);
 
         // Sort call locations within a given file in document order
         for fn_calls in calls.values_mut() {
index 593484fc1596707406b0b0b45b97feb08d2a1bfc..47848665966fc7393cb6f898077994f6dec2b591 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 593484fc1596707406b0b0b45b97feb08d2a1bfc
+Subproject commit 47848665966fc7393cb6f898077994f6dec2b591
index 17b3859a77b645a0053f77263f12484df818418f..eb2c8e5bae1c43c7b81c6d5a641f11326f1386a5 100644 (file)
@@ -9,7 +9,7 @@
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 14;
+pub const FORMAT_VERSION: u32 = 15;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -391,6 +391,14 @@ pub enum WherePredicate {
         #[serde(rename = "type")]
         type_: Type,
         bounds: Vec<GenericBound>,
+        /// Used for Higher-Rank Trait Bounds (HRTBs)
+        /// ```plain
+        /// where for<'a> &'a T: Iterator,"
+        ///       ^^^^^^^
+        ///       |
+        ///       this part
+        /// ```
+        generic_params: Vec<GenericParamDef>,
     },
     RegionPredicate {
         lifetime: String,
@@ -408,7 +416,13 @@ pub enum GenericBound {
     TraitBound {
         #[serde(rename = "trait")]
         trait_: Type,
-        /// Used for HRTBs
+        /// Used for Higher-Rank Trait Bounds (HRTBs)
+        /// ```plain
+        /// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
+        ///          ^^^^^^^^^^^
+        ///          |
+        ///          this part
+        /// ```
         generic_params: Vec<GenericParamDef>,
         modifier: TraitBoundModifier,
     },
@@ -487,6 +501,13 @@ pub enum Type {
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub struct FunctionPointer {
     pub decl: FnDecl,
+    /// Used for Higher-Rank Trait Bounds (HRTBs)
+    /// ```plain
+    /// for<'c> fn(val: &'c i32) -> i32
+    /// ^^^^^^^
+    ///       |
+    ///       this part
+    /// ```
     pub generic_params: Vec<GenericParamDef>,
     pub header: Header,
 }
index a87152e0321b9b4a658f53e1772894c8e471b904..f70caea2fb9e26417730742ec11bff205e4f536a 100644 (file)
@@ -6,21 +6,21 @@
 use std::arch::asm;
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64() {
     asm!("", clobber_abi("sysv64"));
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64() {
     asm!("", clobber_abi("win64"));
 }
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64_edx() {
     let foo: i32;
@@ -28,7 +28,7 @@ pub unsafe fn clobber_sysv64_edx() {
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{tmm0},~{tmm1},~{tmm2},~{tmm3},~{tmm4},~{tmm5},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64_edx() {
     let foo: i32;
index 8845cfbe76792a0e0a25c7b21d0b5188607c61e0..ac30e18ec52346791a68bf118c4dc26bc966bd5b 100644 (file)
@@ -6,6 +6,13 @@
 
 use std::arch::asm;
 
+// CHECK-LABEL: @amx_clobber
+// base: call void asm sideeffect inteldialect "", "~{tmm0}"()
+#[no_mangle]
+pub unsafe fn amx_clobber() {
+    asm!("", out("tmm0") _, options(nostack, nomem, preserves_flags));
+}
+
 // CHECK-LABEL: @avx512_clobber
 // base: call void asm sideeffect inteldialect "", "~{xmm31}"()
 // avx512: call float asm sideeffect inteldialect "", "=&{xmm31}"()
index b13d576295c605f968df697caaf99d9c48be21e4..381f11ff1efcc0265fef35d44600c28a503e2918 100644 (file)
@@ -22,7 +22,7 @@ fn main() {
 }
 
 // Here we check that local debuginfo is mapped correctly.
-// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd"
+// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: ""
 
 // And here that debuginfo from other crates are expanded to absolute paths.
 // CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: ""
diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs
new file mode 100644 (file)
index 0000000..fde9b0f
--- /dev/null
@@ -0,0 +1,54 @@
+// compile-flags: -C opt-level=3 --edition=2021
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(portable_simd)]
+
+use std::simd::Simd;
+const N: usize = 8;
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_simd
+pub fn wider_reduce_simd(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <8 x i8>
+    // CHECK-SAME: to <8 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    let x: Simd<u16, N> = x.cast();
+    x.reduce_sum()
+}
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_loop
+pub fn wider_reduce_loop(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <8 x i8>
+    // CHECK-SAME: to <8 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    let mut sum = 0_u16;
+    for i in 0..N {
+        sum += u16::from(x[i]);
+    }
+    sum
+}
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_iter
+pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <8 x i8>
+    // CHECK-SAME: to <8 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    x.as_array().iter().copied().map(u16::from).sum()
+}
+
+// This iterator one is the most interesting, as it's the one
+// which used to not auto-vectorize due to a suboptimality in the
+// `<array::IntoIter as Iterator>::fold` implementation.
+
+#[no_mangle]
+// CHECK-LABEL: @wider_reduce_into_iter
+pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 {
+    // CHECK: zext <8 x i8>
+    // CHECK-SAME: to <8 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    x.to_array().into_iter().map(u16::from).sum()
+}
index 398937a04c9236bfade8d7defb02ae9858665700..e817d5715a189c9d321f83cb18369e69056a8295 100644 (file)
@@ -1,22 +1,27 @@
 // compile-flags: -C panic=abort
 
-// Test that `nounwind` atributes are not applied to `C-unwind` extern functions
-// even when the code is compiled with `panic=abort`.
+// Test that `nounwind` atributes are also applied to extern `C-unwind` Rust functions
+// when the code is compiled with `panic=abort`.
 
 #![crate_type = "lib"]
 #![feature(c_unwind)]
 
-extern "C-unwind" {
-    fn may_unwind();
-}
-
-// CHECK: @rust_item_that_can_unwind() unnamed_addr #0
+// CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]]
 #[no_mangle]
 pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() {
+    // CHECK: call void @_ZN4core9panicking15panic_no_unwind
     may_unwind();
 }
 
+extern "C-unwind" {
+    // CHECK: @may_unwind() unnamed_addr [[ATTR1:#[0-9]+]]
+    fn may_unwind();
+}
+
 // Now, make sure that the LLVM attributes for this functions are correct.  First, make
 // sure that the first item is correctly marked with the `nounwind` attribute:
 //
-// CHECK-NOT: attributes #0 = { {{.*}}nounwind{{.*}} }
+// CHECK: attributes [[ATTR0]] = { {{.*}}nounwind{{.*}} }
+//
+// Now, check that foreign item is correctly marked without the `nounwind` attribute.
+// CHECK-NOT: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}} }
index 46f5e5e20655bd43d7fb50b6df1957a010396e74..450157e64284f74cac6041918f60cdc3e56e8ccb 100644 (file)
@@ -4,22 +4,55 @@
   fn g() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:12:5: 12:12
++     let mut _2: fn() {main};             // in scope 0 at $DIR/cycle.rs:12:5: 12:12
++     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
++     scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
++         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
++         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++         }
++     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:12:5: 12:12
-          _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:12:5: 12:6
-                                           // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) }
+-         _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12
++         StorageLive(_2);                 // scope 0 at $DIR/cycle.rs:12:5: 12:12
++         _2 = main;                       // scope 0 at $DIR/cycle.rs:12:5: 12:12
                                            // mir::Constant
+-                                          // + span: $DIR/cycle.rs:12:5: 12:6
+-                                          // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) }
+-                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:12:7: 12:11
                                            // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
++         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:12:5: 12:12
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:12:12: 12:13
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:11:8: 13:2
           return;                          // scope 0 at $DIR/cycle.rs:13:2: 13:2
++     }
++ 
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     }
++ 
++     bb3 (cleanup): {
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     }
++ 
++     bb4: {
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
index c8d1448d949d44707efac924bc109e865a084de7..5e2f70799e41e40d86584e3d6c8ba7b8ff6120d7 100644 (file)
@@ -4,22 +4,72 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:17:5: 17:9
++     let mut _2: fn() {g};                // in scope 0 at $DIR/cycle.rs:17:5: 17:9
++     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
++     scope 1 (inlined f::<fn() {g}>) {    // at $DIR/cycle.rs:17:5: 17:9
++         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
++         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
++         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
++             scope 3 (inlined g) {        // at $SRC_DIR/core/src/ops/function.rs:LL:COL
++                 let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12
++                 scope 4 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
++                     debug g => _6;       // in scope 4 at $DIR/cycle.rs:5:6: 5:7
++                     let _7: ();          // in scope 4 at $DIR/cycle.rs:6:5: 6:8
++                     let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6
++                     scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
++                     }
++                 }
++             }
++         }
++     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:17:5: 17:9
-          _1 = f::<fn() {g}>(g) -> bb1;    // scope 0 at $DIR/cycle.rs:17:5: 17:9
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:17:5: 17:6
-                                           // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) }
+-         _1 = f::<fn() {g}>(g) -> bb1;    // scope 0 at $DIR/cycle.rs:17:5: 17:9
++         StorageLive(_2);                 // scope 0 at $DIR/cycle.rs:17:5: 17:9
++         _2 = g;                          // scope 0 at $DIR/cycle.rs:17:5: 17:9
                                            // mir::Constant
+-                                          // + span: $DIR/cycle.rs:17:5: 17:6
+-                                          // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) }
+-                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:17:7: 17:8
                                            // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
++         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
++         StorageLive(_7);                 // scope 4 at $DIR/cycle.rs:6:5: 6:8
++         StorageLive(_8);                 // scope 4 at $DIR/cycle.rs:6:5: 6:6
++         _8 = &_6;                        // scope 4 at $DIR/cycle.rs:6:5: 6:6
++         _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
       bb1: {
++         StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:17:5: 17:9
           StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:17:9: 17:10
           _0 = const ();                   // scope 0 at $DIR/cycle.rs:16:11: 18:2
           return;                          // scope 0 at $DIR/cycle.rs:18:2: 18:2
++     }
++ 
++     bb2 (cleanup): {
++         drop(_2) -> bb3;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
++     }
++ 
++     bb3 (cleanup): {
++         resume;                          // scope 1 at $DIR/cycle.rs:5:1: 7:2
++     }
++ 
++     bb4: {
++         StorageDead(_8);                 // scope 4 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_7);                 // scope 4 at $DIR/cycle.rs:6:8: 6:9
++         StorageDead(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
++         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
++         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/dyn-trait.rs b/src/test/mir-opt/inline/dyn-trait.rs
new file mode 100644 (file)
index 0000000..6a46e1e
--- /dev/null
@@ -0,0 +1,35 @@
+#![crate_type = "lib"]
+
+use std::fmt::Debug;
+
+pub trait Cache {
+    type V: Debug;
+
+    fn store_nocache(&self);
+}
+
+pub trait Query {
+    type V;
+    type C: Cache<V = Self::V>;
+
+    fn cache<T>(s: &T) -> &Self::C;
+}
+
+// EMIT_MIR dyn_trait.mk_cycle.Inline.diff
+#[inline(always)]
+pub fn mk_cycle<V: Debug>(c: &dyn Cache<V = V>) {
+    c.store_nocache()
+}
+
+// EMIT_MIR dyn_trait.try_execute_query.Inline.diff
+#[inline(always)]
+pub fn try_execute_query<C: Cache>(c: &C) {
+    mk_cycle(c)
+}
+
+// EMIT_MIR dyn_trait.get_query.Inline.diff
+#[inline(always)]
+pub fn get_query<Q: Query, T>(t: &T) {
+    let c = Q::cache(t);
+    try_execute_query(c)
+}
diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
new file mode 100644 (file)
index 0000000..953d7b8
--- /dev/null
@@ -0,0 +1,62 @@
+- // MIR for `get_query` before Inline
++ // MIR for `get_query` after Inline
+  
+  fn get_query(_1: &T) -> () {
+      debug t => _1;                       // in scope 0 at $DIR/dyn-trait.rs:32:31: 32:32
+      let mut _0: ();                      // return place in scope 0 at $DIR/dyn-trait.rs:32:38: 32:38
+      let _2: &<Q as Query>::C;            // in scope 0 at $DIR/dyn-trait.rs:33:9: 33:10
+      let mut _3: &T;                      // in scope 0 at $DIR/dyn-trait.rs:33:22: 33:23
+      let mut _4: &<Q as Query>::C;        // in scope 0 at $DIR/dyn-trait.rs:34:23: 34:24
+      scope 1 {
+          debug c => _2;                   // in scope 1 at $DIR/dyn-trait.rs:33:9: 33:10
++         scope 2 (inlined try_execute_query::<<Q as Query>::C>) { // at $DIR/dyn-trait.rs:34:5: 34:25
++             debug c => _4;               // in scope 2 at $DIR/dyn-trait.rs:26:36: 26:37
++             let mut _5: &dyn Cache<V = <Q as Query>::V>; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++             let mut _6: &<Q as Query>::C; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++             scope 3 (inlined mk_cycle::<<Q as Query>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16
++                 debug c => _5;           // in scope 3 at $DIR/dyn-trait.rs:20:27: 20:28
++                 let mut _7: &dyn Cache<V = <Q as Query>::V>; // in scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
++             }
++         }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/dyn-trait.rs:33:9: 33:10
+          StorageLive(_3);                 // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23
+          _3 = &(*_1);                     // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23
+          _2 = <Q as Query>::cache::<T>(move _3) -> bb1; // scope 0 at $DIR/dyn-trait.rs:33:13: 33:24
+                                           // mir::Constant
+                                           // + span: $DIR/dyn-trait.rs:33:13: 33:21
+                                           // + user_ty: UserType(0)
+                                           // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/dyn-trait.rs:33:23: 33:24
+          StorageLive(_4);                 // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24
+          _4 = &(*_2);                     // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24
+-         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn-trait.rs:34:5: 34:25
++         StorageLive(_5);                 // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++         StorageLive(_6);                 // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++         _6 = _4;                         // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++         _5 = move _6 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++         StorageDead(_6);                 // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
++         StorageLive(_7);                 // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
++         _7 = _5;                         // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
++         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
+                                           // mir::Constant
+-                                          // + span: $DIR/dyn-trait.rs:34:5: 34:22
+-                                          // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
++                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2: {
++         StorageDead(_7);                 // scope 3 at $DIR/dyn-trait.rs:21:21: 21:22
++         StorageDead(_5);                 // scope 2 at $DIR/dyn-trait.rs:27:15: 27:16
+          StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:34:24: 34:25
+          StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:35:1: 35:2
+          return;                          // scope 0 at $DIR/dyn-trait.rs:35:2: 35:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
new file mode 100644 (file)
index 0000000..2730932
--- /dev/null
@@ -0,0 +1,23 @@
+- // MIR for `mk_cycle` before Inline
++ // MIR for `mk_cycle` after Inline
+  
+  fn mk_cycle(_1: &dyn Cache<V = V>) -> () {
+      debug c => _1;                       // in scope 0 at $DIR/dyn-trait.rs:20:27: 20:28
+      let mut _0: ();                      // return place in scope 0 at $DIR/dyn-trait.rs:20:49: 20:49
+      let mut _2: &dyn Cache<V = V>;       // in scope 0 at $DIR/dyn-trait.rs:21:5: 21:22
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22
+          _2 = &(*_1);                     // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22
+          _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22
+                                           // mir::Constant
+                                           // + span: $DIR/dyn-trait.rs:21:7: 21:20
+                                           // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:21:21: 21:22
+          return;                          // scope 0 at $DIR/dyn-trait.rs:22:2: 22:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
new file mode 100644 (file)
index 0000000..93bba58
--- /dev/null
@@ -0,0 +1,37 @@
+- // MIR for `try_execute_query` before Inline
++ // MIR for `try_execute_query` after Inline
+  
+  fn try_execute_query(_1: &C) -> () {
+      debug c => _1;                       // in scope 0 at $DIR/dyn-trait.rs:26:36: 26:37
+      let mut _0: ();                      // return place in scope 0 at $DIR/dyn-trait.rs:26:43: 26:43
+      let mut _2: &dyn Cache<V = <C as Cache>::V>; // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+      let mut _3: &C;                      // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
++     scope 1 (inlined mk_cycle::<<C as Cache>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16
++         debug c => _2;                   // in scope 1 at $DIR/dyn-trait.rs:20:27: 20:28
++         let mut _4: &dyn Cache<V = <C as Cache>::V>; // in scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
++     }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+          StorageLive(_3);                 // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+          _3 = &(*_1);                     // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+          _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+          StorageDead(_3);                 // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15
+-         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:27:5: 27:16
++         StorageLive(_4);                 // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
++         _4 = _2;                         // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
++         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
+                                           // mir::Constant
+-                                          // + span: $DIR/dyn-trait.rs:27:5: 27:13
+-                                          // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
++                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
++         StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:21:21: 21:22
+          StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:27:15: 27:16
+          return;                          // scope 0 at $DIR/dyn-trait.rs:28:2: 28:2
+      }
+  }
+  
index fddf7e6e1f0a7a3119972a5a9cce8929cbd1658c..267f53a8dfe7b4f7b57b6fb1ff6872595b20303a 100644 (file)
@@ -4,20 +4,13 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11
       let _1: ();                          // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+     scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31
-+         }
-+     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
--         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline-cycle-generic.rs:31:9: 31:28
+          _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
                                            // mir::Constant
--                                          // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
-+                                          // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26
-+                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(Scalar(<ZST>)) }
+                                           // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
       }
   
       bb1: {
index 86e6d9e756c51d9946e1828195a4de2c090699ed..c3b82aa853c786e757577df794518aa2a7c6ca6a 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_borrowck::consumers::BodyWithBorrowckFacts;
 use rustc_driver::Compilation;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_hir::def::DefKind;
 use rustc_interface::interface::Compiler;
 use rustc_interface::{Config, Queries};
 use rustc_middle::ty::query::query_values::mir_borrowck;
@@ -65,11 +65,34 @@ fn after_analysis<'tcx>(
         queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
             // Collect definition ids of MIR bodies.
             let hir = tcx.hir();
-            let mut visitor = HirVisitor { bodies: Vec::new() };
-            hir.visit_all_item_likes(&mut visitor);
+            let mut bodies = Vec::new();
+
+            let crate_items = tcx.hir_crate_items(());
+            for id in crate_items.items() {
+                if matches!(tcx.def_kind(id.def_id), DefKind::Fn) {
+                    bodies.push(id.def_id);
+                }
+            }
+
+            for id in crate_items.trait_items() {
+                if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
+                    let trait_item = hir.trait_item(id);
+                    if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
+                        if let rustc_hir::TraitFn::Provided(_) = trait_fn {
+                            bodies.push(trait_item.def_id);
+                        }
+                    }
+                }
+            }
+
+            for id in crate_items.impl_items() {
+                if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
+                    bodies.push(id.def_id);
+                }
+            }
 
             // Trigger borrow checking of all bodies.
-            for def_id in visitor.bodies {
+            for def_id in bodies {
                 let _ = tcx.optimized_mir(def_id);
             }
 
@@ -121,35 +144,6 @@ fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tc
     original_mir_borrowck(tcx, def_id)
 }
 
-/// Visitor that collects all body definition ids mentioned in the program.
-struct HirVisitor {
-    bodies: Vec<LocalDefId>,
-}
-
-impl<'tcx> ItemLikeVisitor<'tcx> for HirVisitor {
-    fn visit_item(&mut self, item: &rustc_hir::Item) {
-        if let rustc_hir::ItemKind::Fn(..) = item.kind {
-            self.bodies.push(item.def_id);
-        }
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &rustc_hir::TraitItem) {
-        if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
-            if let rustc_hir::TraitFn::Provided(_) = trait_fn {
-                self.bodies.push(trait_item.def_id);
-            }
-        }
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &rustc_hir::ImplItem) {
-        if let rustc_hir::ImplItemKind::Fn(..) = impl_item.kind {
-            self.bodies.push(impl_item.def_id);
-        }
-    }
-
-    fn visit_foreign_item(&mut self, _foreign_item: &rustc_hir::ForeignItem) {}
-}
-
 /// Pull MIR bodies stored in the thread-local.
 fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
     MIR_BODIES.with(|state| {
diff --git a/src/test/run-make/remap-path-prefix-dwarf/Makefile b/src/test/run-make/remap-path-prefix-dwarf/Makefile
new file mode 100644 (file)
index 0000000..561a343
--- /dev/null
@@ -0,0 +1,77 @@
+# This test makes sure that --remap-path-prefix has the expected effects on paths in debuginfo.
+# It tests several cases, each of them has a detailed description attached to it.
+
+# ignore-windows
+
+SRC_DIR := $(abspath .)
+SRC_DIR_PARENT := $(abspath ..)
+
+-include ../../run-make-fulldeps/tools.mk
+
+all: \
+  abs_input_outside_working_dir \
+  rel_input_remap_working_dir \
+  rel_input_remap_working_dir_parent \
+  rel_input_remap_working_dir_child \
+  abs_input_inside_working_dir \
+  abs_input_outside_working_dir
+
+# The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path *is* within
+# the working directory of the compiler. We are remapping the path that contains `src`.
+abs_input_inside_working_dir:
+       # We explicitly switch to a directory that *is* a prefix of the directory our
+       # source code is contained in.
+       cd $(SRC_DIR) && $(RUSTC) $(SRC_DIR)/src/quux.rs -o "$(TMPDIR)/abs_input_inside_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix $(SRC_DIR)=REMAPPED
+       # We expect the path to the main source file to be remapped.
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir.rlib | $(CGREP) "REMAPPED/src/quux.rs"
+       # No weird duplication of remapped components (see #78479)
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir.rlib | $(CGREP) -v "REMAPPED/REMAPPED"
+
+# The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path is *not* within
+# the working directory of the compiler. We are remapping both the path that contains `src` and
+# the working directory to the same thing. This setup corresponds to a workaround that is needed
+# when trying to remap everything to something that looks like a local path.
+# Relative paths are interpreted as relative to the compiler's working directory (e.g. in
+# debuginfo). If we also remap the working directory, the compiler strip it from other paths so
+# that the final outcome is the desired one again.
+abs_input_outside_working_dir:
+       # We explicitly switch to a directory that is *not* a prefix of the directory our
+       # source code is contained in.
+       cd $(TMPDIR) && $(RUSTC) $(SRC_DIR)/src/quux.rs -o "$(TMPDIR)/abs_input_outside_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix $(SRC_DIR)=REMAPPED --remap-path-prefix $(TMPDIR)=REMAPPED
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_outside_working_dir.rlib | $(CGREP) "REMAPPED/src/quux.rs"
+       # No weird duplication of remapped components (see #78479)
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_outside_working_dir.rlib | $(CGREP) -v "REMAPPED/REMAPPED"
+
+# The compiler is called with a *RELATIVE PATH* as input. We are remapping the working directory of
+# the compiler, which naturally is an implicit prefix of our relative input path. Debuginfo will
+# expand the relative path to an absolute path and we expect the working directory to be remapped
+# in that expansion.
+rel_input_remap_working_dir:
+       cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)=REMAPPED"
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir.rlib" | $(CGREP) "REMAPPED/src/quux.rs"
+       # No weird duplication of remapped components (see #78479)
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
+
+# The compiler is called with a *RELATIVE PATH* as input. We are remapping a *SUB-DIRECTORY* of the
+# compiler's working directory. This test makes sure that that directory is remapped even though it
+# won't actually show up in this form in the compiler's SourceMap and instead is only constructed
+# on demand during debuginfo generation.
+rel_input_remap_working_dir_child:
+       cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)/src=REMAPPED"
+       # We expect `src/quux.rs` to have been remapped to `REMAPPED/quux.rs`.
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) "REMAPPED/quux.rs"
+       # We don't want to find the path that we just remapped anywhere in the DWARF
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) -v "$(SRC_DIR)/src"
+       # No weird duplication of remapped components (see #78479)
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
+
+# The compiler is called with a *RELATIVE PATH* as input. We are remapping a *PARENT DIRECTORY* of
+# the compiler's working directory.
+rel_input_remap_working_dir_parent:
+       cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR_PARENT)=REMAPPED"
+       # We expect `src/quux.rs` to have been remapped to `REMAPPED/remap-path-prefix-dwarf/src/quux.rs`.
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) "REMAPPED/remap-path-prefix-dwarf/src/quux.rs"
+       # We don't want to find the path that we just remapped anywhere in the DWARF
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) -v "$(SRC_DIR_PARENT)"
+       # No weird duplication of remapped components (see #78479)
+       "$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
diff --git a/src/test/run-make/remap-path-prefix-dwarf/src/quux.rs b/src/test/run-make/remap-path-prefix-dwarf/src/quux.rs
new file mode 100644 (file)
index 0000000..38d5ef6
--- /dev/null
@@ -0,0 +1,5 @@
+#![crate_type = "rlib"]
+
+pub fn foo() {
+    println!("foo");
+}
index aca8390dfb3d5d914605fc3182fbd6f26babfd90..d0b3175114cce90897c05097cdf11b0247062f35 100644 (file)
@@ -45,3 +45,37 @@ goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
 wait-for: "#crate-search"
 assert-property: ("#crate-search", {"value": "lib2"})
 assert-false: "#results .externcrate"
+
+// Checking that the text for the "title" is correct (the "All" comes from the "<select>").
+assert-text: ("#search-settings", "Results for test in All", STARTS_WITH)
+
+// Checking the display of the crate filter.
+// We start with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+timeout: 2000
+wait-for: "#crate-search"
+assert-css: ("#crate-search", {
+    "border": "1px solid rgb(224, 224, 224)",
+    "color": "rgb(0, 0, 0)",
+    "background-color": "rgb(255, 255, 255)",
+})
+
+// We now check the dark theme.
+click: "#settings-menu"
+wait-for: "#settings"
+click: "#theme-dark"
+wait-for-css: ("#crate-search", {
+    "border": "1px solid rgb(240, 240, 240)",
+    "color": "rgb(17, 17, 17)",
+    "background-color": "rgb(240, 240, 240)",
+})
+
+// And finally we check the ayu theme.
+click: "#theme-ayu"
+wait-for-css: ("#crate-search", {
+    "border": "1px solid rgb(66, 76, 87)",
+    "color": "rgb(197, 197, 197)",
+    "background-color": "rgb(20, 25, 32)",
+})
index 6c4611b1cb2a613f01906a3d222a7d10234f7fbe..9a9c45a9b7fe5b7f818df3f64338afd30c295dda 100644 (file)
@@ -5,36 +5,25 @@ assert-false: "#settings"
 // We now click on the settings button.
 click: "#settings-menu"
 wait-for: "#settings"
-assert: "#main-content.hidden"
 assert-css: ("#settings", {"display": "block"})
 // Let's close it by clicking on the same button.
 click: "#settings-menu"
-assert-false: "#alternative-display #settings"
-assert: "#not-displayed #settings"
-assert: "#main-content:not(.hidden)"
-
-// Let's open and then close it again with the "close settings" button.
-click: "#settings-menu"
-wait-for: "#alternative-display #settings"
-assert: "#main-content.hidden"
-click: "#back"
-wait-for: "#not-displayed #settings"
-assert: "#main-content:not(.hidden)"
+wait-for-css: ("#settings", {"display": "none"})
 
 // Let's check that pressing "ESCAPE" is closing it.
 click: "#settings-menu"
-wait-for: "#alternative-display #settings"
+wait-for-css: ("#settings", {"display": "block"})
 press-key: "Escape"
-wait-for: "#not-displayed #settings"
-assert: "#main-content:not(.hidden)"
+wait-for-css: ("#settings", {"display": "none"})
 
 // Let's click on it when the search results are displayed.
 focus: ".search-input"
 write: "test"
 wait-for: "#alternative-display #search"
 click: "#settings-menu"
-wait-for: "#alternative-display #settings"
-assert: "#not-displayed #search"
+wait-for-css: ("#settings", {"display": "block"})
+// Ensure that the search is still displayed.
+wait-for: "#alternative-display #search"
 assert: "#main-content.hidden"
 
 // Now let's check the content of the settings menu.
@@ -65,3 +54,8 @@ assert: ".setting-line.hidden #theme"
 // We check their text as well.
 assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
 assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
+
+// Now we go to the settings page to check that the CSS is loaded as expected.
+goto: file://|DOC_PATH|/settings.html
+wait-for: "#settings"
+assert-css: (".setting-line .toggle", {"width": "45px", "margin-right": "20px"})
index 42d945d0eb81700a5c9d09771cc637ff3454ced6..37a7c1662949dd85cdec6b8f492917b14710abd8 100644 (file)
@@ -12,15 +12,3 @@ assert-css: ("#help", {"display": "flex"})
 assert-false: "#help.hidden"
 press-key: "Escape"
 assert-css: ("#help.hidden", {"display": "none"})
-// Check for the themes list.
-assert-css: ("#theme-choices", {"display": "none"})
-press-key: "t"
-assert-css: ("#theme-choices", {"display": "block"})
-press-key: "t"
-// We ensure that 't' hides back the menu.
-assert-css: ("#theme-choices", {"display": "none"})
-press-key: "t"
-assert-css: ("#theme-choices", {"display": "block"})
-press-key: "Escape"
-// We ensure that 'Escape' hides the menu too.
-assert-css: ("#theme-choices", {"display": "none"})
index 9706511ea19c398fda3051fc9651f0f53a27c1e0..fb1c37ae68e74d982e695da799756c90c66630a4 100644 (file)
@@ -1,12 +1,21 @@
 // Ensures that the theme change is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
-click: "#theme-picker"
-click: "#theme-choices > button:first-child"
-// should be the ayu theme so let's check the color
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+click: "#settings-menu"
+wait-for: "#theme-ayu"
+click: "#theme-ayu"
+// should be the ayu theme so let's check the color.
 wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" })
-click: "#theme-choices > button:last-child"
-// should be the light theme so let's check the color
+assert-local-storage: { "rustdoc-theme": "ayu" }
+click: "#theme-light"
+// should be the light theme so let's check the color.
 wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+click: "#theme-dark"
+// Should be the dark theme so let's check the color.
+wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
 
 goto: file://|DOC_PATH|/settings.html
 wait-for: "#settings"
diff --git a/src/test/rustdoc-js/prototype.js b/src/test/rustdoc-js/prototype.js
new file mode 100644 (file)
index 0000000..2f1d841
--- /dev/null
@@ -0,0 +1,16 @@
+// exact-check
+
+const QUERY = ['constructor', '__proto__'];
+
+const EXPECTED = [
+    {
+        'others': [],
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        'others': [],
+        'returned': [],
+        'in_args': [],
+    },
+];
diff --git a/src/test/rustdoc-js/prototype.rs b/src/test/rustdoc-js/prototype.rs
new file mode 100644 (file)
index 0000000..5f6d73c
--- /dev/null
@@ -0,0 +1,4 @@
+// The alias needed to be there to reproduce the bug
+// that used to be here.
+#[doc(alias="other_alias")]
+pub fn something_else() {}
diff --git a/src/test/rustdoc-json/fn_pointer/generics.rs b/src/test/rustdoc-json/fn_pointer/generics.rs
new file mode 100644 (file)
index 0000000..646f720
--- /dev/null
@@ -0,0 +1,14 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+// @count generics.json "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][0]" '"val"'
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.inputs[0][1].inner.lifetime" \"\'c\"
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.decl.output" '{ "kind": "primitive", "inner": "i32" }'
+// @count - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].name" \"\'c\"
+// @is - "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type.inner.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32;
index 3b03724b040aea2bcb67882c9ded04d0ca0e8d4d..69150443c29dc9059a3c2c0c10c807bcf3c94844 100644 (file)
@@ -6,6 +6,9 @@
 // @set foo = generic_args.json "$.index[*][?(@.name=='Foo')].id"
 pub trait Foo {}
 
+// @set generic_foo = generic_args.json "$.index[*][?(@.name=='GenericFoo')].id"
+pub trait GenericFoo<'a> {}
+
 // @is - "$.index[*][?(@.name=='generics')].inner.generics.where_predicates" "[]"
 // @count - "$.index[*][?(@.name=='generics')].inner.generics.params[*]" 1
 // @is - "$.index[*][?(@.name=='generics')].inner.generics.params[0].name" '"F"'
@@ -29,19 +32,40 @@ pub fn generics<F: Foo>(f: F) {}
 // @is - "$.index[*][?(@.name=='impl_trait')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $foo
 pub fn impl_trait(f: impl Foo) {}
 
-// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.params[*]" 1
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.params[*]" 3
 // @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].name" '"F"'
 // @is - "$.index[*][?(@.name=='where_clase')].inner.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}'
-// @count - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[*]" 1
+// @count - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[*]" 3
 // @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][0]" '"f"'
 // @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].kind" '"generic"'
 // @is - "$.index[*][?(@.name=='where_clase')].inner.decl.inputs[0][1].inner" '"F"'
-// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[*]" 1
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[*]" 3
+
 // @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F", "kind": "generic"}'
 // @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[*]" 1
 // @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo
-pub fn where_clase<F>(f: F)
+
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.type" '{"inner": "G", "kind": "generic"}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.inner.id" $generic_foo
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[1].bound_predicate.generic_params" "[]"
+
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.lifetime" \"\'b\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.type.inner.type" '{"inner": "H", "kind": "generic"}'
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.inner.id" $foo
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]"
+// @count - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\"
+// @is - "$.index[*][?(@.name=='where_clase')].inner.generics.where_predicates[2].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
+pub fn where_clase<F, G, H>(f: F, g: G, h: H)
 where
     F: Foo,
+    G: for<'a> GenericFoo<'a>,
+    for<'b> &'b H: Foo,
 {
 }
index 84d63c20aa8b5cf35734acba64cb6385e4959721..8490584c1b42b346517dd4f709468cade6dbdcf3 100644 (file)
@@ -10,12 +10,11 @@ macro_rules! before_but_limited_to_module {
     }
 }
 
-/// [before_but_limited_to_module] FIXME: This error should be reported
-// ERROR unresolved link to `before_but_limited_to_module`
-/// [after] FIXME: This error should be reported
-// ERROR unresolved link to `after`
-/// [str] FIXME: This error shouldn not be reported
-//~^ ERROR `str` is both a builtin type and a macro
+/// [before_but_limited_to_module]
+//~^ ERROR unresolved link to `before_but_limited_to_module`
+/// [after]
+//~^ ERROR unresolved link to `after`
+/// [str]
 fn check() {}
 
 macro_rules! after {
index 4b984f4f6c01605c2f2dc63806155945ae4f4ec7..8e17323fddebbdd4e1a8b0dcc0041c211a9ab430 100644 (file)
@@ -1,22 +1,23 @@
-error: `str` is both a builtin type and a macro
-  --> $DIR/macro-rules-error.rs:17:6
+error: unresolved link to `before_but_limited_to_module`
+  --> $DIR/macro-rules-error.rs:13:6
    |
-LL | /// [str] FIXME: This error shouldn not be reported
-   |      ^^^ ambiguous link
+LL | /// [before_but_limited_to_module]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope
    |
 note: the lint level is defined here
   --> $DIR/macro-rules-error.rs:5:9
    |
 LL | #![deny(rustdoc::broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: to link to the builtin type, prefix with `prim@`
+   = note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location
+
+error: unresolved link to `after`
+  --> $DIR/macro-rules-error.rs:15:6
    |
-LL | /// [prim@str] FIXME: This error shouldn not be reported
-   |      +++++
-help: to link to the macro, add an exclamation mark
+LL | /// [after]
+   |      ^^^^^ no item named `after` in scope
    |
-LL | /// [str!] FIXME: This error shouldn not be reported
-   |         +
+   = note: `macro_rules` named `after` exists in this crate, but it is not in scope at this link's location
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
index c63410fa35bde6d91233d06a0b8c1ef003cf57f1..1cdc5d18c28983cb8506f78cbd3f19f311e0e9b1 100644 (file)
@@ -327,7 +327,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-//~^ ERROR no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
+//~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
 #[error(code = "E0123", slug = "foo")]
 struct ArgFieldWithoutSkip {
     #[primary_span]
@@ -482,3 +482,25 @@ struct VecField {
     #[label]
     spans: Vec<Span>,
 }
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct UnitField {
+    #[primary_span]
+    spans: Span,
+    #[help]
+    foo: (),
+    #[help = "a"]
+    bar: (),
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct OptUnitField {
+    #[primary_span]
+    spans: Span,
+    #[help]
+    foo: Option<()>,
+    #[help = "a"]
+    bar: Option<()>,
+}
index b1738b60bc0d39ca9718b5e0406f1af879958aba..2583363120a2950e1e2a1c2ab7acfaca436a757f 100644 (file)
@@ -349,17 +349,26 @@ error: cannot find attribute `nonsense` in this scope
 LL |     #[nonsense]
    |       ^^^^^^^^
 
-error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
+error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
   --> $DIR/diagnostic-derive.rs:329:10
    |
-LL | struct Hello {}
-   | ------------ method `into_diagnostic_arg` not found for this
-...
 LL | #[derive(SessionDiagnostic)]
-   |          ^^^^^^^^^^^^^^^^^ method not found in `Hello`
-   |
+   |          ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
+   |
+   = help: the following other types implement trait `IntoDiagnosticArg`:
+             &'a str
+             Ident
+             String
+             Symbol
+             rustc_middle::ty::Ty<'tcx>
+             usize
+note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
+  --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:531:19
+   |
+LL |         arg: impl IntoDiagnosticArg,
+   |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 43 previous errors
 
-For more information about this error, try `rustc --explain E0599`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/asm/generic-const.rs b/src/test/ui/asm/generic-const.rs
new file mode 100644 (file)
index 0000000..55c5587
--- /dev/null
@@ -0,0 +1,30 @@
+// needs-asm-support
+// build-pass
+
+#![feature(asm_const, asm_sym)]
+
+use std::arch::asm;
+
+fn foofoo<const N: usize>() {}
+
+unsafe fn foo<const N: usize>() {
+    asm!("/* {0} */", const N);
+    asm!("/* {0} */", const N + 1);
+    asm!("/* {0} */", sym foofoo::<N>);
+}
+
+fn barbar<T>() {}
+
+unsafe fn bar<T>() {
+    asm!("/* {0} */", const std::mem::size_of::<T>());
+    asm!("/* {0} */", const std::mem::size_of::<(T, T)>());
+    asm!("/* {0} */", sym barbar::<T>);
+    asm!("/* {0} */", sym barbar::<(T, T)>);
+}
+
+fn main() {
+    unsafe {
+        foo::<0>();
+        bar::<usize>();
+    }
+}
index 9f0121e11b4470a001e1f2f7e1ae3a1aa07aefaa..367a035387bc8f785017077fd42a977363db4450 100644 (file)
@@ -63,7 +63,6 @@ const fn const_bar<T>(x: T) -> T {
 
 unsafe fn generic<T>() {
     asm!("{}", sym generic::<T>);
-    //~^ generic parameters may not be used in const operations
 }
 
 // Const operands must be integers and must be constants.
index 7dba69fb7459276987dc7ac45bf996507fb44ab9..bf5ea1befb69e9ae918531b14e4a5b616be97e78 100644 (file)
@@ -33,15 +33,6 @@ LL |         asm!("{}", sym x);
    |
    = help: `sym` operands must refer to either a function or a static
 
-error: generic parameters may not be used in const operations
-  --> $DIR/type-check-1.rs:65:30
-   |
-LL |     asm!("{}", sym generic::<T>);
-   |                              ^ cannot perform const operation using `T`
-   |
-   = note: type parameters may not be used in const expressions
-   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
 error[E0308]: mismatched types
   --> $DIR/type-check-1.rs:55:26
    |
@@ -109,13 +100,13 @@ LL |         asm!("{}", inout(reg) v[..]);
    = note: all inline asm arguments must have a statically known size
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:74:25
+  --> $DIR/type-check-1.rs:73:25
    |
 LL | global_asm!("{}", const 0f32);
    |                         ^^^^ expected integer, found `f32`
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:76:25
+  --> $DIR/type-check-1.rs:75:25
    |
 LL | global_asm!("{}", const 0 as *mut u8);
    |                         ^^^^^^^^^^^^ expected integer, found *-ptr
@@ -123,7 +114,7 @@ LL | global_asm!("{}", const 0 as *mut u8);
    = note:     expected type `{integer}`
            found raw pointer `*mut u8`
 
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0435.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-consts/issue-88599-ref-self.rs b/src/test/ui/associated-consts/issue-88599-ref-self.rs
new file mode 100644 (file)
index 0000000..f1144db
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait First {
+    const CONST: usize;
+}
+pub trait Second {}
+
+impl<'a> First for dyn Second
+where
+    &'a Self: First,
+{
+    const CONST: usize = <&Self>::CONST;
+}
+
+trait Third: First
+where
+    [u8; Self::CONST]:
+{
+    const VAL: [u8; Self::CONST] = [0; Self::CONST];
+}
+
+fn main() {}
index 9c29e969de8da77a123c453d33b244a80f306090..a65f84ae58eadd479dffcd1d22aac7e643993330 100644 (file)
@@ -2,10 +2,18 @@ error[E0271]: type mismatch resolving `<T as Deref>::Target == T`
   --> $DIR/hr-associated-type-projection-1.rs:13:33
    |
 LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
-   |      - this type parameter      ^^^^^^^^^^^^^^^^^ expected associated type, found type parameter `T`
+   |      - this type parameter      ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
    |
-   = note: expected associated type `<T as Deref>::Target`
-               found type parameter `T`
+   = note: expected type parameter `T`
+             found associated type `<T as Deref>::Target`
+note: required by a bound in `UnsafeCopy`
+  --> $DIR/hr-associated-type-projection-1.rs:3:64
+   |
+LL | trait UnsafeCopy<'a, T: Copy>
+   |       ---------- required by a bound in this
+LL | where
+LL |     for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+   |                                                                ^^^^^^^^^^ required by this bound in `UnsafeCopy`
 help: consider further restricting this bound
    |
 LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<'_, T> for T {
diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs
new file mode 100644 (file)
index 0000000..c3423ad
--- /dev/null
@@ -0,0 +1,14 @@
+// edition:2018
+// compile-flags: -Zdrop-tracking
+// Regression test for issue #73741
+// Ensures that we don't emit spurious errors when
+// a type error ocurrs in an `async fn`
+
+async fn weird() {
+    1 = 2; //~ ERROR invalid left-hand side
+
+    let mut loop_count = 0;
+    async {}.await
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr
new file mode 100644 (file)
index 0000000..d4e3b6c
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-73741-type-err-drop-tracking.rs:8:7
+   |
+LL |     1 = 2;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
index 95ee51a88261aaefc28eb8ddc293de1a00a2bc33..68303b842088ecadca31671af29cf1e884c719e6 100644 (file)
@@ -12,20 +12,14 @@ LL |     assert_eq!(foo, y);
 error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
   --> $DIR/issue-77910-1.rs:8:5
    |
+LL | fn foo(s: &i32) -> &i32 {
+   |    --- consider calling this function
+...
 LL |     assert_eq!(foo, y);
    |     ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
-   = help: the following other types implement trait `Debug`:
-             extern "C" fn() -> Ret
-             extern "C" fn(A) -> Ret
-             extern "C" fn(A, ...) -> Ret
-             extern "C" fn(A, B) -> Ret
-             extern "C" fn(A, B, ...) -> Ret
-             extern "C" fn(A, B, C) -> Ret
-             extern "C" fn(A, B, C, ...) -> Ret
-             extern "C" fn(A, B, C, D) -> Ret
-           and 68 others
+   = help: use parentheses to call the function: `foo(s)`
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
index b1e59e9d5de362a70b3ef16d636045279732f5f2..e2b177b951cc9a2c2bda0f492468fc4e97faa295 100644 (file)
@@ -2,8 +2,13 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/builtin-superkinds-self-type.rs:10:16
    |
 LL | impl <T: Sync> Foo for T { }
-   |                ^^^ ...so that the type `T` will meet its required lifetime bounds
+   |                ^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
+note: ...that is required by this bound
+  --> $DIR/builtin-superkinds-self-type.rs:6:24
+   |
+LL | trait Foo : Sized+Sync+'static {
+   |                        ^^^^^^^
 help: consider adding an explicit lifetime bound...
    |
 LL | impl <T: Sync + 'static> Foo for T { }
diff --git a/src/test/ui/coherence/coherence-with-closure.rs b/src/test/ui/coherence/coherence-with-closure.rs
new file mode 100644 (file)
index 0000000..6e3281d
--- /dev/null
@@ -0,0 +1,15 @@
+// Test that encountering closures during coherence does not cause issues.
+#![feature(type_alias_impl_trait)]
+type OpaqueClosure = impl Sized;
+fn defining_use() -> OpaqueClosure {
+    || ()
+}
+
+struct Wrapper<T>(T);
+trait Trait {}
+impl Trait for Wrapper<OpaqueClosure> {}
+//~^ ERROR cannot implement trait on type alias impl trait
+impl<T: Sync> Trait for Wrapper<T> {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr
new file mode 100644 (file)
index 0000000..20b986c
--- /dev/null
@@ -0,0 +1,24 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/coherence-with-closure.rs:10:24
+   |
+LL | impl Trait for Wrapper<OpaqueClosure> {}
+   |                        ^^^^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/coherence-with-closure.rs:3:22
+   |
+LL | type OpaqueClosure = impl Sized;
+   |                      ^^^^^^^^^^
+
+error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>`
+  --> $DIR/coherence-with-closure.rs:12:1
+   |
+LL | impl Trait for Wrapper<OpaqueClosure> {}
+   | ------------------------------------- first implementation here
+LL |
+LL | impl<T: Sync> Trait for Wrapper<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-with-generator.rs b/src/test/ui/coherence/coherence-with-generator.rs
new file mode 100644 (file)
index 0000000..d34c391
--- /dev/null
@@ -0,0 +1,19 @@
+// Test that encountering closures during coherence does not cause issues.
+#![feature(type_alias_impl_trait, generators)]
+type OpaqueGenerator = impl Sized;
+fn defining_use() -> OpaqueGenerator {
+    || {
+        for i in 0..10 {
+            yield i;
+        }
+    }
+}
+
+struct Wrapper<T>(T);
+trait Trait {}
+impl Trait for Wrapper<OpaqueGenerator> {}
+//~^ ERROR cannot implement trait on type alias impl trait
+impl<T: Sync> Trait for Wrapper<T> {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr
new file mode 100644 (file)
index 0000000..249ad3c
--- /dev/null
@@ -0,0 +1,24 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/coherence-with-generator.rs:14:24
+   |
+LL | impl Trait for Wrapper<OpaqueGenerator> {}
+   |                        ^^^^^^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/coherence-with-generator.rs:3:24
+   |
+LL | type OpaqueGenerator = impl Sized;
+   |                        ^^^^^^^^^^
+
+error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>`
+  --> $DIR/coherence-with-generator.rs:16:1
+   |
+LL | impl Trait for Wrapper<OpaqueGenerator> {}
+   | --------------------------------------- first implementation here
+LL |
+LL | impl<T: Sync> Trait for Wrapper<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
index 847843fe1a63ef721e48a0fe1cbe84f616a54127..1ea310d063b82a6db2fe30bfd88d429e21d9efbd 100644 (file)
@@ -1,6 +1,6 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
-//~^ ERROR overly complex generic constant
+//~^ ERROR cycle detected when building an abstract representation
 
 fn main() {}
index 18010413b9394528e0ef615a33b48fa5cfb2b1e3..a15dd2016e9e4cc2138de513fd443af4ba9883a7 100644 (file)
@@ -1,13 +1,26 @@
-error: overly complex generic constant
+error[E0391]: cycle detected when building an abstract representation for test::{constant#0}
   --> $DIR/closures.rs:3:35
    |
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
-   |                                   ^^^^-------^^
-   |                                       |
-   |                                       borrowing is not supported in generic constants
+   |                                   ^^^^^^^^^^^^^
    |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
+note: ...which requires building THIR for `test::{constant#0}`...
+  --> $DIR/closures.rs:3:35
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires type-checking `test::{constant#0}`...
+  --> $DIR/closures.rs:3:35
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   |                                   ^^^^^^^^^^^^^
+   = note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle
+note: cycle used when checking that `test` is well-formed
+  --> $DIR/closures.rs:3:1
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0391`.
index 350bd941939b1aa7256de4941951c56c9d86912d..7873b3463c1178ea42e6fdbe3ea552493cb1250c 100644 (file)
@@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:18:1
    |
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
index 13a4fde0830e4d2945080aa0c23dea9b5cc468dc..473497501113ceaa74e25740b651fe1c150bff6c 100644 (file)
@@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:18:1
    |
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
diff --git a/src/test/ui/consts/const-fn-ptr.rs b/src/test/ui/consts/const-fn-ptr.rs
new file mode 100644 (file)
index 0000000..b1befdf
--- /dev/null
@@ -0,0 +1,16 @@
+const fn make_fn_ptr() -> fn() {
+    || {}
+}
+
+static STAT: () = make_fn_ptr()();
+//~^ ERROR function pointer
+
+const CONST: () = make_fn_ptr()();
+//~^ ERROR function pointer
+
+const fn call_ptr() {
+    make_fn_ptr()();
+    //~^ ERROR function pointer
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-fn-ptr.stderr b/src/test/ui/consts/const-fn-ptr.stderr
new file mode 100644 (file)
index 0000000..84b02a2
--- /dev/null
@@ -0,0 +1,20 @@
+error: function pointer calls are not allowed in statics
+  --> $DIR/const-fn-ptr.rs:5:19
+   |
+LL | static STAT: () = make_fn_ptr()();
+   |                   ^^^^^^^^^^^^^^^
+
+error: function pointer calls are not allowed in constants
+  --> $DIR/const-fn-ptr.rs:8:19
+   |
+LL | const CONST: () = make_fn_ptr()();
+   |                   ^^^^^^^^^^^^^^^
+
+error: function pointer calls are not allowed in constant functions
+  --> $DIR/const-fn-ptr.rs:12:5
+   |
+LL |     make_fn_ptr()();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index b997aff0e837cfa7b7b8870dc1e19f7836682ff3..3b80b3486a82225c0fb8a17e6158ea2f2ac8e1c3 100644 (file)
@@ -7,7 +7,7 @@ LL | const fn foo() { (||{})() }
    = note: closures need an RFC before allowed to be called in constant functions
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: function pointers are not allowed in const fn
+error: function pointer calls are not allowed in constant functions
   --> $DIR/issue-56164.rs:7:5
    |
 LL |     input()
index 22314160c5e89e5a839696ddb295ee2fa954246a..2beb531cc6890c5b4600f0391d187de7bec617aa 100644 (file)
@@ -14,7 +14,7 @@
 static PTR_INT_CAST: () = {
     let x = &0 as *const _ as usize;
     //~^ ERROR could not evaluate static initializer
-    //~| unable to turn pointer into raw bytes
+    //~| "exposing pointers" needs an rfc before being allowed inside constants
     let _v = x == x;
 };
 
index 2764d10348a761689260ea58f83f9b270ba23aef..61d34e2e35df9d53269bc78977219405146654bd 100644 (file)
@@ -8,7 +8,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ptr_arith.rs:15:13
    |
 LL |     let x = &0 as *const _ as usize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ptr_arith.rs:23:14
index e2f5175bf0ac98186db436187812a108781aafc4..6280a7478e70c19cea7c909a0d4d649e7a0baad2 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:4:1
    |
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type [!; 1]
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
index c145eddef575b31afc4d743b0f4c18a40133617e..c5a71e5be51b663cbb56953bced96032c81bb096 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:4:1
    |
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type [!; 1]
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
index b64123389c2c16f7ea9401afd2e8e41397ef0037..7113d913cd0fa49b9f3cb972f42258d7c19073d0 100644 (file)
@@ -1,4 +1,4 @@
-#[link(name = "")] //~ ERROR: given with empty name
+#[link(name = "")] //~ ERROR: link name must not be empty
 extern "C" {}
 
 fn main() {}
index b9d1841f16ca374496887a76b74c8c773b771131..adcf3670d1d7189757dae64a9264aa3e88ff01ef 100644 (file)
@@ -1,8 +1,8 @@
-error[E0454]: `#[link(name = "")]` given with empty name
-  --> $DIR/empty-linkname.rs:1:1
+error[E0454]: link name must not be empty
+  --> $DIR/empty-linkname.rs:1:15
    |
 LL | #[link(name = "")]
-   | ^^^^^^^^^^^^^^^^^^ empty name given
+   |               ^^ empty link name
 
 error: aborting due to previous error
 
index 2dc6976fe0e9cf6e8312dabc5b4f3aa482b9e32f..fa8c39427323c8fd89e7d87bf3cf2991c10393c8 100644 (file)
@@ -2,10 +2,10 @@ error[E0138]: multiple `start` functions
   --> $DIR/E0138.rs:7:1
    |
 LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ---------------------------------------------------------- previous `#[start]` function here
+   | ---------------------------------------------------- previous `#[start]` function here
 ...
 LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
 
 error: aborting due to previous error
 
index 6b62bef112fe74aa43801b68973fc02c09c0cb5f..b9a506fee830a71eff8598441d26f08562c0fbf5 100644 (file)
@@ -1,8 +1,8 @@
-error[E0454]: `#[link(name = "")]` given with empty name
-  --> $DIR/E0454.rs:1:1
+error[E0454]: link name must not be empty
+  --> $DIR/E0454.rs:1:15
    |
 LL | #[link(name = "")] extern "C" {}
-   | ^^^^^^^^^^^^^^^^^^ empty name given
+   |               ^^ empty link name
 
 error: aborting due to previous error
 
index 0f2fec029e78ddb22fdb2fbef6bcf35f99e8419f..e641bba541ee0249f6e9041db506fa3f7eedb87f 100644 (file)
@@ -1,12 +1,10 @@
-error[E0458]: unknown kind: `wonderful_unicorn`
-  --> $DIR/E0458.rs:1:8
+error[E0458]: unknown link kind `wonderful_unicorn`, expected one of: static, dylib, framework, raw-dylib
+  --> $DIR/E0458.rs:1:15
    |
 LL | #[link(kind = "wonderful_unicorn")] extern "C" {}
-   | -------^^^^^^^^^^^^^^^^^^^^^^^^^^--
-   |        |
-   |        unknown kind
+   |               ^^^^^^^^^^^^^^^^^^^ unknown link kind
 
-error[E0459]: `#[link(...)]` specified without `name = "foo"`
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
   --> $DIR/E0458.rs:1:1
    |
 LL | #[link(kind = "wonderful_unicorn")] extern "C" {}
index 4e0d51e87538ad04e1208d18b9662a29af053d9f..8f0dd25e0309a4cdc826af85d093215e3e9d02b9 100644 (file)
@@ -1,4 +1,4 @@
-error[E0459]: `#[link(...)]` specified without `name = "foo"`
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
   --> $DIR/E0459.rs:1:1
    |
 LL | #[link(kind = "dylib")] extern "C" {}
index d41d7b258aafb5714649f2ecd772a2f4d49ed63d..936918a3cfc864b542c94d3d59435a0bb9602726 100644 (file)
@@ -2,8 +2,14 @@
 
 use std::arch::asm;
 
+unsafe fn foo<const N: usize>() {
+    asm!("mov eax, {}", const N + 1);
+    //~^ ERROR const operands for inline assembly are unstable
+}
+
 fn main() {
     unsafe {
+        foo::<0>();
         asm!("mov eax, {}", const 123);
         //~^ ERROR const operands for inline assembly are unstable
     }
index 0202ccbe5a2d232339977f87fb5ea352c66d8d1d..c248374ec4924cf2e742210620f8d371754e1438 100644 (file)
@@ -1,5 +1,14 @@
 error[E0658]: const operands for inline assembly are unstable
-  --> $DIR/feature-gate-asm_const.rs:7:29
+  --> $DIR/feature-gate-asm_const.rs:6:25
+   |
+LL |     asm!("mov eax, {}", const N + 1);
+   |                         ^^^^^^^^^^^
+   |
+   = note: see issue #93332 <https://github.com/rust-lang/rust/issues/93332> for more information
+   = help: add `#![feature(asm_const)]` to the crate attributes to enable
+
+error[E0658]: const operands for inline assembly are unstable
+  --> $DIR/feature-gate-asm_const.rs:13:29
    |
 LL |         asm!("mov eax, {}", const 123);
    |                             ^^^^^^^^^
@@ -7,6 +16,6 @@ LL |         asm!("mov eax, {}", const 123);
    = note: see issue #93332 <https://github.com/rust-lang/rust/issues/93332> for more information
    = help: add `#![feature(asm_const)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index e4d781c6859324d2a0d17bebece4d805ade4c414..0de6b3abb18bb093faca77161f60ff29edac66db 100644 (file)
@@ -2,9 +2,18 @@
 
 use std::arch::asm;
 
+fn bar<const N: usize>() {}
+
+fn foo<const N: usize>() {
+    unsafe {
+        asm!("mov eax, {}", sym bar::<N>);
+        //~^ ERROR sym operands for inline assembly are unstable
+    }
+}
+
 fn main() {
     unsafe {
-        asm!("mov eax, {}", sym main);
+        asm!("mov eax, {}", sym foo::<0>);
         //~^ ERROR sym operands for inline assembly are unstable
     }
 }
index 68f2d0f6c18b0bb6e78594abfa27e46b4b909db4..d4b16f60b0b4196ffa862e44221794c70f2b4360 100644 (file)
@@ -1,12 +1,21 @@
 error[E0658]: sym operands for inline assembly are unstable
-  --> $DIR/feature-gate-asm_sym.rs:7:29
+  --> $DIR/feature-gate-asm_sym.rs:9:29
    |
-LL |         asm!("mov eax, {}", sym main);
-   |                             ^^^^^^^^
+LL |         asm!("mov eax, {}", sym bar::<N>);
+   |                             ^^^^^^^^^^^^
    |
    = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information
    = help: add `#![feature(asm_sym)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: sym operands for inline assembly are unstable
+  --> $DIR/feature-gate-asm_sym.rs:16:29
+   |
+LL |         asm!("mov eax, {}", sym foo::<0>);
+   |                             ^^^^^^^^^^^^
+   |
+   = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information
+   = help: add `#![feature(asm_sym)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 41a7dfc3f379fc554160f6c54817d889e580a189..8f47d596521d9dba2162d3ec70069ff494b629dc 100644 (file)
@@ -1,8 +1,8 @@
-error[E0658]: kind="link_cfg" is unstable
-  --> $DIR/feature-gate-link_cfg.rs:1:1
+error[E0658]: link cfg is unstable
+  --> $DIR/feature-gate-link_cfg.rs:1:22
    |
 LL | #[link(name = "foo", cfg(foo))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                      ^^^^^^^^
    |
    = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information
    = help: add `#![feature(link_cfg)]` to the crate attributes to enable
index fedee8123980e362d5d436ed56563ea2c943437d..132bc6ab04af2dc0f1cae3e9c6486e0302cf465a 100644 (file)
@@ -1,5 +1,5 @@
-#[link(name = "foo", modifiers = "+as-needed")]
-//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
+#[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
+//~^ ERROR: linking modifier `as-needed` is unstable
 extern "C" {}
 
 fn main() {}
index 96750aa6e808aa1b8e01de227dd4286840ea753a..2ef6a1c040424a80a254e4c62e002279b2ccbfce 100644 (file)
@@ -1,8 +1,8 @@
-error[E0658]: `#[link(modifiers="as-needed")]` is unstable
-  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:34
+error[E0658]: linking modifier `as-needed` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:50
    |
-LL | #[link(name = "foo", modifiers = "+as-needed")]
-   |                                  ^^^^^^^^^^^^
+LL | #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
+   |                                                  ^^^^^^^^^^^^
    |
    = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
    = help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable
index 900605c3b375b6858e6ffbcc2010956935537089..743bcc9a1b3818ed29989cbc0ddeaf63babd1e67 100644 (file)
@@ -1,2 +1,2 @@
-error: bundle linking modifier is currently unstable and only accepted on the nightly compiler
+error: linking modifier `bundle` is unstable and only accepted on the nightly compiler
 
index c3c3cff17c403494578d4604c71844185ab22291..c1d5a31aaa4dfe8c715ef80be6b9cf52791416c0 100644 (file)
@@ -1,5 +1,5 @@
-#[link(name = "foo", modifiers = "+bundle")]
-//~^ ERROR: `#[link(modifiers="bundle")]` is unstable
+#[link(name = "foo", kind = "static", modifiers = "+bundle")]
+//~^ ERROR: linking modifier `bundle` is unstable
 extern "C" {}
 
 fn main() {}
index 984b90d9b6c2e38c2b07395776ec0625cead2b92..dcaa7fcc64f02bb7d5ce4f6f1337b8a48182417e 100644 (file)
@@ -1,8 +1,8 @@
-error[E0658]: `#[link(modifiers="bundle")]` is unstable
-  --> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:34
+error[E0658]: linking modifier `bundle` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:51
    |
-LL | #[link(name = "foo", modifiers = "+bundle")]
-   |                                  ^^^^^^^^^
+LL | #[link(name = "foo", kind = "static", modifiers = "+bundle")]
+   |                                                   ^^^^^^^^^
    |
    = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
    = help: add `#![feature(native_link_modifiers_bundle)]` to the crate attributes to enable
index 57527be1112cb55115750e194e89bea8534882bf..7b09195dc3fb0c4a4c56b21d67ece79bb8dd2c00 100644 (file)
@@ -1,5 +1,5 @@
 #[link(name = "foo", modifiers = "+verbatim")]
-//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable
+//~^ ERROR: linking modifier `verbatim` is unstable
 extern "C" {}
 
 fn main() {}
index 5c64c0d21bdb418d7acf95a016c35b6ace8046a8..3bfbeb8db35fe3d4ba6b51f9f52366fa079244a3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: `#[link(modifiers="verbatim")]` is unstable
+error[E0658]: linking modifier `verbatim` is unstable
   --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:1:34
    |
 LL | #[link(name = "foo", modifiers = "+verbatim")]
index 995d9ced4801a639e5cc1a9a84027ed83d40d59c..f894f517b38df9ea27b4253b17ab415371466fb3 100644 (file)
@@ -1,6 +1,6 @@
 // only-windows
 #[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
+//~^ ERROR: link kind `raw-dylib` is unstable
 extern "C" {}
 
 fn main() {}
index bb64af38b2cb92d1db9fdf110a3808ebc07f99e7..ca7a61f64134fbdfec16007fa2782ae7b0051316 100644 (file)
@@ -1,8 +1,8 @@
-error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib.rs:2:1
+error[E0658]: link kind `raw-dylib` is unstable
+  --> $DIR/feature-gate-raw-dylib.rs:2:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^
    |
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
    = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
index 76c317f7410123f986715812aee7072fd51d001b..782d9e39456159362ccdda5da977d900254f7d52 100644 (file)
@@ -1,2 +1,2 @@
-warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle`
+warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`. Try `static:-bundle`
 
index e4bfe8e8e05cae507bda21f81492bf3e91ceb0f5..50f1b7ff3fc48f67282591054f9c440c8d75001c 100644 (file)
@@ -1,6 +1,6 @@
 #[link(name = "foo", kind = "static-nobundle")]
-//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
-//~^^ ERROR: kind="static-nobundle" is unstable
+//~^ WARNING: link kind `static-nobundle` has been superseded by specifying modifier `-bundle` with link kind `static`
+//~^^ ERROR: link kind `static-nobundle` is unstable
 extern "C" {}
 
 fn main() {}
index eaf2e0db511108f51bacf5e0098f13bf30a3e3fb..094661aeb57af9ce3f0426507f94643f0700d9a0 100644 (file)
@@ -1,14 +1,14 @@
-warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
-  --> $DIR/feature-gate-static-nobundle.rs:1:22
+warning: link kind `static-nobundle` has been superseded by specifying modifier `-bundle` with link kind `static`
+  --> $DIR/feature-gate-static-nobundle.rs:1:29
    |
 LL | #[link(name = "foo", kind = "static-nobundle")]
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^
 
-error[E0658]: kind="static-nobundle" is unstable
-  --> $DIR/feature-gate-static-nobundle.rs:1:22
+error[E0658]: link kind `static-nobundle` is unstable
+  --> $DIR/feature-gate-static-nobundle.rs:1:29
    |
 LL | #[link(name = "foo", kind = "static-nobundle")]
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^
    |
    = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
    = help: add `#![feature(static_nobundle)]` to the crate attributes to enable
index bc13a5d7d7b46b171ccb7db7416a3aa3e9d8b589..93afa78459d3da72ca90891af547f6f47523ff9b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: trait upcasting coercion is experimental
+error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental
   --> $DIR/feature-gate-trait_upcasting.rs:11:25
    |
 LL |     let foo: &dyn Foo = bar;
@@ -6,6 +6,7 @@ LL |     let foo: &dyn Foo = bar;
    |
    = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
    = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `&dyn Bar` into `&dyn Foo`
 
 error: aborting due to previous error
 
index b0e295178c8a561224d53ff603c49a5e60e88791..d8d2eca570e3241480d009746fc8e1eefbc05aad 100644 (file)
@@ -581,6 +581,10 @@ mod inner { #![link()] }
     //~^ WARN attribute should be applied to an `extern` block
     //~| WARN this was previously accepted
     //~| NOTE not an `extern` block
+
+    #[link()] extern "Rust" {}
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
 }
 
 struct StructForDeprecated;
index 2431957e5391dd7a6ee31902bdb83896e09b5097..cf9f89d8fde2524b5283ff934571e4132816a262 100644 (file)
@@ -310,7 +310,7 @@ LL | | }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:1
    |
 LL |   #[link()]
@@ -328,55 +328,55 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:618:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -407,7 +407,7 @@ LL | #![cold]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
    |
 LL | #![link()]
@@ -863,7 +863,7 @@ LL |     #[link_section = "1800"] impl S { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:17
    |
 LL |     mod inner { #![link()] }
@@ -871,7 +871,7 @@ LL |     mod inner { #![link()] }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5
    |
 LL |     #[link()] fn f() { }
@@ -879,7 +879,7 @@ LL |     #[link()] fn f() { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:5
    |
 LL |     #[link()] struct S;
@@ -887,7 +887,7 @@ LL |     #[link()] struct S;
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:5
    |
 LL |     #[link()] type T = S;
@@ -895,7 +895,7 @@ LL |     #[link()] type T = S;
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
-warning: attribute should be applied to an `extern` block
+warning: attribute should be applied to an `extern` block with non-Rust ABI
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:580:5
    |
 LL |     #[link()] impl S { }
@@ -903,260 +903,268 @@ LL |     #[link()] impl S { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block with non-Rust ABI
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5
+   |
+LL |     #[link()] extern "Rust" {}
+   |     ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:17
    |
 LL |     mod inner { #![must_use] }
    |                 ^^^^^^^^^^^^
 
 warning: `#[must_use]` has no effect when applied to a type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:5
    |
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
 
 warning: `#[must_use]` has no effect when applied to an item
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:5
    |
 LL |     #[must_use] impl S { }
    |     ^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:621:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:624:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:686:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1169,5 +1177,5 @@ LL | #![feature(rust1)]
    |
    = note: `#[warn(stable_features)]` on by default
 
-warning: 172 warnings emitted
+warning: 173 warnings emitted
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr
new file mode 100644 (file)
index 0000000..15e83ab
--- /dev/null
@@ -0,0 +1,18 @@
+error: higher-ranked lifetime error
+  --> $DIR/issue-59311.rs:17:5
+   |
+LL |     v.t(|| {});
+   |     ^^^^^^^^^^
+   |
+   = note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
+
+error: higher-ranked lifetime error
+  --> $DIR/issue-59311.rs:17:9
+   |
+LL |     v.t(|| {});
+   |         ^^^^^
+   |
+   = note: could not prove for<'a> &'a V: 'static
+
+error: aborting due to 2 previous errors
+
index d617571753c1d28559ab06c4de64756a359d184b..69708577285607ca9573267e414387446d124757 100644 (file)
@@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
 where
     for<'a> &'a V: T + 'static,
 {
-    v.t(|| {}); //~ ERROR: higher-ranked lifetime error
+    v.t(|| {}); //~ ERROR: `&'a V` does not fulfill the required lifetime
 }
 
 fn main() {}
index c16c8206153248d8202e782e21b85c7d79e39073..3dd05bba5c0a1b3b00a2fd1bebb84f1e0b163e4f 100644 (file)
@@ -1,10 +1,15 @@
-error: higher-ranked lifetime error
-  --> $DIR/issue-59311.rs:17:9
+error[E0477]: the type `&'a V` does not fulfill the required lifetime
+  --> $DIR/issue-59311.rs:17:5
    |
 LL |     v.t(|| {});
-   |         ^^^^^
+   |     ^^^^^^^^^^
    |
-   = note: could not prove for<'a> &'a V: 'static
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/issue-59311.rs:15:24
+   |
+LL |     for<'a> &'a V: T + 'static,
+   |                        ^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0477`.
index 768d1c36619da09d8809c8b685660224626fce36..4d38cb19e9bf2e00dc68007899b44a319fbd7ba0 100644 (file)
@@ -11,3 +11,20 @@ fn foo<T>(t: T) -> usize
 fn main() {
     foo::<Vec<u32>>(vec![]);
 }
+
+mod another {
+    use std::ops::Deref;
+
+    fn test<T, TDeref>()
+    where
+        T: Deref<Target = TDeref>,
+        TDeref: ?Sized,
+        for<'a> &'a TDeref: IntoIterator,
+        for<'a> <&'a TDeref as IntoIterator>::IntoIter: Clone,
+    {
+    }
+
+    fn main() {
+        test::<Vec<u8>, _>();
+    }
+}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs
new file mode 100644 (file)
index 0000000..ffd6857
--- /dev/null
@@ -0,0 +1,31 @@
+// check-pass
+
+trait Variable<'a> {
+    type Type;
+}
+
+impl Variable<'_> for () {
+    type Type = ();
+}
+
+fn check<F, T>(_: F)
+where
+    F: Fn(T), // <- if removed, all fn_* then require type annotations
+    F: for<'a> Fn(<T as Variable<'a>>::Type),
+    T: for<'a> Variable<'a>,
+{
+}
+
+fn test(arg: impl Fn(())) {
+    fn fn_1(_: ()) {}
+    let fn_2 = |_: ()| ();
+    let fn_3 = |a| fn_1(a);
+    let fn_4 = arg;
+
+    check(fn_1); // Error
+    check(fn_2); // Ok
+    check(fn_3); // Ok
+    check(fn_4); // Error
+}
+
+fn main() {}
index a70166e03a7b1219622f010572fccba4643beb85..8d7a1d56f83202cee5a315af4e8ee43944839ba3 100644 (file)
@@ -1,5 +1,3 @@
-// check-pass
-
 trait Trait<'a> {
     type Out;
     fn call(&'a self) -> Self::Out;
@@ -15,6 +13,7 @@ fn call(&'a self) -> Self::Out {
 }
 
 fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
+    //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
     X(())
 }
 
diff --git a/src/test/ui/impl-trait/issues/issue-54895.stderr b/src/test/ui/impl-trait/issues/issue-54895.stderr
new file mode 100644 (file)
index 0000000..7d22f02
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-54895.rs:15:53
+   |
+LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
+   |                                                     ^^
+   |
+note: lifetime declared here
+  --> $DIR/issue-54895.rs:15:20
+   |
+LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> {
+   |                    ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issues/issue-67830.nll.stderr b/src/test/ui/impl-trait/issues/issue-67830.nll.stderr
deleted file mode 100644 (file)
index 17fbe04..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-67830.rs:23:5
-   |
-LL |     Wrap(|a| Some(a).into_iter())
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
-   |
-   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
-
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-67830.rs:23:5
-   |
-LL |     Wrap(|a| Some(a).into_iter())
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
-   |
-   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
-
-error: aborting due to 2 previous errors
-
index a308d975b43959b828cb3f634331a7f4bcf8a7bf..92f7e005dbf0c26ea7479e9807d62f3310a0dadf 100644 (file)
@@ -19,7 +19,7 @@ fn call(&self, arg: A) -> Self::Output {
 
 struct A;
 fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
-    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
     Wrap(|a| Some(a).into_iter())
 }
 
index 4c0490c721bc4110f703b85077cf68b06fc1fea1..d3ea8cb0377c7503bec82d7dc7f30acba420658c 100644 (file)
@@ -1,11 +1,14 @@
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/issue-67830.rs:21:14
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-67830.rs:21:62
    |
 LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |                                                              ^^
    |
-   = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`...
-   = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2`
+note: lifetime declared here
+  --> $DIR/issue-67830.rs:21:23
+   |
+LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> {
+   |                       ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
deleted file mode 100644 (file)
index 66cffa9..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:17:5
-   |
-LL |     &()
-   |     ^^^ implementation of `Hrtb` is not general enough
-   |
-   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
-   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
-
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:17:5
-   |
-LL |     &()
-   |     ^^^ implementation of `Hrtb` is not general enough
-   |
-   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
-   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
-
-error: lifetime may not live long enough
-  --> $DIR/issue-88236-2.rs:20:5
-   |
-LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-   |                  -- lifetime `'b` defined here
-LL |     x
-   |     ^ returning this value requires that `'b` must outlive `'static`
-   |
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
-   |
-LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
-   |                                                                                  ++++
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound
-   |
-LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> {
-   |                                                                                 ++++
-
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:20:5
-   |
-LL |     x
-   |     ^ implementation of `Hrtb` is not general enough
-   |
-   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
-   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
-
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:20:5
-   |
-LL |     x
-   |     ^ implementation of `Hrtb` is not general enough
-   |
-   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
-   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
-
-error: aborting due to 5 previous errors
-
index af26a1f54c46d5e498a6786f4f05565acc754471..fde8a6704cc45708566a58ef8275386c11fe1d29 100644 (file)
@@ -13,11 +13,16 @@ impl<'a> Hrtb<'a> for &'a () {
 }
 
 fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+
 fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-    &() //~^ ERROR implementation of `Hrtb` is not general enough
+    //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+    &()
 }
+
 fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-    x //~^ ERROR implementation of `Hrtb` is not general enough
+    //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+    x
 }
 
 fn main() {}
index 9574b880f7d11c179a10cef6be1d984157f08f1d..8605d07abe9430ac58136cd6f79e2c392c4727ac 100644 (file)
@@ -1,20 +1,38 @@
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:16:38
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-88236-2.rs:15:61
+   |
+LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+   |                                                             ^^
+   |
+note: lifetime declared here
+  --> $DIR/issue-88236-2.rs:15:28
+   |
+LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+   |                            ^^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-88236-2.rs:18:80
    |
 LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough
+   |                                                                                ^^
    |
-   = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`...
-   = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1`
+note: lifetime declared here
+  --> $DIR/issue-88236-2.rs:18:47
+   |
+LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                                               ^^
 
-error: implementation of `Hrtb` is not general enough
-  --> $DIR/issue-88236-2.rs:19:36
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-88236-2.rs:23:78
    |
 LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough
+   |                                                                              ^^
    |
-   = note: `Hrtb<'1>` would have to be implemented for the type `&()`, for any lifetime `'1`...
-   = note: ...but `Hrtb<'_>` is actually implemented for the type `&()`
+note: lifetime declared here
+  --> $DIR/issue-88236-2.rs:23:45
+   |
+LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
+   |                                             ^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
index 2ea35270a7e3b5cc0e6784bc8bff5375d7e693d4..36d12417354a2a4509aeaa1233294c57ad391d58 100644 (file)
@@ -1,5 +1,3 @@
-// check-pass
-
 // this used to cause stack overflows
 
 trait Hrtb<'a> {
@@ -15,5 +13,6 @@ impl<'a> Hrtb<'a> for &'a () {
 }
 
 fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-88236.stderr b/src/test/ui/impl-trait/issues/issue-88236.stderr
new file mode 100644 (file)
index 0000000..7a4cc57
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/issue-88236.rs:15:61
+   |
+LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+   |                                                             ^^
+   |
+note: lifetime declared here
+  --> $DIR/issue-88236.rs:15:28
+   |
+LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {}
+   |                            ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/nested-rpit-hrtb.rs b/src/test/ui/impl-trait/nested-rpit-hrtb.rs
new file mode 100644 (file)
index 0000000..abf6a7e
--- /dev/null
@@ -0,0 +1,64 @@
+// Test the interaction between rested RPIT and HRTB.
+
+trait Foo<'a> {
+    type Assoc;
+}
+
+impl Foo<'_> for () {
+    type Assoc = ();
+}
+
+// Alternative version of `Foo` whose impl uses `'a`.
+trait Bar<'a> {
+    type Assoc;
+}
+
+impl<'a> Bar<'a> for () {
+    type Assoc = &'a ();
+}
+
+trait Qux<'a> {}
+
+impl Qux<'_> for () {}
+
+// This is not supported.
+fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+
+// This is not supported.
+fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+
+fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+
+fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
+//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+
+// This should pass.
+fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {}
+
+// This should pass.
+fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'b> {}
+
+// This should pass.
+fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
+
+// This should pass.
+fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {}
+
+// This should pass.
+fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {}
+
+// `'b` is not in scope for the outlives bound.
+fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
+//~^ ERROR use of undeclared lifetime name `'b` [E0261]
+
+// This should pass.
+fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {}
+
+// `'b` is not in scope for the outlives bound.
+fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
+//~^ ERROR use of undeclared lifetime name `'b` [E0261]
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/nested-rpit-hrtb.stderr b/src/test/ui/impl-trait/nested-rpit-hrtb.stderr
new file mode 100644 (file)
index 0000000..3dbe6eb
--- /dev/null
@@ -0,0 +1,82 @@
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/nested-rpit-hrtb.rs:54:77
+   |
+LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                                                                             ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL | fn two_htrb_outlives() -> impl for<'b, 'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                                    +++
+help: consider introducing lifetime `'b` here
+   |
+LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                     ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/nested-rpit-hrtb.rs:61:82
+   |
+LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                                                                                  ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL | fn two_htrb_outlives_uses() -> impl for<'b, 'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                                         +++
+help: consider introducing lifetime `'b` here
+   |
+LL | fn two_htrb_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
+   |                          ++++
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/nested-rpit-hrtb.rs:25:69
+   |
+LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {}
+   |                                                                     ^^
+   |
+note: lifetime declared here
+  --> $DIR/nested-rpit-hrtb.rs:25:36
+   |
+LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {}
+   |                                    ^^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/nested-rpit-hrtb.rs:29:68
+   |
+LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {}
+   |                                                                    ^^
+   |
+note: lifetime declared here
+  --> $DIR/nested-rpit-hrtb.rs:29:39
+   |
+LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {}
+   |                                       ^^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/nested-rpit-hrtb.rs:32:74
+   |
+LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {}
+   |                                                                          ^^
+   |
+note: lifetime declared here
+  --> $DIR/nested-rpit-hrtb.rs:32:41
+   |
+LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {}
+   |                                         ^^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+  --> $DIR/nested-rpit-hrtb.rs:35:73
+   |
+LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
+   |                                                                         ^^
+   |
+note: lifetime declared here
+  --> $DIR/nested-rpit-hrtb.rs:35:44
+   |
+LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
+   |                                            ^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/imports/unused-imports-in-test-mode.rs b/src/test/ui/imports/unused-imports-in-test-mode.rs
new file mode 100644 (file)
index 0000000..ed0bb65
--- /dev/null
@@ -0,0 +1,84 @@
+// compile-flags: --test
+
+#![deny(unused_imports)]
+
+use std::io::BufRead; //~ ERROR unused import: `std::io::BufRead`
+
+fn a() {}
+fn b() {}
+
+mod test {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod tests {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod test_a {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod a_test {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod tests_a {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod a_tests {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod fastest_search {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+#[cfg(test)]
+mod test_has_attr {
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+mod test_has_no_attr {
+    #[cfg(test)]
+    use super::a;  //~ ERROR unused import: `super::a`
+
+    fn foo() {
+        use crate::b;  //~ ERROR unused import: `crate::b`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/unused-imports-in-test-mode.stderr b/src/test/ui/imports/unused-imports-in-test-mode.stderr
new file mode 100644 (file)
index 0000000..1847abd
--- /dev/null
@@ -0,0 +1,122 @@
+error: unused import: `std::io::BufRead`
+  --> $DIR/unused-imports-in-test-mode.rs:5:5
+   |
+LL | use std::io::BufRead;
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-imports-in-test-mode.rs:3:9
+   |
+LL | #![deny(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:11:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:14:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:19:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:22:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:27:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:30:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:35:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:38:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:43:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:46:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:51:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:54:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:59:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:62:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:68:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:71:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: unused import: `super::a`
+  --> $DIR/unused-imports-in-test-mode.rs:77:9
+   |
+LL |     use super::a;
+   |         ^^^^^^^^
+
+error: unused import: `crate::b`
+  --> $DIR/unused-imports-in-test-mode.rs:80:13
+   |
+LL |         use crate::b;
+   |             ^^^^^^^^
+
+error: aborting due to 19 previous errors
+
diff --git a/src/test/ui/inference/issue-28935.rs b/src/test/ui/inference/issue-28935.rs
new file mode 100644 (file)
index 0000000..872822d
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+use std::cell::RefCell;
+
+pub fn f(v: Vec<RefCell<u8>>) {
+    let _t = &mut *v[0].borrow_mut();
+}
+
+fn main() {}
index e1946467583e908c1ea23d85bdaacd88a9a909ac..7c0d83516ea29d09450b99cbd96d3881f796e431 100644 (file)
@@ -6,7 +6,8 @@
 fn foo<const V: usize>() {
     match 0 {
         const { V } => {},
-        //~^ ERROR const parameters cannot be referenced in patterns [E0158]
+        //~^ ERROR constant pattern depends on a generic parameter
+        //~| ERROR constant pattern depends on a generic parameter
         _ => {},
     }
 }
index ade200d99ba39c46390e7b9009866ec396c2f683..77267f12fb11a74ae5ece696413ba7c85bf491ed 100644 (file)
@@ -1,21 +1,26 @@
-error[E0158]: const parameters cannot be referenced in patterns
+error: constant pattern depends on a generic parameter
   --> $DIR/const-match-pat-generic.rs:8:9
    |
 LL |         const { V } => {},
    |         ^^^^^^^^^^^
 
 error: constant pattern depends on a generic parameter
-  --> $DIR/const-match-pat-generic.rs:20:9
+  --> $DIR/const-match-pat-generic.rs:21:9
    |
 LL |         const { f(V) } => {},
    |         ^^^^^^^^^^^^^^
 
 error: constant pattern depends on a generic parameter
-  --> $DIR/const-match-pat-generic.rs:20:9
+  --> $DIR/const-match-pat-generic.rs:8:9
+   |
+LL |         const { V } => {},
+   |         ^^^^^^^^^^^
+
+error: constant pattern depends on a generic parameter
+  --> $DIR/const-match-pat-generic.rs:21:9
    |
 LL |         const { f(V) } => {},
    |         ^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0158`.
index a70e7c416bc0f3157df6e54901e8eb25a91f80f5..17bfae2a4e46bdd33fa983a2d29f512a92579916 100644 (file)
@@ -1,4 +1,4 @@
-error[E0658]: trait upcasting coercion is experimental
+error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
   --> $DIR/issue-11515.rs:9:33
    |
 LL |     let test = box Test { func: closure };
@@ -6,6 +6,7 @@ LL |     let test = box Test { func: closure };
    |
    = note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
    = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
+   = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>`
 
 error: aborting due to previous error
 
index 965ecde6f3c044d27e89dd9140d7968386565132..1c6df0da60c0e773d487de067bf3322a5ca45f70 100644 (file)
@@ -1,4 +1,6 @@
 // build-pass
+// compiler-opts: -Zmir-opt-level=2
+
 #![allow(dead_code)]
 trait Foo {
     fn foo(&self);
index 73d17928251178c84162c7cd48ef1b511c9cd65c..1a210887154f45ac177b3691c8717ebbe2ea9426 100644 (file)
@@ -1,4 +1,4 @@
-#[link(name = "foo", cfg("rlib"))] //~ ERROR invalid argument for `cfg(..)`
+#[link(name = "foo", cfg("rlib"))] //~ ERROR link cfg must have a single predicate argument
 extern "C" {}
 
 fn main() {}
index 7bf64dc693c5e27d9494957330a4499b1836ef69..b0ad25063de83d3629da45991e44548ee51361ad 100644 (file)
@@ -1,8 +1,8 @@
-error: invalid argument for `cfg(..)`
-  --> $DIR/issue-43925.rs:1:26
+error: link cfg must have a single predicate argument
+  --> $DIR/issue-43925.rs:1:22
    |
 LL | #[link(name = "foo", cfg("rlib"))]
-   |                          ^^^^^^
+   |                      ^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 0171c12b1cc4e982c5737258b985cc6315f75e10..6d3003552dc0dfc244ae14c981910a2a512bc212 100644 (file)
@@ -1,4 +1,4 @@
-#[link(name = "foo", cfg())] //~ ERROR `cfg()` must have an argument
+#[link(name = "foo", cfg())] //~ ERROR link cfg must have a single predicate argument
 extern "C" {}
 
 fn main() {}
index d83e9bd7ed4646c8f395f6e7ea1c4a59a9ed2b9f..f67f91a6bd3d80645f7bf596f0db9b793a49673d 100644 (file)
@@ -1,4 +1,4 @@
-error: `cfg()` must have an argument
+error: link cfg must have a single predicate argument
   --> $DIR/issue-43926.rs:1:22
    |
 LL | #[link(name = "foo", cfg())]
index b743f0df4b11ae41bcc7ba5fb75bc0104102f931..f53ddb95416d15adf0b0266dcdb887cebc8dd9bc 100644 (file)
@@ -5,11 +5,6 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              -^^^^^
    |                              |
    |                              cannot use `+=` on type `&isize`
-   |
-help: `+=` can be used on `isize`, you can dereference `x`
-   |
-LL |     let x = |ref x: isize| { *x += 1; };
-   |                              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/linkage-attr/bad-extern-link-attrs.rs b/src/test/ui/linkage-attr/bad-extern-link-attrs.rs
deleted file mode 100644 (file)
index 43fe8c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#[link()] //~ ERROR: specified without `name =
-#[link(name = "")] //~ ERROR: with empty name
-#[link(name = "foo")]
-#[link(name = "foo", kind = "bar")] //~ ERROR: unknown kind
-extern "C" {}
-
-fn main() {}
diff --git a/src/test/ui/linkage-attr/bad-extern-link-attrs.stderr b/src/test/ui/linkage-attr/bad-extern-link-attrs.stderr
deleted file mode 100644 (file)
index 525c605..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0459]: `#[link(...)]` specified without `name = "foo"`
-  --> $DIR/bad-extern-link-attrs.rs:1:1
-   |
-LL | #[link()]
-   | ^^^^^^^^^ missing `name` argument
-
-error[E0454]: `#[link(name = "")]` given with empty name
-  --> $DIR/bad-extern-link-attrs.rs:2:1
-   |
-LL | #[link(name = "")]
-   | ^^^^^^^^^^^^^^^^^^ empty name given
-
-error[E0458]: unknown kind: `bar`
-  --> $DIR/bad-extern-link-attrs.rs:4:22
-   |
-LL | #[link(name = "foo", kind = "bar")]
-   | ---------------------^^^^^^^^^^^^--
-   |                      |
-   |                      unknown kind
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0454, E0458, E0459.
-For more information about an error, try `rustc --explain E0454`.
diff --git a/src/test/ui/linkage-attr/link-attr-validation-early.rs b/src/test/ui/linkage-attr/link-attr-validation-early.rs
new file mode 100644 (file)
index 0000000..b9a835f
--- /dev/null
@@ -0,0 +1,8 @@
+// Top-level ill-formed
+#[link] //~ ERROR attribute must be of the form
+        //~| WARN this was previously accepted
+#[link = "foo"] //~ ERROR attribute must be of the form
+                //~| WARN this was previously accepted
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/linkage-attr/link-attr-validation-early.stderr b/src/test/ui/linkage-attr/link-attr-validation-early.stderr
new file mode 100644 (file)
index 0000000..d36601e
--- /dev/null
@@ -0,0 +1,21 @@
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+  --> $DIR/link-attr-validation-early.rs:2:1
+   |
+LL | #[link]
+   | ^^^^^^^
+   |
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]`
+  --> $DIR/link-attr-validation-early.rs:4:1
+   |
+LL | #[link = "foo"]
+   | ^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/linkage-attr/link-attr-validation-late.rs b/src/test/ui/linkage-attr/link-attr-validation-late.rs
new file mode 100644 (file)
index 0000000..b454fbd
--- /dev/null
@@ -0,0 +1,40 @@
+#![feature(native_link_modifiers_verbatim)]
+#![feature(link_cfg)]
+
+// Top-level ill-formed
+#[link(name = "...", "literal")] //~ ERROR unexpected `#[link]` argument
+#[link(name = "...", unknown)] //~ ERROR unexpected `#[link]` argument
+extern "C" {}
+
+// Duplicate arguments
+#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments
+#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments
+#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments
+#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments
+#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments
+extern "C" {}
+
+// Ill-formed arguments
+#[link(name)] //~ ERROR link name must be of the form `name = "string"`
+              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
+#[link(name())] //~ ERROR link name must be of the form `name = "string"`
+              //~| ERROR `#[link]` attribute requires a `name = "string"` argument
+#[link(name = "...", kind)] //~ ERROR link kind must be of the form `kind = "string"`
+#[link(name = "...", kind())] //~ ERROR link kind must be of the form `kind = "string"`
+#[link(name = "...", modifiers)] //~ ERROR link modifiers must be of the form `modifiers = "string"`
+#[link(name = "...", modifiers())] //~ ERROR link modifiers must be of the form `modifiers = "string"`
+#[link(name = "...", cfg)] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
+#[link(name = "...", cfg = "literal")] //~ ERROR link cfg must be of the form `cfg(/* predicate */)`
+#[link(name = "...", cfg("literal"))] //~ ERROR link cfg must have a single predicate argument
+#[link(name = "...", wasm_import_module)] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
+#[link(name = "...", wasm_import_module())] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"`
+extern "C" {}
+
+// Basic modifier validation
+#[link(name = "...", modifiers = "")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
+#[link(name = "...", modifiers = "no-plus-minus")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix
+#[link(name = "...", modifiers = "+unknown")] //~ ERROR unknown linking modifier `unknown`
+#[link(name = "...", modifiers = "+verbatim,+verbatim")] //~ ERROR multiple `verbatim` modifiers
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/linkage-attr/link-attr-validation-late.stderr b/src/test/ui/linkage-attr/link-attr-validation-late.stderr
new file mode 100644 (file)
index 0000000..bb08f9a
--- /dev/null
@@ -0,0 +1,147 @@
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
+  --> $DIR/link-attr-validation-late.rs:5:22
+   |
+LL | #[link(name = "...", "literal")]
+   |                      ^^^^^^^^^
+
+error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module
+  --> $DIR/link-attr-validation-late.rs:6:22
+   |
+LL | #[link(name = "...", unknown)]
+   |                      ^^^^^^^
+
+error: multiple `name` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:10:22
+   |
+LL | #[link(name = "foo", name = "bar")]
+   |                      ^^^^^^^^^^^^
+
+error: multiple `kind` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:11:38
+   |
+LL | #[link(name = "...", kind = "dylib", kind = "bar")]
+   |                                      ^^^^^^^^^^^^
+
+error: multiple `modifiers` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:12:47
+   |
+LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")]
+   |                                               ^^^^^^^^^^^^^^^^^
+
+error: multiple `cfg` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:13:34
+   |
+LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))]
+   |                                  ^^^^^^^^^^
+
+error: multiple `wasm_import_module` arguments in a single `#[link]` attribute
+  --> $DIR/link-attr-validation-late.rs:14:36
+   |
+LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: link name must be of the form `name = "string"`
+  --> $DIR/link-attr-validation-late.rs:18:8
+   |
+LL | #[link(name)]
+   |        ^^^^
+
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/link-attr-validation-late.rs:18:1
+   |
+LL | #[link(name)]
+   | ^^^^^^^^^^^^^ missing `name` argument
+
+error: link name must be of the form `name = "string"`
+  --> $DIR/link-attr-validation-late.rs:20:8
+   |
+LL | #[link(name())]
+   |        ^^^^^^
+
+error[E0459]: `#[link]` attribute requires a `name = "string"` argument
+  --> $DIR/link-attr-validation-late.rs:20:1
+   |
+LL | #[link(name())]
+   | ^^^^^^^^^^^^^^^ missing `name` argument
+
+error: link kind must be of the form `kind = "string"`
+  --> $DIR/link-attr-validation-late.rs:22:22
+   |
+LL | #[link(name = "...", kind)]
+   |                      ^^^^
+
+error: link kind must be of the form `kind = "string"`
+  --> $DIR/link-attr-validation-late.rs:23:22
+   |
+LL | #[link(name = "...", kind())]
+   |                      ^^^^^^
+
+error: link modifiers must be of the form `modifiers = "string"`
+  --> $DIR/link-attr-validation-late.rs:24:22
+   |
+LL | #[link(name = "...", modifiers)]
+   |                      ^^^^^^^^^
+
+error: link modifiers must be of the form `modifiers = "string"`
+  --> $DIR/link-attr-validation-late.rs:25:22
+   |
+LL | #[link(name = "...", modifiers())]
+   |                      ^^^^^^^^^^^
+
+error: link cfg must be of the form `cfg(/* predicate */)`
+  --> $DIR/link-attr-validation-late.rs:26:22
+   |
+LL | #[link(name = "...", cfg)]
+   |                      ^^^
+
+error: link cfg must be of the form `cfg(/* predicate */)`
+  --> $DIR/link-attr-validation-late.rs:27:22
+   |
+LL | #[link(name = "...", cfg = "literal")]
+   |                      ^^^^^^^^^^^^^^^
+
+error: link cfg must have a single predicate argument
+  --> $DIR/link-attr-validation-late.rs:28:22
+   |
+LL | #[link(name = "...", cfg("literal"))]
+   |                      ^^^^^^^^^^^^^^
+
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/link-attr-validation-late.rs:29:22
+   |
+LL | #[link(name = "...", wasm_import_module)]
+   |                      ^^^^^^^^^^^^^^^^^^
+
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/link-attr-validation-late.rs:30:22
+   |
+LL | #[link(name = "...", wasm_import_module())]
+   |                      ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:34:34
+   |
+LL | #[link(name = "...", modifiers = "")]
+   |                                  ^^
+
+error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:35:34
+   |
+LL | #[link(name = "...", modifiers = "no-plus-minus")]
+   |                                  ^^^^^^^^^^^^^^^
+
+error: unknown linking modifier `unknown`, expected one of: bundle, verbatim, whole-archive, as-needed
+  --> $DIR/link-attr-validation-late.rs:36:34
+   |
+LL | #[link(name = "...", modifiers = "+unknown")]
+   |                                  ^^^^^^^^^^
+
+error: multiple `verbatim` modifiers in a single `modifiers` argument
+  --> $DIR/link-attr-validation-late.rs:37:34
+   |
+LL | #[link(name = "...", modifiers = "+verbatim,+verbatim")]
+   |                                  ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
+For more information about this error, try `rustc --explain E0459`.
index f6c4f896d67c1ea4b6987e10f80d6f83a204fca3..25b8c3cc62e1619b54d3939d854572d5400c28c4 100644 (file)
@@ -192,6 +192,12 @@ fn line() {
     let _ = line!();
 }
 
+#[test]
+fn matches() {
+    let _ = matches!(1, x if x > 0);
+    let _ = matches!(1, x if x > 0,);
+}
+
 #[test]
 fn module_path() {
     let _ = module_path!();
index 0058af9b79ebfe14cbbbf5ad5da956f75b74fc27..3d64b0a67a1dfe5fafe61e52cdfe2c67110facfb 100644 (file)
@@ -8,7 +8,7 @@ note: here is a function named `main`
   --> $DIR/main-wrong-location.rs:4:5
    |
 LL |     fn main() { }
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^
    = note: you have one or more functions named `main` not defined at the crate level
    = help: consider moving the `main` function definitions
 
index 9d092ae6db48bc0b44dc0fb9be675591625965f5..bc9b6be029429bcebd1b88e9b235311df101c52f 100644 (file)
@@ -1,5 +1,5 @@
 // compile-flags:-l static=
-// error-pattern: empty library name given via `-l`
+// error-pattern: library name must not be empty
 
 fn main() {
 }
index ed3c4c4fc4d5d8a91e533629d1b2ad06ffa30c03..7fd7a1066b49bf82adbe74e23c8971f3334a35b1 100644 (file)
@@ -1,4 +1,2 @@
-error: empty library name given via `-l`
-
-error: aborting due to previous error
+error: library name must not be empty
 
index 86830a599b5dcfb3c521e5694cce33797b45cde9..d1609338db666755db148ed46d448ff9630f2adb 100644 (file)
@@ -1,5 +1,5 @@
 // compile-flags:-l bar=foo
-// error-pattern: unknown library kind `bar`, expected one of dylib, framework, or static
+// error-pattern: unknown library kind `bar`, expected one of: static, dylib, framework
 
 fn main() {
 }
index 03c33a9751208f3c12e7eafb3b7bc59cbbb92166..86146956699f3f7d0cf8b8de1cffbf075d235fe9 100644 (file)
@@ -1,2 +1,2 @@
-error: unknown library kind `bar`, expected one of dylib, framework, or static
+error: unknown library kind `bar`, expected one of: static, dylib, framework
 
index 0474526fcc1cf8aadda303cfd9324a755bafb2b4..57c5966e96048e6ded09cedaf7a952c504994ebb 100644 (file)
@@ -1,7 +1,7 @@
 // ignore-macos
 // ignore-ios
 // compile-flags:-l framework=foo
-// error-pattern: native frameworks are only available on macOS targets
+// error-pattern: library kind `framework` is only supported on Apple targets
 
 fn main() {
 }
index 3e8da8b2f931fc4cc41df47c401e5aa513e572e4..de045d56c9ccd79c3c5ef7372fb64bb1c6192150 100644 (file)
@@ -1,4 +1,4 @@
-error: native frameworks are only available on macOS targets
+error: library kind `framework` is only supported on Apple targets
 
 error: aborting due to previous error
 
index 34814db593f3dad97d48a5dfd51f39633f3459dc..7a40186d504c688a6940449ce9c15cd6c5bea0c5 100644 (file)
@@ -1,5 +1,5 @@
 // compile-flags:-l raw-dylib=foo
-// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+// error-pattern: unknown library kind `raw-dylib`, expected one of: static, dylib, framework
 
 fn main() {
 }
index acb4463cb04a7eb0e36b39d601bf091d13bb11c6..4965c0af5f241579c384bda9a6e733b81bf8df60 100644 (file)
@@ -1,2 +1,2 @@
-error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+error: unknown library kind `raw-dylib`, expected one of: static, dylib, framework
 
index 6f93d38ca93b0d257f0c7aab2102c83aa06a2216..086d8cff95770277b0497e47eb849bd3daeac8b1 100644 (file)
@@ -1,6 +1,6 @@
 // Unspecified kind should fail with an error
 
 // compile-flags: -l =mylib
-// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+// error-pattern: unknown library kind ``, expected one of: static, dylib, framework
 
 fn main() {}
index 2a4a82d538f5b0707e24516860c7a559ef845f12..37846c0b06f69bb7d8a7a6b4571b5b4c001edca5 100644 (file)
@@ -1,2 +1,2 @@
-error: unknown library kind ``, expected one of dylib, framework, or static
+error: unknown library kind ``, expected one of: static, dylib, framework
 
index c0c355770574e9086742169fd5f98c8b4cef7718..45ec8ec85e3017a66345a60cede3a0d3a63dce9b 100644 (file)
@@ -1,6 +1,6 @@
 // Unspecified kind should fail with an error
 
 // compile-flags: -l :+bundle=mylib
-// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+// error-pattern: unknown library kind ``, expected one of: static, dylib, framework
 
 fn main() {}
index 2a4a82d538f5b0707e24516860c7a559ef845f12..37846c0b06f69bb7d8a7a6b4571b5b4c001edca5 100644 (file)
@@ -1,2 +1,2 @@
-error: unknown library kind ``, expected one of dylib, framework, or static
+error: unknown library kind ``, expected one of: static, dylib, framework
 
index 9200d7bfb0ce3427dc4f6c5f68d42989dc7935d5..aa5b59c5b6f9e07c7330a755d903e6b50ba17eea 100644 (file)
@@ -1,2 +1,2 @@
-error: duplicating linking modifier is currently unstable and only accepted on the nightly compiler
+error: multiple `whole-archive` modifiers in a single `-l` option
 
index f6d770559e6e03e8c6b9636c5aad66bfd908dd06..3912ac9f13d6c64265d68d82aa8e3c27ec3f01c4 100644 (file)
@@ -3,12 +3,13 @@
 #![feature(native_link_modifiers_bundle)]
 
 #[link(name = "foo")]
-#[link( //~ ERROR multiple `modifiers` arguments in a single `#[link]` attribute
+#[link(
     name = "bar",
     kind = "static",
     modifiers = "+whole-archive,-whole-archive",
-    //~^ ERROR same modifier is used multiple times in a single `modifiers` argument
+    //~^ ERROR multiple `whole-archive` modifiers in a single `modifiers` argument
     modifiers = "+bundle"
+    //~^ ERROR multiple `modifiers` arguments in a single `#[link]` attribute
 )]
 extern "C" {}
 //~^ ERROR overriding linking modifiers from command line is not supported
index 8644d2382d2ba915aca051b0265a69f4adccd24a..55362910e71c6df009fbe2aa83781d06a3252da4 100644 (file)
@@ -1,29 +1,23 @@
-error: same modifier is used multiple times in a single `modifiers` argument
-  --> $DIR/modifiers-override.rs:9:5
+error: multiple `modifiers` arguments in a single `#[link]` attribute
+  --> $DIR/modifiers-override.rs:11:5
    |
-LL |     modifiers = "+whole-archive,-whole-archive",
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     modifiers = "+bundle"
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: multiple `modifiers` arguments in a single `#[link]` attribute
-  --> $DIR/modifiers-override.rs:6:1
+error: multiple `whole-archive` modifiers in a single `modifiers` argument
+  --> $DIR/modifiers-override.rs:9:17
    |
-LL | / #[link(
-LL | |     name = "bar",
-LL | |     kind = "static",
-LL | |     modifiers = "+whole-archive,-whole-archive",
-LL | |
-LL | |     modifiers = "+bundle"
-LL | | )]
-   | |__^
+LL |     modifiers = "+whole-archive,-whole-archive",
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: overriding linking modifiers from command line is not supported
-  --> $DIR/modifiers-override.rs:13:1
+  --> $DIR/modifiers-override.rs:14:1
    |
 LL | extern "C" {}
    | ^^^^^^^^^^^^^
 
 error: overriding linking modifiers from command line is not supported
-  --> $DIR/modifiers-override.rs:13:1
+  --> $DIR/modifiers-override.rs:14:1
    |
 LL | extern "C" {}
    | ^^^^^^^^^^^^^
diff --git a/src/test/ui/nll/issue-54779-anon-static-lifetime.rs b/src/test/ui/nll/issue-54779-anon-static-lifetime.rs
new file mode 100644 (file)
index 0000000..4bb983d
--- /dev/null
@@ -0,0 +1,51 @@
+// Regression test for #54779, checks if the diagnostics are confusing.
+
+#![feature(nll)]
+
+trait DebugWith<Cx: ?Sized> {
+    fn debug_with<'me>(&'me self, cx: &'me Cx) -> DebugCxPair<'me, Self, Cx> {
+        DebugCxPair { value: self, cx }
+    }
+
+    fn fmt_with(&self, cx: &Cx, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
+}
+
+struct DebugCxPair<'me, Value: ?Sized, Cx: ?Sized>
+where
+    Value: DebugWith<Cx>,
+{
+    value: &'me Value,
+    cx: &'me Cx,
+}
+
+trait DebugContext {}
+
+struct Foo {
+    bar: Bar,
+}
+
+impl DebugWith<dyn DebugContext> for Foo {
+    fn fmt_with(
+        &self,
+        cx: &dyn DebugContext,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        let Foo { bar } = self;
+        bar.debug_with(cx); //~ ERROR: lifetime may not live long enough
+        Ok(())
+    }
+}
+
+struct Bar {}
+
+impl DebugWith<dyn DebugContext> for Bar {
+    fn fmt_with(
+        &self,
+        cx: &dyn DebugContext,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        Ok(())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-54779-anon-static-lifetime.stderr b/src/test/ui/nll/issue-54779-anon-static-lifetime.stderr
new file mode 100644 (file)
index 0000000..9dc9bdb
--- /dev/null
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-54779-anon-static-lifetime.rs:34:24
+   |
+LL |         cx: &dyn DebugContext,
+   |             - let's call the lifetime of this reference `'1`
+...
+LL |         bar.debug_with(cx);
+   |                        ^^ cast requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
index 31b853e24fe5bae1c57975f5ee76698a685954a9..958183ec0d73eea33e81cca48308c663a1535937 100644 (file)
@@ -2,6 +2,6 @@
 
 #[link(name = "foo", kind = "framework")]
 extern "C" {}
-//~^^ ERROR: native frameworks are only available on macOS
+//~^^ ERROR: link kind `framework` is only supported on Apple targets
 
 fn main() {}
index f3532913423356ded2f97c430ae44ac5486d8f67..e4a5c98dc5cd512b8488ea65416c6dbf757666ab 100644 (file)
@@ -1,8 +1,8 @@
-error[E0455]: native frameworks are only available on macOS targets
-  --> $DIR/osx-frameworks.rs:3:1
+error[E0455]: link kind `framework` is only supported on Apple targets
+  --> $DIR/osx-frameworks.rs:3:29
    |
 LL | #[link(name = "foo", kind = "framework")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-81804.rs b/src/test/ui/parser/issue-81804.rs
new file mode 100644 (file)
index 0000000..803bde1
--- /dev/null
@@ -0,0 +1,9 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected pattern, found `=`
+// error-pattern: expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
+// error-pattern: expected item, found `]`
+
+fn main() {}
+
+fn p([=(}
diff --git a/src/test/ui/parser/issue-81804.stderr b/src/test/ui/parser/issue-81804.stderr
new file mode 100644 (file)
index 0000000..19c4422
--- /dev/null
@@ -0,0 +1,41 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-81804.rs:9:11
+   |
+LL | fn p([=(}
+   |     --    ^
+   |     ||
+   |     |unclosed delimiter
+   |     unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-81804.rs:9:11
+   |
+LL | fn p([=(}
+   |     --    ^
+   |     ||
+   |     |unclosed delimiter
+   |     unclosed delimiter
+
+error: expected pattern, found `=`
+  --> $DIR/issue-81804.rs:9:7
+   |
+LL | fn p([=(}
+   |       ^ expected pattern
+
+error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
+  --> $DIR/issue-81804.rs:9:8
+   |
+LL | fn p([=(}
+   |        ^ -^
+   |        | |
+   |        | help: `)` may belong here
+   |        unclosed delimiter
+
+error: expected item, found `]`
+  --> $DIR/issue-81804.rs:9:11
+   |
+LL | fn p([=(}
+   |           ^ expected item
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/privacy/auxiliary/ctor_aux.rs b/src/test/ui/privacy/auxiliary/ctor_aux.rs
new file mode 100644 (file)
index 0000000..9c99cca
--- /dev/null
@@ -0,0 +1,25 @@
+// edition:2021
+//! Missing docs lint warns about undocumented exported items.
+//! Use the lint to additionally verify that items are reachable
+//! but not exported.
+#![allow(non_camel_case_types)]
+#![deny(missing_docs)]
+
+mod hidden {
+    pub struct s;
+    pub enum e { x, y, z }
+    pub use e::*;
+    impl s {
+        pub fn f(&self) {}
+    }
+    impl e {
+        pub fn g(&self) {}
+    }
+}
+// Hide all type definitions while reexporting their constructors:
+mod e {}
+mod x {}
+mod y {}
+mod z {}
+mod s {}
+pub use hidden::*;
diff --git a/src/test/ui/privacy/ctor.rs b/src/test/ui/privacy/ctor.rs
new file mode 100644 (file)
index 0000000..0ec15d6
--- /dev/null
@@ -0,0 +1,16 @@
+// Verify that a type is considered reachable when its constructor is
+// reachable. The auxiliary library is constructed so that all types are
+// shadowed and cannot be named directly, while their constructors are
+// reexported. Regression test for issue #96934.
+//
+// aux-build:ctor_aux.rs
+// edition:2021
+// build-pass
+
+extern crate ctor_aux;
+
+fn main() {
+    ctor_aux::s.f();
+    ctor_aux::x.g();
+    ctor_aux::y.g();
+}
diff --git a/src/test/ui/rfc-1717-dllimport/rename-modifiers.rs b/src/test/ui/rfc-1717-dllimport/rename-modifiers.rs
new file mode 100644 (file)
index 0000000..30f4db7
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -l dylib=foo:bar
+// error-pattern: overriding linking modifiers from command line is not supported
+
+#![feature(native_link_modifiers_as_needed)]
+
+#![crate_type = "lib"]
+
+#[link(name = "foo", kind = "dylib", modifiers = "-as-needed")]
+extern "C" {}
diff --git a/src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr b/src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr
new file mode 100644 (file)
index 0000000..bee639b
--- /dev/null
@@ -0,0 +1,8 @@
+error: overriding linking modifiers from command line is not supported
+  --> $DIR/rename-modifiers.rs:9:1
+   |
+LL | extern "C" {}
+   | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index fbb941ffd9102ea427646a9ae47f95d654c22398..dd1f4826fe0516599ad798b9372422ce62d44137 100644 (file)
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/typeck.rs:9:22
    |
 LL |         Ok(x) if let Err(_) = x => {},
-   |                      ^^^^^^ expected enum `Option`, found enum `Result`
+   |                      ^^^^^^   - this expression has type `Option<bool>`
+   |                      |
+   |                      expected enum `Option`, found enum `Result`
    |
    = note: expected enum `Option<bool>`
               found enum `Result<_, _>`
@@ -11,7 +13,9 @@ error[E0308]: mismatched types
   --> $DIR/typeck.rs:11:22
    |
 LL |         Ok(x) if let 0 = x => {},
-   |                      ^ expected enum `Option`, found integer
+   |                      ^   - this expression has type `Option<bool>`
+   |                      |
+   |                      expected enum `Option`, found integer
    |
    = note: expected enum `Option<bool>`
               found type `{integer}`
index 7a5d7ac293483f91ea7541f50390865a5a7cb208..5856b18aa160c6c7bf99634d0daba4d08dbd4043 100644 (file)
@@ -3,5 +3,5 @@
 #![feature(raw_dylib)]
 //~^ WARNING: the feature `raw_dylib` is incomplete
 #[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+//~^ ERROR: link kind `raw-dylib` is only supported on Windows targets
 extern "C" {}
index f3879b63f91f7f0841989c7df933d739606c8730..600aac81a35932d0a6b4abd5db6dff38c47f6f87 100644 (file)
@@ -7,11 +7,12 @@ LL | #![feature(raw_dylib)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
-error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
-  --> $DIR/raw-dylib-windows-only.rs:5:1
+error[E0455]: link kind `raw-dylib` is only supported on Windows targets
+  --> $DIR/raw-dylib-windows-only.rs:5:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0455`.
index 0783f04dc9bd3c5583c1f851548f5996e6d5e5aa..ba6af8f15fa89658915f1ddad572cbfd4c52fe3f 100644 (file)
@@ -5,6 +5,7 @@ LL |     foo::<S>(s);
    |     ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
    |
    = help: the trait `Trait` is implemented for `&'a mut S`
+   = note: `for<'b> Trait` is implemented for `&'b mut S`, but not for `&'b S`
 note: required by a bound in `foo`
   --> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20
    |
index 3bd98c7630780a5c9ee02b44418ee0196df4e496..b3cb6dd06142be65bca5fe37c3d00e0a9706edd2 100644 (file)
@@ -8,7 +8,7 @@ LL |     opt = None;
    |
    = note: expected mutable reference `&mut Option<String>`
                            found enum `Option<_>`
-help: consider dereferencing here to assign to the mutable borrowed piece of memory
+help: consider dereferencing here to assign to the mutably borrowed value
    |
 LL |     *opt = None;
    |     +
@@ -34,7 +34,7 @@ LL |     opt = Some(String::new())
    |
    = note: expected mutable reference `&mut Option<String>`
                            found enum `Option<String>`
-help: consider dereferencing here to assign to the mutable borrowed piece of memory
+help: consider dereferencing here to assign to the mutably borrowed value
    |
 LL |     *opt = Some(String::new())
    |     +
index e4d58d3ccdb29b5994582e4d4fc2eb9b7b7e5d0e..3ad4ed24cf7fc7e09dff18e4a6183dd4160750ff 100644 (file)
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17h87acd86b3a6f1754E)
+error: symbol-name(_ZN5basic4main17hcbad207c0eeb0b3bE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h87acd86b3a6f1754)
+error: demangling(basic::main::hcbad207c0eeb0b3b)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
index c987ebc534302c852aec85945fbce5125aea38c5..21bf21ee71c6ff9a3697e87fb38983f7f1a7e9bd 100644 (file)
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h8d22952c45e20d65E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h2f2efcf580c9b1eeE)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h8d22952c45e20d65)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h2f2efcf580c9b1ee)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
index cbdb6b96f468f48ea83ab127f9fdd683e8d660e9..f36947914179cc45e0f017f6dc32ef4ceb6e35c5 100644 (file)
@@ -2,7 +2,13 @@ error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::It
   --> $DIR/assoc-type-in-superbad.rs:12:16
    |
 LL |     type Key = u32;
-   |                ^^^ expected `i32`, found `u32`
+   |                ^^^ expected `u32`, found `i32`
+   |
+note: required by a bound in `Foo`
+  --> $DIR/assoc-type-in-superbad.rs:7:25
+   |
+LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.rs b/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.rs
new file mode 100644 (file)
index 0000000..538e74e
--- /dev/null
@@ -0,0 +1,24 @@
+struct A<T>(T);
+struct B;
+
+trait I<T> {}
+impl I<i32> for B {}
+impl I<u32> for B {}
+
+trait V<U> {
+    fn method(self) -> U;
+}
+
+impl<T, U> V<U> for A<T>
+where
+    T: I<U>,
+{
+    fn method(self) -> U { unimplemented!() }
+}
+
+fn main() {
+    let a = A(B);
+    a.method();
+    //~^ ERROR type annotations needed
+    //~| ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr b/src/test/ui/traits/not-suggest-non-existing-fully-qualified-path.stderr
new file mode 100644 (file)
index 0000000..65f2d99
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0282]: type annotations needed
+  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
+   |
+LL |     a.method();
+   |     --^^^^^^--
+   |     | |
+   |     | cannot infer type for type parameter `U` declared on the trait `V`
+   |     this method call resolves to `U`
+
+error[E0283]: type annotations needed
+  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
+   |
+LL |     a.method();
+   |     --^^^^^^--
+   |     | |
+   |     | cannot infer type for type parameter `U`
+   |     this method call resolves to `U`
+   |
+note: multiple `impl`s satisfying `B: I<_>` found
+  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:5:1
+   |
+LL | impl I<i32> for B {}
+   | ^^^^^^^^^^^^^^^^^
+LL | impl I<u32> for B {}
+   | ^^^^^^^^^^^^^^^^^
+note: required because of the requirements on the impl of `V<_>` for `A<B>`
+  --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:12:12
+   |
+LL | impl<T, U> V<U> for A<T>
+   |            ^^^^     ^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
index 0ea944ec2df55cd16c86fd976e62c5cdc379e522..2c9b41eea2abeb28209337b450fc04090669179d 100644 (file)
@@ -7,7 +7,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
 
 fn transmute<A, B>(x: A) -> B {
     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-    //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+    //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
 }
 
 fn foo<A, B, T: ?Sized>(x: T::A) -> B
index a3d17fabbe47fadbdafecc4d24dac4ba2d40b0ad..eab42ca568a04b3c24f6c69cb575557d90a1d698 100644 (file)
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
+error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B`
   --> $DIR/enforce-supertrait-projection.rs:9:5
    |
 LL | fn transmute<A, B>(x: A) -> B {
diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr
new file mode 100644 (file)
index 0000000..40829f5
--- /dev/null
@@ -0,0 +1,46 @@
+warning: trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:20:29
+   |
+LL |     for<'any> &'any mut (): Clone,
+   |                             ^^^^^
+   |
+   = note: `#[warn(trivial_bounds)]` on by default
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:28:21
+   |
+LL | struct S where i32: Foo;
+   |                     ^^^
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:31:28
+   |
+LL | impl Foo for () where i32: Foo {
+   |                            ^^^
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:40:19
+   |
+LL | fn f() where i32: Foo {
+   |                   ^^^
+
+warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:48:28
+   |
+LL | fn g() where &'static str: Foo {
+   |                            ^^^
+
+warning: trait bound String: Neg does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:57:13
+   |
+LL |     String: ::std::ops::Neg<Output = String>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: trait bound i32: Iterator does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:65:10
+   |
+LL |     i32: Iterator,
+   |          ^^^^^^^^
+
+warning: 7 warnings emitted
+
diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr
new file mode 100644 (file)
index 0000000..40829f5
--- /dev/null
@@ -0,0 +1,46 @@
+warning: trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:20:29
+   |
+LL |     for<'any> &'any mut (): Clone,
+   |                             ^^^^^
+   |
+   = note: `#[warn(trivial_bounds)]` on by default
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:28:21
+   |
+LL | struct S where i32: Foo;
+   |                     ^^^
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:31:28
+   |
+LL | impl Foo for () where i32: Foo {
+   |                            ^^^
+
+warning: trait bound i32: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:40:19
+   |
+LL | fn f() where i32: Foo {
+   |                   ^^^
+
+warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:48:28
+   |
+LL | fn g() where &'static str: Foo {
+   |                            ^^^
+
+warning: trait bound String: Neg does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:57:13
+   |
+LL |     String: ::std::ops::Neg<Output = String>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: trait bound i32: Iterator does not depend on any type or lifetime parameters
+  --> $DIR/issue-73021-impossible-inline.rs:65:10
+   |
+LL |     i32: Iterator,
+   |          ^^^^^^^^
+
+warning: 7 warnings emitted
+
diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs
new file mode 100644 (file)
index 0000000..ab6677e
--- /dev/null
@@ -0,0 +1,71 @@
+// build-pass
+// revisions: no-opt inline
+// [inline]compile-flags: -Zmir-opt-level=3 --emit=mir
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait Foo {
+    fn test(&self);
+}
+
+fn foo<'a>(s: &'a mut ())
+where
+    &'a mut (): Foo,
+{
+    s.test();
+}
+
+fn clone(it: &mut ()) -> &mut ()
+where
+    for<'any> &'any mut (): Clone,
+    //~^ WARN trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters
+{
+    it.clone()
+}
+
+fn generic_function<X: Foo>(x: X) {}
+
+struct S where i32: Foo;
+//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters
+
+impl Foo for () where i32: Foo {
+//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters
+    fn test(&self) {
+        3i32.test();
+        Foo::test(&4i32);
+        generic_function(5i32);
+    }
+}
+
+fn f() where i32: Foo {
+//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters
+    let s = S;
+    3i32.test();
+    Foo::test(&4i32);
+    generic_function(5i32);
+}
+
+fn g() where &'static str: Foo {
+//~^ WARN trait bound &'static str: Foo does not depend on any type or lifetime parameters
+    "Foo".test();
+    Foo::test(&"Foo");
+    generic_function("Foo");
+}
+
+fn use_op(s: String) -> String
+where
+    String: ::std::ops::Neg<Output = String>,
+//~^ WARN trait bound String: Neg does not depend on any type or lifetime parameters
+{
+    -s
+}
+
+fn use_for()
+where
+    i32: Iterator,
+//~^ WARN trait bound i32: Iterator does not depend on any type or lifetime parameters
+{
+    for _ in 2i32 {}
+}
+
+fn main() {}
index cf46add124cb30a68658f3d1b1ea20c7fcaa6e40..093c1c231861f1893fb4c0e68d35a21546575ddc 100644 (file)
@@ -15,7 +15,6 @@ fn main() {}
 fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
     t
     //~^ ERROR non-defining opaque type use in defining scope
-    //~| ERROR `U` doesn't implement `Debug`
 }
 
 fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
index d661196e1bf190dbaa6fae69ace72ef959ff0cbb..b2edcc5526a4abf329785fae9802006c1e3c3a76 100644 (file)
@@ -1,14 +1,3 @@
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use.rs:16:5
-   |
-LL |     t
-   |     ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-help: consider restricting type parameter `U`
-   |
-LL | type TwoTys<T, U: std::fmt::Debug> = impl Debug;
-   |                 +++++++++++++++++
-
 error: non-defining opaque type use in defining scope
   --> $DIR/generic_duplicate_param_use.rs:16:5
    |
@@ -22,7 +11,7 @@ LL | type TwoTys<T, U> = impl Debug;
    |             ^  ^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:22:5
+  --> $DIR/generic_duplicate_param_use.rs:21:5
    |
 LL |     t
    |     ^
@@ -34,7 +23,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug;
    |                   ^^  ^^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:27:5
+  --> $DIR/generic_duplicate_param_use.rs:26:5
    |
 LL |     t
    |     ^
@@ -45,6 +34,5 @@ note: constant used multiple times
 LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
    |                ^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.rs b/src/test/ui/type-alias-impl-trait/issue-53092.rs
new file mode 100644 (file)
index 0000000..45792ba
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+type Bug<T, U> = impl Fn(T) -> U + Copy;
+
+const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+
+fn make_bug<T, U: From<T>>() -> Bug<T, U> {
+    |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
+}
+
+fn main() {
+    CONST_BUG(0);
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.stderr b/src/test/ui/type-alias-impl-trait/issue-53092.stderr
new file mode 100644 (file)
index 0000000..2d423a0
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `U: From<T>` is not satisfied
+  --> $DIR/issue-53092.rs:9:5
+   |
+LL |     |x| x.into()
+   |     ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
+   |
+note: required by a bound in `make_bug`
+  --> $DIR/issue-53092.rs:8:19
+   |
+LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
+   |                   ^^^^^^^ required by this bound in `make_bug`
+help: consider restricting type parameter `U`
+   |
+LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
+   |              +++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564-working.rs b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs
new file mode 100644 (file)
index 0000000..38accc8
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait IterBits {
+    type BitsIter: Iterator<Item = u8>;
+    fn iter_bits(self, n: u8) -> Self::BitsIter;
+}
+
+impl<T: Copy, E> IterBits for T
+where
+    T: std::ops::Shr<Output = T>
+        + std::ops::BitAnd<T, Output = T>
+        + std::convert::From<u8>
+        + std::convert::TryInto<u8, Error = E>,
+    E: std::fmt::Debug,
+{
+    type BitsIter = impl std::iter::Iterator<Item = u8>;
+    fn iter_bits(self, n: u8) -> Self::BitsIter {
+        (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+    }
+}
+
+fn main() {}
index 0aeebae639e91811cfcda603e03fb34b96f42521..4fc7679311a2e55b031dd0cf0c460c979476212b 100644 (file)
@@ -19,7 +19,6 @@ impl<T: Copy, E> IterBits for T
     fn iter_bits(self, n: u8) -> Self::BitsIter {
         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
         //~^ ERROR non-defining opaque type use in defining scope
-        //~| ERROR type mismatch resolving
     }
 }
 
index 9cb07cbbb44082d0572b9b367b7594e298596ab5..bbc93657be32f27501c851460adbfb0554ee0826 100644 (file)
@@ -1,16 +1,3 @@
-error[E0271]: type mismatch resolving `<[closure@$DIR/issue-60564.rs:20:28: 20:100] as FnOnce<(u8,)>>::Output == I`
-  --> $DIR/issue-60564.rs:20:9
-   |
-LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
-   |                         - this type parameter
-...
-LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found type parameter `I`
-   |
-   = note:        expected type `u8`
-           found type parameter `I`
-   = note: required because of the requirements on the impl of `Iterator` for `Map<Rev<std::ops::Range<u8>>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>`
-
 error: non-defining opaque type use in defining scope
   --> $DIR/issue-60564.rs:20:9
    |
@@ -23,6 +10,5 @@ note: used non-generic type `u8` for generic parameter
 LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
    |                         ^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0271`.
index bffff8787e4a2b3fe49cd0a57c9e016dae1d5050..b50462bf237bb9509f9d090097ef9675af48b8b8 100644 (file)
@@ -8,7 +8,6 @@ trait Trait<T> {}
 
 fn f<'a>() -> Alias<'a, ()> {}
 //~^ ERROR non-defining opaque type use in defining scope
-//~| ERROR the trait bound `(): Trait<U>` is not satisfied
 
 fn main() {}
 
index b79d638ad9951d57817be996f5d83b2e5b2ed0fd..8059621b61a096bc84ed17714d7130d44e864d72 100644 (file)
@@ -1,14 +1,3 @@
-error[E0277]: the trait bound `(): Trait<U>` is not satisfied
-  --> $DIR/issue-68368-non-defining-use.rs:9:29
-   |
-LL | fn f<'a>() -> Alias<'a, ()> {}
-   |                             ^^ the trait `Trait<U>` is not implemented for `()`
-   |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
-   |
-LL | type Alias<'a, U> = impl Trait<U> where (): Trait<U>;
-   |                                   ++++++++++++++++++
-
 error: non-defining opaque type use in defining scope
   --> $DIR/issue-68368-non-defining-use.rs:9:29
    |
@@ -21,6 +10,5 @@ note: used non-generic type `()` for generic parameter
 LL | type Alias<'a, U> = impl Trait<U>;
    |                ^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index b0de8bf6aa4f267d578e319fff1bf448dac14d9d..428454bc04844d836b75c3a7fbde6796a1e84b53 100644 (file)
@@ -19,6 +19,5 @@ impl<T> WithAssoc<T> for () {
 
 fn my_fun() -> Return<()> {}
 //~^ ERROR non-defining opaque type use in defining scope
-//~| ERROR non-defining opaque type use in defining scope
 
 fn main() {}
index d038fbbe1b40a191fc35a9da4cccccc9f95293f7..7b50c8af26e5fe98d74a704b12ff57060e2f612b 100644 (file)
@@ -26,18 +26,6 @@ note: used non-generic type `()` for generic parameter
 LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
    |             ^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
-   |
-LL | fn my_fun() -> Return<()> {}
-   |                           ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
-   |
-LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             ^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs
new file mode 100644 (file)
index 0000000..449e9fb
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce(B);
+
+fn foo<B: Bar>() -> FooFn<B> {
+    fn mop<B: Bar>(bar: B) { bar.bar() }
+    mop // NOTE: no function pointer, but function zst item
+    //~^ ERROR the trait bound `B: Bar` is not satisfied
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom(42);
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr
new file mode 100644 (file)
index 0000000..e000548
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `B: Bar` is not satisfied
+  --> $DIR/wf-check-fn-def.rs:11:5
+   |
+LL |     mop // NOTE: no function pointer, but function zst item
+   |     ^^^ the trait `Bar` is not implemented for `B`
+   |
+note: required by a bound in `mop`
+  --> $DIR/wf-check-fn-def.rs:10:15
+   |
+LL |     fn mop<B: Bar>(bar: B) { bar.bar() }
+   |               ^^^ required by this bound in `mop`
+help: consider restricting type parameter `B`
+   |
+LL | type FooFn<B: Bar> = impl FnOnce(B);
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs
new file mode 100644 (file)
index 0000000..3b8470e
--- /dev/null
@@ -0,0 +1,23 @@
+#![feature(type_alias_impl_trait)]
+
+// build-pass
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce(B);
+
+fn foo<B: Bar>() -> FooFn<B> {
+    fn mop<B: Bar>(bar: B) { bar.bar() }
+    mop as fn(B)
+    // function pointers don't have any obligations on them,
+    // thus the above compiles. It's obviously unsound to just
+    // procure a `FooFn` from the ether without making sure that
+    // the pointer is actually legal for all `B`
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom(42);
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.rs b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs
new file mode 100644 (file)
index 0000000..2c70696
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce();
+
+fn foo<B: Bar>(bar: B) -> FooFn<B> {
+    move || { bar.bar() }
+    //~^ ERROR the trait bound `B: Bar` is not satisfied
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom();
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr
new file mode 100644 (file)
index 0000000..58ae861
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `B: Bar` is not satisfied
+  --> $DIR/wf_check_closures.rs:10:5
+   |
+LL |     move || { bar.bar() }
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `B`
+   |
+note: required by a bound in `foo`
+  --> $DIR/wf_check_closures.rs:9:11
+   |
+LL | fn foo<B: Bar>(bar: B) -> FooFn<B> {
+   |           ^^^ required by this bound in `foo`
+help: consider restricting type parameter `B`
+   |
+LL | type FooFn<B: Bar> = impl FnOnce();
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.fixed b/src/test/ui/typeck/assign-non-lval-derefmut.fixed
new file mode 100644 (file)
index 0000000..0c23199
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let x = std::sync::Mutex::new(1usize);
+    *x.lock().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    *x.lock().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+
+    let mut y = x.lock().unwrap();
+    *y = 2;
+    //~^ ERROR mismatched types
+    *y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.rs b/src/test/ui/typeck/assign-non-lval-derefmut.rs
new file mode 100644 (file)
index 0000000..ec1882f
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let x = std::sync::Mutex::new(1usize);
+    x.lock().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    x.lock().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+
+    let mut y = x.lock().unwrap();
+    y = 2;
+    //~^ ERROR mismatched types
+    y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.stderr b/src/test/ui/typeck/assign-non-lval-derefmut.stderr
new file mode 100644 (file)
index 0000000..a6fcdfe
--- /dev/null
@@ -0,0 +1,58 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assign-non-lval-derefmut.rs:5:23
+   |
+LL |     x.lock().unwrap() = 2;
+   |     ----------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *x.lock().unwrap() = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+  --> $DIR/assign-non-lval-derefmut.rs:7:5
+   |
+LL |     x.lock().unwrap() += 1;
+   |     -----------------^^^^^
+   |     |
+   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |
+help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()`
+   |
+LL |     *x.lock().unwrap() += 1;
+   |     +
+
+error[E0308]: mismatched types
+  --> $DIR/assign-non-lval-derefmut.rs:11:9
+   |
+LL |     let mut y = x.lock().unwrap();
+   |                 ----------------- expected due to this value
+LL |     y = 2;
+   |         ^ expected struct `MutexGuard`, found integer
+   |
+   = note: expected struct `MutexGuard<'_, usize>`
+                found type `{integer}`
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *y = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+  --> $DIR/assign-non-lval-derefmut.rs:13:5
+   |
+LL |     y += 1;
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |
+help: `+=` can be used on `usize`, you can dereference `y`
+   |
+LL |     *y += 1;
+   |     +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308, E0368.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.fixed b/src/test/ui/typeck/assign-non-lval-mut-ref.fixed
new file mode 100644 (file)
index 0000000..10c7b9d
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    *x.last_mut().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    *x.last_mut().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+
+    let y = x.last_mut().unwrap();
+    *y = 2;
+    //~^ ERROR mismatched types
+    *y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.rs b/src/test/ui/typeck/assign-non-lval-mut-ref.rs
new file mode 100644 (file)
index 0000000..bceff0e
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    x.last_mut().unwrap() = 2;
+    //~^ ERROR invalid left-hand side of assignment
+    x.last_mut().unwrap() += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+
+    let y = x.last_mut().unwrap();
+    y = 2;
+    //~^ ERROR mismatched types
+    y += 1;
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `&mut usize`
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
new file mode 100644 (file)
index 0000000..be2e9fe
--- /dev/null
@@ -0,0 +1,56 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assign-non-lval-mut-ref.rs:5:27
+   |
+LL |     x.last_mut().unwrap() = 2;
+   |     --------------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *x.last_mut().unwrap() = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
+  --> $DIR/assign-non-lval-mut-ref.rs:7:5
+   |
+LL |     x.last_mut().unwrap() += 1;
+   |     ---------------------^^^^^
+   |     |
+   |     cannot use `+=` on type `&mut usize`
+   |
+help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
+   |
+LL |     *x.last_mut().unwrap() += 1;
+   |     +
+
+error[E0308]: mismatched types
+  --> $DIR/assign-non-lval-mut-ref.rs:11:9
+   |
+LL |     let y = x.last_mut().unwrap();
+   |             --------------------- expected due to this value
+LL |     y = 2;
+   |         ^ expected `&mut usize`, found integer
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |     *y = 2;
+   |     +
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `&mut usize`
+  --> $DIR/assign-non-lval-mut-ref.rs:13:5
+   |
+LL |     y += 1;
+   |     -^^^^^
+   |     |
+   |     cannot use `+=` on type `&mut usize`
+   |
+help: `+=` can be used on `usize`, you can dereference `y`
+   |
+LL |     *y += 1;
+   |     +
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308, E0368.
+For more information about an error, try `rustc --explain E0070`.
index 70b5b63f1cba7ccb7034b6ecf3e1068e5ada37ad..167edc8942aec47d11cc2c26860ec9ca269de9d1 100644 (file)
@@ -5,6 +5,11 @@ LL |         vec![].last_mut().unwrap() = 3_u8;
    |         -------------------------- ^
    |         |
    |         cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutably borrowed value
+   |
+LL |         *vec![].last_mut().unwrap() = 3_u8;
+   |         +
 
 error: aborting due to previous error
 
index 4152a1065ca14e8d1d1d8e48079d690d7ee5a187..bff08847d37dd3e8355bb29d3e9ca40898458492 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(link_cfg)]
+
 #[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form
 extern "C" {}
 
@@ -7,4 +9,13 @@
 #[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form
 extern "C" {}
 
+#[link(wasm_import_module = "foo", name = "bar")] //~ ERROR: `wasm_import_module` is incompatible with other arguments
+extern "C" {}
+
+#[link(wasm_import_module = "foo", kind = "dylib")] //~ ERROR: `wasm_import_module` is incompatible with other arguments
+extern "C" {}
+
+#[link(wasm_import_module = "foo", cfg(FALSE))] //~ ERROR: `wasm_import_module` is incompatible with other arguments
+extern "C" {}
+
 fn main() {}
index 47d6cb6899723c4b2bcd2b4b5d937ea714928081..e792c33e91a9d23893d033b50a298d1f0501e4b7 100644 (file)
@@ -1,20 +1,38 @@
-error: must be of the form `#[link(wasm_import_module = "...")]`
-  --> $DIR/wasm-import-module.rs:1:22
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/wasm-import-module.rs:3:22
    |
 LL | #[link(name = "...", wasm_import_module)]
    |                      ^^^^^^^^^^^^^^^^^^
 
-error: must be of the form `#[link(wasm_import_module = "...")]`
-  --> $DIR/wasm-import-module.rs:4:22
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/wasm-import-module.rs:6:22
    |
 LL | #[link(name = "...", wasm_import_module(x))]
    |                      ^^^^^^^^^^^^^^^^^^^^^
 
-error: must be of the form `#[link(wasm_import_module = "...")]`
-  --> $DIR/wasm-import-module.rs:7:22
+error: wasm import module must be of the form `wasm_import_module = "string"`
+  --> $DIR/wasm-import-module.rs:9:22
    |
 LL | #[link(name = "...", wasm_import_module())]
    |                      ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+  --> $DIR/wasm-import-module.rs:12:8
+   |
+LL | #[link(wasm_import_module = "foo", name = "bar")]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+  --> $DIR/wasm-import-module.rs:15:8
+   |
+LL | #[link(wasm_import_module = "foo", kind = "dylib")]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
+  --> $DIR/wasm-import-module.rs:18:8
+   |
+LL | #[link(wasm_import_module = "foo", cfg(FALSE))]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
index a44758ac805600edbb6ba51e7e6fb81a6077c0cd..3f052d8eed98c6a24f8b332fb2e6e6249d12d8c1 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a44758ac805600edbb6ba51e7e6fb81a6077c0cd
+Subproject commit 3f052d8eed98c6a24f8b332fb2e6e6249d12d8c1
index cc354b50afa39faa68159d1d16ae8027ff8f5658..826eb0ae6b13b1cdc6d22049c5751969830d106c 100644 (file)
@@ -5,7 +5,7 @@
 use if_chain::if_chain;
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, Guard, HirId, Pat, PatKind};
+use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
@@ -109,7 +109,7 @@ fn check_arm<'tcx>(
             (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
         };
         // the binding must not be used in the if guard
-        if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(_, e))| !is_local_used(cx, *e, binding_id));
+        if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id));
         // ...or anywhere in the inner expression
         if match inner {
             IfLetOrMatch::IfLet(_, _, body, els) => {
index 14098340745b10b9a9654c0ccbd2d8684f5d8b3d..34a5f8444dea0af0d58a1d221db4a1ca3998999a 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks};
+use clippy_utils::{is_default_equivalent, peel_blocks};
 use rustc_hir::{
     def::{DefKind, Res},
     Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@@ -71,8 +71,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                 self_ty,
                 ..
             }) = item.kind;
-            if let attrs = cx.tcx.hir().attrs(item.hir_id());
-            if !is_automatically_derived(attrs);
+            if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
             if !item.span.from_expansion();
             if let Some(def_id) = trait_ref.trait_def_id();
             if cx.tcx.is_diagnostic_item(sym::Default, def_id);
@@ -81,6 +80,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if let ImplItemKind::Fn(_, b) = &impl_item.kind;
             if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
             if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
+            if let attrs = cx.tcx.hir().attrs(item.hir_id());
             if !attrs.iter().any(|attr| attr.doc_str().is_some());
             if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
             if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
index 557e101494e3acd87c9188336c3198cdb89fd639..545bc7d210332706e960f0d96fa72f65c3e5f0f7 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then};
 use clippy_utils::paths;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{is_automatically_derived, is_lint_allowed, match_def_path};
+use clippy_utils::{is_lint_allowed, match_def_path};
 use if_chain::if_chain;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
@@ -171,8 +171,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         }) = item.kind
         {
             let ty = cx.tcx.type_of(item.def_id);
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            let is_automatically_derived = is_automatically_derived(attrs);
+            let is_automatically_derived =
+                cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -201,7 +201,7 @@ fn check_hash_peq<'tcx>(
         then {
             // Look for the PartialEq implementations for `ty`
             cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
-                let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
+                let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
 
                 if peq_is_automatically_derived == hash_is_automatically_derived {
                     return;
@@ -255,7 +255,7 @@ fn check_ord_partial_ord<'tcx>(
         then {
             // Look for the PartialOrd implementations for `ty`
             cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
-                let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id));
+                let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
 
                 if partial_ord_is_automatically_derived == ord_is_automatically_derived {
                     return;
index 1ae2e20c1e060e78aa206ee20a25f31c05f59c65..d3d3ed2c2357e27b5b1f52fac2f7e9c79b166140 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_hir::{
     hir_id::HirIdSet,
     intravisit::{walk_expr, Visitor},
-    Block, Expr, ExprKind, Guard, HirId, Pat, Stmt, StmtKind, UnOp,
+    Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -478,7 +478,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     let mut is_map_used = self.is_map_used;
                     for arm in arms {
                         self.visit_pat(arm.pat);
-                        if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
+                        if let Some(Guard::If(guard) | Guard::IfLet(&Let { init: guard, .. })) = arm.guard {
                             self.visit_non_tail_expr(guard);
                         }
                         is_map_used |= self.visit_cond_arm(arm.body);
index 1b19868e4c70faf2d33f6a5911528f971b25672b..530d6d4de35f1c2bceb58e92c6b8624c9db23c75 100644 (file)
@@ -150,7 +150,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if check_inputs(cx, body.params, args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
             let substs = cx.typeck_results().node_substs(body.value.hir_id);
-            let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
+            let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
             if check_sig(cx, closure_ty, call_ty);
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
index 38e943d2eb8720cd98a0039e5dc3ac188c40d6b8..6672a6cb0b58fb7be926b3d0f074021645f602e2 100644 (file)
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_must_use_ty;
-use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method};
+use clippy_utils::{match_def_path, return_ty, trait_ref_of_method};
 
 use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
-    let attr = must_use_attr(attrs);
+    let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
     if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -44,7 +44,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = must_use_attr(attrs);
+        let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
         } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() {
@@ -67,7 +67,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
 
         let attrs = cx.tcx.hir().attrs(item.hir_id());
-        let attr = must_use_attr(attrs);
+        let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
         } else if let hir::TraitFn::Provided(eid) = *eid {
index 43911a313d5a606aa022b7371e2cf22b63433eed..5c46d6c7df7056856ed7afcd3d37f09b70cd2808 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{Opaque, PredicateKind::Trait};
+use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
@@ -67,7 +67,7 @@ fn check_fn(
             let preds = cx.tcx.explicit_item_bounds(id);
             let mut is_future = false;
             for &(p, _span) in preds {
-                let p = p.subst(cx.tcx, subst);
+                let p = EarlyBinder(p).subst(cx.tcx, subst);
                 if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
                     if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
index b8d620d81713046ac5892d9c6239cb72157d240f..09164690700ef0fa95b7c11584ac7b36938cba8d 100644 (file)
@@ -1,4 +1,3 @@
-use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_lint_allowed, meets_msrv, msrvs};
@@ -161,7 +160,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                 let id = cx.tcx.hir().local_def_id(v.id);
                 (matches!(v.data, hir::VariantData::Unit(_))
                     && v.ident.as_str().starts_with('_')
-                    && is_doc_hidden(cx.tcx.get_attrs(id.to_def_id())))
+                    && cx.tcx.is_doc_hidden(id.to_def_id()))
                 .then(|| (id, v.span))
             });
             if let Some((id, span)) = iter.next()
index 93bf0dc62e076707e4228e784a016a96b80c2f61..fc45ccee18528fbbffe6f6664cd3a91f7d298160 100644 (file)
@@ -193,6 +193,5 @@ fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
 }
 
 fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
-    let attrs = cx.tcx.get_attrs(variant_def.def_id);
-    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
+    cx.tcx.is_doc_hidden(variant_def.def_id) || cx.tcx.has_attr(variant_def.def_id, sym::unstable)
 }
index 5c3e505c06c47821976f3377b1606a4d71c5d83e..9d8f8999ce409488a8c33f5c1c5a7dd0956a70a2 100644 (file)
@@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             ExprKind::MethodCall(path, arguments, _) => {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
-                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
+                let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
                 check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
             },
             _ => (),
index 2f733f221d572250866fd51150826a871b83a504..2bdccb425071b135ebb88e5ff403460912f03fa4 100644 (file)
@@ -85,7 +85,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                             // can't be implemented for unsafe new
                             return;
                         }
-                        if clippy_utils::is_doc_hidden(cx.tcx.hir().attrs(id)) {
+                        if cx.tcx.is_doc_hidden(impl_item.def_id) {
                             // shouldn't be implemented when it is hidden in docs
                             return;
                         }
index beb812793f81ccfe5d40a44ef3c6840051d3bc6a..d66698f8adc6927e1546214232364e2a3c7bfc97 100644 (file)
@@ -596,7 +596,7 @@ fn visit_match(&mut self, expr: &'tcx Expr<'tcx>, arms: &'tcx [Arm<'tcx>]) {
                 let mut vars = std::mem::take(&mut self.ret_vars);
                 let _ = arm.guard.as_ref().map(|guard| {
                     self.visit_expr(match guard {
-                        Guard::If(expr) | Guard::IfLet(_, expr) => expr,
+                        Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => expr,
                     });
                     vars.append(&mut self.ret_vars);
                 });
index 1469cb434c00c07dfeb0190d14c5527bf5e96c25..09ac514d014eb1d67fc1f9a6ad9a58f5061bdaaf 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_hir;
-use clippy_utils::is_automatically_derived;
 use if_chain::if_chain;
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -37,8 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if_chain! {
             if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            if !is_automatically_derived(attrs);
+            if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
             if trait_ref.path.res.def_id() == eq_trait;
             then {
index 1507c75ff612314236bb2b2ed5be935a9fa9088e..37aac8b2a49786efe9cf3fa62d54e2855e4406d8 100644 (file)
@@ -114,7 +114,7 @@ fn check_fn(
             }
 
             // Give up on loops
-            if terminator.successors().any(|s| *s == bb) {
+            if terminator.successors().any(|s| s == bb) {
                 continue;
             }
 
@@ -440,7 +440,7 @@ fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, loc: mir:
             // Short-circuit
             if (usage.cloned_used && usage.clone_consumed_or_mutated) ||
                 // Give up on loops
-                tdata.terminator().successors().any(|s| *s == bb)
+                tdata.terminator().successors().any(|s| s == bb)
             {
                 return CloneUsage {
                     cloned_used: true,
index 94ae0c8f5a65909b68f179dba39a051ef40b861a..f300acf0fb2ba4d300e490449e9a99a4d56c7f04 100644 (file)
@@ -290,7 +290,7 @@ fn visit_exprs_for_binary_ops(
 
     fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         if let Some(adt) = ty.ty_adt_def() {
-            if get_attr(cx.sess(), cx.tcx.get_attrs(adt.did()), "has_significant_drop").count() > 0 {
+            if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 {
                 return true;
             }
         }
index f5e21267a8976e4aff843095c42782569b9c73cd..be6277332db4dbd5d7d9530388c36c62f46e4b13 100644 (file)
@@ -307,7 +307,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     .non_enum_variant()
                     .fields
                     .iter()
-                    .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
+                    .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs));
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
                     return ReducedTy::TypeErasure;
                 };
index ff5be825b781712030c5383b956721384f1184d6..3f4d0fd199d0814cd712d285571c48a83d615379 100644 (file)
@@ -315,11 +315,11 @@ fn arm(&self, arm: &Binding<&hir::Arm<'_>>) {
                 out!("if let Some(Guard::If({expr})) = {arm}.guard;");
                 self.expr(expr);
             },
-            Some(hir::Guard::IfLet(pat, expr)) => {
-                bind!(self, pat, expr);
-                out!("if let Some(Guard::IfLet({pat}, {expr}) = {arm}.guard;");
-                self.pat(pat);
-                self.expr(expr);
+            Some(hir::Guard::IfLet(let_expr)) => {
+                bind!(self, let_expr);
+                out!("if let Some(Guard::IfLet({let_expr}) = {arm}.guard;");
+                self.pat(field!(let_expr.pat));
+                self.expr(field!(let_expr.init));
             },
         }
         self.expr(field!(arm.body));
index 7f448175e3267c7db0fb9e58ba735a40978efb86..904b1a05ccc30dfc50a81f0581bbb3431f751f88 100644 (file)
@@ -1,6 +1,7 @@
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_session::Session;
+use rustc_ast::attr;
 use rustc_span::sym;
 use std::str::FromStr;
 
@@ -158,7 +159,3 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
         .any(|l| attr::list_contains_name(&l, sym::hidden))
 }
 
-/// Return true if the attributes contain `#[unstable]`
-pub fn is_unstable(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| attr.has_name(sym::unstable))
-}
index fdb822c3e5b6d6f5908312885dbff2455323c455..a80c7ee4929584d3885810b7050972aa208f28bb 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use std::cmp::Ordering::{self, Equal};
@@ -420,7 +420,7 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                 let substs = if self.substs.is_empty() {
                     substs
                 } else {
-                    substs.subst(self.lcx.tcx, self.substs)
+                    EarlyBinder(substs).subst(self.lcx.tcx, self.substs)
                 };
 
                 let result = self
index f4da625f1e306a0e083716316ede4a5f07ced8d7..aa21f15ee5d9dedf4452ae62941e5ac295f554c2 100644 (file)
@@ -301,7 +301,9 @@ fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool
     fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
         match (left, right) {
             (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
-            (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
+            (Guard::IfLet(l), Guard::IfLet(r)) => {
+                self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
+            },
             _ => false,
         }
     }
@@ -894,7 +896,7 @@ pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
 
     pub fn hash_guard(&mut self, g: &Guard<'_>) {
         match g {
-            Guard::If(expr) | Guard::IfLet(_, expr) => {
+            Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => {
                 self.hash_expr(expr);
             },
         }
index 7d46952d9718b5cbcdf149de40a1a9206d1afa25..6db7f247a9925cb3ff2530837c3b80ed2e391498 100644 (file)
@@ -66,7 +66,7 @@
 use std::sync::{Mutex, MutexGuard};
 
 use if_chain::if_chain;
-use rustc_ast::ast::{self, Attribute, LitKind};
+use rustc_ast::ast::{self, LitKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
     def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
-    ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
+    HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
     Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
     TraitRef, TyKind, UnOp,
 };
@@ -1472,12 +1471,6 @@ pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>
     }
 }
 
-/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
-/// implementations have.
-pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
-    has_attr(attrs, sym::automatically_derived)
-}
-
 pub fn is_self(slf: &Param<'_>) -> bool {
     if let PatKind::Binding(.., name, _) = slf.pat.kind {
         name.name == kw::SelfLower
@@ -1724,11 +1717,6 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
     None
 }
 
-// Finds the `#[must_use]` attribute, if any
-pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
-    attrs.iter().find(|a| a.has_name(sym::must_use))
-}
-
 // check if expr is calling method or function with #[must_use] attribute
 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let did = match expr.kind {
@@ -1745,7 +1733,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
+    did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
 }
 
 /// Checks if an expression represents the identity function
@@ -2079,35 +2067,6 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
     false
 }
 
-struct TestItemNamesVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    names: Vec<Symbol>,
-}
-
-impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> {
-    fn visit_item(&mut self, item: &Item<'_>) {
-        if let ItemKind::Const(ty, _body) = item.kind {
-            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
-                // We could also check for the type name `test::TestDescAndFn`
-                if let Res::Def(DefKind::Struct, _) = path.res {
-                    let has_test_marker = self
-                        .tcx
-                        .hir()
-                        .attrs(item.hir_id())
-                        .iter()
-                        .any(|a| a.has_name(sym::rustc_test_marker));
-                    if has_test_marker {
-                        self.names.push(item.ident.name);
-                    }
-                }
-            }
-        }
-    }
-    fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
-    fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
-    fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
-}
-
 static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
 
 fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
@@ -2116,10 +2075,28 @@ fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(
     match map.entry(module) {
         Entry::Occupied(entry) => f(entry.get()),
         Entry::Vacant(entry) => {
-            let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
-            tcx.hir().visit_item_likes_in_module(module, &mut visitor);
-            visitor.names.sort_unstable();
-            f(&*entry.insert(visitor.names))
+            let mut names = Vec::new();
+            for id in tcx.hir().module_items(module) {
+                if matches!(tcx.def_kind(id.def_id), DefKind::Const)
+                    && let item = tcx.hir().item(id)
+                    && let ItemKind::Const(ty, _body) = item.kind {
+                    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+                        // We could also check for the type name `test::TestDescAndFn`
+                        if let Res::Def(DefKind::Struct, _) = path.res {
+                            let has_test_marker = tcx
+                                .hir()
+                                .attrs(item.hir_id())
+                                .iter()
+                                .any(|a| a.has_name(sym::rustc_test_marker));
+                            if has_test_marker {
+                                names.push(item.ident.name);
+                            }
+                        }
+                    }
+                }
+            }
+            names.sort_unstable();
+            f(&*entry.insert(names))
         },
     }
 }
index 75808b1b17461d657f322903733e48fdf467fc2d..66d373a1bf81a79506dea1c10b526c88c18cb8c1 100644 (file)
@@ -14,7 +14,6 @@
 use rustc_semver::RustcVersion;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi::RustIntrinsic;
 use std::borrow::Cow;
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
@@ -323,7 +322,7 @@ fn check_terminator<'a, 'tcx>(
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute {
+                if tcx.is_intrinsic(fn_def_id) && tcx.item_name(fn_def_id) == sym::transmute {
                     return Err((
                         span,
                         "can only call `transmute` from const items, not `const fn`".into(),
index 901e3e5390c5dbbe9a4ac6d54a6adaaa0a737ec7..b09eb8c6cd10b89c7756bfe350083c05700d2ac7 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use std::iter;
 
-use crate::{match_def_path, must_use_attr, path_res, paths};
+use crate::{match_def_path, path_res, paths};
 
 // Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -178,18 +178,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(),
-        ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+        ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
+        ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
         ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
-        ty::Opaque(ref def_id, _) => {
+        ty::Opaque(def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
-                    if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+                    if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
                     }
                 }
@@ -199,7 +199,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Dynamic(binder, _) => {
             for predicate in binder.iter() {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
-                    if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+                    if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
                         return true;
                     }
                 }
@@ -520,7 +520,7 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
         let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs();
         match *ty.kind() {
             ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())),
-            ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs))),
+            ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs))),
             ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)),
             ty::Dynamic(bounds, _) => {
                 let lang_items = cx.tcx.lang_items();
index 2cb368c6881887cd6042740739bdfcbeb2c58fcd..ea13ae13208ada66dc0008bbc38845d3a7dbc607 100644 (file)
@@ -246,6 +246,10 @@ pub struct Config {
     /// Only run tests that match these filters
     pub filters: Vec<String>,
 
+    /// Skip tests tests matching these substrings. Corresponds to
+    /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags.
+    pub skip: Vec<String>,
+
     /// Exactly match the filter, rather than a substring
     pub filter_exact: bool,
 
index 3d11ea21acf9fccbb126c324ef6e8b10fe1248c8..e23cccf6cd1294320f0aa9ead725fb2e1318fe89 100644 (file)
@@ -91,6 +91,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
         .optflag("", "ignored", "run tests marked as ignored")
+        .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING")
         .optflag("", "exact", "filters match exactly")
         .optopt(
             "",
@@ -236,6 +237,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         debugger: None,
         run_ignored,
         filters: matches.free.clone(),
+        skip: matches.opt_strs("skip"),
         filter_exact: matches.opt_present("exact"),
         force_pass_mode: matches.opt_str("pass").map(|mode| {
             mode.parse::<PassMode>()
@@ -312,6 +314,7 @@ pub fn log_config(config: &Config) {
     logv(c, format!("mode: {}", config.mode));
     logv(c, format!("run_ignored: {}", config.run_ignored));
     logv(c, format!("filters: {:?}", config.filters));
+    logv(c, format!("skip: {:?}", config.skip));
     logv(c, format!("filter_exact: {}", config.filter_exact));
     logv(
         c,
@@ -506,7 +509,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         shuffle: false,
         shuffle_seed: None,
         test_threads: None,
-        skip: vec![],
+        skip: config.skip.clone(),
         list: false,
         options: test::Options::new(),
         time_options: None,
@@ -595,6 +598,7 @@ fn collect_tests_from_dir(
             debug!("found test file: {:?}", file_path.display());
             let paths =
                 TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
+
             tests.extend(make_test(config, &paths, inputs))
         } else if file_path.is_dir() {
             let relative_file_path = relative_dir_path.join(file.file_name());
index 6d94fe3ebb9cb53b76480ba6561e31dd203fe075..a59a0584d5e99245753b2d39621d534345af6d53 100644 (file)
@@ -3494,22 +3494,21 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
         normalize_path(parent_dir, "$DIR");
 
         // Paths into the libstd/libcore
-        let src_dir = self
-            .config
-            .src_base
-            .parent()
-            .unwrap()
-            .parent()
-            .unwrap()
-            .parent()
-            .unwrap()
-            .join("library");
+        let base_dir = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap();
+        let src_dir = base_dir.join("library");
         normalize_path(&src_dir, "$SRC_DIR");
 
+        // `ui-fulldeps` tests can show paths to the compiler source when testing macros from
+        // `rustc_macros`
+        // eg. /home/user/rust/compiler
+        let compiler_src_dir = base_dir.join("compiler");
+        normalize_path(&compiler_src_dir, "$COMPILER_DIR");
+
         if let Some(virtual_rust_source_base_dir) =
             option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
         {
             normalize_path(&virtual_rust_source_base_dir.join("library"), "$SRC_DIR");
+            normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$COMPILER_DIR");
         }
 
         // Paths into the build directory
index 3b8b6aa8b689971d3b8776cefe3d809501e1b8ff..19ef76477c0ea1722f91ab6b1c2dcb365f064992 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3b8b6aa8b689971d3b8776cefe3d809501e1b8ff
+Subproject commit 19ef76477c0ea1722f91ab6b1c2dcb365f064992
index d75884567afee2db06aa351e2b051883e8d08f11..8532410a1bf3a5c21436cf08231ed1bddacfc8ef 100644 (file)
@@ -138,7 +138,7 @@ async function main(argv) {
     try {
         // This is more convenient that setting fields one by one.
         let args = [
-            "--variable", "DOC_PATH", opts["doc_folder"],
+            "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error",
         ];
         if (opts["debug"]) {
             debug = true;
index 98d0f5dc656c17ac0cd4359630e5aba742d9b121..df3185758bfc087e23bda0b6828dd86fb0665ede 100644 (file)
@@ -1,182 +1,6 @@
 const fs = require('fs');
 const path = require('path');
 
-function getNextStep(content, pos, stop) {
-    while (pos < content.length && content[pos] !== stop &&
-           (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
-        pos += 1;
-    }
-    if (pos >= content.length) {
-        return null;
-    }
-    if (content[pos] !== stop) {
-        return pos * -1;
-    }
-    return pos;
-}
-
-// Stupid function extractor based on indent. Doesn't support block
-// comments. If someone puts a ' or an " in a block comment this
-// will blow up. Template strings are not tested and might also be
-// broken.
-function extractFunction(content, functionName) {
-    var level = 0;
-    var splitter = "function " + functionName + "(";
-    var stop;
-    var pos, start;
-
-    while (true) {
-        start = content.indexOf(splitter);
-        if (start === -1) {
-            break;
-        }
-        pos = start;
-        while (pos < content.length && content[pos] !== ')') {
-            pos += 1;
-        }
-        if (pos >= content.length) {
-            break;
-        }
-        pos = getNextStep(content, pos + 1, '{');
-        if (pos === null) {
-            break;
-        } else if (pos < 0) {
-            content = content.slice(-pos);
-            continue;
-        }
-        while (pos < content.length) {
-            // Eat single-line comments
-            if (content[pos] === '/' && pos > 0 && content[pos - 1] === '/') {
-                do {
-                    pos += 1;
-                } while (pos < content.length && content[pos] !== '\n');
-
-            // Eat multiline comment.
-            } else if (content[pos] === '*' && pos > 0 && content[pos - 1] === '/') {
-                do {
-                    pos += 1;
-                } while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
-
-            // Eat quoted strings
-            } else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
-                       (pos === 0 || content[pos - 1] !== '/')) {
-                stop = content[pos];
-                do {
-                    if (content[pos] === '\\') {
-                        pos += 1;
-                    }
-                    pos += 1;
-                } while (pos < content.length && content[pos] !== stop);
-
-            // Otherwise, check for block level.
-            } else if (content[pos] === '{') {
-                level += 1;
-            } else if (content[pos] === '}') {
-                level -= 1;
-                if (level === 0) {
-                    return content.slice(start, pos + 1);
-                }
-            }
-            pos += 1;
-        }
-        content = content.slice(start + 1);
-    }
-    return null;
-}
-
-// Stupid function extractor for array.
-function extractArrayVariable(content, arrayName, kind) {
-    if (typeof kind === "undefined") {
-        kind = "let ";
-    }
-    var splitter = kind + arrayName;
-    while (true) {
-        var start = content.indexOf(splitter);
-        if (start === -1) {
-            break;
-        }
-        var pos = getNextStep(content, start, '=');
-        if (pos === null) {
-            break;
-        } else if (pos < 0) {
-            content = content.slice(-pos);
-            continue;
-        }
-        pos = getNextStep(content, pos, '[');
-        if (pos === null) {
-            break;
-        } else if (pos < 0) {
-            content = content.slice(-pos);
-            continue;
-        }
-        while (pos < content.length) {
-            if (content[pos] === '"' || content[pos] === "'") {
-                var stop = content[pos];
-                do {
-                    if (content[pos] === '\\') {
-                        pos += 2;
-                    } else {
-                        pos += 1;
-                    }
-                } while (pos < content.length &&
-                         (content[pos] !== stop || content[pos - 1] === '\\'));
-            } else if (content[pos] === ']' &&
-                       pos + 1 < content.length &&
-                       content[pos + 1] === ';') {
-                return content.slice(start, pos + 2);
-            }
-            pos += 1;
-        }
-        content = content.slice(start + 1);
-    }
-    if (kind === "let ") {
-        return extractArrayVariable(content, arrayName, "const ");
-    }
-    return null;
-}
-
-// Stupid function extractor for variable.
-function extractVariable(content, varName, kind) {
-    if (typeof kind === "undefined") {
-        kind = "let ";
-    }
-    var splitter = kind + varName;
-    while (true) {
-        var start = content.indexOf(splitter);
-        if (start === -1) {
-            break;
-        }
-        var pos = getNextStep(content, start, '=');
-        if (pos === null) {
-            break;
-        } else if (pos < 0) {
-            content = content.slice(-pos);
-            continue;
-        }
-        while (pos < content.length) {
-            if (content[pos] === '"' || content[pos] === "'") {
-                var stop = content[pos];
-                do {
-                    if (content[pos] === '\\') {
-                        pos += 2;
-                    } else {
-                        pos += 1;
-                    }
-                } while (pos < content.length &&
-                         (content[pos] !== stop || content[pos - 1] === '\\'));
-            } else if (content[pos] === ';' || content[pos] === ',') {
-                return content.slice(start, pos + 1);
-            }
-            pos += 1;
-        }
-        content = content.slice(start + 1);
-    }
-    if (kind === "let ") {
-        return extractVariable(content, varName, "const ");
-    }
-    return null;
-}
-
 function loadContent(content) {
     var Module = module.constructor;
     var m = new Module();
@@ -194,20 +18,6 @@ function readFile(filePath) {
     return fs.readFileSync(filePath, 'utf8');
 }
 
-function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
-    var content = '';
-    for (var i = 0; i < thingsToLoad.length; ++i) {
-        var tmp = funcToCall(fileContent, thingsToLoad[i]);
-        if (tmp === null) {
-            console.log('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
-            process.exit(1);
-        }
-        content += tmp;
-        content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
-    }
-    return content;
-}
-
 function contentToDiffLine(key, value) {
     return `"${key}": "${value}",`;
 }
@@ -264,46 +74,6 @@ function lookForEntry(entry, data) {
     return null;
 }
 
-function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
-    if (searchIndex[searchIndex.length - 1].length === 0) {
-        searchIndex.pop();
-    }
-    searchIndex.pop();
-    var fullSearchIndex = searchIndex.join("\n") + '\nexports.rawSearchIndex = searchIndex;';
-    searchIndex = loadContent(fullSearchIndex);
-    var finalJS = "";
-
-    var arraysToLoad = ["itemTypes"];
-    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER",
-                           "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
-                           "TY_PRIMITIVE", "TY_KEYWORD",
-                           "levenshtein_row2"];
-    // execQuery first parameter is built in getQuery (which takes in the search input).
-    // execQuery last parameter is built in buildIndex.
-    // buildIndex requires the hashmap from search-index.
-    var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "buildIndex", "execQuery", "parseQuery", "createQueryResults",
-                           "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
-                           "parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
-                           "isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
-                           "itemTypeFromName", "isEndCharacter", "isErrorCharacter",
-                           "isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
-                           "checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
-
-    const functions = ["hasOwnPropertyRustdoc", "onEach"];
-    ALIASES = {};
-    finalJS += 'window = { "currentCrate": "' + crate + '", rootPath: "../" };\n';
-    finalJS += loadThings(functions, 'function', extractFunction, storageJs);
-    finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, searchJs);
-    finalJS += loadThings(variablesToLoad, 'variable', extractVariable, searchJs);
-    finalJS += loadThings(functionsToLoad, 'function', extractFunction, searchJs);
-
-    var loaded = loadContent(finalJS);
-    var index = loaded.buildIndex(searchIndex.rawSearchIndex);
-
-    return [loaded, index];
-}
-
 // This function checks if `expected` has all the required fields needed for the checks.
 function checkNeededFields(fullPath, expected, error_text, queryName, position) {
     let fieldsToCheck;
@@ -359,8 +129,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
                 'compared to EXPECTED');
         }
     } else if (expected !== null && typeof expected !== "undefined" &&
-               expected.constructor == Object)
-    {
+               expected.constructor == Object) {
         for (const key in expected) {
             if (!expected.hasOwnProperty(key)) {
                 continue;
@@ -382,21 +151,20 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
     }
 }
 
-function runParser(query, expected, loaded, loadedFile, queryName) {
+function runParser(query, expected, parseQuery, queryName) {
     var error_text = [];
     checkNeededFields("", expected, error_text, queryName, null);
     if (error_text.length === 0) {
-        valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
+        valueCheck('', expected, parseQuery(query), error_text, queryName);
     }
     return error_text;
 }
 
-function runSearch(query, expected, index, loaded, loadedFile, queryName) {
-    const filter_crate = loadedFile.FILTER_CRATE;
+function runSearch(query, expected, doSearch, loadedFile, queryName) {
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
+    var results = doSearch(query, loadedFile.FILTER_CRATE);
     var error_text = [];
 
     for (var key in expected) {
@@ -488,7 +256,7 @@ function runCheck(loadedFile, key, callback) {
     return 0;
 }
 
-function runChecks(testFile, loaded, index) {
+function runChecks(testFile, doSearch, parseQuery) {
     var checkExpected = false;
     var checkParsed = false;
     var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
@@ -518,24 +286,40 @@ function runChecks(testFile, loaded, index) {
 
     if (checkExpected) {
         res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
-            return runSearch(query, expected, index, loaded, loadedFile, text);
+            return runSearch(query, expected, doSearch, loadedFile, text);
         });
     }
     if (checkParsed) {
         res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
-            return runParser(query, expected, loaded, loadedFile, text);
+            return runParser(query, expected, parseQuery, text);
         });
     }
     return res;
 }
 
-function load_files(doc_folder, resource_suffix, crate) {
-    var searchJs = readFile(path.join(doc_folder, "search" + resource_suffix + ".js"));
-    var storageJs = readFile(path.join(doc_folder, "storage" + resource_suffix + ".js"));
-    var searchIndex = readFile(
-        path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n");
-
-    return loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate);
+/**
+ * Load searchNNN.js and search-indexNNN.js.
+ *
+ * @param {string} doc_folder      - Path to a folder generated by running rustdoc
+ * @param {string} resource_suffix - Version number between filename and .js, e.g. "1.59.0"
+ * @returns {Object}               - Object containing two keys: `doSearch`, which runs a search
+ *   with the loaded index and returns a table of results; and `parseQuery`, which is the
+ *   `parseQuery` function exported from the search module.
+ */
+function loadSearchJS(doc_folder, resource_suffix) {
+    const searchJs = path.join(doc_folder, "search" + resource_suffix + ".js");
+    const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
+    const searchIndex = require(searchIndexJs);
+    const searchModule = require(searchJs);
+    const searchWords = searchModule.initSearch(searchIndex.searchIndex);
+
+    return {
+        doSearch: function (queryStr, filterCrate, currentCrate) {
+            return searchModule.execQuery(searchModule.parseQuery(queryStr), searchWords,
+                filterCrate, currentCrate);
+        },
+        parseQuery: searchModule.parseQuery,
+    }
 }
 
 function showHelp() {
@@ -598,35 +382,34 @@ function parseOptions(args) {
     return null;
 }
 
-function checkFile(test_file, opts, loaded, index) {
-    const test_name = path.basename(test_file, ".js");
-
-    process.stdout.write('Checking "' + test_name + '" ... ');
-    return runChecks(test_file, loaded, index);
-}
-
 function main(argv) {
     var opts = parseOptions(argv.slice(2));
     if (opts === null) {
         return 1;
     }
 
-    var [loaded, index] = load_files(
+    let parseAndSearch = loadSearchJS(
         opts["doc_folder"],
-        opts["resource_suffix"],
-        opts["crate_name"]);
+        opts["resource_suffix"]);
     var errors = 0;
 
+    let doSearch = function (queryStr, filterCrate) {
+        return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]);
+    };
+
     if (opts["test_file"].length !== 0) {
-        opts["test_file"].forEach(function(file) {
-            errors += checkFile(file, opts, loaded, index);
+        opts["test_file"].forEach(function (file) {
+            process.stdout.write(`Testing ${file} ... `);
+            errors += runChecks(file, doSearch, parseAndSearch.parseQuery);
         });
     } else if (opts["test_folder"].length !== 0) {
-        fs.readdirSync(opts["test_folder"]).forEach(function(file) {
+        fs.readdirSync(opts["test_folder"]).forEach(function (file) {
             if (!file.endsWith(".js")) {
                 return;
             }
-            errors += checkFile(path.join(opts["test_folder"], file), opts, loaded, index);
+            process.stdout.write(`Testing ${file} ... `);
+            errors += runChecks(path.join(opts["test_folder"], file), doSearch,
+                    parseAndSearch.parseQuery);
         });
     }
     return errors > 0 ? 1 : 0;
index 76d05362056834143a07e0e1fa723bc9e1e49f71..af92bdd9f58d13be4fa85f2e311ed2f1da561123 100644 (file)
@@ -1 +1 @@
-1.62.0
+1.63.0