]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #75137 - Aaron1011:fix/hygiene-skip-expndata, r=petrochenkov
authorbors <bors@rust-lang.org>
Sun, 9 Aug 2020 18:19:34 +0000 (18:19 +0000)
committerbors <bors@rust-lang.org>
Sun, 9 Aug 2020 18:19:34 +0000 (18:19 +0000)
Don't serialize ExpnData for foreign crates

When we encode an ExpnId into the crate metadata, we write out the
CrateNum of the crate that 'owns' the corresponding `ExpnData`, which
is later used to decode the `ExpnData` from its owning crate.

However, we current serialize the `ExpnData` for all `ExpnIds` that we
serialize, even if the `ExpnData` was already serialized into a foreign
crate. This commit skips encoding this kind of `ExpnData`, which should
hopefully speed up metadata encoding and reduce the total metadata size.

377 files changed:
.github/workflows/ci.yml
Cargo.lock
library/alloc/src/alloc.rs
library/alloc/src/alloc/tests.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/navigate.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/lib.rs
library/alloc/src/raw_vec.rs
library/alloc/src/raw_vec/tests.rs
library/alloc/src/rc.rs
library/alloc/src/sync.rs
library/alloc/tests/btree/map.rs
library/alloc/tests/heap.rs
library/alloc/tests/lib.rs
library/core/src/alloc/mod.rs
library/core/src/array/iter.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/num/mod.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/str/mod.rs
library/panic_unwind/src/lib.rs
library/std/Cargo.toml
library/std/src/alloc.rs
library/std/src/collections/hash/map.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/net/ip.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/rt.rs
library/std/src/sys/hermit/mod.rs
library/std/src/sys/hermit/thread.rs
library/std/src/sys/unix/fd.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys_common/backtrace.rs
library/test/src/helpers/concurrency.rs
library/test/src/lib.rs
library/unwind/src/lib.rs
src/ci/github-actions/ci.yml
src/doc/book
src/doc/embedded-book
src/doc/reference
src/doc/rust-by-example
src/etc/gdb_providers.py
src/etc/lldb_providers.py
src/etc/natvis/libstd.natvis
src/librustc_ast/Cargo.toml
src/librustc_ast/ast.rs
src/librustc_ast/attr/mod.rs
src/librustc_ast/entry.rs
src/librustc_ast/expand/allocator.rs
src/librustc_ast/expand/mod.rs
src/librustc_ast/lib.rs
src/librustc_ast/mut_visit.rs
src/librustc_ast/token.rs
src/librustc_ast/util/comments.rs
src/librustc_ast/util/comments/tests.rs
src/librustc_ast/util/lev_distance/tests.rs
src/librustc_ast/visit.rs
src/librustc_ast_lowering/expr.rs
src/librustc_ast_lowering/item.rs
src/librustc_ast_lowering/lib.rs
src/librustc_ast_passes/ast_validation.rs
src/librustc_ast_passes/feature_gate.rs
src/librustc_ast_pretty/pprust.rs
src/librustc_ast_pretty/pprust/tests.rs
src/librustc_attr/builtin.rs
src/librustc_builtin_macros/cfg.rs
src/librustc_builtin_macros/cfg_accessible.rs
src/librustc_builtin_macros/deriving/default.rs
src/librustc_builtin_macros/deriving/generic/mod.rs
src/librustc_builtin_macros/env.rs
src/librustc_builtin_macros/global_allocator.rs
src/librustc_builtin_macros/llvm_asm.rs
src/librustc_builtin_macros/proc_macro_harness.rs
src/librustc_builtin_macros/standard_library_imports.rs
src/librustc_builtin_macros/test.rs
src/librustc_builtin_macros/test_harness.rs
src/librustc_builtin_macros/util.rs
src/librustc_codegen_llvm/consts.rs
src/librustc_codegen_llvm/coverageinfo/mapgen.rs
src/librustc_codegen_llvm/coverageinfo/mod.rs
src/librustc_codegen_llvm/debuginfo/gdb.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/coverageinfo/map.rs
src/librustc_codegen_ssa/coverageinfo/mod.rs
src/librustc_codegen_ssa/mir/place.rs
src/librustc_codegen_ssa/traits/coverageinfo.rs
src/librustc_driver/lib.rs
src/librustc_error_codes/error_codes/E0271.md
src/librustc_error_codes/error_codes/E0502.md
src/librustc_error_codes/error_codes/E0745.md
src/librustc_error_codes/error_codes/E0746.md
src/librustc_error_codes/error_codes/E0747.md
src/librustc_error_codes/error_codes/E0750.md
src/librustc_errors/emitter.rs
src/librustc_expand/base.rs
src/librustc_expand/config.rs
src/librustc_expand/expand.rs
src/librustc_expand/mbe/macro_rules.rs
src/librustc_expand/module.rs
src/librustc_expand/mut_visit/tests.rs
src/librustc_expand/parse/lexer/tests.rs
src/librustc_expand/parse/tests.rs
src/librustc_expand/proc_macro.rs
src/librustc_expand/proc_macro_server.rs
src/librustc_expand/tests.rs
src/librustc_expand/tokenstream/tests.rs
src/librustc_feature/active.rs
src/librustc_hir/def.rs
src/librustc_hir/lang_items.rs
src/librustc_hir/weak_lang_items.rs
src/librustc_incremental/assert_dep_graph.rs
src/librustc_incremental/assert_module_sources.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_index/bit_set.rs
src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
src/librustc_infer/infer/glb.rs
src/librustc_infer/infer/nll_relate/mod.rs
src/librustc_infer/infer/region_constraints/leak_check.rs
src/librustc_infer/infer/sub.rs
src/librustc_interface/interface.rs
src/librustc_interface/passes.rs
src/librustc_interface/proc_macro_decls.rs
src/librustc_interface/queries.rs
src/librustc_interface/tests.rs
src/librustc_interface/util.rs
src/librustc_lint/builtin.rs
src/librustc_lint/levels.rs
src/librustc_lint/nonstandard_style.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/link_args.rs
src/librustc_metadata/native_libs.rs
src/librustc_metadata/rmeta/decoder.rs
src/librustc_metadata/rmeta/decoder/cstore_impl.rs
src/librustc_metadata/rmeta/encoder.rs
src/librustc_metadata/rmeta/mod.rs
src/librustc_middle/middle/limits.rs
src/librustc_middle/mir/coverage/mod.rs
src/librustc_middle/mir/interpret/value.rs
src/librustc_middle/mir/mod.rs
src/librustc_middle/query/mod.rs
src/librustc_middle/traits/query.rs
src/librustc_middle/ty/context.rs
src/librustc_middle/ty/flags.rs
src/librustc_middle/ty/fold.rs
src/librustc_middle/ty/instance.rs
src/librustc_middle/ty/mod.rs
src/librustc_middle/ty/query/job.rs
src/librustc_middle/ty/subst.rs
src/librustc_middle/ty/trait_def.rs
src/librustc_mir/borrow_check/diagnostics/mod.rs
src/librustc_mir/dataflow/framework/engine.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/util.rs
src/librustc_mir/monomorphize/polymorphize.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/instrument_coverage.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_mir/transform/rustc_peek.rs
src/librustc_mir/transform/simplify_try.rs
src/librustc_mir/transform/validate.rs
src/librustc_mir_build/build/mod.rs
src/librustc_mir_build/thir/cx/mod.rs
src/librustc_parse/lexer/mod.rs
src/librustc_parse/lib.rs
src/librustc_parse/parser/attr.rs
src/librustc_parse/parser/diagnostics.rs
src/librustc_parse/parser/generics.rs
src/librustc_parse/parser/item.rs
src/librustc_parse/parser/mod.rs
src/librustc_parse_format/lib.rs
src/librustc_passes/check_attr.rs
src/librustc_passes/check_const.rs
src/librustc_passes/dead.rs
src/librustc_passes/diagnostic_items.rs
src/librustc_passes/entry.rs
src/librustc_passes/lang_items.rs
src/librustc_passes/layout_test.rs
src/librustc_passes/lib_features.rs
src/librustc_passes/liveness.rs
src/librustc_passes/stability.rs
src/librustc_passes/weak_lang_items.rs
src/librustc_plugin_impl/build.rs
src/librustc_plugin_impl/lib.rs
src/librustc_plugin_impl/load.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/lifetimes.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_save_analysis/lib.rs
src/librustc_session/filesearch.rs
src/librustc_session/output.rs
src/librustc_session/session.rs
src/librustc_span/hygiene.rs
src/librustc_span/lib.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/test.rs
src/librustc_target/spec/wasm32_base.rs
src/librustc_trait_selection/autoderef.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_trait_selection/traits/on_unimplemented.rs
src/librustc_trait_selection/traits/select/mod.rs
src/librustc_traits/chalk/db.rs
src/librustc_ty/ty.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/pat.rs
src/librustc_typeck/check/place_op.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/collect/type_of.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/mem_categorization.rs
src/librustdoc/clean/cfg/tests.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/docfs.rs
src/librustdoc/html/highlight/tests.rs
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/test.rs
src/test/codegen-units/polymorphization/pr-75255.rs [new file with mode: 0644]
src/test/codegen/some-global-nonnull.rs [new file with mode: 0644]
src/test/debuginfo/function-arguments-naked.rs
src/test/debuginfo/pretty-std-collections-hash.rs
src/test/mir-opt/const-promotion-extern-static.rs
src/test/mir-opt/const_allocation.rs
src/test/mir-opt/const_allocation2.rs
src/test/mir-opt/const_allocation3.rs
src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit [new file with mode: 0644]
src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit [new file with mode: 0644]
src/test/mir-opt/const_prop/large_array_index.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
src/test/mir-opt/inline/inline-into-box-place.rs
src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage.rs
src/test/rustdoc-ui/auxiliary/extern_macros.rs [new file with mode: 0644]
src/test/rustdoc-ui/doctest-output.rs
src/test/rustdoc-ui/doctest-output.stdout
src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr [new file with mode: 0644]
src/test/rustdoc/auxiliary/elided-lifetime.rs [new file with mode: 0644]
src/test/rustdoc/elided-lifetime.rs [new file with mode: 0644]
src/test/rustdoc/intra-link-trait-item.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui/allocator/custom.rs
src/test/ui/allocator/xcrate-use.rs
src/test/ui/asm/bad-arch.rs [new file with mode: 0644]
src/test/ui/asm/bad-arch.stderr [new file with mode: 0644]
src/test/ui/async-await/issue-68523-start.rs
src/test/ui/async-await/issue-68523-start.stderr
src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs [new file with mode: 0644]
src/test/ui/const-generics/const-param-in-trait-ungated.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
src/test/ui/const-generics/defaults/wrong-order.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/wrong-order.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/wrong-order.rs
src/test/ui/const-generics/defaults/wrong-order.stderr [deleted file]
src/test/ui/const-generics/issues/issue-56445.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-56445.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-56445.rs
src/test/ui/const-generics/issues/issue-56445.stderr [deleted file]
src/test/ui/const-generics/issues/issue-60263.stderr
src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs
src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr [deleted file]
src/test/ui/const-generics/issues/issue-61336-1.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61336-1.rs
src/test/ui/const-generics/issues/issue-61336-1.stderr [deleted file]
src/test/ui/const-generics/issues/issue-61336-2.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61336-2.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61336-2.rs
src/test/ui/const-generics/issues/issue-61336-2.stderr [deleted file]
src/test/ui/const-generics/issues/issue-61336.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61336.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61336.rs
src/test/ui/const-generics/issues/issue-61422.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61422.rs
src/test/ui/const-generics/issues/issue-61422.stderr [deleted file]
src/test/ui/const-generics/issues/issue-61432.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61432.rs
src/test/ui/const-generics/issues/issue-61432.stderr [deleted file]
src/test/ui/const-generics/issues/issue-61747.full.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61747.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-61747.rs
src/test/ui/const-generics/issues/issue-61747.stderr [deleted file]
src/test/ui/const-generics/issues/issue-64494.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-64494.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-72787.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-72787.stderr [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/assoc_const.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/complex-expression.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/complex-expression.stderr [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/complex-types.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/complex-types.stderr [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs
src/test/ui/consts/unsizing-cast-non-null.rs [new file with mode: 0644]
src/test/ui/consts/unsizing-cast-non-null.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-asm.rs
src/test/ui/feature-gates/feature-gate-asm2.rs
src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
src/test/ui/feature-gates/feature-gate-const_generics.stderr
src/test/ui/higher-rank-trait-bounds/issue-59311.rs [new file with mode: 0644]
src/test/ui/higher-rank-trait-bounds/issue-59311.stderr [new file with mode: 0644]
src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr
src/test/ui/panics/issue-47429-short-backtraces.rs [new file with mode: 0644]
src/test/ui/panics/issue-47429-short-backtraces.run.stderr [new file with mode: 0644]
src/test/ui/polymorphization/closure_in_upvar/fn.rs [new file with mode: 0644]
src/test/ui/polymorphization/closure_in_upvar/fnmut.rs [new file with mode: 0644]
src/test/ui/polymorphization/closure_in_upvar/fnonce.rs [new file with mode: 0644]
src/test/ui/polymorphization/closure_in_upvar/other.rs [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function-1.rs [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function-1.stderr [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function-2.rs [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function-2.stderr [new file with mode: 0644]
src/test/ui/polymorphization/promoted-function.rs
src/test/ui/polymorphization/unsized_cast.rs
src/test/ui/polymorphization/unsized_cast.stderr
src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs [new file with mode: 0644]
src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr [new file with mode: 0644]
src/test/ui/proc-macro/doc-comment-preserved.rs [new file with mode: 0644]
src/test/ui/proc-macro/doc-comment-preserved.stdout [new file with mode: 0644]
src/test/ui/realloc-16687.rs
src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
src/test/ui/regions/regions-mock-codegen.rs
src/test/ui/rfc-2091-track-caller/error-with-main.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-main.stderr [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-start.rs [new file with mode: 0644]
src/test/ui/rfc-2091-track-caller/error-with-start.stderr [new file with mode: 0644]
src/test/ui/simd/simd-intrinsic-generic-bitmask.rs
src/test/ui/simd/simd-intrinsic-generic-select.rs
src/tools/cargo
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/functions.rs
src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
src/tools/clippy/clippy_lints/src/non_expressive_names.rs
src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/clippy/clippy_lints/src/utils/attrs.rs
src/tools/clippy/clippy_lints/src/utils/mod.rs
src/tools/clippy/tests/ui/indexing_slicing_index.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/error_index_generator/main.rs
src/tools/miri
src/tools/publish_toolstate.py
src/tools/tidy/src/error_codes_check.rs
src/tools/unicode-table-generator/src/main.rs

index 86f60349c67771dcd0fc0f0fb504948382e16067..a19cca9071f011c582289a2807bcb96293f63839 100644 (file)
@@ -575,6 +575,7 @@ jobs:
       CACHE_DOMAIN: ci-caches-gha.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
     strategy:
+      fail-fast: false
       matrix:
         include:
           - name: aarch64-gnu
index d4f4ec7f6f0a3ae00a39e8fed136aeca559ef890..57e7079dfb2f063ace55c010f4c54eeb6a87b121 100644 (file)
@@ -137,12 +137,6 @@ dependencies = [
  "winapi 0.3.8",
 ]
 
-[[package]]
-name = "autocfg"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
-
 [[package]]
 name = "autocfg"
 version = "1.0.0"
@@ -766,7 +760,7 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg",
  "cfg-if",
  "lazy_static",
 ]
@@ -1245,11 +1239,11 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.6.2"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cd9867f119b19fecb08cd5c326ad4488d7a1da4bf75b4d95d71db742525aaab"
+checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
 dependencies = [
- "autocfg 0.1.7",
+ "autocfg",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -2079,7 +2073,7 @@ version = "0.9.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986"
 dependencies = [
- "autocfg 1.0.0",
+ "autocfg",
  "cc",
  "libc",
  "openssl-src",
@@ -3201,7 +3195,6 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
- "scoped-tls",
  "smallvec 1.4.0",
  "tracing",
 ]
@@ -4925,7 +4918,7 @@ dependencies = [
  "ansi_term 0.12.1",
  "lazy_static",
  "matchers",
- "parking_lot 0.9.0",
+ "parking_lot 0.10.2",
  "regex",
  "sharded-slab",
  "smallvec 1.4.0",
index 98c7ac3f2ef17cde30f163dfd658c70a0bfeae45..518ac11b5a009850d07869b8d182ba4b483680ee 100644 (file)
@@ -164,25 +164,34 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for Global {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
-        unsafe {
-            let size = layout.size();
-            if size == 0 {
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
-            } else {
-                let raw_ptr = match init {
-                    AllocInit::Uninitialized => alloc(layout),
-                    AllocInit::Zeroed => alloc_zeroed(layout),
-                };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
-                Ok(MemoryBlock { ptr, size })
-            }
-        }
+    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(alloc(layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
+    }
+
+    #[inline]
+    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
     }
 
     #[inline]
     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
+            // SAFETY: `layout` is non-zero in size,
+            // other conditions must be upheld by the caller
             unsafe { dealloc(ptr.as_ptr(), layout) }
         }
     }
@@ -193,38 +202,59 @@ unsafe fn grow(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-        init: AllocInit,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
         debug_assert!(
-            new_size >= size,
-            "`new_size` must be greater than or equal to `memory.size()`"
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = realloc(ptr.as_ptr(), layout, new_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+            }
         }
+    }
 
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if layout.size() == 0 => {
-                let new_layout =
-                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
-                self.alloc(new_layout, init)
-            }
-            ReallocPlacement::MayMove => {
-                // `realloc` probably checks for `new_size > size` or something similar.
-                let ptr = unsafe {
-                    intrinsics::assume(new_size > size);
-                    realloc(ptr.as_ptr(), layout, new_size)
-                };
-                let memory =
-                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
-                unsafe {
-                    init.init_offset(memory, size);
+    #[inline]
+    unsafe fn grow_zeroed(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        debug_assert!(
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
+
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = realloc(ptr.as_ptr(), layout, new_size);
+                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
                 }
-                Ok(memory)
             }
         }
     }
@@ -235,35 +265,34 @@ unsafe fn shrink(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let old_size = layout.size();
         debug_assert!(
-            new_size <= size,
-            "`new_size` must be smaller than or equal to `memory.size()`"
+            new_size <= old_size,
+            "`new_size` must be smaller than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
-        }
-
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if new_size == 0 => {
-                unsafe {
-                    self.dealloc(ptr, layout);
-                }
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
-            }
-            ReallocPlacement::MayMove => {
-                // `realloc` probably checks for `new_size < size` or something similar.
-                let ptr = unsafe {
-                    intrinsics::assume(new_size < size);
-                    realloc(ptr.as_ptr(), layout, new_size)
-                };
-                Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
+        let ptr = if new_size == old_size {
+            ptr
+        } else if new_size == 0 {
+            // SAFETY: `layout` is non-zero in size as `old_size` != `new_size`
+            // Other conditions must be upheld by the caller
+            unsafe {
+                self.dealloc(ptr, layout);
             }
-        }
+            layout.dangling()
+        } else {
+            // SAFETY: new_size is not zero,
+            // Other conditions must be upheld by the caller
+            let raw_ptr = unsafe {
+                // `realloc` probably checks for `new_size < old_size` or something similar.
+                intrinsics::assume(new_size < old_size);
+                realloc(ptr.as_ptr(), layout, new_size)
+            };
+            NonNull::new(raw_ptr).ok_or(AllocErr)?
+        };
+
+        Ok(NonNull::slice_from_raw_parts(ptr, new_size))
     }
 }
 
@@ -274,8 +303,8 @@ unsafe fn shrink(
 #[inline]
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
-    match Global.alloc(layout, AllocInit::Uninitialized) {
-        Ok(memory) => memory.ptr.as_ptr(),
+    match Global.alloc(layout) {
+        Ok(ptr) => ptr.as_non_null_ptr().as_ptr(),
         Err(_) => handle_alloc_error(layout),
     }
 }
index 1c003983df9892a1c13aef1d7796a9ad36594559..f7463d0daac93ad9fb9876c3e286c5ccd38d682e 100644 (file)
@@ -8,17 +8,16 @@
 fn allocate_zeroed() {
     unsafe {
         let layout = Layout::from_size_align(1024, 1).unwrap();
-        let memory = Global
-            .alloc(layout.clone(), AllocInit::Zeroed)
-            .unwrap_or_else(|_| handle_alloc_error(layout));
+        let ptr =
+            Global.alloc_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout));
 
-        let mut i = memory.ptr.cast::<u8>().as_ptr();
+        let mut i = ptr.as_non_null_ptr().as_ptr();
         let end = i.add(layout.size());
         while i < end {
             assert_eq!(*i, 0);
             i = i.offset(1);
         }
-        Global.dealloc(memory.ptr, layout);
+        Global.dealloc(ptr.as_non_null_ptr(), layout);
     }
 }
 
index 65e0c984fe893d0eaba2faf63adb74de20447e24..5e304beff78ab1cb469ce5bdab2e24a2004e4407 100644 (file)
 use core::ptr::{self, Unique};
 use core::task::{Context, Poll};
 
-use crate::alloc::{self, AllocInit, AllocRef, Global};
+use crate::alloc::{self, AllocRef, Global};
 use crate::borrow::Cow;
 use crate::raw_vec::RawVec;
 use crate::str::from_boxed_utf8_unchecked;
@@ -197,11 +197,7 @@ pub fn new(x: T) -> Box<T> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
         let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
-        let ptr = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
-            .ptr
-            .cast();
+        let ptr = Global.alloc(layout).unwrap_or_else(|_| alloc::handle_alloc_error(layout)).cast();
         unsafe { Box::from_raw(ptr.as_ptr()) }
     }
 
@@ -227,9 +223,8 @@ pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
     pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
         let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
         let ptr = Global
-            .alloc(layout, AllocInit::Zeroed)
+            .alloc_zeroed(layout)
             .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
-            .ptr
             .cast();
         unsafe { Box::from_raw(ptr.as_ptr()) }
     }
index 1db629c3bdf8da0e7f9754c9514e6b88168a4b9f..7e27aeb85392c05c813c7d63e9eb26294e2785fc 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
 use core::borrow::Borrow;
 use core::cmp::Ordering;
 use core::fmt::Debug;
@@ -355,6 +357,30 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+/// An owning iterator over the keys of a `BTreeMap`.
+///
+/// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
+/// See its documentation for more.
+///
+/// [`into_keys`]: BTreeMap::into_keys
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[derive(Debug)]
+pub struct IntoKeys<K, V> {
+    inner: IntoIter<K, V>,
+}
+
+/// An owning iterator over the values of a `BTreeMap`.
+///
+/// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
+/// See its documentation for more.
+///
+/// [`into_values`]: BTreeMap::into_values
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[derive(Debug)]
+pub struct IntoValues<K, V> {
+    inner: IntoIter<K, V>,
+}
+
 /// An iterator over a sub-range of entries in a `BTreeMap`.
 ///
 /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
@@ -1291,10 +1317,56 @@ fn dfs<'a, K, V>(node: NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>)
 
         self.length = dfs(self.root.as_ref().unwrap().as_ref());
     }
+
+    /// Creates a consuming iterator visiting all the keys, in sorted order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `K`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_into_keys_values)]
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(2, "b");
+    /// a.insert(1, "a");
+    ///
+    /// let keys: Vec<i32> = a.into_keys().collect();
+    /// assert_eq!(keys, [1, 2]);
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    pub fn into_keys(self) -> IntoKeys<K, V> {
+        IntoKeys { inner: self.into_iter() }
+    }
+
+    /// Creates a consuming iterator visiting all the values, in order by key.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `V`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_into_keys_values)]
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut a = BTreeMap::new();
+    /// a.insert(1, "hello");
+    /// a.insert(2, "goodbye");
+    ///
+    /// let values: Vec<&str> = a.into_values().collect();
+    /// assert_eq!(values, ["hello", "goodbye"]);
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    pub fn into_values(self) -> IntoValues<K, V> {
+        IntoValues { inner: self.into_iter() }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
+impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
     type Item = (&'a K, &'a V);
     type IntoIter = Iter<'a, K, V>;
 
@@ -1363,7 +1435,7 @@ fn clone(&self) -> Self {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
+impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
     type Item = (&'a K, &'a mut V);
     type IntoIter = IterMut<'a, K, V>;
 
@@ -1697,10 +1769,9 @@ pub(super) fn next<F>(&mut self, pred: &mut F) -> Option<(K, V)>
             let (k, v) = kv.kv_mut();
             if pred(k, v) {
                 *self.length -= 1;
-                let RemoveResult { old_kv, pos, emptied_internal_root } = kv.remove_kv_tracking();
+                let (kv, pos) = kv.remove_kv_tracking(|_| self.emptied_internal_root = true);
                 self.cur_leaf_edge = Some(pos);
-                self.emptied_internal_root |= emptied_internal_root;
-                return Some(old_kv);
+                return Some(kv);
             }
             self.cur_leaf_edge = Some(kv.next_leaf_edge());
         }
@@ -1781,6 +1852,82 @@ unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
     }
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoKeys<K, V> {
+    type Item = K;
+
+    fn next(&mut self) -> Option<K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+
+    fn last(mut self) -> Option<K> {
+        self.next_back()
+    }
+
+    fn min(mut self) -> Option<K> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<K> {
+        self.next_back()
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> DoubleEndedIterator for IntoKeys<K, V> {
+    fn next_back(&mut self) -> Option<K> {
+        self.inner.next_back().map(|(k, _)| k)
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoKeys<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoValues<K, V> {
+    type Item = V;
+
+    fn next(&mut self) -> Option<V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+
+    fn last(mut self) -> Option<V> {
+        self.next_back()
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> DoubleEndedIterator for IntoValues<K, V> {
+    fn next_back(&mut self) -> Option<V> {
+        self.inner.next_back().map(|(_, v)| v)
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoValues<K, V> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoValues<K, V> {}
+
 #[stable(feature = "btree_range", since = "1.17.0")]
 impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> {
     fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
@@ -2645,35 +2792,28 @@ pub fn remove(self) -> V {
     fn remove_kv(self) -> (K, V) {
         *self.length -= 1;
 
-        let RemoveResult { old_kv, pos, emptied_internal_root } = self.handle.remove_kv_tracking();
-        let root = pos.into_node().into_root_mut();
-        if emptied_internal_root {
-            root.pop_internal_level();
-        }
+        let (old_kv, _) =
+            self.handle.remove_kv_tracking(|root| root.into_root_mut().pop_internal_level());
         old_kv
     }
 }
 
-struct RemoveResult<'a, K, V> {
-    // Key and value removed.
-    old_kv: (K, V),
-    // Unique location at the leaf level that the removed KV lopgically collapsed into.
-    pos: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
-    // Whether the remove left behind and empty internal root node, that should be removed
-    // using `pop_internal_level`.
-    emptied_internal_root: bool,
-}
-
 impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
     /// Removes a key/value-pair from the tree, and returns that pair, as well as
     /// the leaf edge corresponding to that former pair. It's possible this leaves
     /// an empty internal root node, which the caller should subsequently pop from
     /// the map holding the tree. The caller should also decrement the map's length.
-    fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
-        let (mut pos, old_key, old_val, was_internal) = match self.force() {
+    fn remove_kv_tracking<F>(
+        self,
+        handle_emptied_internal_root: F,
+    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>)
+    where
+        F: FnOnce(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
+    {
+        let (old_kv, mut pos, was_internal) = match self.force() {
             Leaf(leaf) => {
-                let (hole, old_key, old_val) = leaf.remove();
-                (hole, old_key, old_val, false)
+                let (old_kv, pos) = leaf.remove();
+                (old_kv, pos, false)
             }
             Internal(mut internal) => {
                 // Replace the location freed in the internal node with the next KV,
@@ -2688,17 +2828,16 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
                 let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
                 let to_remove = unsafe { unwrap_unchecked(to_remove) };
 
-                let (hole, key, val) = to_remove.remove();
+                let (kv, pos) = to_remove.remove();
 
-                let old_key = unsafe { mem::replace(&mut *key_loc, key) };
-                let old_val = unsafe { mem::replace(&mut *val_loc, val) };
+                let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) };
+                let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) };
 
-                (hole, old_key, old_val, true)
+                ((old_key, old_val), pos, true)
             }
         };
 
         // Handle underflow
-        let mut emptied_internal_root = false;
         let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
         let mut at_leaf = true;
         while cur_node.len() < node::MIN_LEN {
@@ -2719,8 +2858,10 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
 
                     let parent = edge.into_node();
                     if parent.len() == 0 {
-                        // This empty parent must be the root, and should be popped off the tree.
-                        emptied_internal_root = true;
+                        // The parent that was just emptied must be the root,
+                        // because nodes on a lower level would not have been
+                        // left underfull. It has to be popped off the tree soon.
+                        handle_emptied_internal_root(parent);
                         break;
                     } else {
                         cur_node = parent.forget_type();
@@ -2747,7 +2888,7 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
             pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
         }
 
-        RemoveResult { old_kv: (old_key, old_val), pos, emptied_internal_root }
+        (old_kv, pos)
     }
 }
 
index 0dcb593096467be93aa45c28839f86d143939fc3..33b1ee003ed3af1c98082a3cc2b942364aeca907 100644 (file)
@@ -1,3 +1,5 @@
+use core::intrinsics;
+use core::mem;
 use core::ptr;
 
 use super::node::{marker, ForceResult::*, Handle, NodeRef};
@@ -79,16 +81,24 @@ unsafe fn $name <K, V>(
 def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}
 
 /// This replaces the value behind the `v` unique reference by calling the
-/// relevant function.
+/// relevant function, and returns a result obtained along the way.
 ///
-/// Safety: The change closure must not panic.
+/// If a panic occurs in the `change` closure, the entire process will be aborted.
 #[inline]
-unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
+fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
+    struct PanicGuard;
+    impl Drop for PanicGuard {
+        fn drop(&mut self) {
+            intrinsics::abort()
+        }
+    }
+    let guard = PanicGuard;
     let value = unsafe { ptr::read(v) };
     let (new_value, ret) = change(value);
     unsafe {
         ptr::write(v, new_value);
     }
+    mem::forget(guard);
     ret
 }
 
@@ -97,26 +107,22 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
     /// key and value in between.
     /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
     pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
-        unsafe {
-            replace(self, |leaf_edge| {
-                let kv = leaf_edge.next_kv();
-                let kv = unwrap_unchecked(kv.ok());
-                (kv.next_leaf_edge(), kv.into_kv())
-            })
-        }
+        replace(self, |leaf_edge| {
+            let kv = leaf_edge.next_kv();
+            let kv = unsafe { unwrap_unchecked(kv.ok()) };
+            (kv.next_leaf_edge(), kv.into_kv())
+        })
     }
 
     /// Moves the leaf edge handle to the previous leaf edge and returns references to the
     /// key and value in between.
     /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
     pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
-        unsafe {
-            replace(self, |leaf_edge| {
-                let kv = leaf_edge.next_back_kv();
-                let kv = unwrap_unchecked(kv.ok());
-                (kv.next_back_leaf_edge(), kv.into_kv())
-            })
-        }
+        replace(self, |leaf_edge| {
+            let kv = leaf_edge.next_back_kv();
+            let kv = unsafe { unwrap_unchecked(kv.ok()) };
+            (kv.next_back_leaf_edge(), kv.into_kv())
+        })
     }
 }
 
@@ -127,16 +133,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
     /// - The caller must ensure that the leaf edge is not the last one in the tree.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        unsafe {
-            let kv = replace(self, |leaf_edge| {
-                let kv = leaf_edge.next_kv();
-                let kv = unwrap_unchecked(kv.ok());
-                (ptr::read(&kv).next_leaf_edge(), kv)
-            });
-            // Doing the descend (and perhaps another move) invalidates the references
-            // returned by `into_kv_mut`, so we have to do this last.
-            kv.into_kv_mut()
-        }
+        let kv = replace(self, |leaf_edge| {
+            let kv = leaf_edge.next_kv();
+            let kv = unsafe { unwrap_unchecked(kv.ok()) };
+            (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
+        });
+        // Doing the descend (and perhaps another move) invalidates the references
+        // returned by `into_kv_mut`, so we have to do this last.
+        kv.into_kv_mut()
     }
 
     /// Moves the leaf edge handle to the previous leaf and returns references to the
@@ -145,16 +149,14 @@ pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
     /// - The caller must ensure that the leaf edge is not the first one in the tree.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        unsafe {
-            let kv = replace(self, |leaf_edge| {
-                let kv = leaf_edge.next_back_kv();
-                let kv = unwrap_unchecked(kv.ok());
-                (ptr::read(&kv).next_back_leaf_edge(), kv)
-            });
-            // Doing the descend (and perhaps another move) invalidates the references
-            // returned by `into_kv_mut`, so we have to do this last.
-            kv.into_kv_mut()
-        }
+        let kv = replace(self, |leaf_edge| {
+            let kv = leaf_edge.next_back_kv();
+            let kv = unsafe { unwrap_unchecked(kv.ok()) };
+            (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
+        });
+        // Doing the descend (and perhaps another move) invalidates the references
+        // returned by `into_kv_mut`, so we have to do this last.
+        kv.into_kv_mut()
     }
 }
 
@@ -172,14 +174,12 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
     ///   call this method again subject to both preconditions listed in the first point,
     ///   or call counterpart `next_back_unchecked` subject to its preconditions.
     pub unsafe fn next_unchecked(&mut self) -> (K, V) {
-        unsafe {
-            replace(self, |leaf_edge| {
-                let kv = next_kv_unchecked_dealloc(leaf_edge);
-                let k = ptr::read(kv.reborrow().into_kv().0);
-                let v = ptr::read(kv.reborrow().into_kv().1);
-                (kv.next_leaf_edge(), (k, v))
-            })
-        }
+        replace(self, |leaf_edge| {
+            let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) };
+            let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
+            let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
+            (kv.next_leaf_edge(), (k, v))
+        })
     }
 
     /// Moves the leaf edge handle to the previous leaf edge and returns the key
@@ -195,14 +195,12 @@ pub unsafe fn next_unchecked(&mut self) -> (K, V) {
     ///   call this method again subject to both preconditions listed in the first point,
     ///   or call counterpart `next_unchecked` subject to its preconditions.
     pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
-        unsafe {
-            replace(self, |leaf_edge| {
-                let kv = next_back_kv_unchecked_dealloc(leaf_edge);
-                let k = ptr::read(kv.reborrow().into_kv().0);
-                let v = ptr::read(kv.reborrow().into_kv().1);
-                (kv.next_back_leaf_edge(), (k, v))
-            })
-        }
+        replace(self, |leaf_edge| {
+            let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) };
+            let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
+            let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
+            (kv.next_back_leaf_edge(), (k, v))
+        })
     }
 }
 
index 6a4c495ea14642d0ec1f8f720df9508621885116..4e52c16d20d20d81fc2cbd424124fb98eb71d226 100644 (file)
@@ -1083,12 +1083,12 @@ pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, R
     /// between the now adjacent key/value pairs (if any) to the left and right of this handle.
     pub fn remove(
         mut self,
-    ) -> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
         unsafe {
             let k = slice_remove(self.node.keys_mut(), self.idx);
             let v = slice_remove(self.node.vals_mut(), self.idx);
             (*self.node.as_leaf_mut()).len -= 1;
-            (self.left_edge(), k, v)
+            ((k, v), self.left_edge())
         }
     }
 }
index 097db30d634cce9d154a045f00acb38f6dba558a..9ac23886d4e15666c6b871f3e9fe1263784d91fe 100644 (file)
 #![feature(negative_impls)]
 #![feature(new_uninit)]
 #![feature(nll)]
+#![feature(nonnull_slice_from_raw_parts)]
 #![feature(optin_builtin_traits)]
 #![feature(or_patterns)]
 #![feature(pattern)]
 #![feature(rustc_attrs)]
 #![feature(receiver_trait)]
 #![feature(min_specialization)]
+#![feature(slice_ptr_get)]
+#![feature(slice_ptr_len)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(str_internals)]
index ed81ce71ddfac76a3614cbf04dc47f39fefa5e94..247b636c808acf5e15a2b16acf212860872c73b3 100644 (file)
@@ -1,25 +1,27 @@
 #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
 #![doc(hidden)]
 
-use core::alloc::{LayoutErr, MemoryBlock};
+use core::alloc::LayoutErr;
 use core::cmp;
 use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::ops::Drop;
 use core::ptr::{NonNull, Unique};
 use core::slice;
 
-use crate::alloc::{
-    handle_alloc_error,
-    AllocInit::{self, *},
-    AllocRef, Global, Layout,
-    ReallocPlacement::{self, *},
-};
+use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout};
 use crate::boxed::Box;
 use crate::collections::TryReserveError::{self, *};
 
 #[cfg(test)]
 mod tests;
 
+enum AllocInit {
+    /// The contents of the new memory are uninitialized.
+    Uninitialized,
+    /// The new memory is guaranteed to be zeroed.
+    Zeroed,
+}
+
 /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
 /// a buffer of memory on the heap without having to worry about all the corner cases
 /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
@@ -156,14 +158,14 @@ pub const fn new_in(alloc: A) -> Self {
     /// allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
-        Self::allocate_in(capacity, Uninitialized, alloc)
+        Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
     }
 
     /// Like `with_capacity_zeroed`, but parameterized over the choice
     /// of allocator for the returned `RawVec`.
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
-        Self::allocate_in(capacity, Zeroed, alloc)
+        Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
     }
 
     fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self {
@@ -180,14 +182,18 @@ fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self {
                 Ok(_) => {}
                 Err(_) => capacity_overflow(),
             }
-            let memory = match alloc.alloc(layout, init) {
-                Ok(memory) => memory,
+            let result = match init {
+                AllocInit::Uninitialized => alloc.alloc(layout),
+                AllocInit::Zeroed => alloc.alloc_zeroed(layout),
+            };
+            let ptr = match result {
+                Ok(ptr) => ptr,
                 Err(_) => handle_alloc_error(layout),
             };
 
             Self {
-                ptr: unsafe { Unique::new_unchecked(memory.ptr.cast().as_ptr()) },
-                cap: Self::capacity_from_bytes(memory.size),
+                ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
+                cap: Self::capacity_from_bytes(ptr.len()),
                 alloc,
             }
         }
@@ -197,13 +203,15 @@ fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self {
     ///
     /// # Safety
     ///
-    /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
+    /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
+    /// `capacity`.
     /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
     /// systems). ZST vectors may have a capacity up to `usize::MAX`.
-    /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
+    /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
+    /// guaranteed.
     #[inline]
-    pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
-        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a }
+    pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
+        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc }
     }
 
     /// Gets a raw pointer to the start of the allocation. Note that this is
@@ -358,7 +366,7 @@ pub fn try_reserve_exact(
     ///
     /// Aborts on OOM.
     pub fn shrink_to_fit(&mut self, amount: usize) {
-        match self.shrink(amount, MayMove) {
+        match self.shrink(amount) {
             Err(CapacityOverflow) => capacity_overflow(),
             Err(AllocError { layout, .. }) => handle_alloc_error(layout),
             Ok(()) => { /* yay */ }
@@ -378,9 +386,9 @@ fn capacity_from_bytes(excess: usize) -> usize {
         excess / mem::size_of::<T>()
     }
 
-    fn set_memory(&mut self, memory: MemoryBlock) {
-        self.ptr = unsafe { Unique::new_unchecked(memory.ptr.cast().as_ptr()) };
-        self.cap = Self::capacity_from_bytes(memory.size);
+    fn set_ptr(&mut self, ptr: NonNull<[u8]>) {
+        self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) };
+        self.cap = Self::capacity_from_bytes(ptr.len());
     }
 
     // This method is usually instantiated many times. So we want it to be as
@@ -426,8 +434,8 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes
         let new_layout = Layout::array::<T>(cap);
 
         // `finish_grow` is non-generic over `T`.
-        let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
-        self.set_memory(memory);
+        let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
+        self.set_ptr(ptr);
         Ok(())
     }
 
@@ -445,30 +453,24 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve
         let new_layout = Layout::array::<T>(cap);
 
         // `finish_grow` is non-generic over `T`.
-        let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
-        self.set_memory(memory);
+        let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
+        self.set_ptr(ptr);
         Ok(())
     }
 
-    fn shrink(
-        &mut self,
-        amount: usize,
-        placement: ReallocPlacement,
-    ) -> Result<(), TryReserveError> {
+    fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> {
         assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity");
 
         let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
         let new_size = amount * mem::size_of::<T>();
 
-        let memory = unsafe {
-            self.alloc.shrink(ptr, layout, new_size, placement).map_err(|_| {
-                TryReserveError::AllocError {
-                    layout: Layout::from_size_align_unchecked(new_size, layout.align()),
-                    non_exhaustive: (),
-                }
+        let ptr = unsafe {
+            self.alloc.shrink(ptr, layout, new_size).map_err(|_| TryReserveError::AllocError {
+                layout: Layout::from_size_align_unchecked(new_size, layout.align()),
+                non_exhaustive: (),
             })?
         };
-        self.set_memory(memory);
+        self.set_ptr(ptr);
         Ok(())
     }
 }
@@ -481,7 +483,7 @@ fn finish_grow<A>(
     new_layout: Result<Layout, LayoutErr>,
     current_memory: Option<(NonNull<u8>, Layout)>,
     alloc: &mut A,
-) -> Result<MemoryBlock, TryReserveError>
+) -> Result<NonNull<[u8]>, TryReserveError>
 where
     A: AllocRef,
 {
@@ -492,9 +494,9 @@ fn finish_grow<A>(
 
     let memory = if let Some((ptr, old_layout)) = current_memory {
         debug_assert_eq!(old_layout.align(), new_layout.align());
-        unsafe { alloc.grow(ptr, old_layout, new_layout.size(), MayMove, Uninitialized) }
+        unsafe { alloc.grow(ptr, old_layout, new_layout.size()) }
     } else {
-        alloc.alloc(new_layout, Uninitialized)
+        alloc.alloc(new_layout)
     }
     .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?;
 
index 5408faa079c1532ee3462acb023416ffd9ef145e..cadd913aa6bf244f1f6e9bc530dd069dcc002a36 100644 (file)
@@ -20,12 +20,12 @@ struct BoundedAlloc {
         fuel: usize,
     }
     unsafe impl AllocRef for BoundedAlloc {
-        fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
+        fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
             let size = layout.size();
             if size > self.fuel {
                 return Err(AllocErr);
             }
-            match Global.alloc(layout, init) {
+            match Global.alloc(layout) {
                 ok @ Ok(_) => {
                     self.fuel -= size;
                     ok
index 1c61050147d817d4c8f5ecbe0189463b7fcf7240..d0a47ccea0a76f96fabc05773bb226bd74d69a37 100644 (file)
 use core::ptr::{self, NonNull};
 use core::slice::from_raw_parts_mut;
 
-use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
+use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::string::String;
 use crate::vec::Vec;
@@ -928,12 +928,10 @@ unsafe fn allocate_for_layout(
         let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
 
         // Allocate for the layout.
-        let mem = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| handle_alloc_error(layout));
+        let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
 
         // Initialize the RcBox
-        let inner = mem_to_rcbox(mem.ptr.as_ptr());
+        let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr());
         unsafe {
             debug_assert_eq!(Layout::for_value(&*inner), layout);
 
index 343a17b002f57d8281f9b55d007c872da17a1f60..b37633031375883844506603a0e2c2872c699a09 100644 (file)
@@ -23,7 +23,7 @@
 use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 
-use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
+use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::is_dangling;
@@ -883,12 +883,10 @@ unsafe fn allocate_for_layout(
         // reference (see #54908).
         let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align();
 
-        let mem = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| handle_alloc_error(layout));
+        let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
 
         // Initialize the ArcInner
-        let inner = mem_to_arcinner(mem.ptr.as_ptr());
+        let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr());
         debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout);
 
         unsafe {
@@ -988,7 +986,7 @@ fn drop(&mut self) {
                     let slice = from_raw_parts_mut(self.elems, self.n_elems);
                     ptr::drop_in_place(slice);
 
-                    Global.dealloc(self.mem.cast(), self.layout);
+                    Global.dealloc(self.mem, self.layout);
                 }
             }
         }
index f9f81716e357c243b3c7ec9add10b11f6dabff5e..5777bd60907144b9ccac9c0f30b973977a35761a 100644 (file)
@@ -1461,3 +1461,27 @@ fn drop(&mut self) {
         assert_eq!(DROPS.load(Ordering::SeqCst), size);
     }
 }
+
+#[test]
+fn test_into_keys() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: BTreeMap<_, _> = vec.into_iter().collect();
+    let keys: Vec<_> = map.into_keys().collect();
+
+    assert_eq!(keys.len(), 3);
+    assert!(keys.contains(&1));
+    assert!(keys.contains(&2));
+    assert!(keys.contains(&3));
+}
+
+#[test]
+fn test_into_values() {
+    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: BTreeMap<_, _> = vec.into_iter().collect();
+    let values: Vec<_> = map.into_values().collect();
+
+    assert_eq!(values.len(), 3);
+    assert!(values.contains(&'a'));
+    assert!(values.contains(&'b'));
+    assert!(values.contains(&'c'));
+}
index 62f062b83d75d77c5e34dfc62b2b347501716236..cbde2a7e28e8f134004678ecd8b64478c27f4943 100644 (file)
@@ -1,4 +1,4 @@
-use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
+use std::alloc::{AllocRef, Global, Layout, System};
 
 /// Issue #45955 and #62251.
 #[test]
@@ -20,18 +20,12 @@ fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
             unsafe {
                 let pointers: Vec<_> = (0..iterations)
                     .map(|_| {
-                        allocator
-                            .alloc(
-                                Layout::from_size_align(size, align).unwrap(),
-                                AllocInit::Uninitialized,
-                            )
-                            .unwrap()
-                            .ptr
+                        allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
                     })
                     .collect();
                 for &ptr in &pointers {
                     assert_eq!(
-                        (ptr.as_ptr() as usize) % align,
+                        (ptr.as_non_null_ptr().as_ptr() as usize) % align,
                         0,
                         "Got a pointer less aligned than requested"
                     )
@@ -39,7 +33,10 @@ fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
 
                 // Clean up
                 for &ptr in &pointers {
-                    allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
+                    allocator.dealloc(
+                        ptr.as_non_null_ptr(),
+                        Layout::from_size_align(size, align).unwrap(),
+                    )
                 }
             }
         }
index fa20a46671591f4aef2c91dc1735ffc533d5a058..3aacd4a687e384b454ab9eb12a83b732022208a7 100644 (file)
@@ -4,6 +4,7 @@
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(map_first_last)]
+#![feature(map_into_keys_values)]
 #![feature(new_uninit)]
 #![feature(pattern)]
 #![feature(str_split_once)]
@@ -13,6 +14,7 @@
 #![feature(associated_type_bounds)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(binary_heap_drain_sorted)]
+#![feature(slice_ptr_get)]
 #![feature(split_inclusive)]
 #![feature(binary_heap_retain)]
 
index be4e051b1ca42b71e32f4218eebd39a8ea1e4d1a..2833768f213bfc8ae95e2a7f03a819930c8790ce 100644 (file)
@@ -29,92 +29,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// A desired initial state for allocated memory.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub enum AllocInit {
-    /// The contents of the new memory are uninitialized.
-    Uninitialized,
-    /// The new memory is guaranteed to be zeroed.
-    Zeroed,
-}
-
-impl AllocInit {
-    /// Initialize the specified memory block.
-    ///
-    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
-    ///
-    /// [off]: AllocInit::init_offset
-    ///
-    /// # Safety
-    ///
-    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
-    ///
-    /// [valid]: ../../core/ptr/index.html#safety
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub unsafe fn init(self, memory: MemoryBlock) {
-        // SAFETY: the safety contract for `init_offset` must be
-        // upheld by the caller.
-        unsafe { self.init_offset(memory, 0) }
-    }
-
-    /// Initialize the memory block like specified by `init` at the specified `offset`.
-    ///
-    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
-    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
-    ///
-    /// # Safety
-    ///
-    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
-    /// * `offset` must be smaller than or equal to `memory.size`
-    ///
-    /// [valid]: ../../core/ptr/index.html#safety
-    #[inline]
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
-        debug_assert!(
-            offset <= memory.size,
-            "`offset` must be smaller than or equal to `memory.size`"
-        );
-        match self {
-            AllocInit::Uninitialized => (),
-            AllocInit::Zeroed => {
-                // SAFETY: the caller must guarantee that `offset` is smaller than or equal to `memory.size`,
-                // so the memory from `memory.ptr + offset` of length `memory.size - offset`
-                // is guaranteed to be contaned in `memory` and thus valid for writes.
-                unsafe { memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset) }
-            }
-        }
-    }
-}
-
-/// Represents a block of allocated memory returned by an allocator.
-#[derive(Debug, Copy, Clone)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub struct MemoryBlock {
-    pub ptr: NonNull<u8>,
-    pub size: usize,
-}
-
-/// A placement constraint when growing or shrinking an existing allocation.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub enum ReallocPlacement {
-    /// The allocator is allowed to move the allocation to a different memory address.
-    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
-    //                          allocator" and link it at "valid location".
-    ///
-    /// If the allocation _does_ move, it's the responsibility of the allocator
-    /// to also move the data from the previous location to the new location.
-    MayMove,
-    /// The address of the new memory must not change.
-    ///
-    /// If the allocation would have to be moved to a new location to fit, the
-    /// reallocation request will fail.
-    InPlace,
-}
-
 /// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
 /// data described via [`Layout`][].
 ///
@@ -175,12 +89,12 @@ pub enum ReallocPlacement {
 pub unsafe trait AllocRef {
     /// Attempts to allocate a block of memory.
     ///
-    /// On success, returns a [`MemoryBlock`][] meeting the size and alignment guarantees of `layout`.
+    /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`.
     ///
-    /// The returned block may have a larger size than specified by `layout.size()` and is
-    /// initialized as specified by [`init`], all the way up to the returned size of the block.
+    /// The returned block may have a larger size than specified by `layout.size()`, and may or may
+    /// not have its contents initialized.
     ///
-    /// [`init`]: AllocInit
+    /// [`NonNull<[u8]>`]: NonNull
     ///
     /// # Errors
     ///
@@ -195,7 +109,29 @@ pub unsafe trait AllocRef {
     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
     ///
     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;
+    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr>;
+
+    /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized.
+    ///
+    /// # Errors
+    ///
+    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
+    /// allocator's size or alignment constraints.
+    ///
+    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
+    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
+    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
+    ///
+    /// Clients wishing to abort computation in response to an allocation error are encouraged to
+    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
+    ///
+    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
+    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let ptr = self.alloc(layout)?;
+        // SAFETY: `alloc` returns a valid memory block
+        unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) }
+        Ok(ptr)
+    }
 
     /// Deallocates the memory referenced by `ptr`.
     ///
@@ -210,44 +146,100 @@ pub unsafe trait AllocRef {
 
     /// Attempts to extend the memory block.
     ///
-    /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
+    /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
     /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
     /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
-    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
-    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
-    ///
-    /// If [`MayMove`] is used then ownership of the memory block referenced by `ptr`
-    /// is transferred to this allocator. The memory may or may not be freed, and should be
-    /// considered unusable (unless of course it is transferred back to the caller again via the
-    /// return value of this method).
+    /// allocation referenced by `ptr` to fit the new layout.
     ///
     /// 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.
     ///
-    /// The memory block will contain the following contents after a successful call to `grow`:
+    /// [`NonNull<[u8]>`]: NonNull
+    ///
+    /// # Safety
+    ///
+    /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
+    /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.),
+    /// * `new_size` must be greater than or equal to `layout.size()`, and
+    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
+    ///   (i.e., the rounded value must be less than or equal to `usize::MAX`).
+    // Note: We can't require that `new_size` is strictly greater than `layout.size()` because of ZSTs.
+    // alternative: `new_size` must be strictly greater than `layout.size()` or both are zero
+    ///
+    /// [*currently allocated*]: #currently-allocated-memory
+    /// [*fit*]: #memory-fitting
+    ///
+    /// # Errors
+    ///
+    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
+    /// constraints of the allocator, or if growing otherwise fails.
+    ///
+    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
+    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
+    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
+    ///
+    /// Clients wishing to abort computation in response to an allocation error are encouraged to
+    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
+    ///
+    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
+    unsafe fn grow(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        debug_assert!(
+            new_size >= size,
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
+
+        if size == new_size {
+            return Ok(NonNull::slice_from_raw_parts(ptr, size));
+        }
+
+        let new_layout =
+            // SAFETY: the caller must ensure that the `new_size` does not overflow.
+            // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
+            // The caller must ensure that `new_size` is greater than or equal to zero. If it's equal
+            // to zero, it's catched beforehand.
+            unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
+        let new_ptr = self.alloc(new_layout)?;
+
+        // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new
+        // memory allocation are valid for reads and writes for `size` bytes. Also, because the old
+        // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to
+        // `copy_nonoverlapping` is safe.
+        // The safety contract for `dealloc` must be upheld by the caller.
+        unsafe {
+            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size);
+            self.dealloc(ptr, layout);
+            Ok(new_ptr)
+        }
+    }
+
+    /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
+    /// returned.
+    ///
+    /// The memory block will contain the following contents after a successful call to
+    /// `grow_zeroed`:
     ///   * Bytes `0..layout.size()` are preserved from the original allocation.
-    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
-    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
-    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
+    ///   * Bytes `layout.size()..old_size` will either be preserved or zeroed,
+    ///     depending on the allocator implementation. `old_size` refers to the size of
+    ///     the `MemoryBlock` prior to the `grow_zeroed` call, which may be larger than the size
     ///     that was originally requested when it was allocated.
-    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
+    ///   * Bytes `old_size..new_size` are zeroed. `new_size` refers to
     ///     the size of the `MemoryBlock` returned by the `grow` call.
     ///
-    /// [`InPlace`]: ReallocPlacement::InPlace
-    /// [`MayMove`]: ReallocPlacement::MayMove
-    /// [`placement`]: ReallocPlacement
-    /// [`init`]: AllocInit
-    ///
     /// # Safety
     ///
     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
     /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.),
-    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
-    // An alternative would be
-    // * `new_size must be strictly greater than `memory.size` or both are zero
     /// * `new_size` must be greater than or equal to `layout.size()`, and
     /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
     ///   (i.e., the rounded value must be less than or equal to `usize::MAX`).
+    // Note: We can't require that `new_size` is strictly greater than `layout.size()` because of ZSTs.
+    // alternative: `new_size` must be strictly greater than `layout.size()` or both are zero
     ///
     /// [*currently allocated*]: #currently-allocated-memory
     /// [*fit*]: #memory-fitting
@@ -265,55 +257,48 @@ pub unsafe trait AllocRef {
     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
     ///
     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
-    unsafe fn grow(
+    unsafe fn grow_zeroed(
         &mut self,
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-        init: AllocInit,
-    ) -> Result<MemoryBlock, AllocErr> {
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove => {
-                let size = layout.size();
-                debug_assert!(
-                    new_size >= size,
-                    "`new_size` must be greater than or equal to `layout.size()`"
-                );
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        debug_assert!(
+            new_size >= size,
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
 
-                if new_size == size {
-                    return Ok(MemoryBlock { ptr, size });
-                }
+        if size == new_size {
+            return Ok(NonNull::slice_from_raw_parts(ptr, size));
+        }
 
-                let new_layout =
-                    // SAFETY: the caller must ensure that the `new_size` does not overflow.
-                    // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
-                    // The caller must ensure that `new_size` is greater than zero.
-                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
-                let new_memory = self.alloc(new_layout, init)?;
+        let new_layout =
+            // SAFETY: the caller must ensure that the `new_size` does not overflow.
+            // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
+            // The caller must ensure that `new_size` is greater than or equal to zero. If it's equal
+            // to zero, it's caught beforehand.
+            unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
+        let new_ptr = self.alloc_zeroed(new_layout)?;
 
-                // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new
-                // memory allocation are valid for reads and writes for `size` bytes. Also, because the old
-                // allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to
-                // `copy_nonoverlapping` is safe.
-                // The safety contract for `dealloc` must be upheld by the caller.
-                unsafe {
-                    ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
-                    self.dealloc(ptr, layout);
-                    Ok(new_memory)
-                }
-            }
+        // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new
+        // memory allocation are valid for reads and writes for `size` bytes. Also, because the old
+        // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to
+        // `copy_nonoverlapping` is safe.
+        // The safety contract for `dealloc` must be upheld by the caller.
+        unsafe {
+            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size);
+            self.dealloc(ptr, layout);
+            Ok(new_ptr)
         }
     }
 
     /// Attempts to shrink the memory block.
     ///
-    /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
+    /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
     /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
     /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
-    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
-    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
+    /// allocation referenced by `ptr` to fit the new layout.
     ///
     /// 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
@@ -323,19 +308,15 @@ unsafe fn grow(
     /// 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.
     ///
-    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
-    ///
-    /// [`InPlace`]: ReallocPlacement::InPlace
-    /// [`placement`]: ReallocPlacement
+    /// [`NonNull<[u8]>`]: NonNull
     ///
     /// # Safety
     ///
     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
     /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and
-    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
-    // An alternative would be
-    // * `new_size must be strictly smaller than `memory.size` or both are zero
     /// * `new_size` must be smaller than or equal to `layout.size()`.
+    // Note: We can't require that `new_size` is strictly smaller than `layout.size()` because of ZSTs.
+    // alternative: `new_size` must be smaller than `layout.size()` or both are zero
     ///
     /// [*currently allocated*]: #currently-allocated-memory
     /// [*fit*]: #memory-fitting
@@ -358,39 +339,33 @@ unsafe fn shrink(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-    ) -> Result<MemoryBlock, AllocErr> {
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove => {
-                let size = layout.size();
-                debug_assert!(
-                    new_size <= size,
-                    "`new_size` must be smaller than or equal to `layout.size()`"
-                );
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        debug_assert!(
+            new_size <= size,
+            "`new_size` must be smaller than or equal to `layout.size()`"
+        );
 
-                if new_size == size {
-                    return Ok(MemoryBlock { ptr, size });
-                }
+        if size == new_size {
+            return Ok(NonNull::slice_from_raw_parts(ptr, size));
+        }
 
-                let new_layout =
-                // SAFETY: the caller must ensure that the `new_size` does not overflow.
-                // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
-                // The caller must ensure that `new_size` is greater than zero.
-                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
-                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
+        let new_layout =
+        // SAFETY: the caller must ensure that the `new_size` does not overflow.
+        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
+        // The caller must ensure that `new_size` is greater than zero.
+            unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
+        let new_ptr = self.alloc(new_layout)?;
 
-                // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new
-                // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the
-                // old allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to
-                // `copy_nonoverlapping` is safe.
-                // The safety contract for `dealloc` must be upheld by the caller.
-                unsafe {
-                    ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
-                    self.dealloc(ptr, layout);
-                    Ok(new_memory)
-                }
-            }
+        // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new
+        // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the
+        // old allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to
+        // `copy_nonoverlapping` is safe.
+        // The safety contract for `dealloc` must be upheld by the caller.
+        unsafe {
+            ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size);
+            self.dealloc(ptr, layout);
+            Ok(new_ptr)
         }
     }
 
@@ -409,8 +384,13 @@ unsafe impl<A> AllocRef for &mut A
     A: AllocRef + ?Sized,
 {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
-        (**self).alloc(layout, init)
+    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        (**self).alloc(layout)
+    }
+
+    #[inline]
+    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        (**self).alloc_zeroed(layout)
     }
 
     #[inline]
@@ -425,11 +405,20 @@ unsafe fn grow(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-        init: AllocInit,
-    ) -> Result<MemoryBlock, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        // SAFETY: the safety contract must be upheld by the caller
+        unsafe { (**self).grow(ptr, layout, new_size) }
+    }
+
+    #[inline]
+    unsafe fn grow_zeroed(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+    ) -> Result<NonNull<[u8]>, AllocErr> {
         // SAFETY: the safety contract must be upheld by the caller
-        unsafe { (**self).grow(ptr, layout, new_size, placement, init) }
+        unsafe { (**self).grow_zeroed(ptr, layout, new_size) }
     }
 
     #[inline]
@@ -438,9 +427,8 @@ unsafe fn shrink(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-    ) -> Result<MemoryBlock, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocErr> {
         // SAFETY: the safety contract must be upheld by the caller
-        unsafe { (**self).shrink(ptr, layout, new_size, placement) }
+        unsafe { (**self).shrink(ptr, layout, new_size) }
     }
 }
index 174f7e26efbace91d244be28e0640b452e73fa58..919070aadf972123ce3ca83cdc72ac9fbf80e69b 100644 (file)
@@ -56,38 +56,34 @@ impl<T, const N: usize> IntoIter<T, N> {
 
         // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
         // works with const generics:
-        //     `mem::transmute::<[T; {N}], [MaybeUninit<T>; {N}]>(array)`
+        //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
         //
-        // Until then, we do it manually here. We first create a bitwise copy
-        // but cast the pointer so that it is treated as a different type. Then
-        // we forget `array` so that it is not dropped.
-        let data = unsafe {
-            let data = ptr::read(&array as *const [T; N] as *const [MaybeUninit<T>; N]);
+        // Until then, we can use `mem::transmute_copy` to create a bitwise copy
+        // as a different type, then forget `array` so that it is not dropped.
+        unsafe {
+            let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
             mem::forget(array);
-            data
-        };
-
-        Self { data, alive: 0..N }
+            iter
+        }
     }
 
     /// Returns an immutable slice of all elements that have not been yielded
     /// yet.
     fn as_slice(&self) -> &[T] {
-        let slice = &self.data[self.alive.clone()];
-        // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
-        // the size and alignment of `T`. Furthermore, we know that all
-        // elements within `alive` are properly initialized.
-        unsafe { mem::transmute::<&[MaybeUninit<T>], &[T]>(slice) }
+        // SAFETY: We know that all elements within `alive` are properly initialized.
+        unsafe {
+            let slice = self.data.get_unchecked(self.alive.clone());
+            MaybeUninit::slice_get_ref(slice)
+        }
     }
 
     /// Returns a mutable slice of all elements that have not been yielded yet.
     fn as_mut_slice(&mut self) -> &mut [T] {
-        // This transmute is safe, same as in `as_slice` above.
-        let slice = &mut self.data[self.alive.clone()];
-        // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
-        // the size and alignment of `T`. Furthermore, we know that all
-        // elements within `alive` are properly initialized.
-        unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(slice) }
+        // SAFETY: We know that all elements within `alive` are properly initialized.
+        unsafe {
+            let slice = self.data.get_unchecked_mut(self.alive.clone());
+            MaybeUninit::slice_get_mut(slice)
+        }
     }
 }
 
@@ -95,30 +91,20 @@ fn as_mut_slice(&mut self) -> &mut [T] {
 impl<T, const N: usize> Iterator for IntoIter<T, N> {
     type Item = T;
     fn next(&mut self) -> Option<Self::Item> {
-        if self.alive.start == self.alive.end {
-            return None;
-        }
-
-        // Bump start index.
+        // Get the next index from the front.
         //
-        // From the check above we know that `alive.start != alive.end`.
-        // Combine this with the invariant `alive.start <= alive.end`, we know
-        // that `alive.start < alive.end`. Increasing `alive.start` by 1
-        // maintains the invariant regarding `alive`. However, due to this
-        // change, for a short time, the alive zone is not `data[alive]`
-        // anymore, but `data[idx..alive.end]`.
-        let idx = self.alive.start;
-        self.alive.start += 1;
-
-        // Read the element from the array.
-        // SAFETY: This is safe: `idx` is an index
-        // into the "alive" region of the array. Reading this element means
-        // that `data[idx]` is regarded as dead now (i.e. do not touch). As
-        // `idx` was the start of the alive-zone, the alive zone is now
-        // `data[alive]` again, restoring all invariants.
-        let out = unsafe { self.data.get_unchecked(idx).read() };
-
-        Some(out)
+        // Increasing `alive.start` by 1 maintains the invariant regarding
+        // `alive`. However, due to this change, for a short time, the alive
+        // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
+        self.alive.next().map(|idx| {
+            // Read the element from the array.
+            // SAFETY: `idx` is an index into the former "alive" region of the
+            // array. Reading this element means that `data[idx]` is regarded as
+            // dead now (i.e. do not touch). As `idx` was the start of the
+            // alive-zone, the alive zone is now `data[alive]` again, restoring
+            // all invariants.
+            unsafe { self.data.get_unchecked(idx).read() }
+        })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -138,33 +124,20 @@ fn last(mut self) -> Option<Self::Item> {
 #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
 impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
     fn next_back(&mut self) -> Option<Self::Item> {
-        if self.alive.start == self.alive.end {
-            return None;
-        }
-
-        // Decrease end index.
+        // Get the next index from the back.
         //
-        // From the check above we know that `alive.start != alive.end`.
-        // Combine this with the invariant `alive.start <= alive.end`, we know
-        // that `alive.start < alive.end`. As `alive.start` cannot be negative,
-        // `alive.end` is at least 1, meaning that we can safely decrement it
-        // by one. This also maintains the invariant `alive.start <=
-        // alive.end`. However, due to this change, for a short time, the alive
-        // zone is not `data[alive]` anymore, but `data[alive.start..alive.end
-        // + 1]`.
-        self.alive.end -= 1;
-
-        // Read the element from the array.
-        // SAFETY: This is safe: `alive.end` is an
-        // index into the "alive" region of the array. Compare the previous
-        // comment that states that the alive region is
-        // `data[alive.start..alive.end + 1]`. Reading this element means that
-        // `data[alive.end]` is regarded as dead now (i.e. do not touch). As
-        // `alive.end` was the end of the alive-zone, the alive zone is now
-        // `data[alive]` again, restoring all invariants.
-        let out = unsafe { self.data.get_unchecked(self.alive.end).read() };
-
-        Some(out)
+        // Decreasing `alive.end` by 1 maintains the invariant regarding
+        // `alive`. However, due to this change, for a short time, the alive
+        // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
+        self.alive.next_back().map(|idx| {
+            // Read the element from the array.
+            // SAFETY: `idx` is an index into the former "alive" region of the
+            // array. Reading this element means that `data[idx]` is regarded as
+            // dead now (i.e. do not touch). As `idx` was the end of the
+            // alive-zone, the alive zone is now `data[alive]` again, restoring
+            // all invariants.
+            unsafe { self.data.get_unchecked(idx).read() }
+        })
     }
 }
 
@@ -203,26 +176,19 @@ unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
 #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
 impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
     fn clone(&self) -> Self {
-        // SAFETY: each point of unsafety is documented inside the unsafe block
-        unsafe {
-            // This creates a new uninitialized array. Note that the `assume_init`
-            // refers to the array, not the individual elements. And it is Ok if
-            // the array is in an uninitialized state as all elements may be
-            // uninitialized (all bit patterns are valid). Compare the
-            // `MaybeUninit` docs for more information.
-            let mut new_data: [MaybeUninit<T>; N] = MaybeUninit::uninit().assume_init();
-
-            // Clone all alive elements.
-            for idx in self.alive.clone() {
-                // The element at `idx` in the old array is alive, so we can
-                // safely call `get_ref()`. We then clone it, and write the
-                // clone into the new array.
-                let clone = self.data.get_unchecked(idx).get_ref().clone();
-                new_data.get_unchecked_mut(idx).write(clone);
-            }
-
-            Self { data: new_data, alive: self.alive.clone() }
+        // Note, we don't really need to match the exact same alive range, so
+        // we can just clone into offset 0 regardless of where `self` is.
+        let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };
+
+        // Clone all alive elements.
+        for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
+            // Write a clone into the new array, then update its alive range.
+            // If cloning panics, we'll correctly drop the previous items.
+            dst.write(src.clone());
+            new.alive.end += 1;
         }
+
+        new
     }
 }
 
index 3116815f5d655a03461d6cfbc19f19a056aa78ec..3dc0ee2b555300d8c5183b3141517fb1b8a15c98 100644 (file)
@@ -119,9 +119,11 @@ pub fn black_box<T>(dummy: T) -> T {
     // box. This isn't the greatest implementation since it probably deoptimizes
     // more than we want, but it's so far good enough.
 
+    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
     // SAFETY: the inline assembly is a no-op.
     unsafe {
         llvm_asm!("" : : "r"(&dummy));
-        dummy
     }
+
+    dummy
 }
index 44b86438f2a89534932e1a40075e1100bb782065..3a28bc79effafd6fc25b0bf4036ab5ad89d15543 100644 (file)
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
-    /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
-    /// generation.
+    /// option is enabled. The source code region information is extracted prior to code generation,
+    /// and added to the "coverage map", which is injected into the generated code as additional
+    /// data. This intrinsic then triggers the generation of LLVM intrinsic call
+    /// `instrprof.increment`, using the remaining args (`function_source_hash` and `index`).
     #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
     pub fn count_code_region(
         function_source_hash: u64,
         index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// Internal marker for code coverage expressions, injected into the MIR when the
@@ -1973,8 +1978,11 @@ pub fn coverage_counter_add(
         index: u32,
         left_index: u32,
         right_index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// This marker identifies a code region and two other counters or counter expressions
@@ -1986,14 +1994,24 @@ pub fn coverage_counter_subtract(
         index: u32,
         left_index: u32,
         right_index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// This marker identifies a code region to be added to the "coverage map" to indicate source
     /// code that can never be reached.
     /// (See `coverage_counter_add` for more information.)
-    pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32);
+    #[cfg(not(bootstrap))]
+    pub fn coverage_unreachable(
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    );
 
     /// See documentation of `<*const T>::guaranteed_eq` for details.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
index cf721b01ce3c681c4090e4ba9d718604158de9fd..027498d3911c8fcac38383ee5df5cb0add760480 100644 (file)
@@ -405,9 +405,11 @@ pub fn write(&mut self, val: T) -> &mut T {
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
     #[inline(always)]
-    pub fn as_ptr(&self) -> *const T {
-        unsafe { &*self.value as *const T }
+    pub const fn as_ptr(&self) -> *const T {
+        // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
+        self as *const _ as *const T
     }
 
     /// Gets a mutable pointer to the contained value. Reading from this pointer or turning it
@@ -442,9 +444,11 @@ pub fn as_ptr(&self) -> *const T {
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
     /// until they are, it is advisable to avoid them.)
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
     #[inline(always)]
-    pub fn as_mut_ptr(&mut self) -> *mut T {
-        unsafe { &mut *self.value as *mut T }
+    pub const fn as_mut_ptr(&mut self) -> *mut T {
+        // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
+        self as *mut _ as *mut T
     }
 
     /// Extracts the value from the `MaybeUninit<T>` container. This is a great way
index eb50dc28b9f1101e8afe9d9c04de69fc4f3c947b..68937176270356a031ac23cf1fed6053f5edff5a 100644 (file)
@@ -2346,17 +2346,12 @@ pub const fn is_negative(self) -> bool { self < 0 }
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
             // SAFETY: const sound because integers are plain old datatypes so we can always
             // transmute them to arrays of bytes
-            #[allow_internal_unstable(const_fn_union)]
+            #[allow_internal_unstable(const_fn_transmute)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                #[repr(C)]
-                union Bytes {
-                    val: $SelfT,
-                    bytes: [u8; mem::size_of::<$SelfT>()],
-                }
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
                 // arrays of bytes
-                unsafe { Bytes { val: self }.bytes }
+                unsafe { mem::transmute(self) }
             }
         }
 
@@ -2464,16 +2459,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
             // SAFETY: const sound because integers are plain old datatypes so we can always
             // transmute to them
-            #[allow_internal_unstable(const_fn_union)]
+            #[allow_internal_unstable(const_fn_transmute)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                #[repr(C)]
-                union Bytes {
-                    val: $SelfT,
-                    bytes: [u8; mem::size_of::<$SelfT>()],
-                }
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { Bytes { bytes }.val }
+                unsafe { mem::transmute(bytes) }
             }
         }
 
@@ -4368,23 +4358,18 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
             // SAFETY: const sound because integers are plain old datatypes so we can always
             // transmute them to arrays of bytes
-            #[allow_internal_unstable(const_fn_union)]
+            #[allow_internal_unstable(const_fn_transmute)]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
-                #[repr(C)]
-                union Bytes {
-                    val: $SelfT,
-                    bytes: [u8; mem::size_of::<$SelfT>()],
-                }
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
                 // arrays of bytes
-                unsafe { Bytes { val: self }.bytes }
+                unsafe { mem::transmute(self) }
             }
         }
 
         doc_comment! {
-            concat!("Create an integer value from its representation as a byte array in
-big endian.
+            concat!("Create a native endian integer value from its representation
+as a byte array in big endian.
 ",
 $from_xe_bytes_doc,
 "
@@ -4416,8 +4401,8 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 
         doc_comment! {
             concat!("
-Create an integer value from its representation as a byte array in
-little endian.
+Create a native endian integer value from its representation
+as a byte array in little endian.
 ",
 $from_xe_bytes_doc,
 "
@@ -4448,8 +4433,8 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
         }
 
         doc_comment! {
-            concat!("Create an integer value from its memory representation as a byte
-array in native endianness.
+            concat!("Create a native endian integer value from its memory representation
+as a byte array in native endianness.
 
 As the target platform's native endianness is used, portable code
 likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
@@ -4486,16 +4471,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
             #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
             // SAFETY: const sound because integers are plain old datatypes so we can always
             // transmute to them
-            #[allow_internal_unstable(const_fn_union)]
+            #[allow_internal_unstable(const_fn_transmute)]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
-                #[repr(C)]
-                union Bytes {
-                    val: $SelfT,
-                    bytes: [u8; mem::size_of::<$SelfT>()],
-                }
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
-                unsafe { Bytes { bytes }.val }
+                unsafe { mem::transmute(bytes) }
             }
         }
 
index a2acc239bd38f942da26c334b1254e4a6a24db00..a16970e9fd1802863411b74ac32da08acf1a24b2 100644 (file)
@@ -656,6 +656,38 @@ pub const fn wrapping_sub(self, count: usize) -> Self
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
+    /// Sets the pointer value to `ptr`.
+    ///
+    /// In case `self` is a (fat) pointer to an unsized type, this operation
+    /// will only affect the pointer part, whereas for (thin) pointers to
+    /// sized types, this has the same effect as a simple assignment.
+    ///
+    /// # Examples
+    ///
+    /// This function is primarily useful for allowing byte-wise pointer
+    /// arithmetic on potentially fat pointers:
+    ///
+    /// ```
+    /// #![feature(set_ptr_value)]
+    /// # use core::fmt::Debug;
+    /// let arr: [i32; 3] = [1, 2, 3];
+    /// let mut ptr = &arr[0] as *const dyn Debug;
+    /// let thin = ptr as *const u8;
+    /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
+    /// assert_eq!(unsafe { *(ptr as *const i32) }, 3);
+    /// ```
+    #[unstable(feature = "set_ptr_value", issue = "75091")]
+    #[inline]
+    pub fn set_ptr_value(mut self, val: *const ()) -> Self {
+        let thin = &mut self as *mut *const T as *mut *const ();
+        // SAFETY: In case of a thin pointer, this operations is identical
+        // to a simple assignment. In case of a fat pointer, with the current
+        // fat pointer layout implementation, the first field of such a
+        // pointer is always the data pointer, which is likewise assigned.
+        unsafe { *thin = val };
+        self
+    }
+
     /// Reads the value from `self` without moving it. This leaves the
     /// memory in `self` unchanged.
     ///
index 17fa90ecc08b5c81acc3e672bf9f3a6db429178d..b47f90c59962926462cd306ac87baf8d4f05f580 100644 (file)
@@ -712,6 +712,38 @@ pub const fn wrapping_sub(self, count: usize) -> Self
         self.wrapping_offset((count as isize).wrapping_neg())
     }
 
+    /// Sets the pointer value to `ptr`.
+    ///
+    /// In case `self` is a (fat) pointer to an unsized type, this operation
+    /// will only affect the pointer part, whereas for (thin) pointers to
+    /// sized types, this has the same effect as a simple assignment.
+    ///
+    /// # Examples
+    ///
+    /// This function is primarily useful for allowing byte-wise pointer
+    /// arithmetic on potentially fat pointers:
+    ///
+    /// ```
+    /// #![feature(set_ptr_value)]
+    /// # use core::fmt::Debug;
+    /// let mut arr: [i32; 3] = [1, 2, 3];
+    /// let mut ptr = &mut arr[0] as *mut dyn Debug;
+    /// let thin = ptr as *mut u8;
+    /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
+    /// assert_eq!(unsafe { *(ptr as *mut i32) }, 3);
+    /// ```
+    #[unstable(feature = "set_ptr_value", issue = "75091")]
+    #[inline]
+    pub fn set_ptr_value(mut self, val: *mut ()) -> Self {
+        let thin = &mut self as *mut *mut T as *mut *mut ();
+        // SAFETY: In case of a thin pointer, this operations is identical
+        // to a simple assignment. In case of a fat pointer, with the current
+        // fat pointer layout implementation, the first field of such a
+        // pointer is always the data pointer, which is likewise assigned.
+        unsafe { *thin = val };
+        self
+    }
+
     /// Reads the value from `self` without moving it. This leaves the
     /// memory in `self` unchanged.
     ///
index 9f843a570990d615b795f7233734686b42675ed2..d876ab23653f367925b8f904ad1891705a080356 100644 (file)
@@ -117,6 +117,24 @@ pub const fn as_ptr(self) -> *mut T {
     /// The resulting lifetime is bound to self so this behaves "as if"
     /// it were actually an instance of T that is getting borrowed. If a longer
     /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that all of the following is true:
+    /// - `self` is properly aligned
+    /// - `self` must point to an initialized instance of T; in particular, the pointer must be
+    ///   "dereferencable" in the sense defined [here].
+    ///
+    /// This applies even if the result of this method is unused!
+    /// (The part about being initialized is not yet fully decided, but until
+    /// it is, the only safe approach is to ensure that they are indeed initialized.)
+    ///
+    /// Additionally, the lifetime of `self` does not necessarily reflect the actual
+    /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular,
+    /// for the duration of this lifetime, the memory the pointer points to must not
+    /// get mutated (except inside `UnsafeCell`).
+    ///
+    /// [here]: crate::ptr#safety
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
     pub unsafe fn as_ref(&self) -> &T {
@@ -130,6 +148,24 @@ pub unsafe fn as_ref(&self) -> &T {
     /// The resulting lifetime is bound to self so this behaves "as if"
     /// it were actually an instance of T that is getting borrowed. If a longer
     /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
+    ///
+    /// # Safety
+    ///
+    /// When calling this method, you have to ensure that all of the following is true:
+    /// - `self` is properly aligned
+    /// - `self` must point to an initialized instance of T; in particular, the pointer must be
+    ///   "dereferenceable" in the sense defined [here].
+    ///
+    /// This applies even if the result of this method is unused!
+    /// (The part about being initialized is not yet fully decided, but until
+    /// it is the only safe approach is to ensure that they are indeed initialized.)
+    ///
+    /// Additionally, the lifetime of `self` does not necessarily reflect the actual
+    /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular,
+    /// for the duration of this lifetime, the memory this pointer points to must not
+    /// get accessed (read or written) through any other pointer.
+    ///
+    /// [here]: crate::ptr#safety
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
     pub unsafe fn as_mut(&mut self) -> &mut T {
@@ -224,6 +260,24 @@ pub const fn as_non_null_ptr(self) -> NonNull<T> {
         unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
     }
 
+    /// Returns a raw pointer to the slice's buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
+    /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8);
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    pub const fn as_mut_ptr(self) -> *mut T {
+        self.as_non_null_ptr().as_ptr()
+    }
+
     /// Returns a raw pointer to an element or subslice, without doing bounds
     /// checking.
     ///
index 9d7e38d0e183100b6cd79dbd775dfd39f4dc5852..eac4741cd260ad483969d3dfdc70f9cb838f2c45 100644 (file)
@@ -1923,7 +1923,10 @@ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
             let (start, end) = (self.start, self.end);
-            self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end))
+            match self.get(slice) {
+                Some(s) => s,
+                None => super::slice_error_fail(slice, start, end),
+            }
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
@@ -1995,7 +1998,10 @@ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
             let end = self.end;
-            self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
+            match self.get(slice) {
+                Some(s) => s,
+                None => super::slice_error_fail(slice, 0, end),
+            }
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
@@ -2068,7 +2074,10 @@ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
             let (start, end) = (self.start, slice.len());
-            self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end))
+            match self.get(slice) {
+                Some(s) => s,
+                None => super::slice_error_fail(slice, start, end),
+            }
         }
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
index 72eab0763d8bcdf3e24122c64cc8e3e5bc2091cf..7d14893c4cc2e45a1e2c908dce780f8582eceb3a 100644 (file)
@@ -50,6 +50,7 @@
     } else if #[cfg(any(
         all(target_family = "windows", target_env = "gnu"),
         target_os = "cloudabi",
+        target_os = "psp",
         target_family = "unix",
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
@@ -65,7 +66,6 @@
         // - os=uefi
         // - nvptx64-nvidia-cuda
         // - avr-unknown-unknown
-        // - mipsel-sony-psp
         #[path = "dummy.rs"]
         mod real_imp;
     }
index 474765d8638116fd6b3740a32842b618fb4210a1..fc07fa77b85e7660cebdd53a9e24d30cae5c5ff7 100644 (file)
@@ -20,7 +20,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of
 compiler_builtins = { version = "0.1.32" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
-hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] }
 
 # Dependencies of the `backtrace` crate
 addr2line = { version = "0.13.0", optional = true, default-features = false }
index c44ce9873d508a44ef3bb40fe82515e858c162c3..4712cc95b4ab744fd11e655c546c11bd9b0dc897 100644 (file)
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for System {
     #[inline]
-    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
-        unsafe {
-            let size = layout.size();
-            if size == 0 {
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
-            } else {
-                let raw_ptr = match init {
-                    AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
-                    AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
-                };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
-                Ok(MemoryBlock { ptr, size })
-            }
-        }
+    fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(GlobalAlloc::alloc(&System, layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
+    }
+
+    #[inline]
+    fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        let size = layout.size();
+        let ptr = if size == 0 {
+            layout.dangling()
+        } else {
+            // SAFETY: `layout` is non-zero in size,
+            unsafe { NonNull::new(GlobalAlloc::alloc_zeroed(&System, layout)).ok_or(AllocErr)? }
+        };
+        Ok(NonNull::slice_from_raw_parts(ptr, size))
     }
 
     #[inline]
     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
-            // SAFETY: The safety guarantees are explained in the documentation
-            // for the `GlobalAlloc` trait and its `dealloc` method.
-            unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) }
+            // SAFETY: `layout` is non-zero in size,
+            // other conditions must be upheld by the caller
+            unsafe { GlobalAlloc::dealloc(&System, ptr.as_ptr(), layout) }
         }
     }
 
@@ -171,53 +178,59 @@ unsafe fn grow(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-        init: AllocInit,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
         debug_assert!(
-            new_size >= size,
-            "`new_size` must be greater than or equal to `memory.size()`"
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+            }
         }
+    }
 
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if layout.size() == 0 => {
-                let new_layout =
-                    // SAFETY: The new size and layout alignement guarantees
-                    // are transferred to the caller (they come from parameters).
-                    //
-                    // See the preconditions for `Layout::from_size_align` to
-                    // see what must be checked.
-                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
-                self.alloc(new_layout, init)
-            }
-            ReallocPlacement::MayMove => {
-                // SAFETY:
-                //
-                // The safety guarantees are explained in the documentation
-                // for the `GlobalAlloc` trait and its `dealloc` method.
-                //
-                // `realloc` probably checks for `new_size > size` or something
-                // similar.
-                //
-                // For the guarantees about `init_offset`, see its documentation:
-                // `ptr` is assumed valid (and checked for non-NUL) and
-                // `memory.size` is set to `new_size` so the offset being `size`
-                // is valid.
-                let memory = unsafe {
-                    intrinsics::assume(new_size > size);
-                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                    let memory =
-                        MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
-                    init.init_offset(memory, size);
-                    memory
-                };
-                Ok(memory)
+    #[inline]
+    unsafe fn grow_zeroed(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        debug_assert!(
+            new_size >= layout.size(),
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
+
+        // SAFETY: `new_size` must be non-zero, which is checked in the match expression.
+        // Other conditions must be upheld by the caller
+        unsafe {
+            match layout.size() {
+                old_size if old_size == new_size => {
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
+                0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())),
+                old_size => {
+                    // `realloc` probably checks for `new_size > size` or something similar.
+                    intrinsics::assume(new_size > old_size);
+                    let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size);
+                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+                    let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                    Ok(NonNull::slice_from_raw_parts(ptr, new_size))
+                }
             }
         }
     }
@@ -228,45 +241,34 @@ unsafe fn shrink(
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
-        placement: ReallocPlacement,
-    ) -> Result<MemoryBlock, AllocErr> {
-        let size = layout.size();
+    ) -> Result<NonNull<[u8]>, AllocErr> {
+        let old_size = layout.size();
         debug_assert!(
-            new_size <= size,
-            "`new_size` must be smaller than or equal to `memory.size()`"
+            new_size <= old_size,
+            "`new_size` must be smaller than or equal to `layout.size()`"
         );
 
-        if size == new_size {
-            return Ok(MemoryBlock { ptr, size });
-        }
-
-        match placement {
-            ReallocPlacement::InPlace => Err(AllocErr),
-            ReallocPlacement::MayMove if new_size == 0 => {
-                // SAFETY: see `GlobalAlloc::dealloc` for the guarantees that
-                // must be respected. `ptr` and `layout` are parameters and so
-                // those guarantees must be checked by the caller.
-                unsafe { self.dealloc(ptr, layout) };
-                Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
+        let ptr = if new_size == old_size {
+            ptr
+        } else if new_size == 0 {
+            // SAFETY: `layout` is non-zero in size as `old_size` != `new_size`
+            // Other conditions must be upheld by the caller
+            unsafe {
+                self.dealloc(ptr, layout);
             }
-            ReallocPlacement::MayMove => {
-                // SAFETY:
-                //
-                // See `GlobalAlloc::realloc` for more informations about the
-                // guarantees expected by this method. `ptr`, `layout` and
-                // `new_size` are parameters and the responsibility for their
-                // correctness is left to the caller.
-                //
-                // `realloc` probably checks for `new_size < size` or something
-                // similar.
-                let memory = unsafe {
-                    intrinsics::assume(new_size < size);
-                    let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size);
-                    MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }
-                };
-                Ok(memory)
-            }
-        }
+            layout.dangling()
+        } else {
+            // SAFETY: new_size is not zero,
+            // Other conditions must be upheld by the caller
+            let raw_ptr = unsafe {
+                // `realloc` probably checks for `new_size < old_size` or something similar.
+                intrinsics::assume(new_size < old_size);
+                GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size)
+            };
+            NonNull::new(raw_ptr).ok_or(AllocErr)?
+        };
+
+        Ok(NonNull::slice_from_raw_parts(ptr, new_size))
     }
 }
 static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
index 7b48deee1abdf73f013f49637742fc7e13424d46..70f7214e2f1d78d3c5f2e1d3a5c798f43fe5ecf3 100644 (file)
@@ -580,7 +580,7 @@ pub fn reserve(&mut self, additional: usize) {
     #[inline]
     #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
     pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
-        self.base.try_reserve(additional).map_err(map_collection_alloc_err)
+        self.base.try_reserve(additional).map_err(map_try_reserve_error)
     }
 
     /// Shrinks the capacity of the map as much as possible. It will drop
@@ -872,6 +872,52 @@ pub fn retain<F>(&mut self, f: F)
     {
         self.base.retain(f)
     }
+
+    /// Creates a consuming iterator visiting all the keys in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `K`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_into_keys_values)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// let vec: Vec<&str> = map.into_keys().collect();
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    pub fn into_keys(self) -> IntoKeys<K, V> {
+        IntoKeys { inner: self.into_iter() }
+    }
+
+    /// Creates a consuming iterator visiting all the values in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `V`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(map_into_keys_values)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map = HashMap::new();
+    /// map.insert("a", 1);
+    /// map.insert("b", 2);
+    /// map.insert("c", 3);
+    ///
+    /// let vec: Vec<i32> = map.into_values().collect();
+    /// ```
+    #[inline]
+    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    pub fn into_values(self) -> IntoValues<K, V> {
+        IntoValues { inner: self.into_iter() }
+    }
 }
 
 impl<K, V, S> HashMap<K, V, S>
@@ -1154,6 +1200,28 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+/// An owning iterator over the keys of a `HashMap`.
+///
+/// This `struct` is created by the [`into_keys`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_keys`]: HashMap::into_keys
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+pub struct IntoKeys<K, V> {
+    inner: IntoIter<K, V>,
+}
+
+/// An owning iterator over the values of a `HashMap`.
+///
+/// This `struct` is created by the [`into_values`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_values`]: HashMap::into_values
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+pub struct IntoValues<K, V> {
+    inner: IntoIter<K, V>,
+}
+
 /// A builder for computing where in a HashMap a key-value pair would be stored.
 ///
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
@@ -1827,6 +1895,66 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoKeys<K, V> {
+    type Item = K;
+
+    #[inline]
+    fn next(&mut self) -> Option<K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoKeys<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
+    }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoValues<K, V> {
+    type Item = V;
+
+    #[inline]
+    fn next(&mut self) -> Option<V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoValues<K, V> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoValues<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
+    }
+}
+
 #[stable(feature = "drain", since = "1.6.0")]
 impl<'a, K, V> Iterator for Drain<'a, K, V> {
     type Item = (K, V);
@@ -2569,10 +2697,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K,
 }
 
 #[inline]
-fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError {
+fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError {
     match err {
-        hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow,
-        hashbrown::CollectionAllocErr::AllocErr { layout } => {
+        hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow,
+        hashbrown::TryReserveError::AllocError { layout } => {
             TryReserveError::AllocError { layout, non_exhaustive: () }
         }
     }
@@ -3084,6 +3212,30 @@ fn test_values_mut() {
         assert!(values.contains(&6));
     }
 
+    #[test]
+    fn test_into_keys() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let keys: Vec<_> = map.into_keys().collect();
+
+        assert_eq!(keys.len(), 3);
+        assert!(keys.contains(&1));
+        assert!(keys.contains(&2));
+        assert!(keys.contains(&3));
+    }
+
+    #[test]
+    fn test_into_values() {
+        let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+        let map: HashMap<_, _> = vec.into_iter().collect();
+        let values: Vec<_> = map.into_values().collect();
+
+        assert_eq!(values.len(), 3);
+        assert!(values.contains(&'a'));
+        assert!(values.contains(&'b'));
+        assert!(values.contains(&'c'));
+    }
+
     #[test]
     fn test_find() {
         let mut m = HashMap::new();
index c98008688ab4f078d39f7511e3b522faddb8601a..ff343625a19ed75932bf944f9e9cd57f394aa1e1 100644 (file)
@@ -943,8 +943,7 @@ mod mod_keyword {}
 /// Capture a [closure]'s environment by value.
 ///
 /// `move` converts any variables captured by reference or mutable reference
-/// to owned by value variables. The three [`Fn` trait]'s mirror the ways to capture
-/// variables, when `move` is used, the closures is represented by the `FnOnce` trait.
+/// to owned by value variables.
 ///
 /// ```rust
 /// let capture = "hello";
@@ -953,6 +952,23 @@ mod mod_keyword {}
 /// };
 /// ```
 ///
+/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though
+/// they capture variables by `move`. This is because the traits implemented by
+/// a closure type are determined by *what* the closure does with captured
+/// values, not *how* it captures them:
+///
+/// ```rust
+/// fn create_fn() -> impl Fn() {
+///     let text = "Fn".to_owned();
+///
+///     move || println!("This is a: {}", text)
+/// }
+///
+///     let fn_plain = create_fn();
+///
+///     fn_plain();
+/// ```
+///
 /// `move` is often used when [threads] are involved.
 ///
 /// ```rust
index c81b949af656691364182ee2b5b026567eea07e8..0569e46241a8075622e76c247e5b990b80b372a9 100644 (file)
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
+#![feature(nonnull_slice_from_raw_parts)]
 #![feature(once_cell)]
 #![feature(optin_builtin_traits)]
 #![feature(or_patterns)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
+#![feature(slice_ptr_get)]
+#![feature(slice_ptr_len)]
 #![feature(slice_strip)]
 #![feature(staged_api)]
 #![feature(std_internals)]
index a64b43ca3ad45f92a8991659f310f2f538734699..159ab981b237d5a822f42ce646c9d7be625235b0 100644 (file)
@@ -319,15 +319,9 @@ impl Ipv4Addr {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
     pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
-        // FIXME: should just be u32::from_be_bytes([a, b, c, d]),
-        // once that method is no longer rustc_const_unstable
-        Ipv4Addr {
-            inner: c::in_addr {
-                s_addr: u32::to_be(
-                    ((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32),
-                ),
-            },
-        }
+        // `s_addr` is stored as BE on all machine and the array is in BE order.
+        // So the native endian conversion method is used so that it's never swapped.
+        Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
     }
 
     /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
@@ -967,11 +961,6 @@ fn as_inner(&self) -> &c::in_addr {
         &self.inner
     }
 }
-impl FromInner<c::in_addr> for Ipv4Addr {
-    fn from_inner(addr: c::in_addr) -> Ipv4Addr {
-        Ipv4Addr { inner: addr }
-    }
-}
 
 #[stable(feature = "ip_u32", since = "1.1.0")]
 impl From<Ipv4Addr> for u32 {
@@ -982,8 +971,8 @@ impl From<Ipv4Addr> for u32 {
     /// ```
     /// use std::net::Ipv4Addr;
     ///
-    /// let addr = Ipv4Addr::new(13, 12, 11, 10);
-    /// assert_eq!(0x0d0c0b0au32, u32::from(addr));
+    /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe);
+    /// assert_eq!(0xcafebabe, u32::from(addr));
     /// ```
     fn from(ip: Ipv4Addr) -> u32 {
         let ip = ip.octets();
@@ -1000,8 +989,8 @@ impl From<u32> for Ipv4Addr {
     /// ```
     /// use std::net::Ipv4Addr;
     ///
-    /// let addr = Ipv4Addr::from(0x0d0c0b0au32);
-    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+    /// let addr = Ipv4Addr::from(0xcafebabe);
+    /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr);
     /// ```
     fn from(ip: u32) -> Ipv4Addr {
         Ipv4Addr::from(ip.to_be_bytes())
index ab2a60103069d6571179c20c565f5e64800d6f0b..21ab0faed3e5ad6ef1771c1c4f792117a7cf5a81 100644 (file)
@@ -434,7 +434,9 @@ fn get(&mut self) -> &(dyn Any + Send) {
 
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
-    rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+    crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+        rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+    })
 }
 
 /// This is the entry point of panicking for the non-format-string variants of
@@ -453,7 +455,10 @@ pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
         intrinsics::abort()
     }
 
-    rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller());
+    let loc = Location::caller();
+    return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+    });
 
     struct PanicPayload<A> {
         inner: Option<A>,
index 392c815ef2803a5002d03564d49e5f330c55e884..a468f6b4b8d547dcfb89de10f153c81c678d8c0f 100644 (file)
 //! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect();
 //! ```
 //!
-//! [`Component`]: ../../std/path/enum.Component.html
-//! [`components`]: ../../std/path/struct.Path.html#method.components
-//! [`PathBuf`]: ../../std/path/struct.PathBuf.html
-//! [`Path`]: ../../std/path/struct.Path.html
-//! [`push`]: ../../std/path/struct.PathBuf.html#method.push
-//! [`String`]: ../../std/string/struct.String.html
-//!
-//! [`str`]: ../../std/primitive.str.html
-//! [`OsString`]: ../../std/ffi/struct.OsString.html
-//! [`OsStr`]: ../../std/ffi/struct.OsStr.html
+//! [`components`]: Path::components
+//! [`push`]: PathBuf::push
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -390,12 +382,9 @@ enum State {
 /// # }
 /// ```
 ///
-/// [`as_os_str`]: #method.as_os_str
-/// [`Component`]: enum.Component.html
-/// [`kind`]: #method.kind
-/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
-/// [`Prefix` variant]: enum.Component.html#variant.Prefix
-/// [`Prefix`]: enum.Prefix.html
+/// [`as_os_str`]: PrefixComponent::as_os_str
+/// [`kind`]: PrefixComponent::kind
+/// [`Prefix` variant]: Component::Prefix
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Copy, Clone, Eq, Debug)]
 pub struct PrefixComponent<'a> {
@@ -411,16 +400,12 @@ impl<'a> PrefixComponent<'a> {
     ///
     /// See [`Prefix`]'s documentation for more information on the different
     /// kinds of prefixes.
-    ///
-    /// [`Prefix`]: enum.Prefix.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn kind(&self) -> Prefix<'a> {
         self.parsed
     }
 
     /// Returns the raw [`OsStr`] slice for this prefix.
-    ///
-    /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_os_str(&self) -> &'a OsStr {
         self.raw
@@ -477,10 +462,6 @@ fn hash<H: Hasher>(&self, h: &mut H) {
 ///     Component::Normal("bar.txt".as_ref()),
 /// ]);
 /// ```
-///
-/// [`Components`]: struct.Components.html
-/// [`Path`]: struct.Path.html
-/// [`Path::components`]: struct.Path.html#method.components
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum Component<'a> {
@@ -490,8 +471,6 @@ pub enum Component<'a> {
     /// for more.
     ///
     /// Does not occur on Unix.
-    ///
-    /// [`Prefix`]: enum.Prefix.html
     #[stable(feature = "rust1", since = "1.0.0")]
     Prefix(#[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>),
 
@@ -529,8 +508,6 @@ impl<'a> Component<'a> {
     /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
     /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
     /// ```
-    ///
-    /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_os_str(self) -> &'a OsStr {
         match self {
@@ -574,9 +551,7 @@ fn as_ref(&self) -> &Path {
 /// }
 /// ```
 ///
-/// [`Component`]: enum.Component.html
-/// [`components`]: struct.Path.html#method.components
-/// [`Path`]: struct.Path.html
+/// [`components`]: Path::components
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Components<'a> {
@@ -602,10 +577,7 @@ pub struct Components<'a> {
 /// This `struct` is created by the [`iter`] method on [`Path`].
 /// See its documentation for more.
 ///
-/// [`Component`]: enum.Component.html
-/// [`iter`]: struct.Path.html#method.iter
-/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
-/// [`Path`]: struct.Path.html
+/// [`iter`]: Path::iter
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a> {
@@ -1002,8 +974,7 @@ fn cmp(&self, other: &Self) -> cmp::Ordering {
 /// }
 /// ```
 ///
-/// [`ancestors`]: struct.Path.html#method.ancestors
-/// [`Path`]: struct.Path.html
+/// [`ancestors`]: Path::ancestors
 #[derive(Copy, Clone, Debug)]
 #[stable(feature = "path_ancestors", since = "1.28.0")]
 pub struct Ancestors<'a> {
@@ -1034,11 +1005,8 @@ impl FusedIterator for Ancestors<'_> {}
 /// the path in place. It also implements [`Deref`] to [`Path`], meaning that
 /// all methods on [`Path`] slices are available on `PathBuf` values as well.
 ///
-/// [`String`]: ../string/struct.String.html
-/// [`Path`]: struct.Path.html
-/// [`push`]: struct.PathBuf.html#method.push
-/// [`set_extension`]: struct.PathBuf.html#method.set_extension
-/// [`Deref`]: ../ops/trait.Deref.html
+/// [`push`]: PathBuf::push
+/// [`set_extension`]: PathBuf::set_extension
 ///
 /// More details about the overall approach can be found in
 /// the [module documentation](index.html).
@@ -1127,8 +1095,7 @@ pub fn new() -> PathBuf {
     /// assert_eq!(capacity, path.capacity());
     /// ```
     ///
-    /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`with_capacity`]: OsString::with_capacity
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn with_capacity(capacity: usize) -> PathBuf {
         PathBuf { inner: OsString::with_capacity(capacity) }
@@ -1136,8 +1103,6 @@ pub fn with_capacity(capacity: usize) -> PathBuf {
 
     /// Coerces to a [`Path`] slice.
     ///
-    /// [`Path`]: struct.Path.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -1224,18 +1189,17 @@ fn _push(&mut self, path: &Path) {
     /// Returns `false` and does nothing if [`self.parent`] is [`None`].
     /// Otherwise, returns `true`.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`self.parent`]: struct.PathBuf.html#method.parent
+    /// [`self.parent`]: Path::parent
     ///
     /// # Examples
     ///
     /// ```
     /// use std::path::{Path, PathBuf};
     ///
-    /// let mut p = PathBuf::from("/test/test.rs");
+    /// let mut p = PathBuf::from("/spirited/away.rs");
     ///
     /// p.pop();
-    /// assert_eq!(Path::new("/test"), p);
+    /// assert_eq!(Path::new("/spirited"), p);
     /// p.pop();
     /// assert_eq!(Path::new("/"), p);
     /// ```
@@ -1259,9 +1223,8 @@ pub fn pop(&mut self) -> bool {
     /// `file_name`. The new path will be a sibling of the original path.
     /// (That is, it will have the same parent.)
     ///
-    /// [`self.file_name`]: struct.PathBuf.html#method.file_name
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`pop`]: struct.PathBuf.html#method.pop
+    /// [`self.file_name`]: Path::file_name
+    /// [`pop`]: PathBuf::pop
     ///
     /// # Examples
     ///
@@ -1297,9 +1260,8 @@ fn _set_file_name(&mut self, file_name: &OsStr) {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
-    /// [`self.file_name`]: struct.PathBuf.html#method.file_name
-    /// [`self.extension`]: struct.PathBuf.html#method.extension
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`self.file_name`]: Path::file_name
+    /// [`self.extension`]: Path::extension
     ///
     /// # Examples
     ///
@@ -1344,8 +1306,6 @@ fn _set_extension(&mut self, extension: &OsStr) -> bool {
 
     /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
     ///
-    /// [`OsString`]: ../ffi/struct.OsString.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -1360,9 +1320,6 @@ pub fn into_os_string(self) -> OsString {
     }
 
     /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
-    ///
-    /// [`Box`]: ../../std/boxed/struct.Box.html
-    /// [`Path`]: struct.Path.html
     #[stable(feature = "into_boxed_path", since = "1.20.0")]
     pub fn into_boxed_path(self) -> Box<Path> {
         let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
@@ -1371,8 +1328,7 @@ pub fn into_boxed_path(self) -> Box<Path> {
 
     /// Invokes [`capacity`] on the underlying instance of [`OsString`].
     ///
-    /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`capacity`]: OsString::capacity
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
@@ -1380,8 +1336,7 @@ pub fn capacity(&self) -> usize {
 
     /// Invokes [`clear`] on the underlying instance of [`OsString`].
     ///
-    /// [`clear`]: ../ffi/struct.OsString.html#method.clear
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`clear`]: OsString::clear
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn clear(&mut self) {
         self.inner.clear()
@@ -1389,8 +1344,7 @@ pub fn clear(&mut self) {
 
     /// Invokes [`reserve`] on the underlying instance of [`OsString`].
     ///
-    /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`reserve`]: OsString::reserve
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
@@ -1398,8 +1352,7 @@ pub fn reserve(&mut self, additional: usize) {
 
     /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
     ///
-    /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`reserve_exact`]: OsString::reserve_exact
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
@@ -1407,8 +1360,7 @@ pub fn reserve_exact(&mut self, additional: usize) {
 
     /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
     ///
-    /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`shrink_to_fit`]: OsString::shrink_to_fit
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
     pub fn shrink_to_fit(&mut self) {
         self.inner.shrink_to_fit()
@@ -1416,8 +1368,7 @@ pub fn shrink_to_fit(&mut self) {
 
     /// Invokes [`shrink_to`] on the underlying instance of [`OsString`].
     ///
-    /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to
-    /// [`OsString`]: ../ffi/struct.OsString.html
+    /// [`shrink_to`]: OsString::shrink_to
     #[unstable(feature = "shrink_to", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         self.inner.shrink_to(min_capacity)
@@ -1703,10 +1654,6 @@ fn as_ref(&self) -> &OsStr {
 /// pointer like `&` or [`Box`]. For an owned version of this type,
 /// see [`PathBuf`].
 ///
-/// [`str`]: ../primitive.str.html
-/// [`Box`]: ../boxed/struct.Box.html
-/// [`PathBuf`]: struct.PathBuf.html
-///
 /// More details about the overall approach can be found in
 /// the [module documentation](index.html).
 ///
@@ -1745,8 +1692,7 @@ pub struct Path {
 /// This `struct` is created by the [`strip_prefix`] method on [`Path`].
 /// See its documentation for more.
 ///
-/// [`strip_prefix`]: struct.Path.html#method.strip_prefix
-/// [`Path`]: struct.Path.html
+/// [`strip_prefix`]: Path::strip_prefix
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[stable(since = "1.7.0", feature = "strip_prefix")]
 pub struct StripPrefixError(());
@@ -1791,8 +1737,6 @@ pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
 
     /// Yields the underlying [`OsStr`] slice.
     ///
-    /// [`OsStr`]: ../ffi/struct.OsStr.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -1812,7 +1756,7 @@ pub fn as_os_str(&self) -> &OsStr {
     /// Note that validation is performed because non-UTF-8 strings are
     /// perfectly valid for some OS.
     ///
-    /// [`&str`]: ../primitive.str.html
+    /// [`&str`]: str
     ///
     /// # Examples
     ///
@@ -1832,8 +1776,8 @@ pub fn to_str(&self) -> Option<&str> {
     /// Any non-Unicode sequences are replaced with
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
     ///
-    /// [`Cow<str>`]: ../borrow/enum.Cow.html
-    /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+    /// [`Cow<str>`]: Cow
+    /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER
     ///
     /// # Examples
     ///
@@ -1855,8 +1799,6 @@ pub fn to_string_lossy(&self) -> Cow<'_, str> {
 
     /// Converts a `Path` to an owned [`PathBuf`].
     ///
-    /// [`PathBuf`]: struct.PathBuf.html
-    ///
     /// # Examples
     ///
     /// ```
@@ -1888,7 +1830,7 @@ pub fn to_path_buf(&self) -> PathBuf {
     /// assert!(!Path::new("foo.txt").is_absolute());
     /// ```
     ///
-    /// [`has_root`]: #method.has_root
+    /// [`has_root`]: Path::has_root
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow(deprecated)]
     pub fn is_absolute(&self) -> bool {
@@ -1912,7 +1854,7 @@ pub fn is_absolute(&self) -> bool {
     /// assert!(Path::new("foo.txt").is_relative());
     /// ```
     ///
-    /// [`is_absolute`]: #method.is_absolute
+    /// [`is_absolute`]: Path::is_absolute
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_relative(&self) -> bool {
         !self.is_absolute()
@@ -1947,8 +1889,6 @@ pub fn has_root(&self) -> bool {
     ///
     /// Returns [`None`] if the path terminates in a root or prefix.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -1992,10 +1932,16 @@ pub fn parent(&self) -> Option<&Path> {
     /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
     /// assert_eq!(ancestors.next(), Some(Path::new("/")));
     /// assert_eq!(ancestors.next(), None);
+    ///
+    /// let mut ancestors = Path::new("../foo/bar").ancestors();
+    /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar")));
+    /// assert_eq!(ancestors.next(), Some(Path::new("../foo")));
+    /// assert_eq!(ancestors.next(), Some(Path::new("..")));
+    /// assert_eq!(ancestors.next(), Some(Path::new("")));
+    /// assert_eq!(ancestors.next(), None);
     /// ```
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`parent`]: struct.Path.html#method.parent
+    /// [`parent`]: Path::parent
     #[stable(feature = "path_ancestors", since = "1.28.0")]
     pub fn ancestors(&self) -> Ancestors<'_> {
         Ancestors { next: Some(&self) }
@@ -2008,8 +1954,6 @@ pub fn ancestors(&self) -> Ancestors<'_> {
     ///
     /// Returns [`None`] if the path terminates in `..`.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2038,8 +1982,7 @@ pub fn file_name(&self) -> Option<&OsStr> {
     /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
     /// returns `false`), returns [`Err`].
     ///
-    /// [`starts_with`]: #method.starts_with
-    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`starts_with`]: Path::starts_with
     ///
     /// # Examples
     ///
@@ -2053,8 +1996,9 @@ pub fn file_name(&self) -> Option<&OsStr> {
     /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
     /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
     /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
-    /// assert_eq!(path.strip_prefix("test").is_ok(), false);
-    /// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+    ///
+    /// assert!(path.strip_prefix("test").is_err());
+    /// assert!(path.strip_prefix("/haha").is_err());
     ///
     /// let prefix = PathBuf::from("/test/");
     /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
@@ -2124,7 +2068,7 @@ fn _ends_with(&self, child: &Path) -> bool {
 
     /// Extracts the stem (non-extension) portion of [`self.file_name`].
     ///
-    /// [`self.file_name`]: struct.Path.html#method.file_name
+    /// [`self.file_name`]: Path::file_name
     ///
     /// The stem is:
     ///
@@ -2133,16 +2077,13 @@ fn _ends_with(&self, child: &Path) -> bool {
     /// * The entire file name if the file name begins with `.` and has no other `.`s within;
     /// * Otherwise, the portion of the file name before the final `.`
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
     /// use std::path::Path;
     ///
-    /// let path = Path::new("foo.rs");
-    ///
-    /// assert_eq!("foo", path.file_stem().unwrap());
+    /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap());
+    /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn file_stem(&self) -> Option<&OsStr> {
@@ -2158,17 +2099,15 @@ pub fn file_stem(&self) -> Option<&OsStr> {
     /// * [`None`], if the file name begins with `.` and has no other `.`s within;
     /// * Otherwise, the portion of the file name after the final `.`
     ///
-    /// [`self.file_name`]: struct.Path.html#method.file_name
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`self.file_name`]: Path::file_name
     ///
     /// # Examples
     ///
     /// ```
     /// use std::path::Path;
     ///
-    /// let path = Path::new("foo.rs");
-    ///
-    /// assert_eq!("rs", path.extension().unwrap());
+    /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap());
+    /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn extension(&self) -> Option<&OsStr> {
@@ -2179,9 +2118,6 @@ pub fn extension(&self) -> Option<&OsStr> {
     ///
     /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
     ///
-    /// [`PathBuf`]: struct.PathBuf.html
-    /// [`PathBuf::push`]: struct.PathBuf.html#method.push
-    ///
     /// # Examples
     ///
     /// ```
@@ -2205,9 +2141,6 @@ fn _join(&self, path: &Path) -> PathBuf {
     ///
     /// See [`PathBuf::set_file_name`] for more details.
     ///
-    /// [`PathBuf`]: struct.PathBuf.html
-    /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
-    ///
     /// # Examples
     ///
     /// ```
@@ -2234,9 +2167,6 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
     ///
     /// See [`PathBuf::set_extension`] for more details.
     ///
-    /// [`PathBuf`]: struct.PathBuf.html
-    /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
-    ///
     /// # Examples
     ///
     /// ```
@@ -2247,6 +2177,8 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
     ///
     /// let path = Path::new("foo.tar.gz");
     /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
+    /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz"));
+    /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
@@ -2291,8 +2223,7 @@ fn _with_extension(&self, extension: &OsStr) -> PathBuf {
     /// assert_eq!(components.next(), None)
     /// ```
     ///
-    /// [`Component`]: enum.Component.html
-    /// [`CurDir`]: enum.Component.html#variant.CurDir
+    /// [`CurDir`]: Component::CurDir
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn components(&self) -> Components<'_> {
         let prefix = parse_prefix(self.as_os_str());
@@ -2312,8 +2243,7 @@ pub fn components(&self) -> Components<'_> {
     /// For more information about the particulars of how the path is separated
     /// into components, see [`components`].
     ///
-    /// [`components`]: #method.components
-    /// [`OsStr`]: ../ffi/struct.OsStr.html
+    /// [`components`]: Path::components
     ///
     /// # Examples
     ///
@@ -2335,7 +2265,7 @@ pub fn iter(&self) -> Iter<'_> {
     /// Returns an object that implements [`Display`] for safely printing paths
     /// that may contain non-Unicode data.
     ///
-    /// [`Display`]: ../fmt/trait.Display.html
+    /// [`Display`]: fmt::Display
     ///
     /// # Examples
     ///
@@ -2358,8 +2288,6 @@ pub fn display(&self) -> Display<'_> {
     ///
     /// This is an alias to [`fs::metadata`].
     ///
-    /// [`fs::metadata`]: ../fs/fn.metadata.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2378,8 +2306,6 @@ pub fn metadata(&self) -> io::Result<fs::Metadata> {
     ///
     /// This is an alias to [`fs::symlink_metadata`].
     ///
-    /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2399,8 +2325,6 @@ pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
     ///
     /// This is an alias to [`fs::canonicalize`].
     ///
-    /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2418,8 +2342,6 @@ pub fn canonicalize(&self) -> io::Result<PathBuf> {
     ///
     /// This is an alias to [`fs::read_link`].
     ///
-    /// [`fs::read_link`]: ../fs/fn.read_link.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2435,15 +2357,11 @@ pub fn read_link(&self) -> io::Result<PathBuf> {
 
     /// Returns an iterator over the entries within a directory.
     ///
-    /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
+    /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
     /// errors may be encountered after an iterator is initially constructed.
     ///
     /// This is an alias to [`fs::read_dir`].
     ///
-    /// [`io::Result`]: ../io/type.Result.html
-    /// [`DirEntry`]: ../fs/struct.DirEntry.html
-    /// [`fs::read_dir`]: ../fs/fn.read_dir.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2473,15 +2391,13 @@ pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
     ///
     /// ```no_run
     /// use std::path::Path;
-    /// assert_eq!(Path::new("does_not_exist.txt").exists(), false);
+    /// assert!(!Path::new("does_not_exist.txt").exists());
     /// ```
     ///
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [fs::metadata].
-    ///
-    /// [fs::metadata]: ../../std/fs/fn.metadata.html
+    /// check errors, call [`fs::metadata`].
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn exists(&self) -> bool {
         fs::metadata(self).is_ok()
@@ -2506,20 +2422,14 @@ pub fn exists(&self) -> bool {
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [`fs::metadata`] and handle its Result. Then call
-    /// [`fs::Metadata::is_file`] if it was Ok.
+    /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+    /// [`fs::Metadata::is_file`] if it was [`Ok`].
     ///
     /// When the goal is simply to read from (or write to) the source, the most
     /// reliable way to test the source can be read (or written to) is to open
     /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
-    /// a Unix-like system for example. See [`File::open`] or
-    /// [`OpenOptions::open`] for more information.
-    ///
-    /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
-    /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
-    /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
-    /// [`File::open`]: ../../std/fs/struct.File.html#method.open
-    /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
+    /// a Unix-like system for example. See [`fs::File::open`] or
+    /// [`fs::OpenOptions::open`] for more information.
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn is_file(&self) -> bool {
         fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
@@ -2544,11 +2454,8 @@ pub fn is_file(&self) -> bool {
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [fs::metadata] and handle its Result. Then call
-    /// [fs::Metadata::is_dir] if it was Ok.
-    ///
-    /// [fs::metadata]: ../../std/fs/fn.metadata.html
-    /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir
+    /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+    /// [`fs::Metadata::is_dir`] if it was [`Ok`].
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn is_dir(&self) -> bool {
         fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
@@ -2556,9 +2463,6 @@ pub fn is_dir(&self) -> bool {
 
     /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
     /// allocating.
-    ///
-    /// [`Box`]: ../../std/boxed/struct.Box.html
-    /// [`PathBuf`]: struct.PathBuf.html
     #[stable(feature = "into_boxed_path", since = "1.20.0")]
     pub fn into_path_buf(self: Box<Path>) -> PathBuf {
         let rw = Box::into_raw(self) as *mut OsStr;
@@ -2597,10 +2501,8 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// println!("{}", path.display());
 /// ```
 ///
-/// [`Display`]: ../../std/fmt/trait.Display.html
-/// [`format!`]: ../../std/macro.format.html
-/// [`Path`]: struct.Path.html
-/// [`Path::display`]: struct.Path.html#method.display
+/// [`Display`]: fmt::Display
+/// [`format!`]: crate::format
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Display<'a> {
     path: &'a Path,
index fb825ab16ebd7ef8d1dc114bd8d0a36b86a461fe..45af9f68a0f6b149c365f04b6ce6f4cea56d61f2 100644 (file)
@@ -48,9 +48,7 @@ fn lang_start_internal(
         sys::args::init(argc, argv);
 
         // Let's run some code!
-        let exit_code = panic::catch_unwind(|| {
-            sys_common::backtrace::__rust_begin_short_backtrace(move || main())
-        });
+        let exit_code = panic::catch_unwind(main);
 
         sys_common::cleanup();
         exit_code.unwrap_or(101) as isize
@@ -64,5 +62,9 @@ fn lang_start<T: crate::process::Termination + 'static>(
     argc: isize,
     argv: *const *const u8,
 ) -> isize {
-    lang_start_internal(&move || main().report(), argc, argv)
+    lang_start_internal(
+        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
+        argc,
+        argv,
+    )
 }
index 675b82ceb775f7b0a35c116cc54b2c39d0c93b90..8eaf07e52d69a228c945b4bb537993866849c3a2 100644 (file)
@@ -106,7 +106,7 @@ pub fn init() {
     argv: *const *const c_char,
     env: *const *const c_char,
 ) -> ! {
-    use crate::sys::hermit::fast_thread_local::run_dtors;
+    use crate::sys::hermit::thread_local_dtor::run_dtors;
     extern "C" {
         fn main(argc: isize, argv: *const *const c_char) -> i32;
     }
index e11afed668728f08abe9be030ca22af6f231bab7..7bd71e120de40a02f7cbbc96a3ccc64b8e37cf8f 100644 (file)
@@ -4,7 +4,7 @@
 use crate::io;
 use crate::mem;
 use crate::sys::hermit::abi;
-use crate::sys::hermit::fast_thread_local::run_dtors;
+use crate::sys::hermit::thread_local_dtor::run_dtors;
 use crate::time::Duration;
 
 pub type Tid = abi::Tid;
index 84c4d662161bca7fac8a938c71e5799618787e10..ba169b251b0bc7ad768593f8fef355ce8e800d39 100644 (file)
@@ -3,6 +3,8 @@
 use crate::cmp;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
 use crate::mem;
+#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::cvt;
 use crate::sys_common::AsInner;
 
@@ -26,6 +28,27 @@ pub struct FileDesc {
 #[cfg(not(target_os = "macos"))]
 const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
 
+#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
+fn max_iov() -> usize {
+    static LIM: AtomicUsize = AtomicUsize::new(0);
+
+    let mut lim = LIM.load(Ordering::Relaxed);
+    if lim == 0 {
+        let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };
+
+        // 16 is the minimum value required by POSIX.
+        lim = if ret > 0 { ret as usize } else { 16 };
+        LIM.store(lim, Ordering::Relaxed);
+    }
+
+    lim
+}
+
+#[cfg(any(target_os = "redox", target_env = "newlib"))]
+fn max_iov() -> usize {
+    16 // The minimum value required by POSIX.
+}
+
 impl FileDesc {
     pub fn new(fd: c_int) -> FileDesc {
         FileDesc { fd }
@@ -54,7 +77,7 @@ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
             libc::readv(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
+                cmp::min(bufs.len(), max_iov()) as c_int,
             )
         })?;
         Ok(ret as usize)
@@ -111,7 +134,7 @@ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
             libc::writev(
                 self.fd,
                 bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
+                cmp::min(bufs.len(), max_iov()) as c_int,
             )
         })?;
         Ok(ret as usize)
@@ -256,3 +279,16 @@ fn drop(&mut self) {
         let _ = unsafe { libc::close(self.fd) };
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::{FileDesc, IoSlice};
+    use core::mem::ManuallyDrop;
+
+    #[test]
+    fn limit_vector_count() {
+        let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
+        let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
+        assert!(stdout.write_vectored(&bufs).is_ok());
+    }
+}
index 9a52371280e159ffb2e0115f8af19086eb90570d..982ec912c44b710eebdb7d78559e9ea314e6f95b 100644 (file)
@@ -99,43 +99,28 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
 
 pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
     let ptr = haystack.as_ptr();
-    let mut len = haystack.len();
     let mut start = &haystack[..];
 
     // For performance reasons unfold the loop eight times.
-    while len >= 8 {
-        if start[0] == needle {
-            return Some((start.as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[1] == needle {
-            return Some((start[1..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[2] == needle {
-            return Some((start[2..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[3] == needle {
-            return Some((start[3..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[4] == needle {
-            return Some((start[4..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[5] == needle {
-            return Some((start[5..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[6] == needle {
-            return Some((start[6..].as_ptr() as usize - ptr as usize) / 2);
-        }
-        if start[7] == needle {
-            return Some((start[7..].as_ptr() as usize - ptr as usize) / 2);
+    while start.len() >= 8 {
+        macro_rules! if_return {
+            ($($n:literal,)+) => {
+                $(
+                    if start[$n] == needle {
+                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
+                    }
+                )+
+            }
         }
 
+        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);
+
         start = &start[8..];
-        len -= 8;
     }
 
-    for (i, c) in start.iter().enumerate() {
+    for c in start {
         if *c == needle {
-            return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
+            return Some((c as *const u16 as usize - ptr as usize) / 2);
         }
     }
     None
index d386a656e4ffdc896aa93fdceb53060d1c75a71c..1c5fbf7d70102fb30d9a3073a34c1082a771b6fd 100644 (file)
@@ -74,6 +74,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
     bt_fmt.add_context()?;
     let mut idx = 0;
     let mut res = Ok(());
+    // Start immediately if we're not using a short backtrace.
+    let mut start = print_fmt != PrintFmt::Short;
     backtrace_rs::trace_unsynchronized(|frame| {
         if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
             return false;
@@ -89,16 +91,24 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
                         stop = true;
                         return;
                     }
+                    if sym.contains("__rust_end_short_backtrace") {
+                        start = true;
+                        return;
+                    }
                 }
             }
 
-            res = bt_fmt.frame().symbol(frame, symbol);
+            if start {
+                res = bt_fmt.frame().symbol(frame, symbol);
+            }
         });
         if stop {
             return false;
         }
         if !hit {
-            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+            if start {
+                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+            }
         }
 
         idx += 1;
@@ -123,10 +133,29 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
 where
     F: FnOnce() -> T,
-    F: Send,
-    T: Send,
 {
-    f()
+    let result = f();
+
+    // prevent this frame from being tail-call optimised away
+    crate::hint::black_box(());
+
+    result
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
+/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// it's fine to optimize away.
+#[cfg_attr(feature = "backtrace", inline(never))]
+pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
+where
+    F: FnOnce() -> T,
+{
+    let result = f();
+
+    // prevent this frame from being tail-call optimised away
+    crate::hint::black_box(());
+
+    result
 }
 
 pub enum RustBacktrace {
index 2fe87247e3acfc0951bb5c751d5f73f76dbb9194..7ca27bf0dc15e90eb0852ef98a0c62bab1e2ba5e 100644 (file)
@@ -4,7 +4,7 @@
 
 #[allow(deprecated)]
 pub fn get_concurrency() -> usize {
-    return match env::var("RUST_TEST_THREADS") {
+    match env::var("RUST_TEST_THREADS") {
         Ok(s) => {
             let opt_n: Option<usize> = s.parse().ok();
             match opt_n {
@@ -13,7 +13,7 @@ pub fn get_concurrency() -> usize {
             }
         }
         Err(..) => num_cpus(),
-    };
+    }
 }
 
 cfg_if::cfg_if! {
index 933b647071f790c38cd5e181c71ede25a7bfb0f6..6bd708ef48798832d5d7ccacc9e1676d623b6235 100644 (file)
@@ -514,7 +514,10 @@ fn run_test_inner(
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
 #[inline(never)]
 fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
-    f()
+    f();
+
+    // prevent this frame from being tail-call optimised away
+    black_box(());
 }
 
 fn run_test_in_process(
index c4d10ab177be9534659df7ae4b69fe9355f47c07..20a2ca984057e94ff4e9045abcce3d3297b83efa 100644 (file)
@@ -19,6 +19,7 @@
     } else if #[cfg(any(
         unix,
         windows,
+        target_os = "psp",
         target_os = "cloudabi",
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
@@ -32,7 +33,6 @@
         // - os=uefi
         // - os=cuda
         // - nvptx64-nvidia-cuda
-        // - mipsel-sony-psp
         // - Any new targets not listed above.
     }
 }
index 8a6973bcdd6c91ce6048a98acc809349480b1730..0ff77de003d311eb826279d1e18b334325287c57 100644 (file)
@@ -587,6 +587,7 @@ jobs:
       <<: [*shared-ci-variables, *dummy-variables]
     if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
     strategy:
+      fail-fast: false
       matrix:
         include:
           #############################
index a914f2c7e5cdb771fa465de142381a51c53b580e..363293c1c5ce9e84ea3935a5e29ce8624801208a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e
+Subproject commit 363293c1c5ce9e84ea3935a5e29ce8624801208a
index 94d9ea8460bcbbbfef1877b47cb930260b5849a7..b5256448a2a4c1bec68b93c0847066f92f2ff5a9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 94d9ea8460bcbbbfef1877b47cb930260b5849a7
+Subproject commit b5256448a2a4c1bec68b93c0847066f92f2ff5a9
index b329ce37424874ad4db94f829a55807c6e21d2cb..c9b2736a059469043177e1e4ed41a55d7c63ac28 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb
+Subproject commit c9b2736a059469043177e1e4ed41a55d7c63ac28
index 229c6945a26a53a751ffa4f9cb418388c00029d3..2e9271981adc32613365810f3428334c07095215 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 229c6945a26a53a751ffa4f9cb418388c00029d3
+Subproject commit 2e9271981adc32613365810f3428334c07095215
index cec9c56a23522b3ee2dd3feb694ce6c35afa4752..67f99ec4e40b923ca315e0d630f63ab22edd6ee5 100644 (file)
@@ -352,8 +352,13 @@ class StdHashMapProvider:
         ctrl = table["ctrl"]["pointer"]
 
         self.size = int(table["items"])
-        self.data_ptr = table["data"]["pointer"]
-        self.pair_type = self.data_ptr.dereference().type
+        self.pair_type = table.type.template_argument(0)
+
+        self.new_layout = not table.type.has_key("data")
+        if self.new_layout:
+            self.data_ptr = ctrl.cast(self.pair_type.pointer())
+        else:
+            self.data_ptr = table["data"]["pointer"]
 
         self.valid_indices = []
         for idx in range(capacity):
@@ -374,6 +379,8 @@ class StdHashMapProvider:
 
         for index in range(self.size):
             idx = self.valid_indices[index]
+            if self.new_layout:
+                idx = -(idx + 1)
             element = (pairs_start + idx).dereference()
             if self.show_values:
                 yield "key{}".format(index), element[ZERO_FIELD]
index 3c7817b3a618d6d33c468d1dbfdd0fd07e308253..19da75c35b456b4e12efdf826c5d61df852a35c2 100644 (file)
@@ -514,6 +514,8 @@ class StdHashMapSyntheticProvider:
         # type: (int) -> SBValue
         pairs_start = self.data_ptr.GetValueAsUnsigned()
         idx = self.valid_indices[index]
+        if self.new_layout:
+            idx = -(idx + 1)
         address = pairs_start + idx * self.pair_type_size
         element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
         if self.show_values:
@@ -529,10 +531,15 @@ class StdHashMapSyntheticProvider:
         ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
 
         self.size = table.GetChildMemberWithName("items").GetValueAsUnsigned()
-        self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0)
-        self.pair_type = self.data_ptr.Dereference().GetType()
+        self.pair_type = table.type.template_args[0]
         self.pair_type_size = self.pair_type.GetByteSize()
 
+        self.new_layout = not table.GetChildMemberWithName("data").IsValid()
+        if self.new_layout:
+            self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType())
+        else:
+            self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0)
+
         u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar)
         u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize()
 
index b3fc3d17af7fe15298a7cc57cec96eec6f633ba9..4e81173d3d0b875c47626b6269173379f1606b04 100644 (file)
@@ -30,6 +30,7 @@
     <Expand>
       <Item Name="[size]">base.table.items</Item>
       <Item Name="[capacity]">base.table.items + base.table.growth_left</Item>
+      <Item Name="[state]">base.hash_builder</Item>
 
       <CustomListItems>
         <Variable Name="i" InitialValue="0" />
@@ -40,7 +41,7 @@
           <If Condition="(base.table.ctrl.pointer[i] &amp; 0x80) == 0">
             <!-- Bucket is populated -->
             <Exec>n--</Exec>
-            <Item Name="{base.table.data.pointer[i].__0}">base.table.data.pointer[i].__1</Item>
+            <Item Name="{static_cast&lt;tuple&lt;$T1, $T2&gt;*&gt;(base.table.ctrl.pointer)[-(i + 1)].__0}">static_cast&lt;tuple&lt;$T1, $T2&gt;*&gt;(base.table.ctrl.pointer)[-(i + 1)].__1</Item>
           </If>
           <Exec>i++</Exec>
         </Loop>
@@ -53,6 +54,7 @@
     <Expand>
       <Item Name="[size]">map.base.table.items</Item>
       <Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item>
+      <Item Name="[state]">map.base.hash_builder</Item>
 
       <CustomListItems>
         <Variable Name="i" InitialValue="0" />
           <If Condition="(map.base.table.ctrl.pointer[i] &amp; 0x80) == 0">
             <!-- Bucket is populated -->
             <Exec>n--</Exec>
-            <Item>map.base.table.data.pointer[i].__0</Item>
-          </If>
-          <Exec>i++</Exec>
-        </Loop>
-      </CustomListItems>
-    </Expand>
-  </Type>
-
-  <Type Name="hashbrown::raw::RawTable&lt;*&gt;">
-    <!-- RawTable has a nice and simple layout.
-      items                     Number of *populated* values in the RawTable (less than the size of ctrl.pointer / data.pointer)
-      growth_left               Remaining capacity before growth
-      ctrl.pointer[i] & 0x80    Indicates the bucket is empty / should be skipped / doesn't count towards items.
-      data.pointer[i]           The (K,V) tuple, if not empty.
-    -->
-    <DisplayString>{{ size={items} }}</DisplayString>
-    <Expand>
-      <Item Name="[size]">items</Item>
-      <Item Name="[capacity]">items + growth_left</Item>
-
-      <CustomListItems>
-        <Variable Name="i" InitialValue="0" />
-        <Variable Name="n" InitialValue="items" />
-        <Size>items</Size>
-        <Loop>
-          <Break Condition="n == 0" />
-          <If Condition="(ctrl.pointer[i] &amp; 0x80) == 0">
-            <!-- Bucket is populated -->
-            <Exec>n--</Exec>
-            <Item>data.pointer[i]</Item>
+            <Item>static_cast&lt;$T1*&gt;(map.base.table.ctrl.pointer)[-(i + 1)]</Item>
           </If>
           <Exec>i++</Exec>
         </Loop>
index a36f49bd4146b60b82ddd07a1603eb7754f632c8..ab0ab7244dbe4818adda88a98852d4105f88ab17 100644 (file)
@@ -12,7 +12,6 @@ doctest = false
 [dependencies]
 rustc_serialize = { path = "../librustc_serialize" }
 log = { package = "tracing", version = "0.1" }
-scoped-tls = "1.0"
 rustc_span = { path = "../librustc_span" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_index = { path = "../librustc_index" }
index 6543117774a682c8a7e28818e56054aec760aa88..83a9de84ed8414f75bc9c56bae4d0be6a0facc7f 100644 (file)
@@ -23,7 +23,7 @@
 pub use UnsafeSource::*;
 
 use crate::ptr::P;
-use crate::token::{self, DelimToken};
+use crate::token::{self, CommentKind, DelimToken};
 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -378,7 +378,7 @@ fn default() -> Generics {
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct WhereClause {
     /// `true` if we ate a `where` token: this can happen
-    /// if we parsed no predicates (e.g. `struct Foo where {}
+    /// if we parsed no predicates (e.g. `struct Foo where {}`).
     /// This allows us to accurately pretty-print
     /// in `nt_to_tokenstream`
     pub has_where_token: bool,
@@ -1052,6 +1052,30 @@ pub fn returns(&self) -> bool {
         }
     }
 
+    /// Is this expr either `N`, or `{ N }`.
+    ///
+    /// If this is not the case, name resolution does not resolve `N` when using
+    /// `feature(min_const_generics)` as more complex expressions are not supported.
+    pub fn is_potential_trivial_const_param(&self) -> bool {
+        let this = if let ExprKind::Block(ref block, None) = self.kind {
+            if block.stmts.len() == 1 {
+                if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
+            } else {
+                self
+            }
+        } else {
+            self
+        };
+
+        if let ExprKind::Path(None, ref path) = this.kind {
+            if path.segments.len() == 1 && path.segments[0].args.is_none() {
+                return true;
+            }
+        }
+
+        false
+    }
+
     pub fn to_bound(&self) -> Option<GenericBound> {
         match &self.kind {
             ExprKind::Path(None, path) => Some(GenericBound::Trait(
@@ -2365,7 +2389,7 @@ pub enum AttrKind {
     /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
     /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
     /// variant (which is much less compact and thus more expensive).
-    DocComment(Symbol),
+    DocComment(CommentKind, Symbol),
 }
 
 /// `TraitRef`s appear in impls.
index 809fda865422a8fea4c2bd94ec819fcd50cedc89..edcbce3e2cfd34cc2bd77563427b97bbab27db50 100644 (file)
@@ -7,75 +7,33 @@
 use crate::ast::{Path, PathSegment};
 use crate::mut_visit::visit_clobber;
 use crate::ptr::P;
-use crate::token::{self, Token};
+use crate::token::{self, CommentKind, Token};
 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 
-use rustc_data_structures::sync::Lock;
 use rustc_index::bit_set::GrowableBitSet;
-use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::source_map::{BytePos, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
-use log::debug;
 use std::iter;
 use std::ops::DerefMut;
 
-// Per-session global variables: this struct is stored in thread-local storage
-// in such a way that it is accessible without any kind of handle to all
-// threads within the compilation session, but is not accessible outside the
-// session.
-pub struct SessionGlobals {
-    used_attrs: Lock<GrowableBitSet<AttrId>>,
-    known_attrs: Lock<GrowableBitSet<AttrId>>,
-    span_session_globals: rustc_span::SessionGlobals,
-}
+pub struct MarkedAttrs(GrowableBitSet<AttrId>);
 
-impl SessionGlobals {
-    fn new(edition: Edition) -> SessionGlobals {
-        SessionGlobals {
-            // We have no idea how many attributes there will be, so just
-            // initiate the vectors with 0 bits. We'll grow them as necessary.
-            used_attrs: Lock::new(GrowableBitSet::new_empty()),
-            known_attrs: Lock::new(GrowableBitSet::new_empty()),
-            span_session_globals: rustc_span::SessionGlobals::new(edition),
-        }
+impl MarkedAttrs {
+    // We have no idea how many attributes there will be, so just
+    // initiate the vectors with 0 bits. We'll grow them as necessary.
+    pub fn new() -> Self {
+        MarkedAttrs(GrowableBitSet::new_empty())
     }
-}
-
-pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
-    let ast_session_globals = SessionGlobals::new(edition);
-    SESSION_GLOBALS.set(&ast_session_globals, || {
-        rustc_span::SESSION_GLOBALS.set(&ast_session_globals.span_session_globals, f)
-    })
-}
-
-pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
-    with_session_globals(DEFAULT_EDITION, f)
-}
 
-scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
-
-pub fn mark_used(attr: &Attribute) {
-    debug!("marking {:?} as used", attr);
-    SESSION_GLOBALS.with(|session_globals| {
-        session_globals.used_attrs.lock().insert(attr.id);
-    });
-}
-
-pub fn is_used(attr: &Attribute) -> bool {
-    SESSION_GLOBALS.with(|session_globals| session_globals.used_attrs.lock().contains(attr.id))
-}
-
-pub fn mark_known(attr: &Attribute) {
-    debug!("marking {:?} as known", attr);
-    SESSION_GLOBALS.with(|session_globals| {
-        session_globals.known_attrs.lock().insert(attr.id);
-    });
-}
+    pub fn mark(&mut self, attr: &Attribute) {
+        self.0.insert(attr.id);
+    }
 
-pub fn is_known(attr: &Attribute) -> bool {
-    SESSION_GLOBALS.with(|session_globals| session_globals.known_attrs.lock().contains(attr.id))
+    pub fn is_marked(&self, attr: &Attribute) -> bool {
+        self.0.contains(attr.id)
+    }
 }
 
 pub fn is_known_lint_tool(m_item: Ident) -> bool {
@@ -169,23 +127,8 @@ impl Attribute {
     pub fn has_name(&self, name: Symbol) -> bool {
         match self.kind {
             AttrKind::Normal(ref item) => item.path == name,
-            AttrKind::DocComment(_) => false,
-        }
-    }
-
-    /// Returns `true` if the attribute's path matches the argument.
-    /// If it matches, then the attribute is marked as used.
-    /// Should only be used by rustc, other tools can use `has_name` instead,
-    /// because only rustc is supposed to report the `unused_attributes` lint.
-    /// `MetaItem` and `NestedMetaItem` are produced by "lowering" an `Attribute`
-    /// and don't have identity, so they only has the `has_name` method,
-    /// and you need to mark the original `Attribute` as used when necessary.
-    pub fn check_name(&self, name: Symbol) -> bool {
-        let matches = self.has_name(name);
-        if matches {
-            mark_used(self);
+            AttrKind::DocComment(..) => false,
         }
-        matches
     }
 
     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
@@ -198,7 +141,7 @@ pub fn ident(&self) -> Option<Ident> {
                     None
                 }
             }
-            AttrKind::DocComment(_) => None,
+            AttrKind::DocComment(..) => None,
         }
     }
     pub fn name_or_empty(&self) -> Symbol {
@@ -218,7 +161,7 @@ pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
                 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
                 _ => None,
             },
-            AttrKind::DocComment(_) => None,
+            AttrKind::DocComment(..) => None,
         }
     }
 
@@ -314,13 +257,13 @@ impl Attribute {
     pub fn is_doc_comment(&self) -> bool {
         match self.kind {
             AttrKind::Normal(_) => false,
-            AttrKind::DocComment(_) => true,
+            AttrKind::DocComment(..) => true,
         }
     }
 
     pub fn doc_str(&self) -> Option<Symbol> {
         match self.kind {
-            AttrKind::DocComment(symbol) => Some(symbol),
+            AttrKind::DocComment(.., data) => Some(data),
             AttrKind::Normal(ref item) if item.path == sym::doc => {
                 item.meta(self.span).and_then(|meta| meta.value_str())
             }
@@ -331,14 +274,14 @@ pub fn doc_str(&self) -> Option<Symbol> {
     pub fn get_normal_item(&self) -> &AttrItem {
         match self.kind {
             AttrKind::Normal(ref item) => item,
-            AttrKind::DocComment(_) => panic!("unexpected doc comment"),
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
         }
     }
 
     pub fn unwrap_normal_item(self) -> AttrItem {
         match self.kind {
             AttrKind::Normal(item) => item,
-            AttrKind::DocComment(_) => panic!("unexpected doc comment"),
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
         }
     }
 
@@ -405,30 +348,19 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute {
     mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
 }
 
-pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute {
-    Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span }
+pub fn mk_doc_comment(
+    comment_kind: CommentKind,
+    style: AttrStyle,
+    data: Symbol,
+    span: Span,
+) -> Attribute {
+    Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
 }
 
 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
     items.iter().any(|item| item.has_name(name))
 }
 
-pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
-    attrs.iter().any(|item| item.check_name(name))
-}
-
-pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
-    attrs.iter().find(|attr| attr.check_name(name))
-}
-
-pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
-    attrs.iter().filter(move |attr| attr.check_name(name))
-}
-
-pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
-    attrs.iter().find(|at| at.check_name(name)).and_then(|at| at.value_str())
-}
-
 impl MetaItem {
     fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
         let mut idents = vec![];
index 90d417a45fd93a30dca670d22a15fb563e88ec4a..290f6006de0790f25cac9f7618e061f54a92e1a7 100644 (file)
@@ -1,7 +1,3 @@
-use crate::ast::{Item, ItemKind};
-use crate::attr;
-use rustc_span::symbol::sym;
-
 pub enum EntryPointType {
     None,
     MainNamed,
@@ -9,27 +5,3 @@ pub enum EntryPointType {
     Start,
     OtherMain, // Not an entry point, but some other function named main
 }
-
-// Beware, this is duplicated in librustc_middle/middle/entry.rs, make sure to keep
-// them in sync.
-pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
-    match item.kind {
-        ItemKind::Fn(..) => {
-            if attr::contains_name(&item.attrs, sym::start) {
-                EntryPointType::Start
-            } else if attr::contains_name(&item.attrs, sym::main) {
-                EntryPointType::MainAttr
-            } else if item.ident.name == sym::main {
-                if depth == 1 {
-                    // This is a top-level function so can be 'main'
-                    EntryPointType::MainNamed
-                } else {
-                    EntryPointType::OtherMain
-                }
-            } else {
-                EntryPointType::None
-            }
-        }
-        _ => EntryPointType::None,
-    }
-}
index 7c67f029f382db1b4107fc73092759e9885ae413..cd27f958e4641868450fbd841313b0b006bc3176 100644 (file)
@@ -1,6 +1,4 @@
-use crate::{ast, attr, visit};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
 
 #[derive(Clone, Copy)]
 pub enum AllocatorKind {
@@ -53,25 +51,3 @@ pub struct AllocatorMethod {
         output: AllocatorTy::ResultPtr,
     },
 ];
-
-pub fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
-    struct Finder {
-        name: Symbol,
-        spans: Vec<Span>,
-    }
-    impl<'ast> visit::Visitor<'ast> for Finder {
-        fn visit_item(&mut self, item: &'ast ast::Item) {
-            if item.ident.name == self.name
-                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
-            {
-                self.spans.push(item.span);
-            }
-            visit::walk_item(self, item)
-        }
-    }
-
-    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
-    let mut f = Finder { name, spans: Vec::new() };
-    visit::walk_crate(&mut f, krate);
-    f.spans
-}
index 3c634ff40ccb1a524182b1b4dbc046888e77a9f9..eebfc38bdf4ec56b510cd71f35c1e33a99cfabd2 100644 (file)
@@ -1,12 +1,3 @@
 //! Definitions shared by macros / syntax extensions and e.g. librustc_middle.
 
-use crate::ast::Attribute;
-use rustc_span::symbol::sym;
-
 pub mod allocator;
-
-pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
-    [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
-        .iter()
-        .any(|kind| attr.check_name(*kind))
-}
index ca68db0b9f6474c70f7d81839c2601d21129a288..3f876169d2236e4baddf2c305cf16a7bbaef517d 100644 (file)
@@ -42,7 +42,6 @@ pub mod util {
 
 pub mod ast;
 pub mod attr;
-pub use attr::{with_default_session_globals, with_session_globals, SESSION_GLOBALS};
 pub mod crate_disambiguator;
 pub mod entry;
 pub mod expand;
index 54f81ef106fe14e39424e5f26fcb4c74212aa43b..df6e8218f6c3ac5201a32614248c38bbe7b68061 100644 (file)
@@ -582,7 +582,7 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
             vis.visit_path(path);
             visit_mac_args(args, vis);
         }
-        AttrKind::DocComment(_) => {}
+        AttrKind::DocComment(..) => {}
     }
     vis.visit_span(span);
 }
index e1c94ddf782881d16571fa154727471f1f2159c3..bcce881ed48c5deef7423eb8bfa4a8b082c5e1b8 100644 (file)
 use std::borrow::Cow;
 use std::{fmt, mem};
 
+#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+pub enum CommentKind {
+    Line,
+    Block,
+}
+
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 #[derive(HashStable_Generic)]
 pub enum BinOpToken {
@@ -238,9 +244,10 @@ pub enum TokenKind {
 
     Interpolated(Lrc<Nonterminal>),
 
-    // Can be expanded into several tokens.
-    /// A doc comment.
-    DocComment(Symbol),
+    /// A doc comment token.
+    /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
+    /// similarly to symbols in string literal tokens.
+    DocComment(CommentKind, ast::AttrStyle, Symbol),
 
     // Junk. These carry no data because we don't really care about the data
     // they *would* carry, and don't really want to allocate a new ident for
index 39921b20226065f74edfa6c541cb6181f07678fb..a73891db160de9739222c96330d032732e828a3d 100644 (file)
@@ -1,11 +1,7 @@
-pub use CommentStyle::*;
-
-use crate::ast;
+use crate::ast::AttrStyle;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
 
-use log::debug;
-
 #[cfg(test)]
 mod tests;
 
@@ -28,43 +24,48 @@ pub struct Comment {
     pub pos: BytePos,
 }
 
-pub fn is_line_doc_comment(s: &str) -> bool {
-    let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/')
-        || s.starts_with("//!");
-    debug!("is {:?} a doc comment? {}", s, res);
-    res
-}
-
-pub fn is_block_doc_comment(s: &str) -> bool {
-    // Prevent `/**/` from being parsed as a doc comment
-    let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*')
-        || s.starts_with("/*!"))
-        && s.len() >= 5;
-    debug!("is {:?} a doc comment? {}", s, res);
-    res
-}
-
-// FIXME(#64197): Try to privatize this again.
-pub fn is_doc_comment(s: &str) -> bool {
-    (s.starts_with("///") && is_line_doc_comment(s))
-        || s.starts_with("//!")
-        || (s.starts_with("/**") && is_block_doc_comment(s))
-        || s.starts_with("/*!")
+/// For a full line comment string returns its doc comment style if it's a doc comment
+/// and returns `None` if it's a regular comment.
+pub fn line_doc_comment_style(line_comment: &str) -> Option<AttrStyle> {
+    let line_comment = line_comment.as_bytes();
+    assert!(line_comment.starts_with(b"//"));
+    match line_comment.get(2) {
+        // `//!` is an inner line doc comment.
+        Some(b'!') => Some(AttrStyle::Inner),
+        Some(b'/') => match line_comment.get(3) {
+            // `////` (more than 3 slashes) is not considered a doc comment.
+            Some(b'/') => None,
+            // Otherwise `///` is an outer line doc comment.
+            _ => Some(AttrStyle::Outer),
+        },
+        _ => None,
+    }
 }
 
-pub fn doc_comment_style(comment: Symbol) -> ast::AttrStyle {
-    let comment = &comment.as_str();
-    assert!(is_doc_comment(comment));
-    if comment.starts_with("//!") || comment.starts_with("/*!") {
-        ast::AttrStyle::Inner
-    } else {
-        ast::AttrStyle::Outer
+/// For a full block comment string returns its doc comment style if it's a doc comment
+/// and returns `None` if it's a regular comment.
+pub fn block_doc_comment_style(block_comment: &str, terminated: bool) -> Option<AttrStyle> {
+    let block_comment = block_comment.as_bytes();
+    assert!(block_comment.starts_with(b"/*"));
+    assert!(!terminated || block_comment.ends_with(b"*/"));
+    match block_comment.get(2) {
+        // `/*!` is an inner block doc comment.
+        Some(b'!') => Some(AttrStyle::Inner),
+        Some(b'*') => match block_comment.get(3) {
+            // `/***` (more than 2 stars) is not considered a doc comment.
+            Some(b'*') => None,
+            // `/**/` is not considered a doc comment.
+            Some(b'/') if block_comment.len() == 4 => None,
+            // Otherwise `/**` is an outer block doc comment.
+            _ => Some(AttrStyle::Outer),
+        },
+        _ => None,
     }
 }
 
-pub fn strip_doc_comment_decoration(comment: Symbol) -> String {
-    let comment = &comment.as_str();
-
+/// Makes a doc string more presentable to users.
+/// Used by rustdoc and perhaps other tools, but not by rustc.
+pub fn beautify_doc_string(data: Symbol) -> String {
     /// remove whitespace-only lines from the start/end of lines
     fn vertical_trim(lines: Vec<String>) -> Vec<String> {
         let mut i = 0;
@@ -126,26 +127,15 @@ fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
         }
     }
 
-    // one-line comments lose their prefix
-    const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
-
-    for prefix in ONELINERS {
-        if comment.starts_with(*prefix) {
-            return (&comment[prefix.len()..]).to_string();
-        }
-    }
-
-    if comment.starts_with("/*") {
-        let lines =
-            comment[3..comment.len() - 2].lines().map(|s| s.to_string()).collect::<Vec<String>>();
-
+    let data = data.as_str();
+    if data.contains('\n') {
+        let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>();
         let lines = vertical_trim(lines);
         let lines = horizontal_trim(lines);
-
-        return lines.join("\n");
+        lines.join("\n")
+    } else {
+        data.to_string()
     }
-
-    panic!("not a doc-comment: {}", comment);
 }
 
 /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
@@ -203,7 +193,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
 
     if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
         comments.push(Comment {
-            style: Isolated,
+            style: CommentStyle::Isolated,
             lines: vec![text[..shebang_len].to_string()],
             pos: start_bpos,
         });
@@ -219,23 +209,23 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
                     while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
                         idx = idx + 1 + next_newline;
                         comments.push(Comment {
-                            style: BlankLine,
+                            style: CommentStyle::BlankLine,
                             lines: vec![],
                             pos: start_bpos + BytePos((pos + idx) as u32),
                         });
                     }
                 }
             }
-            rustc_lexer::TokenKind::BlockComment { terminated: _ } => {
-                if !is_block_doc_comment(token_text) {
+            rustc_lexer::TokenKind::BlockComment { terminated } => {
+                if block_doc_comment_style(token_text, terminated).is_none() {
                     let code_to_the_right = match text[pos + token.len..].chars().next() {
                         Some('\r' | '\n') => false,
                         _ => true,
                     };
                     let style = match (code_to_the_left, code_to_the_right) {
-                        (_, true) => Mixed,
-                        (false, false) => Isolated,
-                        (true, false) => Trailing,
+                        (_, true) => CommentStyle::Mixed,
+                        (false, false) => CommentStyle::Isolated,
+                        (true, false) => CommentStyle::Trailing,
                     };
 
                     // Count the number of chars since the start of the line by rescanning.
@@ -249,9 +239,13 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
                 }
             }
             rustc_lexer::TokenKind::LineComment => {
-                if !is_doc_comment(token_text) {
+                if line_doc_comment_style(token_text).is_none() {
                     comments.push(Comment {
-                        style: if code_to_the_left { Trailing } else { Isolated },
+                        style: if code_to_the_left {
+                            CommentStyle::Trailing
+                        } else {
+                            CommentStyle::Isolated
+                        },
                         lines: vec![token_text.to_string()],
                         pos: start_bpos + BytePos(pos as u32),
                     })
index f08011fe4f862d213e22596d302492dc3de20a43..1919b9341aa341bf198f1331be42582dc8ade75b 100644 (file)
@@ -1,11 +1,18 @@
 use super::*;
-use crate::with_default_session_globals;
+use rustc_span::with_default_session_globals;
+
+#[test]
+fn line_doc_comments() {
+    assert!(line_doc_comment_style("///").is_some());
+    assert!(line_doc_comment_style("/// blah").is_some());
+    assert!(line_doc_comment_style("////").is_none());
+}
 
 #[test]
 fn test_block_doc_comment_1() {
     with_default_session_globals(|| {
-        let comment = "/**\n * Test \n **  Test\n *   Test\n*/";
-        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        let comment = "\n * Test \n **  Test\n *   Test\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
         assert_eq!(stripped, " Test \n*  Test\n   Test");
     })
 }
@@ -13,8 +20,8 @@ fn test_block_doc_comment_1() {
 #[test]
 fn test_block_doc_comment_2() {
     with_default_session_globals(|| {
-        let comment = "/**\n * Test\n *  Test\n*/";
-        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        let comment = "\n * Test\n *  Test\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
         assert_eq!(stripped, " Test\n  Test");
     })
 }
@@ -22,37 +29,22 @@ fn test_block_doc_comment_2() {
 #[test]
 fn test_block_doc_comment_3() {
     with_default_session_globals(|| {
-        let comment = "/**\n let a: *i32;\n *a = 5;\n*/";
-        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        let comment = "\n let a: *i32;\n *a = 5;\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
         assert_eq!(stripped, " let a: *i32;\n *a = 5;");
     })
 }
 
-#[test]
-fn test_block_doc_comment_4() {
-    with_default_session_globals(|| {
-        let comment = "/*******************\n test\n *********************/";
-        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
-        assert_eq!(stripped, " test");
-    })
-}
-
 #[test]
 fn test_line_doc_comment() {
     with_default_session_globals(|| {
-        let stripped = strip_doc_comment_decoration(Symbol::intern("/// test"));
-        assert_eq!(stripped, " test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("///! test"));
-        assert_eq!(stripped, " test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
+        let stripped = beautify_doc_string(Symbol::intern(" test"));
         assert_eq!(stripped, " test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
-        assert_eq!(stripped, " test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("///test"));
-        assert_eq!(stripped, "test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("///!test"));
-        assert_eq!(stripped, "test");
-        let stripped = strip_doc_comment_decoration(Symbol::intern("//test"));
+        let stripped = beautify_doc_string(Symbol::intern("! test"));
+        assert_eq!(stripped, "! test");
+        let stripped = beautify_doc_string(Symbol::intern("test"));
         assert_eq!(stripped, "test");
+        let stripped = beautify_doc_string(Symbol::intern("!test"));
+        assert_eq!(stripped, "!test");
     })
 }
index 94d56a3d7b4ae23944a9df7606147616b1752c10..7ebedbcb76a3695d519018e313bd7d1f254d7f16 100644 (file)
@@ -21,7 +21,7 @@ fn test_lev_distance() {
 
 #[test]
 fn test_find_best_match_for_name() {
-    use crate::with_default_session_globals;
+    use rustc_span::with_default_session_globals;
     with_default_session_globals(|| {
         let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
         assert_eq!(
index ccab46703dffe796e65c01f19de9e117f78ffe3a..2c3d1e97df97574bb932723c861c6dd7c603a94e 100644 (file)
@@ -880,7 +880,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
 pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
     match attr.kind {
         AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args),
-        AttrKind::DocComment(_) => {}
+        AttrKind::DocComment(..) => {}
     }
 }
 
index abd5df537db99f14354b4ce904ab43d03cfc3e14..f9e54903a661acc6734bad331f7325360317b907 100644 (file)
@@ -1067,7 +1067,7 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
             .collect();
 
         // Stop if there were any errors when lowering the register classes
-        if operands.len() != asm.operands.len() {
+        if operands.len() != asm.operands.len() || sess.asm_arch.is_none() {
             return hir::ExprKind::Err;
         }
 
index 5414e5842904726f8d5a32746425d56236553789..5186e62fbf9bc34d866b0225f96122a7c5ed8199 100644 (file)
@@ -3,7 +3,6 @@
 use crate::Arena;
 
 use rustc_ast::ast::*;
-use rustc_ast::attr;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
@@ -205,7 +204,7 @@ pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item<'hir>> {
         let attrs = self.lower_attrs(&i.attrs);
 
         if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind {
-            if !macro_rules || attr::contains_name(&i.attrs, sym::macro_export) {
+            if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) {
                 let hir_id = self.lower_node_id(i.id);
                 let body = P(self.lower_mac_args(body));
                 self.exported_macros.push(hir::MacroDef {
index 9df7ad2a9acf47d22e2c72c948a6b0c4ce4254bd..49bbd50db574ecff3cf5fed940eb35063baefb7c 100644 (file)
@@ -37,7 +37,6 @@
 
 use rustc_ast::ast;
 use rustc_ast::ast::*;
-use rustc_ast::attr;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
@@ -981,7 +980,7 @@ fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
                 path: item.path.clone(),
                 args: self.lower_mac_args(&item.args),
             }),
-            AttrKind::DocComment(comment) => AttrKind::DocComment(comment),
+            AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data),
         };
 
         Attribute { kind, id: attr.id, style: attr.style, span: attr.span }
@@ -2215,7 +2214,7 @@ fn lower_generic_param(
                     synthetic: param
                         .attrs
                         .iter()
-                        .filter(|attr| attr.check_name(sym::rustc_synthetic))
+                        .filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic))
                         .map(|_| hir::SyntheticTyParamKind::ImplTrait)
                         .next(),
                 };
@@ -2236,7 +2235,7 @@ fn lower_generic_param(
             hir_id: self.lower_node_id(param.id),
             name,
             span: param.ident.span,
-            pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
+            pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
             attrs: self.lower_attrs(&param.attrs),
             bounds: self.arena.alloc_from_iter(bounds),
             kind,
index daf3e23d6a1234c2196fe76286000f792f60976c..45a026d4b53fb9216a67b0d82a684f4523fe9225 100644 (file)
@@ -8,8 +8,6 @@
 
 use itertools::{Either, Itertools};
 use rustc_ast::ast::*;
-use rustc_ast::attr;
-use rustc_ast::expand::is_proc_macro_attr;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::walk_list;
@@ -776,7 +774,13 @@ fn validate_generic_param_order<'a>(
             span,
             &format!(
                 "reorder the parameters: lifetimes, then types{}",
-                if sess.features_untracked().const_generics { ", then consts" } else { "" },
+                if sess.features_untracked().const_generics
+                    || sess.features_untracked().min_const_generics
+                {
+                    ", then consts"
+                } else {
+                    ""
+                },
             ),
             ordered_params.clone(),
             Applicability::MachineApplicable,
@@ -891,11 +895,11 @@ fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
     }
 
     fn visit_item(&mut self, item: &'a Item) {
-        if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
+        if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
             self.has_proc_macro_decls = true;
         }
 
-        if attr::contains_name(&item.attrs, sym::no_mangle) {
+        if self.session.contains_name(&item.attrs, sym::no_mangle) {
             self.check_nomangle_item_asciionly(item.ident, item.span);
         }
 
@@ -1027,7 +1031,7 @@ fn visit_item(&mut self, item: &'a Item) {
             }
             ItemKind::Mod(Mod { inline, .. }) => {
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !inline && !attr::contains_name(&item.attrs, sym::path) {
+                if !inline && !self.session.contains_name(&item.attrs, sym::path) {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
index 22eaca4f071e21748c62d7d25d80e92883fa28ca..ce39ceff8f3893d81a424879e601b1271e02e76f 100644 (file)
@@ -1,11 +1,11 @@
 use rustc_ast::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
 use rustc_ast::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
-use rustc_ast::attr;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_errors::{struct_span_err, Handler};
+use rustc_errors::struct_span_err;
 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
-use rustc_feature::{Features, GateIssue, UnstableFeatures};
-use rustc_session::parse::{feature_err, feature_err_issue, ParseSess};
+use rustc_feature::{Features, GateIssue};
+use rustc_session::parse::{feature_err, feature_err_issue};
+use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use tracing::debug;
 
 macro_rules! gate_feature_fn {
-    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
-        let (cx, has_feature, span, name, explain) = (&*$cx, $has_feature, $span, $name, $explain);
-        let has_feature: bool = has_feature(&$cx.features);
+    ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
+        let (visitor, has_feature, span, name, explain) =
+            (&*$visitor, $has_feature, $span, $name, $explain);
+        let has_feature: bool = has_feature(visitor.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !span.allows_unstable($name) {
-            feature_err_issue(cx.parse_sess, name, span, GateIssue::Language, explain).emit();
+            feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
+                .emit();
         }
     }};
 }
 
 macro_rules! gate_feature_post {
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
-        gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain)
+    ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
+        gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
     };
 }
 
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
-    PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
+pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
+    PostExpansionVisitor { sess, features }.visit_attribute(attr)
 }
 
 struct PostExpansionVisitor<'a> {
-    parse_sess: &'a ParseSess,
+    sess: &'a Session,
+
+    // `sess` contains a `Features`, but this might not be that one.
     features: &'a Features,
 }
 
@@ -138,6 +142,7 @@ fn check_abi(&self, abi: ast::StrLit) {
                 );
             }
             abi => self
+                .sess
                 .parse_sess
                 .span_diagnostic
                 .delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
@@ -167,7 +172,7 @@ fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
 
         if !discriminant_spans.is_empty() && has_fields {
             let mut err = feature_err(
-                self.parse_sess,
+                &self.sess.parse_sess,
                 sym::arbitrary_enum_discriminant,
                 discriminant_spans.clone(),
                 "custom discriminant values are not allowed in enums with tuple or struct variants",
@@ -240,7 +245,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
             gate_feature_fn!(self, has_feature, attr.span, name, descr);
         }
         // Check unstable flavors of the `#[doc]` attribute.
-        if attr.check_name(sym::doc) {
+        if self.sess.check_name(attr, sym::doc) {
             for nested_meta in attr.meta_item_list().unwrap_or_default() {
                 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                     $(if nested_meta.has_name(sym::$name) {
@@ -266,7 +271,7 @@ fn visit_name(&mut self, sp: Span, name: Symbol) {
             gate_feature_post!(
                 &self,
                 non_ascii_idents,
-                self.parse_sess.source_map().guess_head_span(sp),
+                self.sess.parse_sess.source_map().guess_head_span(sp),
                 "non-ascii idents are not fully supported"
             );
         }
@@ -281,7 +286,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
             }
 
             ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
+                if self.sess.contains_name(&i.attrs[..], sym::plugin_registrar) {
                     gate_feature_post!(
                         &self,
                         plugin_registrar,
@@ -289,7 +294,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
                         "compiler plugins are experimental and possibly buggy"
                     );
                 }
-                if attr::contains_name(&i.attrs[..], sym::start) {
+                if self.sess.contains_name(&i.attrs[..], sym::start) {
                     gate_feature_post!(
                         &self,
                         start,
@@ -299,7 +304,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
                          over time"
                     );
                 }
-                if attr::contains_name(&i.attrs[..], sym::main) {
+                if self.sess.contains_name(&i.attrs[..], sym::main) {
                     gate_feature_post!(
                         &self,
                         main,
@@ -312,7 +317,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
             }
 
             ast::ItemKind::Struct(..) => {
-                for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
+                for attr in self.sess.filter_by_name(&i.attrs[..], sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
                         if item.has_name(sym::simd) {
                             gate_feature_post!(
@@ -391,7 +396,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
         match i.kind {
             ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
-                let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
+                let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
                 let links_to_llvm = match link_name {
                     Some(val) => val.as_str().starts_with("llvm."),
                     _ => false,
@@ -450,7 +455,7 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
             ast::ExprKind::Type(..) => {
                 // To avoid noise about type ascription in common syntax errors, only emit if it
                 // is the *only* error.
-                if self.parse_sess.span_diagnostic.err_count() == 0 {
+                if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
                     gate_feature_post!(
                         &self,
                         type_ascription,
@@ -526,12 +531,13 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
         if let GenericParamKind::Const { .. } = param.kind {
-            gate_feature_post!(
+            gate_feature_fn!(
                 &self,
-                const_generics,
+                |x: &Features| x.const_generics || x.min_const_generics,
                 param.ident.span,
+                sym::min_const_generics,
                 "const generics are unstable"
-            )
+            );
         }
         visit::walk_generic_param(self, param)
     }
@@ -599,16 +605,11 @@ fn visit_vis(&mut self, vis: &'a ast::Visibility) {
     }
 }
 
-pub fn check_crate(
-    krate: &ast::Crate,
-    parse_sess: &ParseSess,
-    features: &Features,
-    unstable: UnstableFeatures,
-) {
-    maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
-    let mut visitor = PostExpansionVisitor { parse_sess, features };
+pub fn check_crate(krate: &ast::Crate, sess: &Session) {
+    maybe_stage_features(sess, krate);
+    let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
 
-    let spans = parse_sess.gated_spans.spans.borrow();
+    let spans = sess.parse_sess.gated_spans.spans.borrow();
     macro_rules! gate_all {
         ($gate:ident, $msg:literal) => {
             for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
@@ -651,18 +652,18 @@ macro_rules! gate_all {
     gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
     // To avoid noise about type ascription in common syntax errors,
     // only emit if it is the *only* error. (Also check it last.)
-    if parse_sess.span_diagnostic.err_count() == 0 {
+    if sess.parse_sess.span_diagnostic.err_count() == 0 {
         gate_all!(type_ascription, "type ascription is experimental");
     }
 
     visit::walk_crate(&mut visitor, krate);
 }
 
-fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
-    if !unstable.is_nightly_build() {
-        for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
+fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+    if !sess.opts.unstable_features.is_nightly_build() {
+        for attr in krate.attrs.iter().filter(|attr| sess.check_name(attr, sym::feature)) {
             struct_span_err!(
-                span_handler,
+                sess.parse_sess.span_diagnostic,
                 attr.span,
                 E0554,
                 "`#![feature]` may not be used on the {} release channel",
index 4b228629ad719e2e2bac4a58687b2a5a00398326..9d9ca78de558890520e6ffd931e22a53fbe8a603 100644 (file)
@@ -8,10 +8,11 @@
 use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_ast::attr;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::util::classify;
+use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
-use rustc_ast::util::{classify, comments};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
@@ -50,17 +51,17 @@ impl PpAnn for NoAnn {}
 
 pub struct Comments<'a> {
     sm: &'a SourceMap,
-    comments: Vec<comments::Comment>,
+    comments: Vec<Comment>,
     current: usize,
 }
 
 impl<'a> Comments<'a> {
     pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
-        let comments = comments::gather_comments(sm, filename, input);
+        let comments = gather_comments(sm, filename, input);
         Comments { sm, comments, current: 0 }
     }
 
-    pub fn next(&self) -> Option<comments::Comment> {
+    pub fn next(&self) -> Option<Comment> {
         self.comments.get(self.current).cloned()
     }
 
@@ -68,9 +69,9 @@ pub fn trailing_comment(
         &mut self,
         span: rustc_span::Span,
         next_pos: Option<BytePos>,
-    ) -> Option<comments::Comment> {
+    ) -> Option<Comment> {
         if let Some(cmnt) = self.next() {
-            if cmnt.style != comments::Trailing {
+            if cmnt.style != CommentStyle::Trailing {
                 return None;
             }
             let span_line = self.sm.lookup_char_pos(span.hi());
@@ -152,8 +153,8 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
 // and also addresses some specific regressions described in #63896 and #73345.
 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
     if let TokenTree::Token(token) = prev {
-        if let token::DocComment(s) = token.kind {
-            return !s.as_str().starts_with("//");
+        if let token::DocComment(comment_kind, ..) = token.kind {
+            return comment_kind != CommentKind::Line;
         }
     }
     match tt {
@@ -194,6 +195,19 @@ fn binop_to_string(op: BinOpToken) -> &'static str {
     }
 }
 
+fn doc_comment_to_string(
+    comment_kind: CommentKind,
+    attr_style: ast::AttrStyle,
+    data: Symbol,
+) -> String {
+    match (comment_kind, attr_style) {
+        (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
+        (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
+        (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
+        (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
+    }
+}
+
 pub fn literal_to_string(lit: token::Lit) -> String {
     let token::Lit { kind, symbol, suffix } = lit;
     let mut out = match kind {
@@ -271,7 +285,9 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>)
         token::Lifetime(s) => s.to_string(),
 
         /* Other */
-        token::DocComment(s) => s.to_string(),
+        token::DocComment(comment_kind, attr_style, data) => {
+            doc_comment_to_string(comment_kind, attr_style, data)
+        }
         token::Eof => "<eof>".to_string(),
         token::Whitespace => " ".to_string(),
         token::Comment => "/* */".to_string(),
@@ -447,9 +463,9 @@ fn maybe_print_comment(&mut self, pos: BytePos) {
         }
     }
 
-    fn print_comment(&mut self, cmnt: &comments::Comment) {
+    fn print_comment(&mut self, cmnt: &Comment) {
         match cmnt.style {
-            comments::Mixed => {
+            CommentStyle::Mixed => {
                 if !self.is_beginning_of_line() {
                     self.zerobreak();
                 }
@@ -468,7 +484,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) {
                 }
                 self.zerobreak()
             }
-            comments::Isolated => {
+            CommentStyle::Isolated => {
                 self.hardbreak_if_not_bol();
                 for line in &cmnt.lines {
                     // Don't print empty lines because they will end up as trailing
@@ -479,7 +495,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) {
                     self.hardbreak();
                 }
             }
-            comments::Trailing => {
+            CommentStyle::Trailing => {
                 if !self.is_beginning_of_line() {
                     self.word(" ");
                 }
@@ -497,7 +513,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) {
                     self.end();
                 }
             }
-            comments::BlankLine => {
+            CommentStyle::BlankLine => {
                 // We need to do at least one, possibly two hardbreaks.
                 let twice = match self.last_token() {
                     pp::Token::String(s) => ";" == s,
@@ -516,7 +532,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) {
         }
     }
 
-    fn next_comment(&mut self) -> Option<comments::Comment> {
+    fn next_comment(&mut self) -> Option<Comment> {
         self.comments().as_mut().and_then(|c| c.next())
     }
 
@@ -599,8 +615,8 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
                 self.print_attr_item(&item, attr.span);
                 self.word("]");
             }
-            ast::AttrKind::DocComment(comment) => {
-                self.word(comment.to_string());
+            ast::AttrKind::DocComment(comment_kind, data) => {
+                self.word(doc_comment_to_string(comment_kind, attr.style, data));
                 self.hardbreak()
             }
         }
index 96377a4ae02faf68c2af06002a1e4344298a982c..fdbd073255e83cf2aaedd300be7e9496677e411b 100644 (file)
@@ -1,9 +1,9 @@
 use super::*;
 
 use rustc_ast::ast;
-use rustc_ast::with_default_session_globals;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::Ident;
+use rustc_span::with_default_session_globals;
 
 fn fun_to_string(
     decl: &ast::FnDecl,
index 983202aafabd58c4d12e8904d11c458e15af1487..552584bb4d0b9dd17920203ade73dbf12776a764 100644 (file)
@@ -1,13 +1,12 @@
 //! Parsing and validation of builtin attributes
 
-use super::{find_by_name, mark_used};
-
 use rustc_ast::ast::{self, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, Handler};
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
 use rustc_session::parse::{feature_err, ParseSess};
+use rustc_session::Session;
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
@@ -86,9 +85,9 @@ pub enum UnwindAttr {
 }
 
 /// Determine what `#[unwind]` attribute is present in `attrs`, if any.
-pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
+pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option<UnwindAttr> {
     attrs.iter().fold(None, |ia, attr| {
-        if attr.check_name(sym::unwind) {
+        if sess.check_name(attr, sym::unwind) {
             if let Some(meta) = attr.meta() {
                 if let MetaItemKind::List(items) = meta.kind {
                     if items.len() == 1 {
@@ -99,19 +98,22 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
                         }
                     }
 
-                    if let Some(d) = diagnostic {
-                        struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
-                            .span_label(attr.span, "invalid argument")
-                            .span_suggestions(
-                                attr.span,
-                                "the allowed arguments are `allowed` and `aborts`",
-                                (vec!["allowed", "aborts"])
-                                    .into_iter()
-                                    .map(|s| format!("#[unwind({})]", s)),
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
-                    };
+                    struct_span_err!(
+                        sess.diagnostic(),
+                        attr.span,
+                        E0633,
+                        "malformed `unwind` attribute input"
+                    )
+                    .span_label(attr.span, "invalid argument")
+                    .span_suggestions(
+                        attr.span,
+                        "the allowed arguments are `allowed` and `aborts`",
+                        (vec!["allowed", "aborts"])
+                            .into_iter()
+                            .map(|s| format!("#[unwind({})]", s)),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
                 }
             }
         }
@@ -161,22 +163,10 @@ pub fn is_stable(&self) -> bool {
     }
 }
 
-/// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
-/// This will not perform any "sanity checks" on the form of the attributes.
-pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
-    attrs.iter().any(|item| {
-        item.check_name(sym::feature)
-            && item
-                .meta_item_list()
-                .map(|list| list.iter().any(|mi| mi.is_word() && mi.has_name(feature_name)))
-                .unwrap_or(false)
-    })
-}
-
 /// Collects stability info from all stability attributes in `attrs`.
 /// Returns `None` if no stability attributes are found.
 pub fn find_stability(
-    sess: &ParseSess,
+    sess: &Session,
     attrs: &[Attribute],
     item_sp: Span,
 ) -> (Option<Stability>, Option<ConstStability>) {
@@ -184,7 +174,7 @@ pub fn find_stability(
 }
 
 fn find_stability_generic<'a, I>(
-    sess: &ParseSess,
+    sess: &Session,
     attrs_iter: I,
     item_sp: Span,
 ) -> (Option<Stability>, Option<ConstStability>)
@@ -197,7 +187,7 @@ fn find_stability_generic<'a, I>(
     let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
     let mut allow_const_fn_ptr = false;
-    let diagnostic = &sess.span_diagnostic;
+    let diagnostic = &sess.parse_sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
         if ![
@@ -214,7 +204,7 @@ fn find_stability_generic<'a, I>(
             continue; // not a stability level
         }
 
-        mark_used(attr);
+        sess.mark_attr_used(attr);
 
         let meta = attr.meta();
 
@@ -230,7 +220,7 @@ fn find_stability_generic<'a, I>(
             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                 if item.is_some() {
                     handle_errors(
-                        sess,
+                        &sess.parse_sess,
                         meta.span,
                         AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
                     );
@@ -249,10 +239,18 @@ fn find_stability_generic<'a, I>(
             match meta_name {
                 sym::rustc_const_unstable | sym::unstable => {
                     if meta_name == sym::unstable && stab.is_some() {
-                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        handle_errors(
+                            &sess.parse_sess,
+                            attr.span,
+                            AttrError::MultipleStabilityLevels,
+                        );
                         break;
                     } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
-                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        handle_errors(
+                            &sess.parse_sess,
+                            attr.span,
+                            AttrError::MultipleStabilityLevels,
+                        );
                         break;
                     }
 
@@ -318,13 +316,13 @@ fn find_stability_generic<'a, I>(
                                 sym::soft => {
                                     if !mi.is_word() {
                                         let msg = "`soft` should not have any arguments";
-                                        sess.span_diagnostic.span_err(mi.span, msg);
+                                        sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
                                     }
                                     is_soft = true;
                                 }
                                 _ => {
                                     handle_errors(
-                                        sess,
+                                        &sess.parse_sess,
                                         meta.span(),
                                         AttrError::UnknownMetaItem(
                                             pprust::path_to_string(&mi.path),
@@ -336,7 +334,7 @@ fn find_stability_generic<'a, I>(
                             }
                         } else {
                             handle_errors(
-                                sess,
+                                &sess.parse_sess,
                                 meta.span(),
                                 AttrError::UnsupportedLiteral("unsupported literal", false),
                             );
@@ -359,7 +357,7 @@ fn find_stability_generic<'a, I>(
                             }
                         }
                         (None, _, _) => {
-                            handle_errors(sess, attr.span, AttrError::MissingFeature);
+                            handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
                             continue;
                         }
                         _ => {
@@ -371,10 +369,18 @@ fn find_stability_generic<'a, I>(
                 }
                 sym::rustc_const_stable | sym::stable => {
                     if meta_name == sym::stable && stab.is_some() {
-                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        handle_errors(
+                            &sess.parse_sess,
+                            attr.span,
+                            AttrError::MultipleStabilityLevels,
+                        );
                         break;
                     } else if meta_name == sym::rustc_const_stable && const_stab.is_some() {
-                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        handle_errors(
+                            &sess.parse_sess,
+                            attr.span,
+                            AttrError::MultipleStabilityLevels,
+                        );
                         break;
                     }
 
@@ -395,7 +401,7 @@ fn find_stability_generic<'a, I>(
                                 }
                                 _ => {
                                     handle_errors(
-                                        sess,
+                                        &sess.parse_sess,
                                         meta.span(),
                                         AttrError::UnknownMetaItem(
                                             pprust::path_to_string(&mi.path),
@@ -407,7 +413,7 @@ fn find_stability_generic<'a, I>(
                             },
                             NestedMetaItem::Literal(lit) => {
                                 handle_errors(
-                                    sess,
+                                    &sess.parse_sess,
                                     lit.span,
                                     AttrError::UnsupportedLiteral("unsupported literal", false),
                                 );
@@ -431,11 +437,11 @@ fn find_stability_generic<'a, I>(
                             }
                         }
                         (None, _) => {
-                            handle_errors(sess, attr.span, AttrError::MissingFeature);
+                            handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
                             continue;
                         }
                         _ => {
-                            handle_errors(sess, attr.span, AttrError::MissingSince);
+                            handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
                             continue;
                         }
                     }
@@ -466,8 +472,8 @@ fn find_stability_generic<'a, I>(
     (stab, const_stab)
 }
 
-pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
-    super::first_attr_value_str_by_name(attrs, sym::crate_name)
+pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
+    sess.first_attr_value_str_by_name(attrs, sym::crate_name)
 }
 
 /// Tests if a cfg-pattern matches the cfg set
@@ -630,16 +636,12 @@ pub struct Deprecation {
 }
 
 /// Finds the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(
-    sess: &ParseSess,
-    attrs: &[Attribute],
-    item_sp: Span,
-) -> Option<Deprecation> {
+pub fn find_deprecation(sess: &Session, attrs: &[Attribute], item_sp: Span) -> Option<Deprecation> {
     find_deprecation_generic(sess, attrs.iter(), item_sp)
 }
 
 fn find_deprecation_generic<'a, I>(
-    sess: &ParseSess,
+    sess: &Session,
     attrs_iter: I,
     item_sp: Span,
 ) -> Option<Deprecation>
@@ -647,10 +649,11 @@ fn find_deprecation_generic<'a, I>(
     I: Iterator<Item = &'a Attribute>,
 {
     let mut depr: Option<Deprecation> = None;
-    let diagnostic = &sess.span_diagnostic;
+    let diagnostic = &sess.parse_sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
-        if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
+        if !(sess.check_name(attr, sym::deprecated) || sess.check_name(attr, sym::rustc_deprecated))
+        {
             continue;
         }
 
@@ -673,7 +676,7 @@ fn find_deprecation_generic<'a, I>(
                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                     if item.is_some() {
                         handle_errors(
-                            sess,
+                            &sess.parse_sess,
                             meta.span,
                             AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
                         );
@@ -685,7 +688,7 @@ fn find_deprecation_generic<'a, I>(
                     } else {
                         if let Some(lit) = meta.name_value_literal() {
                             handle_errors(
-                                sess,
+                                &sess.parse_sess,
                                 lit.span,
                                 AttrError::UnsupportedLiteral(
                                     "literal in `deprecated` \
@@ -710,28 +713,28 @@ fn find_deprecation_generic<'a, I>(
                                     continue 'outer;
                                 }
                             }
-                            sym::note if attr.check_name(sym::deprecated) => {
+                            sym::note if sess.check_name(attr, sym::deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
-                            sym::reason if attr.check_name(sym::rustc_deprecated) => {
+                            sym::reason if sess.check_name(attr, sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
                             }
-                            sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
+                            sym::suggestion if sess.check_name(attr, sym::rustc_deprecated) => {
                                 if !get(mi, &mut suggestion) {
                                     continue 'outer;
                                 }
                             }
                             _ => {
                                 handle_errors(
-                                    sess,
+                                    &sess.parse_sess,
                                     meta.span(),
                                     AttrError::UnknownMetaItem(
                                         pprust::path_to_string(&mi.path),
-                                        if attr.check_name(sym::deprecated) {
+                                        if sess.check_name(attr, sym::deprecated) {
                                             &["since", "note"]
                                         } else {
                                             &["since", "reason", "suggestion"]
@@ -743,7 +746,7 @@ fn find_deprecation_generic<'a, I>(
                         },
                         NestedMetaItem::Literal(lit) => {
                             handle_errors(
-                                sess,
+                                &sess.parse_sess,
                                 lit.span,
                                 AttrError::UnsupportedLiteral(
                                     "item in `deprecated` must be a key/value pair",
@@ -757,13 +760,13 @@ fn find_deprecation_generic<'a, I>(
             }
         }
 
-        if suggestion.is_some() && attr.check_name(sym::deprecated) {
+        if suggestion.is_some() && sess.check_name(attr, sym::deprecated) {
             unreachable!("only allowed on rustc_deprecated")
         }
 
-        if attr.check_name(sym::rustc_deprecated) {
+        if sess.check_name(attr, sym::rustc_deprecated) {
             if since.is_none() {
-                handle_errors(sess, attr.span, AttrError::MissingSince);
+                handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
                 continue;
             }
 
@@ -773,9 +776,9 @@ fn find_deprecation_generic<'a, I>(
             }
         }
 
-        mark_used(&attr);
+        sess.mark_attr_used(&attr);
 
-        let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
+        let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated);
         depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
     }
 
@@ -818,18 +821,18 @@ pub fn is_signed(self) -> bool {
 /// the same discriminant size that the corresponding C enum would or C
 /// structure layout, `packed` to remove padding, and `transparent` to elegate representation
 /// concerns to the only non-ZST field.
-pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
+pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
     use ReprAttr::*;
 
     let mut acc = Vec::new();
-    let diagnostic = &sess.span_diagnostic;
+    let diagnostic = &sess.parse_sess.span_diagnostic;
     if attr.has_name(sym::repr) {
         if let Some(items) = attr.meta_item_list() {
-            mark_used(attr);
+            sess.mark_attr_used(attr);
             for item in items {
                 if !item.is_meta_item() {
                     handle_errors(
-                        sess,
+                        &sess.parse_sess,
                         item.span(),
                         AttrError::UnsupportedLiteral(
                             "meta item in `repr` must be an identifier",
@@ -973,13 +976,14 @@ pub enum TransparencyError {
 }
 
 pub fn find_transparency(
+    sess: &Session,
     attrs: &[Attribute],
     macro_rules: bool,
 ) -> (Transparency, Option<TransparencyError>) {
     let mut transparency = None;
     let mut error = None;
     for attr in attrs {
-        if attr.check_name(sym::rustc_macro_transparency) {
+        if sess.check_name(attr, sym::rustc_macro_transparency) {
             if let Some((_, old_span)) = transparency {
                 error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span));
                 break;
@@ -1004,18 +1008,20 @@ pub fn find_transparency(
 }
 
 pub fn allow_internal_unstable<'a>(
+    sess: &'a Session,
     attrs: &[Attribute],
-    diag: &'a rustc_errors::Handler,
 ) -> Option<impl Iterator<Item = Symbol> + 'a> {
-    let attr = find_by_name(attrs, sym::allow_internal_unstable)?;
+    let attr = sess.find_by_name(attrs, sym::allow_internal_unstable)?;
     let list = attr.meta_item_list().or_else(|| {
-        diag.span_err(attr.span, "allow_internal_unstable expects list of feature names");
+        sess.diagnostic()
+            .span_err(attr.span, "allow_internal_unstable expects list of feature names");
         None
     })?;
     Some(list.into_iter().filter_map(move |it| {
         let name = it.ident().map(|ident| ident.name);
         if name.is_none() {
-            diag.span_err(it.span(), "`allow_internal_unstable` expects feature names");
+            sess.diagnostic()
+                .span_err(it.span(), "`allow_internal_unstable` expects feature names");
         }
         name
     }))
index 3c09b26af42f256b510d3ec35ee8ab8ce79ffa55..0247ca329915899d82a87ca65d4c72878961194b 100644 (file)
@@ -19,7 +19,7 @@ pub fn expand_cfg(
 
     match parse_cfg(cx, sp, tts) {
         Ok(cfg) => {
-            let matches_cfg = attr::cfg_matches(&cfg, cx.parse_sess, cx.ecfg.features);
+            let matches_cfg = attr::cfg_matches(&cfg, &cx.sess.parse_sess, cx.ecfg.features);
             MacEager::expr(cx.expr_bool(sp, matches_cfg))
         }
         Err(mut err) => {
index 3607a4d0d15b6238d09033a5fbec15b66671e43d..7a91dde5a9d8aaacd71233e1293be6bce6006af8 100644 (file)
@@ -37,7 +37,12 @@ fn expand(
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let template = AttributeTemplate { list: Some("path"), ..Default::default() };
         let attr = &ecx.attribute(meta_item.clone());
-        validate_attr::check_builtin_attribute(ecx.parse_sess, attr, sym::cfg_accessible, template);
+        validate_attr::check_builtin_attribute(
+            &ecx.sess.parse_sess,
+            attr,
+            sym::cfg_accessible,
+            template,
+        );
 
         let path = match validate_input(ecx, meta_item) {
             Some(path) => path,
index 8ca1be1efb635f7685382e853d35e7e57e34d55f..2611855a3a1b5a6709de8b446a64d7c385f41c9c 100644 (file)
@@ -72,7 +72,7 @@ fn default_substructure(
         },
         StaticEnum(..) => {
             struct_span_err!(
-                cx.parse_sess.span_diagnostic,
+                &cx.sess.parse_sess.span_diagnostic,
                 trait_span,
                 E0665,
                 "`Default` cannot be derived for enums, only structs"
index c43d1cf1888c494a012873b554e5c6b1a004a9c4..908aabe902434dd402d2c9fcdadd9d127d6b2f1c 100644 (file)
@@ -392,7 +392,7 @@ pub fn expand_ext(
         match *item {
             Annotatable::Item(ref item) => {
                 let is_packed = item.attrs.iter().any(|attr| {
-                    for r in attr::find_repr_attrs(&cx.parse_sess, attr) {
+                    for r in attr::find_repr_attrs(&cx.sess, attr) {
                         if let attr::ReprPacked(_) = r {
                             return true;
                         }
@@ -677,7 +677,7 @@ fn create_derived_impl(
 
         let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
         // Just mark it now since we know that it'll end up used downstream
-        attr::mark_used(&attr);
+        cx.sess.mark_attr_used(&attr);
         let opt_trait_ref = Some(trait_ref);
         let unused_qual = {
             let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
index 6c3a1ce0958ec5d1f90a90f3cdf34ef1f9462a74..b6f733ee93db08666d1e18b08ecb7711f24a4b59 100644 (file)
@@ -23,7 +23,7 @@ pub fn expand_option_env<'cx>(
 
     let sp = cx.with_def_site_ctxt(sp);
     let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
-    cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
+    cx.sess.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
     let e = match value {
         None => {
             let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
@@ -81,7 +81,7 @@ pub fn expand_env<'cx>(
 
     let sp = cx.with_def_site_ctxt(sp);
     let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
-    cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+    cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
     let e = match value {
         None => {
             cx.span_err(sp, &msg.as_str());
index 89446a1aa96f9a79346ef5421910b41154890f61..ccff8aa90a8ad1a47f1b46590bda60559257c606 100644 (file)
@@ -19,7 +19,7 @@ pub fn expand(
     check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
 
     let not_static = |item: Annotatable| {
-        ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
+        ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
         vec![item]
     };
     let item = match item {
index 0f4efc153b941712f2db69dd217e1f2f6248ca02..77fd71d58ef6b3227ca547d1bd9f39805ad0d826 100644 (file)
@@ -110,7 +110,7 @@ fn parse_inline_asm<'a>(
                     // If we already have a string with instructions,
                     // ending up in Asm state again is an error.
                     return Err(struct_span_err!(
-                        cx.parse_sess.span_diagnostic,
+                        cx.sess.parse_sess.span_diagnostic,
                         sp,
                         E0660,
                         "malformed inline assembly"
@@ -171,7 +171,7 @@ fn parse_inline_asm<'a>(
                         Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
                         _ => {
                             struct_span_err!(
-                                cx.parse_sess.span_diagnostic,
+                                cx.sess.parse_sess.span_diagnostic,
                                 span,
                                 E0661,
                                 "output operand constraint lacks '=' or '+'"
@@ -201,7 +201,7 @@ fn parse_inline_asm<'a>(
 
                     if constraint.as_str().starts_with('=') {
                         struct_span_err!(
-                            cx.parse_sess.span_diagnostic,
+                            cx.sess.parse_sess.span_diagnostic,
                             p.prev_token.span,
                             E0662,
                             "input operand constraint contains '='"
@@ -209,7 +209,7 @@ fn parse_inline_asm<'a>(
                         .emit();
                     } else if constraint.as_str().starts_with('+') {
                         struct_span_err!(
-                            cx.parse_sess.span_diagnostic,
+                            cx.sess.parse_sess.span_diagnostic,
                             p.prev_token.span,
                             E0663,
                             "input operand constraint contains '+'"
@@ -236,7 +236,7 @@ fn parse_inline_asm<'a>(
                         cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
                     } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
                         struct_span_err!(
-                            cx.parse_sess.span_diagnostic,
+                            cx.sess.parse_sess.span_diagnostic,
                             p.prev_token.span,
                             E0664,
                             "clobber should not be surrounded by braces"
index 763bdca35ebe61c166aaf0dc70cc0a572c0b76fa..4f2f066e652f1533b5e1fc4782f4802d19206fac 100644 (file)
@@ -2,13 +2,12 @@
 
 use rustc_ast::ast::{self, NodeId};
 use rustc_ast::attr;
-use rustc_ast::expand::is_proc_macro_attr;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
 use rustc_span::hygiene::AstPass;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -42,6 +41,7 @@ enum ProcMacro {
 }
 
 struct CollectProcMacros<'a> {
+    sess: &'a Session,
     macros: Vec<ProcMacro>,
     in_root: bool,
     handler: &'a rustc_errors::Handler,
@@ -51,7 +51,7 @@ struct CollectProcMacros<'a> {
 }
 
 pub fn inject(
-    sess: &ParseSess,
+    sess: &Session,
     resolver: &mut dyn ResolverExpand,
     mut krate: ast::Crate,
     is_proc_macro_crate: bool,
@@ -64,6 +64,7 @@ pub fn inject(
     let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
     let mut collect = CollectProcMacros {
+        sess,
         macros: Vec::new(),
         in_root: true,
         handler,
@@ -244,7 +245,7 @@ fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
 impl<'a> Visitor<'a> for CollectProcMacros<'a> {
     fn visit_item(&mut self, item: &'a ast::Item) {
         if let ast::ItemKind::MacroDef(..) = item.kind {
-            if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
+            if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) {
                 let msg =
                     "cannot export macro_rules! macros from a `proc-macro` crate type currently";
                 self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
@@ -263,7 +264,7 @@ fn visit_item(&mut self, item: &'a ast::Item) {
         let mut found_attr: Option<&'a ast::Attribute> = None;
 
         for attr in &item.attrs {
-            if is_proc_macro_attr(&attr) {
+            if self.sess.is_proc_macro_attr(&attr) {
                 if let Some(prev_attr) = found_attr {
                     let prev_item = prev_attr.get_normal_item();
                     let item = attr.get_normal_item();
@@ -331,11 +332,11 @@ fn visit_item(&mut self, item: &'a ast::Item) {
             return;
         }
 
-        if attr.check_name(sym::proc_macro_derive) {
+        if self.sess.check_name(attr, sym::proc_macro_derive) {
             self.collect_custom_derive(item, attr);
-        } else if attr.check_name(sym::proc_macro_attribute) {
+        } else if self.sess.check_name(attr, sym::proc_macro_attribute) {
             self.collect_attr_proc_macro(item);
-        } else if attr.check_name(sym::proc_macro) {
+        } else if self.sess.check_name(attr, sym::proc_macro) {
             self.collect_bang_proc_macro(item);
         };
 
index 671ff8ce54f0e9fda51711ea693f4b27cefbadc3..52759fede75cefbe33b7617b99ef61333a75e023 100644 (file)
@@ -1,8 +1,8 @@
+use rustc_ast::ast;
 use rustc_ast::ptr::P;
-use rustc_ast::{ast, attr};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::ExpansionConfig;
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::AstPass;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 pub fn inject(
     mut krate: ast::Crate,
     resolver: &mut dyn ResolverExpand,
-    sess: &ParseSess,
+    sess: &Session,
     alt_std_name: Option<Symbol>,
 ) -> (ast::Crate, Option<Symbol>) {
-    let rust_2018 = sess.edition >= Edition::Edition2018;
+    let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018;
 
     // the first name in this list is the crate name of the crate with the prelude
-    let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
+    let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) {
         return (krate, None);
-    } else if attr::contains_name(&krate.attrs, sym::no_std) {
-        if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
+    } else if sess.contains_name(&krate.attrs, sym::no_std) {
+        if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
             &[sym::core]
         } else {
             &[sym::core, sym::compiler_builtins]
index 29095034ba9f109205a7198f4f80986b11b4ecbe..16a95288ee83656cca01fcd75cc2adc0830d217b 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_ast::attr;
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::*;
+use rustc_session::Session;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -87,7 +88,7 @@ pub fn expand_test_or_bench(
     };
 
     if let ast::ItemKind::MacCall(_) = item.kind {
-        cx.parse_sess.span_diagnostic.span_warn(
+        cx.sess.parse_sess.span_diagnostic.span_warn(
             item.span,
             "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.",
         );
@@ -232,9 +233,15 @@ pub fn expand_test_or_bench(
                                         ),
                                     ),
                                     // ignore: true | false
-                                    field("ignore", cx.expr_bool(sp, should_ignore(&item))),
+                                    field(
+                                        "ignore",
+                                        cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
+                                    ),
                                     // allow_fail: true | false
-                                    field("allow_fail", cx.expr_bool(sp, should_fail(&item))),
+                                    field(
+                                        "allow_fail",
+                                        cx.expr_bool(sp, should_fail(&cx.sess, &item)),
+                                    ),
                                     // should_panic: ...
                                     field(
                                         "should_panic",
@@ -318,18 +325,18 @@ enum ShouldPanic {
     Yes(Option<Symbol>),
 }
 
-fn should_ignore(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, sym::ignore)
+fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
+    sess.contains_name(&i.attrs, sym::ignore)
 }
 
-fn should_fail(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, sym::allow_fail)
+fn should_fail(sess: &Session, i: &ast::Item) -> bool {
+    sess.contains_name(&i.attrs, sym::allow_fail)
 }
 
 fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
-    match attr::find_by_name(&i.attrs, sym::should_panic) {
+    match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
         Some(attr) => {
-            let sd = &cx.parse_sess.span_diagnostic;
+            let sd = &cx.sess.parse_sess.span_diagnostic;
 
             match attr.meta_item_list() {
                 // Handle #[should_panic(expected = "foo")]
@@ -393,8 +400,8 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
 }
 
 fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
-    let sd = &cx.parse_sess.span_diagnostic;
+    let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
+    let sd = &cx.sess.parse_sess.span_diagnostic;
     if let ast::ItemKind::Fn(_, ref sig, ref generics, _) = i.kind {
         if let ast::Unsafe::Yes(span) = sig.header.unsafety {
             sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
@@ -453,7 +460,7 @@ fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     };
 
     if !has_sig {
-        cx.parse_sess.span_diagnostic.span_err(
+        cx.sess.parse_sess.span_diagnostic.span_err(
             i.span,
             "functions used as benches must have \
             signature `fn(&mut Bencher) -> impl Termination`",
index 98c5c6936d779d07199d701029e647d529e8700f..b21a7c1e4d572f3314035cc0c029a688e410d2a1 100644 (file)
@@ -3,13 +3,13 @@
 use log::debug;
 use rustc_ast::ast;
 use rustc_ast::attr;
-use rustc_ast::entry::{self, EntryPointType};
+use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -35,41 +35,35 @@ struct TestCtxt<'a> {
 
 // Traverse the crate, collecting all the test functions, eliding any
 // existing main functions, and synthesizing a main test harness
-pub fn inject(
-    sess: &ParseSess,
-    resolver: &mut dyn ResolverExpand,
-    should_test: bool,
-    krate: &mut ast::Crate,
-    span_diagnostic: &rustc_errors::Handler,
-    features: &Features,
-    panic_strategy: PanicStrategy,
-    platform_panic_strategy: PanicStrategy,
-    enable_panic_abort_tests: bool,
-) {
+pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
+    let span_diagnostic = sess.diagnostic();
+    let panic_strategy = sess.panic_strategy();
+    let platform_panic_strategy = sess.target.target.options.panic_strategy;
+
     // Check for #![reexport_test_harness_main = "some_name"] which gives the
     // main test function the name `some_name` without hygiene. This needs to be
     // unconditional, so that the attribute is still marked as used in
     // non-test builds.
     let reexport_test_harness_main =
-        attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
+        sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
 
     // Do this here so that the test_runner crate attribute gets marked as used
     // even in non-test builds
-    let test_runner = get_test_runner(span_diagnostic, &krate);
+    let test_runner = get_test_runner(sess, span_diagnostic, &krate);
 
-    if should_test {
-        let panic_strategy = match (panic_strategy, enable_panic_abort_tests) {
+    if sess.opts.test {
+        let panic_strategy = match (panic_strategy, sess.opts.debugging_opts.panic_abort_tests) {
             (PanicStrategy::Abort, true) => PanicStrategy::Abort,
-            (PanicStrategy::Abort, false) if panic_strategy == platform_panic_strategy => {
-                // Silently allow compiling with panic=abort on these platforms,
-                // but with old behavior (abort if a test fails).
-                PanicStrategy::Unwind
-            }
             (PanicStrategy::Abort, false) => {
-                span_diagnostic.err(
-                    "building tests with panic=abort is not supported \
-                                     without `-Zpanic_abort_tests`",
-                );
+                if panic_strategy == platform_panic_strategy {
+                    // Silently allow compiling with panic=abort on these platforms,
+                    // but with old behavior (abort if a test fails).
+                } else {
+                    span_diagnostic.err(
+                        "building tests with panic=abort is not supported \
+                                         without `-Zpanic_abort_tests`",
+                    );
+                }
                 PanicStrategy::Unwind
             }
             (PanicStrategy::Unwind, _) => PanicStrategy::Unwind,
@@ -79,7 +73,7 @@ pub fn inject(
             resolver,
             reexport_test_harness_main,
             krate,
-            features,
+            &sess.features_untracked(),
             panic_strategy,
             test_runner,
         )
@@ -101,7 +95,7 @@ fn visit_crate(&mut self, c: &mut ast::Crate) {
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         let mut item = i.into_inner();
-        if is_test_case(&item) {
+        if is_test_case(&self.cx.ext_cx.sess, &item) {
             debug!("this is a test item");
 
             let test = Test { span: item.span, ident: item.ident };
@@ -143,15 +137,39 @@ fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
     }
 }
 
+// Beware, this is duplicated in librustc_passes/entry.rs (with
+// `rustc_hir::Item`), so make sure to keep them in sync.
+fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType {
+    match item.kind {
+        ast::ItemKind::Fn(..) => {
+            if sess.contains_name(&item.attrs, sym::start) {
+                EntryPointType::Start
+            } else if sess.contains_name(&item.attrs, sym::main) {
+                EntryPointType::MainAttr
+            } else if item.ident.name == sym::main {
+                if depth == 1 {
+                    // This is a top-level function so can be 'main'
+                    EntryPointType::MainNamed
+                } else {
+                    EntryPointType::OtherMain
+                }
+            } else {
+                EntryPointType::None
+            }
+        }
+        _ => EntryPointType::None,
+    }
+}
 /// A folder used to remove any entry points (like fn main) because the harness
 /// generator will provide its own
-struct EntryPointCleaner {
+struct EntryPointCleaner<'a> {
     // Current depth in the ast
+    sess: &'a Session,
     depth: usize,
     def_site: Span,
 }
 
-impl MutVisitor for EntryPointCleaner {
+impl<'a> MutVisitor for EntryPointCleaner<'a> {
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         self.depth += 1;
         let item = noop_flat_map_item(i, self).expect_one("noop did something");
@@ -160,7 +178,7 @@ impl MutVisitor for EntryPointCleaner {
         // Remove any #[main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
-        let item = match entry::entry_point_type(&item, self.depth) {
+        let item = match entry_point_type(self.sess, &item, self.depth) {
             EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item
                 .map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
                     let allow_ident = Ident::new(sym::allow, self.def_site);
@@ -170,7 +188,10 @@ impl MutVisitor for EntryPointCleaner {
                     let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item);
                     let attrs = attrs
                         .into_iter()
-                        .filter(|attr| !attr.check_name(sym::main) && !attr.check_name(sym::start))
+                        .filter(|attr| {
+                            !self.sess.check_name(attr, sym::main)
+                                && !self.sess.check_name(attr, sym::start)
+                        })
                         .chain(iter::once(allow_dead_code))
                         .collect();
 
@@ -189,7 +210,7 @@ fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
 
 /// Crawl over the crate, inserting test reexports and the test main function
 fn generate_test_harness(
-    sess: &ParseSess,
+    sess: &Session,
     resolver: &mut dyn ResolverExpand,
     reexport_test_harness_main: Option<Symbol>,
     krate: &mut ast::Crate,
@@ -211,7 +232,7 @@ fn generate_test_harness(
     let def_site = DUMMY_SP.with_def_site_ctxt(expn_id);
 
     // Remove the entry points
-    let mut cleaner = EntryPointCleaner { depth: 0, def_site };
+    let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site };
     cleaner.visit_crate(krate);
 
     let cx = TestCtxt {
@@ -339,12 +360,16 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
     )
 }
 
-fn is_test_case(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, sym::rustc_test_marker)
+fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
+    sess.contains_name(&i.attrs, sym::rustc_test_marker)
 }
 
-fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
-    let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
+fn get_test_runner(
+    sess: &Session,
+    sd: &rustc_errors::Handler,
+    krate: &ast::Crate,
+) -> Option<ast::Path> {
+    let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?;
     let meta_list = test_attr.meta_item_list()?;
     let span = test_attr.span;
     match &*meta_list {
index b486eadd1a8bee4fcfff332e61255dfb3777c6c8..3ee6cd739644061fa9517f5f191611f20aa4c59a 100644 (file)
@@ -8,5 +8,5 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na
     // All the built-in macro attributes are "words" at the moment.
     let template = AttributeTemplate { word: true, ..Default::default() };
     let attr = ecx.attribute(meta_item.clone());
-    validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template);
+    validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template);
 }
index 1288870f55f1f40ccb3b7dd24a23581e6723fa84..acfb294f7c12b220a5f4c2e316d6dc13f5839bd0 100644 (file)
@@ -253,7 +253,7 @@ impl CodegenCx<'ll, 'tcx> {
             debug!("get_static: sym={} attrs={:?}", sym, attrs);
 
             for attr in attrs {
-                if attr.check_name(sym::thread_local) {
+                if self.tcx.sess.check_name(attr, sym::thread_local) {
                     llvm::set_thread_local_mode(g, self.tls_model);
                 }
             }
index 4d9747a43f2e2b64e3c9681c50414a1490faf953..9d2383abeed223264490f9680b079a6b579da855 100644 (file)
@@ -92,7 +92,7 @@ fn new() -> Self {
     fn write_coverage_mappings(
         &mut self,
         expressions: Vec<CounterExpression>,
-        counter_regions: impl Iterator<Item = (Counter, &'a Region)>,
+        counter_regions: impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>,
         coverage_mappings_buffer: &RustString,
     ) {
         let mut counter_regions = counter_regions.collect::<Vec<_>>();
@@ -102,7 +102,7 @@ fn write_coverage_mappings(
 
         let mut virtual_file_mapping = Vec::new();
         let mut mapping_regions = Vec::new();
-        let mut current_file_path = None;
+        let mut current_file_name = None;
         let mut current_file_id = 0;
 
         // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted
@@ -112,22 +112,22 @@ fn write_coverage_mappings(
         // `filenames` array.
         counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
         for (counter, region) in counter_regions {
-            let (file_path, start_line, start_col, end_line, end_col) = region.file_start_and_end();
-            let same_file = current_file_path.as_ref().map_or(false, |p| p == file_path);
+            let Region { file_name, start_line, start_col, end_line, end_col } = *region;
+            let same_file = current_file_name.as_ref().map_or(false, |p| p == file_name);
             if !same_file {
-                if current_file_path.is_some() {
+                if current_file_name.is_some() {
                     current_file_id += 1;
                 }
-                current_file_path = Some(file_path.clone());
-                let filename = CString::new(file_path.to_string_lossy().to_string())
-                    .expect("null error converting filename to C string");
-                debug!("  file_id: {} = '{:?}'", current_file_id, filename);
-                let filenames_index = match self.filename_to_index.get(&filename) {
+                current_file_name = Some(file_name.to_string());
+                let c_filename =
+                    CString::new(file_name).expect("null error converting filename to C string");
+                debug!("  file_id: {} = '{:?}'", current_file_id, c_filename);
+                let filenames_index = match self.filename_to_index.get(&c_filename) {
                     Some(index) => *index,
                     None => {
                         let index = self.filenames.len() as u32;
-                        self.filenames.push(filename.clone());
-                        self.filename_to_index.insert(filename.clone(), index);
+                        self.filenames.push(c_filename.clone());
+                        self.filename_to_index.insert(c_filename.clone(), index);
                         index
                     }
                 };
index 9d2090eae8f19669429e42c172942afa0d901973..7b864e499d1de03391757bf7001c4e6193e2e824 100644 (file)
@@ -6,7 +6,7 @@
 use libc::c_uint;
 use llvm::coverageinfo::CounterMappingRegion;
 use log::debug;
-use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage};
+use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
 use rustc_codegen_ssa::traits::{
     BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
 };
@@ -49,19 +49,18 @@ fn add_counter_region(
         instance: Instance<'tcx>,
         function_source_hash: u64,
         id: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         debug!(
             "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={}, \
-             byte range {}..{}",
-            instance, function_source_hash, id, start_byte_pos, end_byte_pos,
+             at {:?}",
+            instance, function_source_hash, id, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_counter(function_source_hash, id, start_byte_pos, end_byte_pos);
+            .add_counter(function_source_hash, id, region);
     }
 
     fn add_counter_expression_region(
@@ -71,43 +70,30 @@ fn add_counter_expression_region(
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         debug!(
             "adding counter expression to coverage_regions: instance={:?}, id={}, {} {:?} {}, \
-             byte range {}..{}",
-            instance, id_descending_from_max, lhs, op, rhs, start_byte_pos, end_byte_pos,
+             at {:?}",
+            instance, id_descending_from_max, lhs, op, rhs, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_counter_expression(
-                id_descending_from_max,
-                lhs,
-                op,
-                rhs,
-                start_byte_pos,
-                end_byte_pos,
-            );
+            .add_counter_expression(id_descending_from_max, lhs, op, rhs, region);
     }
 
-    fn add_unreachable_region(
-        &mut self,
-        instance: Instance<'tcx>,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    ) {
+    fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>) {
         debug!(
-            "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}",
-            instance, start_byte_pos, end_byte_pos,
+            "adding unreachable code to coverage_regions: instance={:?}, at {:?}",
+            instance, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_unreachable_region(start_byte_pos, end_byte_pos);
+            .add_unreachable_region(region);
     }
 }
 
index 64d4076cbf0dbd37738d1510b230b4db56990f92..29edd66049cdcf1acebfa5fa50da949dabdab749 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_middle::bug;
 use rustc_session::config::DebugInfo;
 
-use rustc_ast::attr;
 use rustc_span::symbol::sym;
 
 /// Inserts a side-effect free instruction sequence that makes sure that the
@@ -61,8 +60,10 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) -
 }
 
 pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
-    let omit_gdb_pretty_printer_section =
-        attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+    let omit_gdb_pretty_printer_section = cx
+        .tcx
+        .sess
+        .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
index 6ae7c7efaee62b4933c33d8d578493e348a9fa55..9d6b15ec4af8cc34f0e4a727ccdef0bc9bdf8729 100644 (file)
@@ -960,7 +960,7 @@ fn pointer_type_metadata(
 fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
     debug!("param_type_metadata: {:?}", t);
     let name = format!("{:?}", t);
-    return unsafe {
+    unsafe {
         llvm::LLVMRustDIBuilderCreateBasicType(
             DIB(cx),
             name.as_ptr().cast(),
@@ -968,7 +968,7 @@ fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
             Size::ZERO.bits(),
             DW_ATE_unsigned,
         )
-    };
+    }
 }
 
 pub fn compile_unit_metadata(
index e3a308181b684f0ce0ae1cea98bfb03eced26bcb..dfd5104a31f6d0ae735aba57aa8c84b476f0b85b 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::coverageinfo::ExprKind;
+use rustc_codegen_ssa::coverageinfo;
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -93,64 +93,64 @@ fn is_codegen_intrinsic(
         let mut is_codegen_intrinsic = true;
         // Set `is_codegen_intrinsic` to `false` to bypass `codegen_intrinsic_call()`.
 
-        if self.tcx.sess.opts.debugging_opts.instrument_coverage {
-            // If the intrinsic is from the local MIR, add the coverage information to the Codegen
-            // context, to be encoded into the local crate's coverage map.
-            if caller_instance.def_id().is_local() {
-                // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
-                // external crate dependencies, where:
-                //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
-                //   2. Only binary is compiled with `-Zinstrument-coverage`
-                //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
-                match intrinsic {
-                    sym::count_code_region => {
-                        use coverage::count_code_region_args::*;
-                        self.add_counter_region(
-                            caller_instance,
-                            op_to_u64(&args[FUNCTION_SOURCE_HASH]),
-                            op_to_u32(&args[COUNTER_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_counter_add | sym::coverage_counter_subtract => {
-                        use coverage::coverage_counter_expression_args::*;
-                        self.add_counter_expression_region(
-                            caller_instance,
-                            op_to_u32(&args[EXPRESSION_ID]),
-                            op_to_u32(&args[LEFT_ID]),
-                            if intrinsic == sym::coverage_counter_add {
-                                ExprKind::Add
-                            } else {
-                                ExprKind::Subtract
-                            },
-                            op_to_u32(&args[RIGHT_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_unreachable => {
-                        use coverage::coverage_unreachable_args::*;
-                        self.add_unreachable_region(
-                            caller_instance,
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    _ => {}
-                }
+        // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
+        // external crate dependencies, where:
+        //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
+        //   2. Only binary is compiled with `-Zinstrument-coverage`
+        //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
+        match intrinsic {
+            sym::count_code_region => {
+                use coverage::count_code_region_args::*;
+                self.add_counter_region(
+                    caller_instance,
+                    op_to_u64(&args[FUNCTION_SOURCE_HASH]),
+                    op_to_u32(&args[COUNTER_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
-
-            // Only the `count_code_region` coverage intrinsic is translated into an actual LLVM
-            // intrinsic call (local or not); otherwise, set `is_codegen_intrinsic` to `false`.
-            match intrinsic {
-                sym::coverage_counter_add
-                | sym::coverage_counter_subtract
-                | sym::coverage_unreachable => {
-                    is_codegen_intrinsic = false;
-                }
-                _ => {}
+            sym::coverage_counter_add | sym::coverage_counter_subtract => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_counter_expression_args::*;
+                self.add_counter_expression_region(
+                    caller_instance,
+                    op_to_u32(&args[EXPRESSION_ID]),
+                    op_to_u32(&args[LEFT_ID]),
+                    if intrinsic == sym::coverage_counter_add {
+                        coverageinfo::ExprKind::Add
+                    } else {
+                        coverageinfo::ExprKind::Subtract
+                    },
+                    op_to_u32(&args[RIGHT_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
+            sym::coverage_unreachable => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_unreachable_args::*;
+                self.add_unreachable_region(
+                    caller_instance,
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
+            }
+            _ => {}
         }
         is_codegen_intrinsic
     }
@@ -215,9 +215,6 @@ fn codegen_intrinsic_call(
                 self.call(llfn, &[], None)
             }
             sym::count_code_region => {
-                // FIXME(richkadel): The current implementation assumes the MIR for the given
-                // caller_instance represents a single function. Validate and/or correct if inlining
-                // and/or monomorphization invalidates these assumptions.
                 let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
                 let mangled_fn = tcx.symbol_name(caller_instance);
                 let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
@@ -2243,6 +2240,10 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> {
     }
 }
 
+fn op_to_str_slice<'tcx>(op: &Operand<'tcx>) -> &'tcx str {
+    Operand::value_from_const(op).try_to_str_slice().expect("Value is &str")
+}
+
 fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 {
     Operand::scalar_from_const(op).to_u32().expect("Scalar is u32")
 }
index b0fae566a5aef39b1b77c167951fccd877db58f0..7d69bb983dd744c2f5a9bf51226c98076930866f 100644 (file)
@@ -9,7 +9,6 @@
 
 use crate::traits::*;
 use jobserver::{Acquired, Client};
-use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::profiling::TimingGuard;
@@ -416,11 +415,12 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
 
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
-    let no_builtins = attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
+    let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
     let is_compiler_builtins =
-        attr::contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
-    let subsystem =
-        attr::first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem);
+        tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
+    let subsystem = tcx
+        .sess
+        .first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem);
     let windows_subsystem = subsystem.map(|subsystem| {
         if subsystem != sym::windows && subsystem != sym::console {
             tcx.sess.fatal(&format!(
@@ -490,7 +490,7 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
     let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
 
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
-        let path = module.object.as_ref().map(|path| path.clone());
+        let path = module.object.as_ref().cloned();
 
         if let Some((id, product)) =
             copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, &path)
index 72138065a90ba965d1eb64419603216d02125fc0..7f6841f9daa603f2b70c4f8ef8a1ef5210ce88a4 100644 (file)
@@ -3,12 +3,8 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::{Pos, SourceMap};
-use rustc_span::{BytePos, FileName, Loc, RealFileName};
 
-use std::cmp::{Ord, Ordering};
-use std::fmt;
-use std::path::PathBuf;
+use std::cmp::Ord;
 
 rustc_index::newtype_index! {
     pub struct ExpressionOperandId {
@@ -38,127 +34,35 @@ pub struct MappedExpressionIndex {
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct Region {
-    start: Loc,
-    end: Loc,
-}
-
-impl Ord for Region {
-    fn cmp(&self, other: &Self) -> Ordering {
-        (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col)
-            .cmp(&(
-                &other.start.file.name,
-                &other.start.line,
-                &other.start.col,
-                &other.end.line,
-                &other.end.col,
-            ))
-    }
-}
-
-impl PartialOrd for Region {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl PartialEq for Region {
-    fn eq(&self, other: &Self) -> bool {
-        self.start.file.name == other.start.file.name
-            && self.start.line == other.start.line
-            && self.start.col == other.start.col
-            && self.end.line == other.end.line
-            && self.end.col == other.end.col
-    }
-}
-
-impl Eq for Region {}
-
-impl fmt::Display for Region {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end();
-        write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col)
-    }
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Region<'tcx> {
+    pub file_name: &'tcx str,
+    pub start_line: u32,
+    pub start_col: u32,
+    pub end_line: u32,
+    pub end_col: u32,
 }
 
-impl Region {
-    pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self {
-        let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos));
-        let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos));
-        assert_eq!(
-            start.file.name, end.file.name,
-            "Region start ({} -> {:?}) and end ({} -> {:?}) don't come from the same source file!",
-            start_byte_pos, start, end_byte_pos, end
-        );
-        Self { start, end }
-    }
-
-    pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) {
-        let start = &self.start;
-        let end = &self.end;
-        match &start.file.name {
-            FileName::Real(RealFileName::Named(path)) => (
-                path,
-                start.line as u32,
-                start.col.to_u32() + 1,
-                end.line as u32,
-                end.col.to_u32() + 1,
-            ),
-            _ => {
-                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)
-            }
-        }
+impl<'tcx> Region<'tcx> {
+    pub fn new(
+        file_name: &'tcx str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self { file_name, start_line, start_col, end_line, end_col }
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct ExpressionRegion {
+pub struct ExpressionRegion<'tcx> {
     lhs: ExpressionOperandId,
     op: ExprKind,
     rhs: ExpressionOperandId,
-    region: Region,
+    region: Region<'tcx>,
 }
 
-// FIXME(richkadel): There seems to be a problem computing the file location in
-// some cases. I need to investigate this more. When I generate and show coverage
-// for the example binary in the crates.io crate `json5format`, I had a couple of
-// notable problems:
-//
-//   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in
-//      various comments (not corresponding to rustdoc code), indicating a possible
-//      problem with the byte_pos-to-source-map implementation.
-//
-//   2. And (perhaps not related) when I build the aforementioned example binary with:
-//      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`
-//      and then run that binary with
-//      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \
-//      some.json5` for some reason the binary generates *TWO* `.profraw` files. One
-//      named `default.profraw` and the other named `formatjson5.profraw` (the expected
-//      name, in this case).
-//
-//   3. I think that if I eliminate regions within a function, their region_ids,
-//      referenced in expressions, will be wrong? I think the ids are implied by their
-//      array position in the final coverage map output (IIRC).
-//
-//   4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some
-//      region start/end byte positions. Just like I couldn't get the function hash at
-//      intrinsic codegen time for external crate functions, I think the SourceMap I
-//      have here only applies to the local crate, and I know I have coverages that
-//      reference external crates.
-//
-//          I still don't know if I fixed the hash problem correctly. If external crates
-//          implement the function, can't I use the coverage counters already compiled
-//          into those external crates? (Maybe not for generics and/or maybe not for
-//          macros... not sure. But I need to understand this better.)
-//
-// If the byte range conversion is wrong, fix it. But if it
-// is right, then it is possible for the start and end to be in different files.
-// Can I do something other than ignore coverages that span multiple files?
-//
-// If I can resolve this, remove the "Option<>" result type wrapper
-// `regions_in_file_order()` accordingly.
-
 /// Collects all of the coverage regions associated with (a) injected counters, (b) counter
 /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
 /// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
@@ -171,19 +75,17 @@ pub struct ExpressionRegion {
 /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
 /// for a gap area is only used as the line execution count if there are no other regions on a
 /// line."
-pub struct FunctionCoverage<'a> {
-    source_map: &'a SourceMap,
+pub struct FunctionCoverage<'tcx> {
     source_hash: u64,
-    counters: IndexVec<CounterValueReference, Option<Region>>,
-    expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion>>,
-    unreachable_regions: Vec<Region>,
+    counters: IndexVec<CounterValueReference, Option<Region<'tcx>>>,
+    expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion<'tcx>>>,
+    unreachable_regions: Vec<Region<'tcx>>,
 }
 
-impl<'a> FunctionCoverage<'a> {
-    pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
+impl<'tcx> FunctionCoverage<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
         let coverageinfo = tcx.coverageinfo(instance.def_id());
         Self {
-            source_map: tcx.sess.source_map(),
             source_hash: 0, // will be set with the first `add_counter()`
             counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize),
             expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize),
@@ -194,20 +96,14 @@ pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
     /// Adds a code region to be counted by an injected counter intrinsic.
     /// The source_hash (computed during coverage instrumentation) should also be provided, and
     /// should be the same for all counters in a given function.
-    pub fn add_counter(
-        &mut self,
-        source_hash: u64,
-        id: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    ) {
+    pub fn add_counter(&mut self, source_hash: u64, id: u32, region: Region<'tcx>) {
         if self.source_hash == 0 {
             self.source_hash = source_hash;
         } else {
             debug_assert_eq!(source_hash, self.source_hash);
         }
         self.counters[CounterValueReference::from(id)]
-            .replace(Region::new(self.source_map, start_byte_pos, end_byte_pos))
+            .replace(region)
             .expect_none("add_counter called with duplicate `id`");
     }
 
@@ -231,8 +127,7 @@ pub fn add_counter_expression(
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         let expression_id = ExpressionOperandId::from(id_descending_from_max);
         let lhs = ExpressionOperandId::from(lhs);
@@ -240,18 +135,13 @@ pub fn add_counter_expression(
 
         let expression_index = self.expression_index(expression_id);
         self.expressions[expression_index]
-            .replace(ExpressionRegion {
-                lhs,
-                op,
-                rhs,
-                region: Region::new(self.source_map, start_byte_pos, end_byte_pos),
-            })
+            .replace(ExpressionRegion { lhs, op, rhs, region })
             .expect_none("add_counter_expression called with duplicate `id_descending_from_max`");
     }
 
     /// Add a region that will be marked as "unreachable", with a constant "zero counter".
-    pub fn add_unreachable_region(&mut self, start_byte_pos: u32, end_byte_pos: u32) {
-        self.unreachable_regions.push(Region::new(self.source_map, start_byte_pos, end_byte_pos));
+    pub fn add_unreachable_region(&mut self, region: Region<'tcx>) {
+        self.unreachable_regions.push(region)
     }
 
     /// Return the source hash, generated from the HIR node structure, and used to indicate whether
@@ -264,8 +154,8 @@ pub fn source_hash(&self) -> u64 {
     /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
     /// `CounterMappingRegion`s.
     pub fn get_expressions_and_counter_regions(
-        &'a self,
-    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) {
+        &'tcx self,
+    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) {
         assert!(self.source_hash != 0);
 
         let counter_regions = self.counter_regions();
@@ -277,7 +167,7 @@ pub fn get_expressions_and_counter_regions(
         (counter_expressions, counter_regions)
     }
 
-    fn counter_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
+    fn counter_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> {
         self.counters.iter_enumerated().filter_map(|(index, entry)| {
             // Option::map() will return None to filter out missing counters. This may happen
             // if, for example, a MIR-instrumented counter is removed during an optimization.
@@ -288,8 +178,8 @@ fn counter_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
     }
 
     fn expressions_with_regions(
-        &'a self,
-    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) {
+        &'tcx self,
+    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) {
         let mut counter_expressions = Vec::with_capacity(self.expressions.len());
         let mut expression_regions = Vec::with_capacity(self.expressions.len());
         let mut new_indexes =
@@ -350,7 +240,7 @@ fn expressions_with_regions(
         (counter_expressions, expression_regions.into_iter())
     }
 
-    fn unreachable_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
+    fn unreachable_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> {
         self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
     }
 
index 1f0ffd289b13a7ca9a158ecb9d42634c8f1cce49..ff794a75c360d97756530437ce29823313ab8a55 100644 (file)
@@ -2,3 +2,4 @@
 pub mod map;
 
 pub use map::ExprKind;
+pub use map::Region;
index 0c8638b673d4fbdab5269a40588e22b2d458ba34..05656774f0e9556cfefeee295ad905e548e30976 100644 (file)
@@ -253,14 +253,13 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
                 };
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
-                let is_niche = {
-                    let relative_max = if relative_max == 0 {
-                        // Avoid calling `const_uint`, which wouldn't work for pointers.
-                        // FIXME(eddyb) check the actual primitive type here.
-                        bx.cx().const_null(niche_llty)
-                    } else {
-                        bx.cx().const_uint(niche_llty, relative_max as u64)
-                    };
+                let is_niche = if relative_max == 0 {
+                    // Avoid calling `const_uint`, which wouldn't work for pointers.
+                    // Also use canonical == 0 instead of non-canonical u<= 0.
+                    // FIXME(eddyb) check the actual primitive type here.
+                    bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty))
+                } else {
+                    let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64);
                     bx.icmp(IntPredicate::IntULE, relative_discr, relative_max)
                 };
 
index db1d86c974ea885477c19222b5f2ea2e5c8fd8f5..2b5878f46bc43bfc7540b45468f6657e5c7e07ee 100644 (file)
@@ -1,5 +1,5 @@
 use super::BackendTypes;
-use crate::coverageinfo::ExprKind;
+use crate::coverageinfo::{ExprKind, Region};
 use rustc_middle::ty::Instance;
 
 pub trait CoverageInfoMethods: BackendTypes {
@@ -12,8 +12,7 @@ fn add_counter_region(
         instance: Instance<'tcx>,
         function_source_hash: u64,
         index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     );
 
     fn add_counter_expression_region(
@@ -23,14 +22,8 @@ fn add_counter_expression_region(
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     );
 
-    fn add_unreachable_region(
-        &mut self,
-        instance: Instance<'tcx>,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    );
+    fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>);
 }
index 7af640c109ed57dbfa134e42159a3fa0f1266d1f..cc954cee9077d8df50e6cd1e52810f42506a15f5 100644 (file)
@@ -677,7 +677,7 @@ fn print_crate_info(
                     let t_outputs = rustc_interface::util::build_output_filenames(
                         input, odir, ofile, attrs, sess,
                     );
-                    let id = rustc_session::output::find_crate_name(Some(sess), attrs, input);
+                    let id = rustc_session::output::find_crate_name(sess, attrs, input);
                     if *req == PrintRequest::CrateName {
                         println!("{}", id);
                         continue;
index 31334069ed8a404ed0a729c702d4ac55747dd2d7..ddd245b1a2b1b7ea6f1ab08a8a459ed7795a2e98 100644 (file)
@@ -5,25 +5,6 @@ Erroneous code example:
 ```compile_fail,E0271
 trait Trait { type AssociatedType; }
 
-fn foo<T>(t: T) where T: Trait<AssociatedType=u32> {
-    println!("in foo");
-}
-
-impl Trait for i8 { type AssociatedType = &'static str; }
-
-foo(3_i8);
-```
-
-This is because of a type mismatch between the associated type of some
-trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
-and another type `U` that is required to be equal to `T::Bar`, but is not.
-Examples follow.
-
-Here is that same example again, with some explanatory comments:
-
-```compile_fail,E0271
-trait Trait { type AssociatedType; }
-
 fn foo<T>(t: T) where T: Trait<AssociatedType=u32> {
 //                    ~~~~~~~~ ~~~~~~~~~~~~~~~~~~
 //                        |            |
@@ -56,11 +37,9 @@ foo(3_i8);
 // therefore the type-checker complains with this error code.
 ```
 
-To avoid those issues, you have to make the types match correctly.
-So we can fix the previous examples like this:
-
+The issue can be resolved by changing the associated type:
+1) in the `foo` implementation:
 ```
-// Basic Example:
 trait Trait { type AssociatedType; }
 
 fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> {
@@ -70,13 +49,17 @@ fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> {
 impl Trait for i8 { type AssociatedType = &'static str; }
 
 foo(3_i8);
+```
 
-// For-Loop Example:
-let vs = vec![1, 2, 3, 4];
-for v in &vs {
-    match v {
-        &1 => {}
-        _ => {}
-    }
+2) in the `Trait` implementation for `i8`:
+```
+trait Trait { type AssociatedType; }
+
+fn foo<T>(t: T) where T: Trait<AssociatedType = u32> {
+    println!("in foo");
 }
+
+impl Trait for i8 { type AssociatedType = u32; }
+
+foo(3_i8);
 ```
index b90c59f5807379247904c6735e6bda3357f75182..dc3ffdfddd9de772a5317fca6857ccab7e52a483 100644 (file)
@@ -5,7 +5,7 @@ Erroneous code example:
 ```compile_fail,E0502
 fn bar(x: &mut i32) {}
 fn foo(a: &mut i32) {
-    let ref y = a; // a is borrowed as immutable.
+    let y = &a; // a is borrowed as immutable.
     bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
             //        as immutable
     println!("{}", y);
@@ -19,7 +19,7 @@ variable before trying to access it mutably:
 fn bar(x: &mut i32) {}
 fn foo(a: &mut i32) {
     bar(a);
-    let ref y = a; // ok!
+    let y = &a; // ok!
     println!("{}", y);
 }
 ```
index 6595691ce786ca3110da5bcc7bd2a3f890c58803..23ee7af30f418b9e8a940173281cd00772c622b6 100644 (file)
@@ -1,20 +1,23 @@
-Cannot take address of temporary value.
+The address of temporary value was taken.
 
 Erroneous code example:
 
 ```compile_fail,E0745
 # #![feature(raw_ref_op)]
 fn temp_address() {
-    let ptr = &raw const 2;   // ERROR
+    let ptr = &raw const 2; // error!
 }
 ```
 
-To avoid the error, first bind the temporary to a named local variable.
+In this example, `2` is destroyed right after the assignment, which means that
+`ptr` now points to an unavailable location.
+
+To avoid this error, first bind the temporary to a named local variable:
 
 ```
 # #![feature(raw_ref_op)]
 fn temp_address() {
     let val = 2;
-    let ptr = &raw const val;
+    let ptr = &raw const val; // ok!
 }
 ```
index 305667e58f8fb3afb669fd325738051b23763842..90755d47f67901188c93af03764be6c1985ab6f7 100644 (file)
@@ -1,4 +1,4 @@
-Return types cannot be `dyn Trait`s as they must be `Sized`.
+An unboxed trait object was used as a return value.
 
 Erroneous code example:
 
@@ -13,11 +13,13 @@ impl T for S {
 
 // Having the trait `T` as return type is invalid because
 // unboxed trait objects do not have a statically known size:
-fn foo() -> dyn T {
+fn foo() -> dyn T { // error!
     S(42)
 }
 ```
 
+Return types cannot be `dyn Trait`s as they must be `Sized`.
+
 To avoid the error there are a couple of options.
 
 If there is a single type involved, you can use [`impl Trait`]:
@@ -32,7 +34,7 @@ If there is a single type involved, you can use [`impl Trait`]:
 # }
 // The compiler will select `S(usize)` as the materialized return type of this
 // function, but callers will only know that the return type implements `T`.
-fn foo() -> impl T {
+fn foo() -> impl T { // ok!
     S(42)
 }
 ```
@@ -57,7 +59,7 @@ impl T for O {
 
 // This now returns a "trait object" and callers are only be able to access
 // associated items from `T`.
-fn foo(x: bool) -> Box<dyn T> {
+fn foo(x: bool) -> Box<dyn T> { // ok!
     if x {
         Box::new(S(42))
     } else {
index df1afbfef46df1c4435158a75287c978dd4ffaa8..caf7e0fba07a343aaf1e1238b3fcd10795b87c49 100644 (file)
@@ -1,4 +1,4 @@
-Generic arguments must be provided in the same order as the corresponding
+Generic arguments were not provided in the same order as the corresponding
 generic parameters are declared.
 
 Erroneous code example:
@@ -11,7 +11,7 @@ type X = S<(), 'static>; // error: the type argument is provided before the
 ```
 
 The argument order should be changed to match the parameter declaration
-order, as in the following.
+order, as in the following:
 
 ```
 struct S<'a, T>(&'a T);
index e0cf56f716f9ddda3752ae915c7b5a080bc42a76..905e852f8d579e60e9984aa12fea4e42adb1ca81 100644 (file)
@@ -1,4 +1,18 @@
-Negative impls cannot be default impls. A default impl supplies
-default values for the items within to be used by other impls, whereas
-a negative impl declares that there are no other impls. These don't
-make sense to combine.
+A negative impl was made default impl.
+
+Erroneous code example:
+
+```compile_fail,E0750
+# #![feature(negative_impls)]
+# #![feature(specialization)]
+trait MyTrait {
+    type Foo;
+}
+
+default impl !MyTrait for u32 {} // error!
+# fn main() {}
+```
+
+Negative impls cannot be default impls. A default impl supplies default values
+for the items within to be used by other impls, whereas a negative impl declares
+that there are no other impls. Combining it does not make sense.
index 1362a1155bcdd358e68573809147005fe47d2b6d..cca8b47c78122a2cd319123e73e607b16c0bbb3d 100644 (file)
@@ -362,7 +362,7 @@ fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrac
                         format!(
                             "in this expansion of `{}`{}",
                             trace.kind.descr(),
-                            if macro_backtrace.len() > 2 {
+                            if macro_backtrace.len() > 1 {
                                 // if macro_backtrace.len() == 1 it'll be
                                 // pointed at by "in this macro invocation"
                                 format!(" (#{})", i + 1)
@@ -393,7 +393,7 @@ fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrac
                         trace.call_site,
                         format!(
                             "in this macro invocation{}",
-                            if macro_backtrace.len() > 2 && always_backtrace {
+                            if macro_backtrace.len() > 1 && always_backtrace {
                                 // only specify order when the macro
                                 // backtrace is multiple levels deep
                                 format!(" (#{})", i + 1)
index daa75d423249aa4da01bb6146224a041acb36f2f..5a36df8299c0b5795d5433f4c44e2886a8ad03d8 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_errors::{DiagnosticBuilder, ErrorReported};
 use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
-use rustc_session::{parse::ParseSess, Limit};
+use rustc_session::{parse::ParseSess, Limit, Session};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
@@ -790,7 +790,7 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
     /// Constructs a syntax extension with the given properties
     /// and other properties converted from attributes.
     pub fn new(
-        sess: &ParseSess,
+        sess: &Session,
         kind: SyntaxExtensionKind,
         span: Span,
         helper_attrs: Vec<Symbol>,
@@ -798,27 +798,29 @@ pub fn new(
         name: Symbol,
         attrs: &[ast::Attribute],
     ) -> SyntaxExtension {
-        let allow_internal_unstable = attr::allow_internal_unstable(&attrs, &sess.span_diagnostic)
+        let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs)
             .map(|features| features.collect::<Vec<Symbol>>().into());
 
         let mut local_inner_macros = false;
-        if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) {
+        if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) {
             if let Some(l) = macro_export.meta_item_list() {
                 local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
             }
         }
 
-        let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro);
+        let is_builtin = sess.contains_name(attrs, sym::rustc_builtin_macro);
         let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
         if const_stability.is_some() {
-            sess.span_diagnostic.span_err(span, "macros cannot have const stability attributes");
+            sess.parse_sess
+                .span_diagnostic
+                .span_err(span, "macros cannot have const stability attributes");
         }
 
         SyntaxExtension {
             kind,
             span,
             allow_internal_unstable,
-            allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe),
+            allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe),
             local_inner_macros,
             stability,
             deprecation: attr::find_deprecation(&sess, attrs, span),
@@ -941,7 +943,7 @@ pub struct ExpansionData {
 /// when a macro expansion occurs, the resulting nodes have the `backtrace()
 /// -> expn_data` of their expansion context stored into their span.
 pub struct ExtCtxt<'a> {
-    pub parse_sess: &'a ParseSess,
+    pub sess: &'a Session,
     pub ecfg: expand::ExpansionConfig<'a>,
     pub reduced_recursion_limit: Option<Limit>,
     pub root_path: PathBuf,
@@ -954,13 +956,13 @@ pub struct ExtCtxt<'a> {
 
 impl<'a> ExtCtxt<'a> {
     pub fn new(
-        parse_sess: &'a ParseSess,
+        sess: &'a Session,
         ecfg: expand::ExpansionConfig<'a>,
         resolver: &'a mut dyn ResolverExpand,
         extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
     ) -> ExtCtxt<'a> {
         ExtCtxt {
-            parse_sess,
+            sess,
             ecfg,
             reduced_recursion_limit: None,
             resolver,
@@ -988,13 +990,13 @@ pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
         expand::MacroExpander::new(self, true)
     }
     pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> {
-        rustc_parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS)
+        rustc_parse::stream_to_parser(&self.sess.parse_sess, stream, MACRO_ARGUMENTS)
     }
     pub fn source_map(&self) -> &'a SourceMap {
-        self.parse_sess.source_map()
+        self.sess.parse_sess.source_map()
     }
     pub fn parse_sess(&self) -> &'a ParseSess {
-        self.parse_sess
+        &self.sess.parse_sess
     }
     pub fn call_site(&self) -> Span {
         self.current_expansion.id.expn_data().call_site
@@ -1026,7 +1028,7 @@ pub fn expansion_cause(&self) -> Option<Span> {
     }
 
     pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
-        self.parse_sess.span_diagnostic.struct_span_err(sp, msg)
+        self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
     }
 
     /// Emit `msg` attached to `sp`, without immediately stopping
@@ -1035,17 +1037,17 @@ pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> Diagnosti
     /// Compilation will be stopped in the near future (at the end of
     /// the macro expansion phase).
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.parse_sess.span_diagnostic.span_err(sp, msg);
+        self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
     }
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        self.parse_sess.span_diagnostic.span_warn(sp, msg);
+        self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
     }
     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
-        self.parse_sess.span_diagnostic.span_bug(sp, msg);
+        self.sess.parse_sess.span_diagnostic.span_bug(sp, msg);
     }
     pub fn trace_macros_diag(&mut self) {
         for (sp, notes) in self.expansions.iter() {
-            let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
+            let mut db = self.sess.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
             for note in notes {
                 db.note(note);
             }
@@ -1055,7 +1057,7 @@ pub fn trace_macros_diag(&mut self) {
         self.expansions.clear();
     }
     pub fn bug(&self, msg: &str) -> ! {
-        self.parse_sess.span_diagnostic.bug(msg);
+        self.sess.parse_sess.span_diagnostic.bug(msg);
     }
     pub fn trace_macros(&self) -> bool {
         self.ecfg.trace_mac
index d79dabb509267aafab3442bc39ea47af63744871..f6ddcd35068c86a5e35a95778bb3654728ca3e75 100644 (file)
@@ -13,7 +13,8 @@
     ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
 };
 use rustc_parse::{parse_in, validate_attr};
-use rustc_session::parse::{feature_err, ParseSess};
+use rustc_session::parse::feature_err;
+use rustc_session::Session;
 use rustc_span::edition::{Edition, ALL_EDITIONS};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
-    pub sess: &'a ParseSess,
+    pub sess: &'a Session,
     pub features: Option<&'a Features>,
 }
 
 fn get_features(
+    sess: &Session,
     span_handler: &Handler,
     krate_attrs: &[ast::Attribute],
-    crate_edition: Edition,
-    allow_features: &Option<Vec<String>>,
 ) -> Features {
     fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
         let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
@@ -53,6 +53,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
 
     let mut features = Features::default();
     let mut edition_enabled_features = FxHashMap::default();
+    let crate_edition = sess.edition();
 
     for &edition in ALL_EDITIONS {
         if edition <= crate_edition {
@@ -70,7 +71,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
     // Process the edition umbrella feature-gates first, to ensure
     // `edition_enabled_features` is completed before it's queried.
     for attr in krate_attrs {
-        if !attr.check_name(sym::feature) {
+        if !sess.check_name(attr, sym::feature) {
             continue;
         }
 
@@ -103,7 +104,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
     }
 
     for attr in krate_attrs {
-        if !attr.check_name(sym::feature) {
+        if !sess.check_name(attr, sym::feature) {
             continue;
         }
 
@@ -165,7 +166,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
                 continue;
             }
 
-            if let Some(allowed) = allow_features.as_ref() {
+            if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() {
                 if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
                     struct_span_err!(
                         span_handler,
@@ -193,16 +194,11 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
 }
 
 // `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(
-    mut krate: ast::Crate,
-    sess: &ParseSess,
-    edition: Edition,
-    allow_features: &Option<Vec<String>>,
-) -> (ast::Crate, Features) {
+pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
     let mut strip_unconfigured = StripUnconfigured { sess, features: None };
 
     let unconfigured_attrs = krate.attrs.clone();
-    let diag = &sess.span_diagnostic;
+    let diag = &sess.parse_sess.span_diagnostic;
     let err_count = diag.err_count();
     let features = match strip_unconfigured.configure(krate.attrs) {
         None => {
@@ -213,7 +209,7 @@ pub fn features(
         }
         Some(attrs) => {
             krate.attrs = attrs;
-            let features = get_features(diag, &krate.attrs, edition, allow_features);
+            let features = get_features(sess, diag, &krate.attrs);
             if err_count == diag.err_count() {
                 // Avoid reconfiguring malformed `cfg_attr`s.
                 strip_unconfigured.features = Some(&features);
@@ -281,9 +277,9 @@ fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
         }
 
         // At this point we know the attribute is considered used.
-        attr::mark_used(&attr);
+        self.sess.mark_attr_used(&attr);
 
-        if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+        if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
             return vec![];
         }
 
@@ -303,8 +299,10 @@ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, S
         match attr.get_normal_item().args {
             ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
                 let msg = "wrong `cfg_attr` delimiters";
-                validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
-                match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
+                validate_attr::check_meta_bad_delim(&self.sess.parse_sess, dspan, delim, msg);
+                match parse_in(&self.sess.parse_sess, tts.clone(), "`cfg_attr` input", |p| {
+                    p.parse_cfg_attr()
+                }) {
                     Ok(r) => return Some(r),
                     Err(mut e) => {
                         e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
@@ -320,6 +318,7 @@ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, S
 
     fn error_malformed_cfg_attr_missing(&self, span: Span) {
         self.sess
+            .parse_sess
             .span_diagnostic
             .struct_span_err(span, "malformed `cfg_attr` attribute input")
             .span_suggestion(
@@ -335,10 +334,10 @@ fn error_malformed_cfg_attr_missing(&self, span: Span) {
     /// Determines if a node with the given attributes should be included in this configuration.
     pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
         attrs.iter().all(|attr| {
-            if !is_cfg(attr) {
+            if !is_cfg(self.sess, attr) {
                 return true;
             }
-            let meta_item = match validate_attr::parse_meta(self.sess, attr) {
+            let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
                 Ok(meta_item) => meta_item,
                 Err(mut err) => {
                     err.emit();
@@ -346,7 +345,7 @@ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
                 }
             };
             let error = |span, msg, suggestion: &str| {
-                let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
+                let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
                 if !suggestion.is_empty() {
                     err.span_suggestion(
                         span,
@@ -364,7 +363,9 @@ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
                 Some([]) => error(span, "`cfg` predicate is not specified", ""),
                 Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
                 Some([single]) => match single.meta_item() {
-                    Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
+                    Some(meta_item) => {
+                        attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
+                    }
                     None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
                 },
             }
@@ -383,7 +384,7 @@ fn visit_expr_attrs(&mut self, attrs: &[Attribute]) {
     pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
         if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
             let mut err = feature_err(
-                self.sess,
+                &self.sess.parse_sess,
                 sym::stmt_expr_attributes,
                 attr.span,
                 "attributes on expressions are experimental",
@@ -452,9 +453,9 @@ pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
         //
         // N.B., this is intentionally not part of the visit_expr() function
         //     in order for filter_map_expr() to be able to avoid this check
-        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
+        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(self.sess, a)) {
             let msg = "removing an expression is not supported in this position";
-            self.sess.span_diagnostic.span_err(attr.span, msg);
+            self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
         }
 
         self.process_cfg_attrs(expr)
@@ -527,6 +528,6 @@ fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) {
     }
 }
 
-fn is_cfg(attr: &Attribute) -> bool {
-    attr.check_name(sym::cfg)
+fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
+    sess.check_name(attr, sym::cfg)
 }
index 0cc340c205ac8db7daf5073f33b87712a7174f96..8da56dc67e59c3b14bdb397beb53ca4751ff64a9 100644 (file)
@@ -527,7 +527,7 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm
     }
 
     fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
-        let attr = attr::find_by_name(item.attrs(), sym::derive);
+        let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
         let span = attr.map_or(item.span(), |attr| attr.span);
         let mut err = self
             .cx
@@ -566,10 +566,7 @@ fn collect_invocations(
 
         let invocations = {
             let mut collector = InvocationCollector {
-                cfg: StripUnconfigured {
-                    sess: self.cx.parse_sess,
-                    features: self.cx.ecfg.features,
-                },
+                cfg: StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features },
                 cx: self.cx,
                 invocations: Vec::new(),
                 monotonic: self.monotonic,
@@ -589,8 +586,7 @@ fn collect_invocations(
     }
 
     fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
-        let mut cfg =
-            StripUnconfigured { sess: self.cx.parse_sess, features: self.cx.ecfg.features };
+        let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features };
         // Since the item itself has already been configured by the InvocationCollector,
         // we know that fold result vector will contain exactly one element
         match item {
@@ -706,7 +702,7 @@ fn expand_invoc(
                 SyntaxExtensionKind::Attr(expander) => {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
-                    let tokens = item.into_tokens(self.cx.parse_sess);
+                    let tokens = item.into_tokens(&self.cx.sess.parse_sess);
                     let attr_item = attr.unwrap_normal_item();
                     if let MacArgs::Eq(..) = attr_item.args {
                         self.cx.span_err(span, "key-value macro attributes are not supported");
@@ -719,7 +715,7 @@ fn expand_invoc(
                     self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span)
                 }
                 SyntaxExtensionKind::LegacyAttr(expander) => {
-                    match validate_attr::parse_meta(self.cx.parse_sess, &attr) {
+                    match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) {
                         Ok(meta) => {
                             let items = match expander.expand(self.cx, span, &meta, item) {
                                 ExpandResult::Ready(items) => items,
@@ -748,9 +744,9 @@ fn expand_invoc(
                     }
                 }
                 SyntaxExtensionKind::NonMacroAttr { mark_used } => {
-                    attr::mark_known(&attr);
+                    self.cx.sess.mark_attr_known(&attr);
                     if *mark_used {
-                        attr::mark_used(&attr);
+                        self.cx.sess.mark_attr_used(&attr);
                     }
                     item.visit_attrs(|attrs| attrs.push(attr));
                     fragment_kind.expect_from_annotatables(iter::once(item))
@@ -808,7 +804,7 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
             return;
         }
         feature_err(
-            self.cx.parse_sess,
+            &self.cx.sess.parse_sess,
             sym::proc_macro_hygiene,
             span,
             &format!("custom attributes cannot be applied to {}", kind),
@@ -843,7 +839,8 @@ fn visit_mac(&mut self, _: &'ast ast::MacCall) {}
         }
 
         if !self.cx.ecfg.proc_macro_hygiene() {
-            annotatable.visit_with(&mut GateProcMacroInput { parse_sess: self.cx.parse_sess });
+            annotatable
+                .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess });
         }
     }
 
@@ -989,7 +986,7 @@ fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> A
                 ..ExpnData::default(
                     ExpnKind::Macro(MacroKind::Attr, sym::derive),
                     item.span(),
-                    self.cx.parse_sess.edition,
+                    self.cx.sess.parse_sess.edition,
                     None,
                 )
             }),
@@ -1049,7 +1046,7 @@ fn find_attr_invoc(
                 if a.has_name(sym::derive) {
                     *after_derive = true;
                 }
-                !attr::is_known(a) && !is_builtin_attr(a)
+                !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
             })
             .map(|i| attrs.remove(i));
         if let Some(attr) = &attr {
@@ -1058,7 +1055,7 @@ fn find_attr_invoc(
                 && !attr.has_name(sym::test)
             {
                 feature_err(
-                    &self.cx.parse_sess,
+                    &self.cx.sess.parse_sess,
                     sym::custom_inner_attributes,
                     attr.span,
                     "non-builtin inner attributes are unstable",
@@ -1109,8 +1106,8 @@ fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.parse_sess, features);
-            validate_attr::check_meta(self.cx.parse_sess, attr);
+            rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
+            validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
 
             // macros are expanded before any lint passes so this warning has to be hardcoded
             if attr.has_name(sym::derive) {
@@ -1123,7 +1120,7 @@ fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
             }
 
             if attr.doc_str().is_some() {
-                self.cx.parse_sess.buffer_lint_with_diagnostic(
+                self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
                     &UNUSED_DOC_COMMENTS,
                     attr.span,
                     ast::CRATE_NODE_ID,
@@ -1429,7 +1426,7 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                 })
             }
             ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
-                let sess = self.cx.parse_sess;
+                let sess = &self.cx.sess.parse_sess;
                 let orig_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
 
@@ -1438,11 +1435,11 @@ fn visit_block(&mut self, block: &mut P<Block>) {
                 let Directory { ownership, path } = if old_mod.inline {
                     // Inline `mod foo { ... }`, but we still need to push directories.
                     item.attrs = attrs;
-                    push_directory(ident, &item.attrs, dir)
+                    push_directory(&self.cx.sess, ident, &item.attrs, dir)
                 } else {
                     // We have an outline `mod foo;` so we need to parse the file.
                     let (new_mod, dir) =
-                        parse_external_mod(sess, ident, span, dir, &mut attrs, pushed);
+                        parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
 
                     let krate = ast::Crate {
                         span: new_mod.inner,
@@ -1639,7 +1636,7 @@ fn flat_map_generic_param(
     fn visit_attribute(&mut self, at: &mut ast::Attribute) {
         // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
         // contents="file contents")]` attributes
-        if !at.check_name(sym::doc) {
+        if !self.cx.sess.check_name(at, sym::doc) {
             return noop_visit_attribute(at, self);
         }
 
@@ -1660,9 +1657,9 @@ fn visit_attribute(&mut self, at: &mut ast::Attribute) {
                 }
 
                 if let Some(file) = it.value_str() {
-                    let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+                    let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
                     self.check_attributes(slice::from_ref(at));
-                    if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
+                    if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
                         // avoid loading the file if they haven't enabled the feature
                         return noop_visit_attribute(at, self);
                     }
index 74d4023b41075b52e4872b2518ac4f5be8c6c8ec..15b2c14a2576c44ccd76af165dae3d34d3cada6f 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_session::parse::ParseSess;
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
@@ -217,7 +218,7 @@ fn generic_extension<'cx>(
     lhses: &[mbe::TokenTree],
     rhses: &[mbe::TokenTree],
 ) -> Box<dyn MacResult + 'cx> {
-    let sess = cx.parse_sess;
+    let sess = &cx.sess.parse_sess;
 
     if cx.trace_macros() {
         let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg));
@@ -378,7 +379,7 @@ fn generic_extension<'cx>(
 
 /// Converts a macro item into a syntax extension.
 pub fn compile_declarative_macro(
-    sess: &ParseSess,
+    sess: &Session,
     features: &Features,
     def: &ast::Item,
     edition: Edition,
@@ -396,7 +397,7 @@ pub fn compile_declarative_macro(
         )
     };
 
-    let diag = &sess.span_diagnostic;
+    let diag = &sess.parse_sess.span_diagnostic;
     let lhs_nm = Ident::new(sym::lhs, def.span);
     let rhs_nm = Ident::new(sym::rhs, def.span);
     let tt_spec = Some(NonterminalKind::TT);
@@ -444,17 +445,20 @@ pub fn compile_declarative_macro(
         ),
     ];
 
-    let parser = Parser::new(sess, body, true, rustc_parse::MACRO_ARGUMENTS);
+    let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
     let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
         Success(m) => m,
         Failure(token, msg) => {
             let s = parse_failure_msg(&token);
             let sp = token.span.substitute_dummy(def.span);
-            sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
+            sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
             return mk_syn_ext(Box::new(macro_rules_dummy_expander));
         }
         Error(sp, msg) => {
-            sess.span_diagnostic.struct_span_err(sp.substitute_dummy(def.span), &msg).emit();
+            sess.parse_sess
+                .span_diagnostic
+                .struct_span_err(sp.substitute_dummy(def.span), &msg)
+                .emit();
             return mk_syn_ext(Box::new(macro_rules_dummy_expander));
         }
         ErrorReported => {
@@ -471,17 +475,18 @@ pub fn compile_declarative_macro(
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
                     if let NtTT(ref tt) = **nt {
-                        let tt = mbe::quoted::parse(tt.clone().into(), true, sess, def.id)
-                            .pop()
-                            .unwrap();
-                        valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt);
+                        let tt =
+                            mbe::quoted::parse(tt.clone().into(), true, &sess.parse_sess, def.id)
+                                .pop()
+                                .unwrap();
+                        valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
                         return tt;
                     }
                 }
-                sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+                sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
+        _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
     };
 
     let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -490,29 +495,34 @@ pub fn compile_declarative_macro(
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
                     if let NtTT(ref tt) = **nt {
-                        return mbe::quoted::parse(tt.clone().into(), false, sess, def.id)
-                            .pop()
-                            .unwrap();
+                        return mbe::quoted::parse(
+                            tt.clone().into(),
+                            false,
+                            &sess.parse_sess,
+                            def.id,
+                        )
+                        .pop()
+                        .unwrap();
                     }
                 }
-                sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+                sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
+        _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
     };
 
     for rhs in &rhses {
-        valid &= check_rhs(sess, rhs);
+        valid &= check_rhs(&sess.parse_sess, rhs);
     }
 
     // don't abort iteration early, so that errors for multiple lhses can be reported
     for lhs in &lhses {
-        valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
+        valid &= check_lhs_no_empty_seq(&sess.parse_sess, slice::from_ref(lhs));
     }
 
-    valid &= macro_check::check_meta_variables(sess, def.id, def.span, &lhses, &rhses);
+    valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses);
 
-    let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
+    let (transparency, transparency_error) = attr::find_transparency(sess, &def.attrs, macro_rules);
     match transparency_error {
         Some(TransparencyError::UnknownTransparency(value, span)) => {
             diag.span_err(span, &format!("unknown macro transparency: `{}`", value))
index 535c1dbad04a9dab1e3f9a5370795577f6f57715..12fe49ed585f06fb01b04d158a0366ec9265e43d 100644 (file)
@@ -1,8 +1,9 @@
 use rustc_ast::ast::{Attribute, Mod};
-use rustc_ast::{attr, token};
+use rustc_ast::token;
 use rustc_errors::{struct_span_err, PResult};
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
+use rustc_session::Session;
 use rustc_span::source_map::{FileName, Span};
 use rustc_span::symbol::{sym, Ident};
 
@@ -39,7 +40,7 @@ pub struct ModulePathSuccess {
 }
 
 crate fn parse_external_mod(
-    sess: &ParseSess,
+    sess: &Session,
     id: Ident,
     span: Span, // The span to blame on errors.
     Directory { mut ownership, path }: Directory,
@@ -53,14 +54,15 @@ pub struct ModulePathSuccess {
         ownership = mp.ownership;
 
         // Ensure file paths are acyclic.
-        let mut included_mod_stack = sess.included_mod_stack.borrow_mut();
-        error_on_circular_module(sess, span, &mp.path, &included_mod_stack)?;
+        let mut included_mod_stack = sess.parse_sess.included_mod_stack.borrow_mut();
+        error_on_circular_module(&sess.parse_sess, span, &mp.path, &included_mod_stack)?;
         included_mod_stack.push(mp.path.clone());
         *pop_mod_stack = true; // We have pushed, so notify caller.
         drop(included_mod_stack);
 
         // Actually parse the external file as a module.
-        let mut module = new_parser_from_file(sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
+        let mut module =
+            new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
         module.0.inline = false;
         module
     };
@@ -98,11 +100,12 @@ fn error_on_circular_module<'a>(
 }
 
 crate fn push_directory(
+    sess: &Session,
     id: Ident,
     attrs: &[Attribute],
     Directory { mut ownership, mut path }: Directory,
 ) -> Directory {
-    if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) {
+    if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
         path.push(&*filename.as_str());
         ownership = DirectoryOwnership::Owned { relative: None };
     } else {
@@ -124,14 +127,14 @@ fn error_on_circular_module<'a>(
 }
 
 fn submod_path<'a>(
-    sess: &'a ParseSess,
+    sess: &'a Session,
     id: Ident,
     span: Span,
     attrs: &[Attribute],
     ownership: DirectoryOwnership,
     dir_path: &Path,
 ) -> PResult<'a, ModulePathSuccess> {
-    if let Some(path) = submod_path_from_attr(attrs, dir_path) {
+    if let Some(path) = submod_path_from_attr(sess, attrs, dir_path) {
         let ownership = match path.file_name().and_then(|s| s.to_str()) {
             // All `#[path]` files are treated as though they are a `mod.rs` file.
             // This means that `mod foo;` declarations inside `#[path]`-included
@@ -151,16 +154,16 @@ fn submod_path<'a>(
         DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
     };
     let ModulePath { path_exists, name, result } =
-        default_submod_path(sess, id, span, relative, dir_path);
+        default_submod_path(&sess.parse_sess, id, span, relative, dir_path);
     match ownership {
         DirectoryOwnership::Owned { .. } => Ok(result?),
         DirectoryOwnership::UnownedViaBlock => {
             let _ = result.map_err(|mut err| err.cancel());
-            error_decl_mod_in_block(sess, span, path_exists, &name)
+            error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
         }
         DirectoryOwnership::UnownedViaMod => {
             let _ = result.map_err(|mut err| err.cancel());
-            error_cannot_declare_mod_here(sess, span, path_exists, &name)
+            error_cannot_declare_mod_here(&sess.parse_sess, span, path_exists, &name)
         }
     }
 }
@@ -218,9 +221,13 @@ fn error_cannot_declare_mod_here<'a, T>(
 /// Derive a submodule path from the first found `#[path = "path_string"]`.
 /// The provided `dir_path` is joined with the `path_string`.
 // Public for rustfmt usage.
-pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
+pub fn submod_path_from_attr(
+    sess: &Session,
+    attrs: &[Attribute],
+    dir_path: &Path,
+) -> Option<PathBuf> {
     // Extract path string from first `#[path = "path_string"]` attribute.
-    let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
+    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?;
     let path_string = path_string.as_str();
 
     // On windows, the base path might have the form
index c22d2a100c32ed9ee81e2566ab38e91fab7030b6..0608ccfffb858b5e6601efaf421cea30c0ed2dad 100644 (file)
@@ -2,9 +2,9 @@
 
 use rustc_ast::ast;
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::with_default_session_globals;
 use rustc_ast_pretty::pprust;
 use rustc_span::symbol::Ident;
+use rustc_span::with_default_session_globals;
 
 // This version doesn't care about getting comments or doc-strings in.
 fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) {
index b3775c78e7345c568a274dfe2a6d788bfe3dfb3a..871844442839cf7fd27f1a735de3cb7be9dbc7b8 100644 (file)
@@ -1,12 +1,12 @@
-use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::util::comments::is_doc_comment;
-use rustc_ast::with_default_session_globals;
+use rustc_ast::ast::AttrStyle;
+use rustc_ast::token::{self, CommentKind, Token, TokenKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{emitter::EmitterWriter, Handler};
 use rustc_parse::lexer::StringReader;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::symbol::Symbol;
+use rustc_span::with_default_session_globals;
 use rustc_span::{BytePos, Span};
 
 use std::io;
@@ -223,13 +223,6 @@ macro_rules! test {
     })
 }
 
-#[test]
-fn line_doc_comments() {
-    assert!(is_doc_comment("///"));
-    assert!(is_doc_comment("/// blah"));
-    assert!(!is_doc_comment("////"));
-}
-
 #[test]
 fn nested_block_comments() {
     with_default_session_globals(|| {
@@ -251,6 +244,9 @@ fn crlf_comments() {
         assert_eq!(comment.kind, token::Comment);
         assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7)));
         assert_eq!(lexer.next_token(), token::Whitespace);
-        assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test")));
+        assert_eq!(
+            lexer.next_token(),
+            token::DocComment(CommentKind::Line, AttrStyle::Outer, Symbol::intern(" test"))
+        );
     })
 }
index fc9b9f2dab04e964d2119b400a419c6a6a1ec390..5c9116b2f139de8a850c33b9067a6aefbcd8451d 100644 (file)
@@ -5,13 +5,13 @@
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::visit;
-use rustc_ast::with_default_session_globals;
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_errors::PResult;
 use rustc_parse::new_parser_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::with_default_session_globals;
 use rustc_span::{BytePos, FileName, Pos, Span};
 
 use std::path::PathBuf;
@@ -244,20 +244,20 @@ fn crlf_doc_comments() {
         let source = "/// doc comment\r\nfn foo() {}".to_string();
         let item = parse_item_from_source_str(name_1, source, &sess).unwrap().unwrap();
         let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
-        assert_eq!(doc.as_str(), "/// doc comment");
+        assert_eq!(doc.as_str(), " doc comment");
 
         let name_2 = FileName::Custom("crlf_source_2".to_string());
         let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
         let item = parse_item_from_source_str(name_2, source, &sess).unwrap().unwrap();
         let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::<Vec<_>>();
-        let b: &[_] = &[Symbol::intern("/// doc comment"), Symbol::intern("/// line 2")];
+        let b: &[_] = &[Symbol::intern(" doc comment"), Symbol::intern(" line 2")];
         assert_eq!(&docs[..], b);
 
         let name_3 = FileName::Custom("clrf_source_3".to_string());
         let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
         let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
         let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
-        assert_eq!(doc.as_str(), "/** doc comment\n *  with CRLF */");
+        assert_eq!(doc.as_str(), " doc comment\n *  with CRLF ");
     });
 }
 
index 54012d62a72a7a54c68dade7752ae5c9724ea079..85fbf3bc0d0b0d5a9813241275aaee512f94c541 100644 (file)
@@ -107,7 +107,7 @@ fn expand(
         let input = if item.pretty_printing_compatibility_hack() {
             TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
         } else {
-            nt_to_tokenstream(&item, ecx.parse_sess, DUMMY_SP)
+            nt_to_tokenstream(&item, &ecx.sess.parse_sess, DUMMY_SP)
         };
 
         let server = proc_macro_server::Rustc::new(ecx);
@@ -123,9 +123,9 @@ fn expand(
             }
         };
 
-        let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
+        let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
         let mut parser =
-            rustc_parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
+            rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive"));
         let mut items = vec![];
 
         loop {
@@ -140,7 +140,7 @@ fn expand(
         }
 
         // fail if there have been errors emitted
-        if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
+        if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before {
             ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit();
         }
 
index 881d7b84b70b085969beddb544c8ba0a1a7a7e3a..dc7ba2d0424fc437ac25c4d5078329bbc9ff3d7d 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_ast::ast;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
-use rustc_ast::util::comments;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Diagnostic;
@@ -148,11 +147,9 @@ macro_rules! op {
                 tt!(Punct::new('\'', true))
             }
             Literal(lit) => tt!(Literal { lit }),
-            DocComment(c) => {
-                let style = comments::doc_comment_style(c);
-                let stripped = comments::strip_doc_comment_decoration(c);
+            DocComment(_, attr_style, data) => {
                 let mut escaped = String::new();
-                for ch in stripped.chars() {
+                for ch in data.as_str().chars() {
                     escaped.extend(ch.escape_debug());
                 }
                 let stream = vec![
@@ -169,7 +166,7 @@ macro_rules! op {
                     span: DelimSpan::from_single(span),
                     flatten: false,
                 }));
-                if style == ast::AttrStyle::Inner {
+                if attr_style == ast::AttrStyle::Inner {
                     stack.push(tt!(Punct::new('!', false)));
                 }
                 tt!(Punct::new('#', false))
@@ -367,7 +364,7 @@ impl<'a> Rustc<'a> {
     pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
         let expn_data = cx.current_expansion.id.expn_data();
         Rustc {
-            sess: cx.parse_sess,
+            sess: &cx.sess.parse_sess,
             def_site: cx.with_def_site_ctxt(expn_data.def_site),
             call_site: cx.with_call_site_ctxt(expn_data.call_site),
             mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
index 283ea0f68d9248f175253a391d33dc3350f0e3be..b562a690f83612bcd96bd805ed8ba922df977b51 100644 (file)
@@ -1,9 +1,9 @@
 use rustc_ast::ast;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::with_default_session_globals;
 use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_stream};
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
+use rustc_span::with_default_session_globals;
 use rustc_span::{BytePos, MultiSpan, Span};
 
 use rustc_data_structures::sync::Lrc;
index bc171bec6ff7a88fda026c6cdecda8d3bfd9fdc3..4e818e9feb08b151b435bd8130749fc354cd9a34 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc_ast::token;
 use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree};
-use rustc_ast::with_default_session_globals;
+use rustc_span::with_default_session_globals;
 use rustc_span::{BytePos, Span, Symbol};
 use smallvec::smallvec;
 
index d7c310a8b4c8b2111e3a77f3e6564ac100fae3bb..31aba8aba2515696945d70773b53292fb9220188 100644 (file)
@@ -576,9 +576,12 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Lazily evaluate constants. This allows constants to depend on type parameters.
     (active, lazy_normalization_consts, "1.46.0", Some(72219), None),
 
-    /// Alloc calling `transmute` in const fn
+    /// Allows calling `transmute` in const fn
     (active, const_fn_transmute, "1.46.0", Some(53605), None),
 
+    /// The smallest useful subset of `const_generics`.
+    (active, min_const_generics, "1.47.0", Some(74878), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
index af1860ca6bfea962a2f7a96b651aed60f8f5fcf2..618f3e99c3f04a3a38617585c1f33bd51e551f80 100644 (file)
@@ -150,7 +150,7 @@ pub fn article(&self) -> &'static str {
         }
     }
 
-    pub fn matches_ns(&self, ns: Namespace) -> bool {
+    pub fn ns(&self) -> Option<Namespace> {
         match self {
             DefKind::Mod
             | DefKind::Struct
@@ -163,7 +163,7 @@ pub fn matches_ns(&self, ns: Namespace) -> bool {
             | DefKind::ForeignTy
             | DefKind::TraitAlias
             | DefKind::AssocTy
-            | DefKind::TyParam => ns == Namespace::TypeNS,
+            | DefKind::TyParam => Some(Namespace::TypeNS),
 
             DefKind::Fn
             | DefKind::Const
@@ -171,9 +171,9 @@ pub fn matches_ns(&self, ns: Namespace) -> bool {
             | DefKind::Static
             | DefKind::Ctor(..)
             | DefKind::AssocFn
-            | DefKind::AssocConst => ns == Namespace::ValueNS,
+            | DefKind::AssocConst => Some(Namespace::ValueNS),
 
-            DefKind::Macro(..) => ns == Namespace::MacroNS,
+            DefKind::Macro(..) => Some(Namespace::MacroNS),
 
             // Not namespaced.
             DefKind::AnonConst
@@ -185,7 +185,7 @@ pub fn matches_ns(&self, ns: Namespace) -> bool {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::GlobalAsm
-            | DefKind::Impl => false,
+            | DefKind::Impl => None,
         }
     }
 }
@@ -453,7 +453,7 @@ pub fn macro_kind(self) -> Option<MacroKind> {
 
     pub fn matches_ns(&self, ns: Namespace) -> bool {
         match self {
-            Res::Def(kind, ..) => kind.matches_ns(ns),
+            Res::Def(kind, ..) => kind.ns() == Some(ns),
             Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS,
             Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS,
             Res::NonMacroAttr(..) => ns == Namespace::MacroNS,
index 4b71407acfb8cf44c57f7b202dd6900b13174326..7f473a458481f853975d3bef708668b4442101ed 100644 (file)
@@ -141,12 +141,20 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
 /// Extracts the first `lang = "$name"` out of a list of attributes.
 /// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
 /// are also extracted out when found.
-pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
+///
+/// About the `check_name` argument: passing in a `Session` would be simpler,
+/// because then we could call `Session::check_name` directly. But we want to
+/// avoid the need for `librustc_hir` to depend on `librustc_session`, so we
+/// use a closure instead.
+pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
+where
+    F: Fn(&'a ast::Attribute, Symbol) -> bool,
+{
     attrs.iter().find_map(|attr| {
         Some(match attr {
-            _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span),
-            _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span),
-            _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span),
+            _ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
+            _ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
+            _ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
             _ => return None,
         })
     })
index c0560eb8d455a9deee694c607e0404b9d843688d..fd64361cb3540009ed34389ce63feb292509e82d 100644 (file)
@@ -20,8 +20,13 @@ macro_rules! weak_lang_items {
     };
 }
 
-pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
-    lang_items::extract(attrs).and_then(|(name, _)| {
+/// The `check_name` argument avoids the need for `librustc_hir` to depend on
+/// `librustc_session`.
+pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
+where
+    F: Fn(&'a ast::Attribute, Symbol) -> bool
+{
+    lang_items::extract(check_name, attrs).and_then(|(name, _)| {
         $(if name == sym::$name {
             Some(sym::$sym)
         } else)* {
index b1665d9e1aeb3a1aaa09d53d0721cfd13d5afb35..df602d8bd1bea3762bb654a8bb3f865211bc0e37 100644 (file)
@@ -117,7 +117,7 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
         let def_id = self.tcx.hir().local_def_id(hir_id);
         let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
         for attr in attrs {
-            if attr.check_name(sym::rustc_if_this_changed) {
+            if self.tcx.sess.check_name(attr, sym::rustc_if_this_changed) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
                     None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
@@ -132,7 +132,7 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
                     },
                 };
                 self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
-            } else if attr.check_name(sym::rustc_then_this_would_need) {
+            } else if self.tcx.sess.check_name(attr, sym::rustc_then_this_would_need) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
                     Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
index d451d9a22a48b359cf2ace4005e5f26e7551439b..ed04a947485c7d234d888276535ef3dcb4446ee8 100644 (file)
@@ -39,8 +39,8 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) {
             .collect_and_partition_mono_items(LOCAL_CRATE)
             .1
             .iter()
-            .map(|cgu| cgu.name())
-            .collect::<BTreeSet<Symbol>>();
+            .map(|cgu| cgu.name().to_string())
+            .collect::<BTreeSet<String>>();
 
         let ams = AssertModuleSource { tcx, available_cgus };
 
@@ -52,31 +52,32 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) {
 
 struct AssertModuleSource<'tcx> {
     tcx: TyCtxt<'tcx>,
-    available_cgus: BTreeSet<Symbol>,
+    available_cgus: BTreeSet<String>,
 }
 
 impl AssertModuleSource<'tcx> {
     fn check_attr(&self, attr: &ast::Attribute) {
-        let (expected_reuse, comp_kind) = if attr.check_name(sym::rustc_partition_reused) {
-            (CguReuse::PreLto, ComparisonKind::AtLeast)
-        } else if attr.check_name(sym::rustc_partition_codegened) {
-            (CguReuse::No, ComparisonKind::Exact)
-        } else if attr.check_name(sym::rustc_expected_cgu_reuse) {
-            match self.field(attr, sym::kind) {
-                sym::no => (CguReuse::No, ComparisonKind::Exact),
-                sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
-                sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
-                sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
-                other => {
-                    self.tcx.sess.span_fatal(
-                        attr.span,
-                        &format!("unknown cgu-reuse-kind `{}` specified", other),
-                    );
+        let (expected_reuse, comp_kind) =
+            if self.tcx.sess.check_name(attr, sym::rustc_partition_reused) {
+                (CguReuse::PreLto, ComparisonKind::AtLeast)
+            } else if self.tcx.sess.check_name(attr, sym::rustc_partition_codegened) {
+                (CguReuse::No, ComparisonKind::Exact)
+            } else if self.tcx.sess.check_name(attr, sym::rustc_expected_cgu_reuse) {
+                match self.field(attr, sym::kind) {
+                    sym::no => (CguReuse::No, ComparisonKind::Exact),
+                    sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
+                    sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
+                    sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
+                    other => {
+                        self.tcx.sess.span_fatal(
+                            attr.span,
+                            &format!("unknown cgu-reuse-kind `{}` specified", other),
+                        );
+                    }
                 }
-            }
-        } else {
-            return;
-        };
+            } else {
+                return;
+            };
 
         if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
             self.tcx.sess.span_fatal(
@@ -121,12 +122,11 @@ fn check_attr(&self, attr: &ast::Attribute) {
 
         debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name);
 
-        if !self.available_cgus.contains(&cgu_name) {
+        if !self.available_cgus.contains(&*cgu_name.as_str()) {
             self.tcx.sess.span_err(
                 attr.span,
                 &format!(
-                    "no module named `{}` (mangled: {}). \
-                          Available modules: {}",
+                    "no module named `{}` (mangled: {}). Available modules: {}",
                     user_path,
                     cgu_name,
                     self.available_cgus
index 02f37f82352a9b762ef180a2e19b3158281b860a..0f254aee8e314d557002426cdbbb9d3fa0615c64 100644 (file)
@@ -180,9 +180,9 @@ pub struct DirtyCleanVisitor<'tcx> {
 impl DirtyCleanVisitor<'tcx> {
     /// Possibly "deserialize" the attribute into a clean/dirty assertion
     fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute) -> Option<Assertion> {
-        let is_clean = if attr.check_name(sym::rustc_dirty) {
+        let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
             false
-        } else if attr.check_name(sym::rustc_clean) {
+        } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
             true
         } else {
             // skip: not rustc_clean/dirty
@@ -523,7 +523,7 @@ pub struct FindAllAttrs<'tcx> {
 impl FindAllAttrs<'tcx> {
     fn is_active_attr(&mut self, attr: &Attribute) -> bool {
         for attr_name in &self.attr_names {
-            if attr.check_name(*attr_name) && check_config(self.tcx, attr) {
+            if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
                 return true;
             }
         }
index b369be252185b378319eca659abce5966c96b855..e4b7c24a24989b3e9adffb533740013db24f773d 100644 (file)
@@ -1034,6 +1034,30 @@ pub trait FiniteBitSetTy:
     fn checked_shr(self, rhs: u32) -> Option<Self>;
 }
 
+impl FiniteBitSetTy for u32 {
+    const DOMAIN_SIZE: u32 = 32;
+
+    const FILLED: Self = Self::MAX;
+    const EMPTY: Self = Self::MIN;
+
+    const ONE: Self = 1u32;
+    const ZERO: Self = 0u32;
+
+    fn checked_shl(self, rhs: u32) -> Option<Self> {
+        self.checked_shl(rhs)
+    }
+
+    fn checked_shr(self, rhs: u32) -> Option<Self> {
+        self.checked_shr(rhs)
+    }
+}
+
+impl std::fmt::Debug for FiniteBitSet<u32> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:032b}", self.0)
+    }
+}
+
 impl FiniteBitSetTy for u64 {
     const DOMAIN_SIZE: u32 = 64;
 
index 72deba990b0b5e5dc5dc6a629cfcede63cce94ab..89142edb2dc61dc58e738062c517b888eb78aae1 100644 (file)
@@ -85,11 +85,7 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
 
                 debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
                 if sub == &ty::ReStatic
-                    && v.0
-                        .into_iter()
-                        .filter(|t| t.span.desugaring_kind().is_none())
-                        .next()
-                        .is_some()
+                    && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some()
                 {
                     // If the failure is due to a `'static` requirement coming from a `dyn` or
                     // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
index 0125e0f48e8852944dc4e5ecdacbf3b42b75c023..7493b8b0a9f772ec7e3fbb903ca3b6cd4ba0ece5 100644 (file)
@@ -257,7 +257,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                             param.param_ty.to_string(),
                             Applicability::MaybeIncorrect,
                         );
-                    } else if let Some(_) = opaque
+                    } else if opaque
                         .bounds
                         .iter()
                         .filter_map(|arg| match arg {
@@ -269,6 +269,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                             _ => None,
                         })
                         .next()
+                        .is_some()
                     {
                     } else {
                         err.span_suggestion_verbose(
index 8a0ab52f383065cd72205619ec3232cf0a6ce8a2..ccba904df9e002270f5e3655568ea091b5fecc35 100644 (file)
@@ -50,7 +50,7 @@ fn relate_with_variance<T: Relate<'tcx>>(
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
             // FIXME(#41044) -- not correct, need test
-            ty::Bivariant => Ok(a.clone()),
+            ty::Bivariant => Ok(a),
             ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
         }
     }
@@ -97,7 +97,7 @@ fn binders<T>(
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
         self.relate_with_variance(ty::Variance::Invariant, a, b)?;
-        Ok(a.clone())
+        Ok(a)
     }
 }
 
index cb1f1c08d88f88cce50efd51249bd7482c324e28..3f5ed36035c1a3c38a8d27c866cffc53b1c64f85 100644 (file)
@@ -719,7 +719,7 @@ fn binders<T>(
             self.a_scopes.pop().unwrap();
         }
 
-        Ok(a.clone())
+        Ok(a)
     }
 }
 
index 32e708bf52b32fc2568ab8ad3f83e94a314a4878..2d4c1e5d050baa160271b2c135b243289b3c1912 100644 (file)
@@ -288,9 +288,9 @@ fn error(
     ) -> TypeError<'tcx> {
         debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
         if self.overly_polymorphic {
-            return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+            TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region)
         } else {
-            return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+            TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region)
         }
     }
 }
index 4f860c77d6541c068e31aface4ae6da3e056761b..308f884f9a63fd59d88fd0acd9f5e1d831722ee6 100644 (file)
@@ -68,7 +68,7 @@ fn relate_with_variance<T: Relate<'tcx>>(
         match variance {
             ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
             ty::Covariant => self.relate(a, b),
-            ty::Bivariant => Ok(a.clone()),
+            ty::Bivariant => Ok(a),
             ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)),
         }
     }
index e50622a005379c1dc9ac2beb4ae4ba8eda09bbe6..4dccf273dd90fc69f6b17a343222a7aa13323da9 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
 use rustc_session::{DiagnosticOutput, Session};
-use rustc_span::edition;
 use rustc_span::source_map::{FileLoader, FileName};
 use std::path::PathBuf;
 use std::result;
@@ -74,7 +73,7 @@ pub fn build_output_filenames(
 
 /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
-    rustc_ast::with_default_session_globals(move || {
+    rustc_span::with_default_session_globals(move || {
         let cfg = cfgspecs
             .into_iter()
             .map(|s| {
@@ -208,13 +207,3 @@ pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R
         || create_compiler_and_run(config, f),
     )
 }
-
-pub fn setup_callbacks_and_run_in_default_thread_pool_with_globals<R: Send>(
-    edition: edition::Edition,
-    f: impl FnOnce() -> R + Send,
-) -> R {
-    // the 1 here is duplicating code in config.opts.debugging_opts.threads
-    // which also defaults to 1; it ultimately doesn't matter as the default
-    // isn't threaded, and just ignores this parameter
-    util::setup_callbacks_and_run_in_thread_pool_with_globals(edition, 1, &None, f)
-}
index 3a562847d3eb5f7161054e2b80f451e003c8b99f..6c0343330c8c9a3a99b43e36168eca00b1c171c6 100644 (file)
@@ -162,12 +162,7 @@ pub fn register_plugins<'a>(
         )
     });
 
-    let (krate, features) = rustc_expand::config::features(
-        krate,
-        &sess.parse_sess,
-        sess.edition(),
-        &sess.opts.debugging_opts.allow_features,
-    );
+    let (krate, features) = rustc_expand::config::features(sess, krate);
     // these need to be set "early" so that expansion sees `quote` if enabled.
     sess.init_features(features);
 
@@ -244,7 +239,7 @@ fn configure_and_expand_inner<'a>(
         let (krate, name) = rustc_builtin_macros::standard_library_imports::inject(
             krate,
             &mut resolver,
-            &sess.parse_sess,
+            &sess,
             alt_std_name,
         );
         if let Some(name) = name {
@@ -253,7 +248,7 @@ fn configure_and_expand_inner<'a>(
         krate
     });
 
-    util::check_attr_crate_type(&krate.attrs, &mut resolver.lint_buffer());
+    util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());
 
     // Expand all macros
     krate = sess.time("macro_expand_crate", || {
@@ -300,7 +295,7 @@ fn configure_and_expand_inner<'a>(
         };
 
         let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k);
-        let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver, Some(&extern_mod_loaded));
+        let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded));
 
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@@ -312,6 +307,7 @@ fn configure_and_expand_inner<'a>(
         });
 
         let mut missing_fragment_specifiers: Vec<_> = ecx
+            .sess
             .parse_sess
             .missing_fragment_specifiers
             .borrow()
@@ -341,17 +337,7 @@ fn configure_and_expand_inner<'a>(
     })?;
 
     sess.time("maybe_building_test_harness", || {
-        rustc_builtin_macros::test_harness::inject(
-            &sess.parse_sess,
-            &mut resolver,
-            sess.opts.test,
-            &mut krate,
-            sess.diagnostic(),
-            &sess.features_untracked(),
-            sess.panic_strategy(),
-            sess.target.target.options.panic_strategy,
-            sess.opts.debugging_opts.panic_abort_tests,
-        )
+        rustc_builtin_macros::test_harness::inject(&sess, &mut resolver, &mut krate)
     });
 
     if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
@@ -385,7 +371,7 @@ fn configure_and_expand_inner<'a>(
             let num_crate_types = crate_types.len();
             let is_test_crate = sess.opts.test;
             rustc_builtin_macros::proc_macro_harness::inject(
-                &sess.parse_sess,
+                &sess,
                 &mut resolver,
                 krate,
                 is_proc_macro_crate,
@@ -415,12 +401,7 @@ fn configure_and_expand_inner<'a>(
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
     sess.time("complete_gated_feature_checking", || {
-        rustc_ast_passes::feature_gate::check_crate(
-            &krate,
-            &sess.parse_sess,
-            &sess.features_untracked(),
-            sess.opts.unstable_features,
-        );
+        rustc_ast_passes::feature_gate::check_crate(&krate, sess);
     });
 
     // Add all buffered lints from the `ParseSess` to the `Session`.
index e91003b450c3c0087fb7881778019c27327f8007..d56115fd6ac56b0c7681bcbab825cd696833c8ee 100644 (file)
@@ -1,4 +1,3 @@
-use rustc_ast::attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -13,19 +12,20 @@ pub fn find(tcx: TyCtxt<'_>) -> Option<DefId> {
 fn proc_macro_decls_static(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> {
     assert_eq!(cnum, LOCAL_CRATE);
 
-    let mut finder = Finder { decls: None };
+    let mut finder = Finder { tcx, decls: None };
     tcx.hir().krate().visit_all_item_likes(&mut finder);
 
     finder.decls.map(|id| tcx.hir().local_def_id(id).to_def_id())
 }
 
-struct Finder {
+struct Finder<'tcx> {
+    tcx: TyCtxt<'tcx>,
     decls: Option<hir::HirId>,
 }
 
-impl<'v> ItemLikeVisitor<'v> for Finder {
+impl<'v> ItemLikeVisitor<'v> for Finder<'_> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        if attr::contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
+        if self.tcx.sess.contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
             self.decls = Some(item.hir_id);
         }
     }
index 4265e6dca6a240acfbda3cad626052c7ea0b1d03..d1a22c69ee0419656360495aef20f7114917765a 100644 (file)
@@ -159,7 +159,7 @@ pub fn crate_name(&self) -> Result<&Query<String>> {
                 None => {
                     let parse_result = self.parse()?;
                     let krate = parse_result.peek();
-                    find_crate_name(Some(self.session()), &krate.attrs, &self.compiler.input)
+                    find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
                 }
             })
         })
@@ -294,7 +294,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
         };
 
         let attrs = &*tcx.get_attrs(def_id.to_def_id());
-        let attrs = attrs.iter().filter(|attr| attr.check_name(sym::rustc_error));
+        let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
         for attr in attrs {
             match attr.meta_item_list() {
                 // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
index 22197a66530ddddb7d1eaba67444109707e5ba2f..e94745519a496608e1c85e21c31ed0a7eb440ed6 100644 (file)
@@ -73,7 +73,7 @@ fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
 // When the user supplies --test we should implicitly supply --cfg test
 #[test]
 fn test_switch_implies_cfg_test() {
-    rustc_ast::with_default_session_globals(|| {
+    rustc_span::with_default_session_globals(|| {
         let matches = optgroups().parse(&["--test".to_string()]).unwrap();
         let (sess, cfg) = mk_session(matches);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
@@ -84,7 +84,7 @@ fn test_switch_implies_cfg_test() {
 // When the user supplies --test and --cfg test, don't implicitly add another --cfg test
 #[test]
 fn test_switch_implies_cfg_test_unless_cfg_test() {
-    rustc_ast::with_default_session_globals(|| {
+    rustc_span::with_default_session_globals(|| {
         let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
         let (sess, cfg) = mk_session(matches);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
@@ -96,20 +96,20 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 
 #[test]
 fn test_can_print_warnings() {
-    rustc_ast::with_default_session_globals(|| {
+    rustc_span::with_default_session_globals(|| {
         let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
         assert!(!sess.diagnostic().can_emit_warnings());
     });
 
-    rustc_ast::with_default_session_globals(|| {
+    rustc_span::with_default_session_globals(|| {
         let matches =
             optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
         assert!(sess.diagnostic().can_emit_warnings());
     });
 
-    rustc_ast::with_default_session_globals(|| {
+    rustc_span::with_default_session_globals(|| {
         let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
         assert!(sess.diagnostic().can_emit_warnings());
index bbb2f9d8b2500b212e496ffcd5a79dc2965c4a29..e403a60ff323b3b38e3b793bb3740a810e392d2e 100644 (file)
@@ -142,7 +142,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
     crate::callbacks::setup_callbacks();
 
     let main_handler = move || {
-        rustc_ast::with_session_globals(edition, || {
+        rustc_span::with_session_globals(edition, || {
             if let Some(stderr) = stderr {
                 io::set_panic(Some(box Sink(stderr.clone())));
             }
@@ -176,27 +176,21 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
 
     let with_pool = move |pool: &rayon::ThreadPool| pool.install(move || f());
 
-    rustc_ast::with_session_globals(edition, || {
-        rustc_ast::SESSION_GLOBALS.with(|ast_session_globals| {
-            rustc_span::SESSION_GLOBALS.with(|span_session_globals| {
-                // The main handler runs for each Rayon worker thread and sets
-                // up the thread local rustc uses. ast_session_globals and
-                // span_session_globals are captured and set on the new
-                // threads. ty::tls::with_thread_locals sets up thread local
-                // callbacks from librustc_ast.
-                let main_handler = move |thread: rayon::ThreadBuilder| {
-                    rustc_ast::SESSION_GLOBALS.set(ast_session_globals, || {
-                        rustc_span::SESSION_GLOBALS.set(span_session_globals, || {
-                            if let Some(stderr) = stderr {
-                                io::set_panic(Some(box Sink(stderr.clone())));
-                            }
-                            thread.run()
-                        })
-                    })
-                };
+    rustc_span::with_session_globals(edition, || {
+        rustc_span::SESSION_GLOBALS.with(|session_globals| {
+            // The main handler runs for each Rayon worker thread and sets up
+            // the thread local rustc uses. `session_globals` is captured and set
+            // on the new threads.
+            let main_handler = move |thread: rayon::ThreadBuilder| {
+                rustc_span::SESSION_GLOBALS.set(session_globals, || {
+                    if let Some(stderr) = stderr {
+                        io::set_panic(Some(box Sink(stderr.clone())));
+                    }
+                    thread.run()
+                })
+            };
 
-                config.build_scoped(main_handler, with_pool).unwrap()
-            })
+            config.build_scoped(main_handler, with_pool).unwrap()
         })
     })
 }
@@ -407,10 +401,14 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat
     CrateDisambiguator::from(hasher.finish::<Fingerprint>())
 }
 
-pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer) {
+pub(crate) fn check_attr_crate_type(
+    sess: &Session,
+    attrs: &[ast::Attribute],
+    lint_buffer: &mut LintBuffer,
+) {
     // Unconditionally collect crate types from attributes to make them used
     for a in attrs.iter() {
-        if a.check_name(sym::crate_type) {
+        if sess.check_name(a, sym::crate_type) {
             if let Some(n) = a.value_str() {
                 if categorize_crate_type(n).is_some() {
                     return;
@@ -465,7 +463,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
     let attr_types: Vec<CrateType> = attrs
         .iter()
         .filter_map(|a| {
-            if a.check_name(sym::crate_type) {
+            if session.check_name(a, sym::crate_type) {
                 match a.value_str() {
                     Some(s) => categorize_crate_type(s),
                     _ => None,
@@ -531,7 +529,7 @@ pub fn build_output_filenames(
                 .opts
                 .crate_name
                 .clone()
-                .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
+                .or_else(|| rustc_attr::find_crate_name(&sess, attrs).map(|n| n.to_string()))
                 .unwrap_or_else(|| input.filestem().to_owned());
 
             OutputFilenames::new(
index 6515708e115a59101249b6a5951de08e6b123760..c42794e00b41e0c3426169af4d7c6d1ef346b243 100644 (file)
@@ -41,6 +41,7 @@
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::FutureIncompatibleInfo;
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -237,7 +238,7 @@ fn report_unsafe(
 
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        if attr.check_name(sym::allow_internal_unsafe) {
+        if cx.sess().check_name(attr, sym::allow_internal_unsafe) {
             self.report_unsafe(cx, attr.span, |lint| {
                 lint.build(
                     "`allow_internal_unsafe` allows defining \
@@ -315,12 +316,12 @@ pub struct MissingDoc {
 
 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
 
-fn has_doc(attr: &ast::Attribute) -> bool {
+fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
     if attr.is_doc_comment() {
         return true;
     }
 
-    if !attr.check_name(sym::doc) {
+    if !sess.check_name(attr, sym::doc) {
         return false;
     }
 
@@ -377,7 +378,7 @@ fn check_missing_docs_attrs(
             }
         }
 
-        let has_doc = attrs.iter().any(|a| has_doc(a));
+        let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
         if !has_doc {
             cx.struct_span_lint(
                 MISSING_DOCS,
@@ -391,10 +392,10 @@ fn check_missing_docs_attrs(
 }
 
 impl<'tcx> LateLintPass<'tcx> for MissingDoc {
-    fn enter_lint_attrs(&mut self, _: &LateContext<'_>, attrs: &[ast::Attribute]) {
+    fn enter_lint_attrs(&mut self, cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
         let doc_hidden = self.doc_hidden()
             || attrs.iter().any(|attr| {
-                attr.check_name(sym::doc)
+                cx.sess().check_name(attr, sym::doc)
                     && match attr.meta_item_list() {
                         None => false,
                         Some(l) => attr::list_contains_name(&l, sym::hidden),
@@ -411,7 +412,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) {
         self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate");
 
         for macro_def in krate.exported_macros {
-            let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
+            let has_doc = macro_def.attrs.iter().any(|a| has_doc(cx.sess(), a));
             if !has_doc {
                 cx.struct_span_lint(
                     MISSING_DOCS,
@@ -737,7 +738,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
                 return;
             }
         }
-        if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
+        if cx.sess().check_name(attr, sym::no_start) || cx.sess().check_name(attr, sym::crate_id) {
             let path_str = pprust::path_to_string(&attr.get_normal_item().path);
             let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
             lint_deprecated_attr(cx, attr, &msg, None);
@@ -763,7 +764,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
 
         let span = sugared_span.take().unwrap_or_else(|| attr.span);
 
-        if attr.is_doc_comment() || attr.check_name(sym::doc) {
+        if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) {
             cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
                 let mut err = lint.build("unused doc comment");
                 err.span_label(
@@ -819,7 +820,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         match it.kind {
             hir::ItemKind::Fn(.., ref generics, _) => {
-                if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
+                if let Some(no_mangle_attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
                     for param in generics.params {
                         match param.kind {
                             GenericParamKind::Lifetime { .. } => {}
@@ -845,7 +846,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                 }
             }
             hir::ItemKind::Const(..) => {
-                if attr::contains_name(&it.attrs, sym::no_mangle) {
+                if cx.sess().contains_name(&it.attrs, sym::no_mangle) {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
                     cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
@@ -938,11 +939,11 @@ fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
 );
 
 impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
-    fn check_attribute(&mut self, ctx: &LateContext<'_>, attr: &ast::Attribute) {
-        if attr.check_name(sym::feature) {
+    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
+        if cx.sess().check_name(attr, sym::feature) {
             if let Some(items) = attr.meta_item_list() {
                 for item in items {
-                    ctx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
+                    cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
                         lint.build("unstable feature").emit()
                     });
                 }
@@ -1381,7 +1382,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
             return;
         }
 
-        if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
+        if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::rustc_test_marker) {
             cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
                 lint.build("cannot test inner items").emit()
             });
@@ -2131,7 +2132,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName
                     overridden_link_name,
                     tcx.get_attrs(did.to_def_id())
                         .iter()
-                        .find(|at| at.check_name(sym::link_name))
+                        .find(|at| tcx.sess.check_name(at, sym::link_name))
                         .unwrap()
                         .span,
                 )
index 2e9cd962a7401e13f4979f6db1895b6686c0c84c..145a07d8dc852d27f8a1bdbd1969983c0232564a 100644 (file)
@@ -125,7 +125,7 @@ pub fn push(
             };
 
             let meta = unwrap_or!(attr.meta(), continue);
-            attr::mark_used(attr);
+            self.sess.mark_attr_used(attr);
 
             let mut metas = unwrap_or!(meta.meta_item_list(), continue);
 
index dc6b8670498c21079c7f6dae1ed25491f0a09138..5ca6f461048c3fc2b7f70f4e7ffd974d688d74fc 100644 (file)
@@ -127,7 +127,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = it
             .attrs
             .iter()
-            .any(|attr| attr::find_repr_attrs(&cx.sess.parse_sess, attr).contains(&attr::ReprC));
+            .any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC));
 
         if has_repr_c {
             return;
@@ -263,7 +263,8 @@ fn check_mod(
         let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
             Some(Ident::from_str(name))
         } else {
-            attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
+            cx.sess()
+                .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
                 .and_then(|attr| attr.meta())
                 .and_then(|meta| {
                     meta.name_value_literal().and_then(|lit| {
@@ -327,7 +328,7 @@ fn check_fn(
             },
             FnKind::ItemFn(ident, _, header, _, attrs) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
-                if header.abi != Abi::Rust && attr::contains_name(attrs, sym::no_mangle) {
+                if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
                     return;
                 }
                 self.check_snake_case(cx, "function", ident);
@@ -407,7 +408,7 @@ fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
 impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         match it.kind {
-            hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => {
+            hir::ItemKind::Static(..) if !cx.sess().contains_name(&it.attrs, sym::no_mangle) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
             }
             hir::ItemKind::Const(..) => {
index de750010ed1e6e1af3a4557d615508191e424809..5c53e435fd76c82e92a76c999081628a405177bc 100644 (file)
@@ -538,7 +538,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
             let guaranteed_nonnull_optimization = tcx
                 .get_attrs(def.did)
                 .iter()
-                .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed));
+                .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed));
 
             if guaranteed_nonnull_optimization {
                 return true;
@@ -556,6 +556,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
         _ => false,
     }
 }
+
 /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
 /// If the type passed in was not scalar, returns None.
 fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
@@ -1074,7 +1075,7 @@ fn check_type_for_ffi_and_report_errors(
             }
             // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
             // argument, which after substitution, is `()`, then this branch can be hit.
-            FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return,
+            FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
             FfiResult::FfiUnsafe { ty, reason, help } => {
                 self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
             }
index 1e98ddbd7db4a1849c988b9595e2a5cb206ce1b6..5de9a16e098819e5161ec22488f6a6cf118d2e40 100644 (file)
@@ -2,7 +2,6 @@
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast::ast;
 use rustc_ast::ast::{ExprKind, StmtKind};
-use rustc_ast::attr;
 use rustc_ast::util::parser;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
@@ -242,7 +241,7 @@ fn check_must_use_def(
             descr_post_path: &str,
         ) -> bool {
             for attr in cx.tcx.get_attrs(def_id).iter() {
-                if attr.check_name(sym::must_use) {
+                if cx.sess().check_name(attr, sym::must_use) {
                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
                         let msg = format!(
                             "unused {}`{}`{} that must be used",
@@ -331,7 +330,7 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
             }
         }
 
-        if !attr::is_used(attr) {
+        if !cx.sess().is_attr_used(attr) {
             debug!("emitting warning for: {:?}", attr);
             cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
                 lint.build("unused attribute").emit()
index 9bc6c054e4d018840cc20987e946dfeb6cbf0561..e15655e3794f53d71c5d6faca100935c0b830ea8 100644 (file)
@@ -4,8 +4,8 @@
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
-use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
-use rustc_ast::{ast, attr};
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_ast::{ast, visit};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
@@ -636,7 +636,8 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // compilation mode also comes into play.
         let desired_strategy = self.sess.panic_strategy();
         let mut runtime_found = false;
-        let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
+        let mut needs_panic_runtime =
+            self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
 
         self.cstore.iter_crate_data(|cnum, data| {
             needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
@@ -716,7 +717,7 @@ fn inject_profiler_runtime(&mut self) {
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
-        self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
+        self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
             [span1, span2, ..] => {
                 self.sess
                     .struct_span_err(*span2, "cannot define multiple global allocators")
@@ -731,7 +732,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         // Check to see if we actually need an allocator. This desire comes
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
-        let mut needs_allocator = attr::contains_name(&krate.attrs, sym::needs_allocator);
+        let mut needs_allocator = self.sess.contains_name(&krate.attrs, sym::needs_allocator);
         self.cstore.iter_crate_data(|_, data| {
             needs_allocator = needs_allocator || data.needs_allocator();
         });
@@ -785,7 +786,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         // allocator. At this point our allocator request is typically fulfilled
         // by the standard library, denoted by the `#![default_lib_allocator]`
         // attribute.
-        let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator);
+        let mut has_default = self.sess.contains_name(&krate.attrs, sym::default_lib_allocator);
         self.cstore.iter_crate_data(|_, data| {
             if data.has_default_lib_allocator() {
                 has_default = true;
@@ -895,12 +896,12 @@ pub fn process_extern_crate(
                 );
                 let name = match orig_name {
                     Some(orig_name) => {
-                        validate_crate_name(Some(self.sess), &orig_name.as_str(), Some(item.span));
+                        validate_crate_name(self.sess, &orig_name.as_str(), Some(item.span));
                         orig_name
                     }
                     None => item.ident.name,
                 };
-                let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
+                let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) {
                     CrateDepKind::MacrosOnly
                 } else {
                     CrateDepKind::Explicit
@@ -945,3 +946,26 @@ pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
         self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
     }
 }
+
+fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
+    struct Finder<'a> {
+        sess: &'a Session,
+        name: Symbol,
+        spans: Vec<Span>,
+    }
+    impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+        fn visit_item(&mut self, item: &'ast ast::Item) {
+            if item.ident.name == self.name
+                && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+            {
+                self.spans.push(item.span);
+            }
+            visit::walk_item(self, item)
+        }
+    }
+
+    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
+    let mut f = Finder { sess, name, spans: Vec::new() };
+    visit::walk_crate(&mut f, krate);
+    f.spans
+}
index c5a43b91b5e9b050baabbd28ad1481c10fff6870..d8f16796083f221112fefa187a5bb8f1e36ede33 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
-    let mut collector = Collector { args: Vec::new() };
+    let mut collector = Collector { tcx, args: Vec::new() };
     tcx.hir().krate().visit_all_item_likes(&mut collector);
 
     for attr in tcx.hir().krate().item.attrs.iter() {
     collector.args
 }
 
-struct Collector {
+struct Collector<'tcx> {
+    tcx: TyCtxt<'tcx>,
     args: Vec<String>,
 }
 
-impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
+impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
     fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         let fm = match it.kind {
             hir::ItemKind::ForeignMod(ref fm) => fm,
@@ -34,7 +35,8 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         }
 
         // First, add all of the custom #[link_args] attributes
-        for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) {
+        let sess = &self.tcx.sess;
+        for m in it.attrs.iter().filter(|a| sess.check_name(a, sym::link_args)) {
             if let Some(linkarg) = m.value_str() {
                 self.add_link_args(linkarg);
             }
@@ -45,7 +47,7 @@ fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
     fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
 }
 
-impl Collector {
+impl<'tcx> Collector<'tcx> {
     fn add_link_args(&mut self, args: Symbol) {
         self.args.extend(args.as_str().split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string()))
     }
index d01c598d059c0a468e6b0ffd17f2aedb39bd84d4..3976475cb063e4b02713d983f32a90ceb9dd1e91 100644 (file)
@@ -43,7 +43,8 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         }
 
         // Process all of the #[link(..)]-style arguments
-        for m in it.attrs.iter().filter(|a| a.check_name(sym::link)) {
+        let sess = &self.tcx.sess;
+        for m in it.attrs.iter().filter(|a| sess.check_name(a, sym::link)) {
             let items = match m.meta_item_list() {
                 Some(item) => item,
                 None => continue,
@@ -71,16 +72,10 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                         "framework" => NativeLibKind::Framework,
                         "raw-dylib" => NativeLibKind::RawDylib,
                         k => {
-                            struct_span_err!(
-                                self.tcx.sess,
-                                item.span(),
-                                E0458,
-                                "unknown kind: `{}`",
-                                k
-                            )
-                            .span_label(item.span(), "unknown kind")
-                            .span_label(m.span, "")
-                            .emit();
+                            struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
+                                .span_label(item.span(), "unknown kind")
+                                .span_label(m.span, "")
+                                .emit();
                             NativeLibKind::Unspecified
                         }
                     };
@@ -92,18 +87,18 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                         None => continue, // skip like historical compilers
                     };
                     if cfg.is_empty() {
-                        self.tcx.sess.span_err(item.span(), "`cfg()` must have an argument");
+                        sess.span_err(item.span(), "`cfg()` must have an argument");
                     } else if let cfg @ Some(..) = cfg[0].meta_item() {
                         lib.cfg = cfg.cloned();
                     } else {
-                        self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
+                        sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
                     }
                 } 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 = \"...\")]`";
-                            self.tcx.sess.span_err(item.span(), msg);
+                            sess.span_err(item.span(), msg);
                         }
                     }
                 } else {
@@ -117,7 +112,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
             let requires_name = kind_specified || lib.wasm_import_module.is_none();
             if lib.name.is_none() && requires_name {
                 struct_span_err!(
-                    self.tcx.sess,
+                    sess,
                     m.span,
                     E0459,
                     "`#[link(...)]` specified without \
index 3c045df45da161a35daf4ee15a2e80b022b220b6..8aea9a9f5885061312aa0c18e9710bf22bf57cb9 100644 (file)
@@ -78,7 +78,8 @@
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[DefIndex]>>,
+    trait_impls:
+        FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
@@ -741,7 +742,7 @@ fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
         };
 
         SyntaxExtension::new(
-            &sess.parse_sess,
+            sess,
             kind,
             self.get_span(id, sess),
             helper_attrs,
@@ -1101,7 +1102,7 @@ fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
                                 // for other constructors correct visibilities
                                 // were already encoded in metadata.
                                 let attrs = self.get_item_attrs(def_id.index, sess);
-                                if attr::contains_name(&attrs, sym::non_exhaustive) {
+                                if sess.contains_name(&attrs, sym::non_exhaustive) {
                                     let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
                                     vis = ty::Visibility::Restricted(crate_def_id);
                                 }
@@ -1150,7 +1151,7 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
             .decode((self, tcx))
     }
 
-    fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> {
+    fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
         self.root
             .tables
             .unused_generic_params
@@ -1289,7 +1290,7 @@ fn get_implementations_for_trait(
         &self,
         tcx: TyCtxt<'tcx>,
         filter: Option<DefId>,
-    ) -> &'tcx [DefId] {
+    ) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
         if self.root.is_proc_macro_crate() {
             // proc-macro crates export no trait impls.
             return &[];
@@ -1305,16 +1306,20 @@ fn get_implementations_for_trait(
 
         if let Some(filter) = filter {
             if let Some(impls) = self.trait_impls.get(&filter) {
-                tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
+                tcx.arena.alloc_from_iter(
+                    impls.decode(self).map(|(idx, simplified_self_ty)| {
+                        (self.local_def_id(idx), simplified_self_ty)
+                    }),
+                )
             } else {
                 &[]
             }
         } else {
-            tcx.arena.alloc_from_iter(
-                self.trait_impls
-                    .values()
-                    .flat_map(|impls| impls.decode(self).map(|idx| self.local_def_id(idx))),
-            )
+            tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| {
+                impls
+                    .decode(self)
+                    .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+            }))
         }
     }
 
index e51862be9a86fde19f8bf13abde658cf4de8e5a2..10b89cdd15a527baf88b75007bbcbadfe30adff8 100644 (file)
@@ -5,7 +5,6 @@
 use crate::rmeta::{self, encoder};
 
 use rustc_ast::ast;
-use rustc_ast::attr;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
@@ -37,7 +36,7 @@ pub fn provide_extern(providers: &mut Providers) {
                 def_id_arg: ty::query::query_keys::$name<$lt>,
             ) -> ty::query::query_values::$name<$lt> {
                 let _prof_timer =
-                    $tcx.prof.generic_activity("metadata_decode_entry");
+                    $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name)));
 
                 #[allow(unused_variables)]
                 let ($def_id, $other) = def_id_arg.into_args();
@@ -415,7 +414,7 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index, sess);
         for attr in attrs.iter() {
-            attr::mark_used(attr);
+            sess.mark_attr_used(attr);
         }
 
         let ident = data.item_ident(id.index, sess);
index 6872693a66cb84f2d5b696a623f12406839874ff..f75f0b74a0e1e19eed3290bd55e477826e1e6f50 100644 (file)
@@ -3,7 +3,6 @@
 
 use log::{debug, trace};
 use rustc_ast::ast;
-use rustc_ast::attr;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::StableHasher;
@@ -162,7 +161,7 @@ impl<'a, 'tcx> SpecializedEncoder<ExpnId> for EncodeContext<'a, 'tcx> {
     fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
         rustc_span::hygiene::raw_encode_expn_id(
             *expn,
-            &mut self.hygiene_ctxt,
+            &self.hygiene_ctxt,
             ExpnDataEncodeMode::Metadata,
             self,
         )
@@ -637,7 +636,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
         let source_map_bytes = self.position() - i;
 
         let attrs = tcx.hir().krate_attrs();
-        let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
+        let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
 
         let root = self.lazy(CrateRoot {
             name: tcx.crate_name(LOCAL_CRATE),
@@ -663,12 +662,12 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
             } else {
                 None
             },
-            compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
-            needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
-            needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
-            no_builtins: attr::contains_name(&attrs, sym::no_builtins),
-            panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
-            profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
+            compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
+            needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
+            needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
+            no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
+            panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
+            profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
             symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
 
             crate_deps,
@@ -1138,8 +1137,11 @@ fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
         debug!("EntryBuilder::encode_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
             record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
-            record!(self.tables.unused_generic_params[def_id.to_def_id()] <-
-                    self.tcx.unused_generic_params(def_id));
+
+            let unused = self.tcx.unused_generic_params(def_id);
+            if !unused.is_empty() {
+                record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
+            }
         }
     }
 
@@ -1611,7 +1613,7 @@ fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
             .into_iter()
             .map(|(trait_def_id, mut impls)| {
                 // Bring everything into deterministic order for hashing
-                impls.sort_by_cached_key(|&index| {
+                impls.sort_by_cached_key(|&(index, _)| {
                     tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index })
                 });
 
@@ -1853,7 +1855,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
 
 struct ImplVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    impls: FxHashMap<DefId, Vec<DefIndex>>,
+    impls: FxHashMap<DefId, Vec<(DefIndex, Option<ty::fast_reject::SimplifiedType>)>>,
 }
 
 impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
@@ -1861,7 +1863,13 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Impl { .. } = item.kind {
             let impl_id = self.tcx.hir().local_def_id(item.hir_id);
             if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id.to_def_id()) {
-                self.impls.entry(trait_ref.def_id).or_default().push(impl_id.local_def_index);
+                let simplified_self_ty =
+                    ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false);
+
+                self.impls
+                    .entry(trait_ref.def_id)
+                    .or_default()
+                    .push((impl_id.local_def_index, simplified_self_ty));
             }
         }
     }
index 12d2f50363c1a85e343e7fbccfd6e196c65b0d1d..1c287be9f6bbcc238f7b83c38b0858b3f77473f0 100644 (file)
@@ -233,7 +233,7 @@ macro_rules! Lazy {
 #[derive(RustcEncodable, RustcDecodable)]
 crate struct TraitImpls {
     trait_id: (u32, DefIndex),
-    impls: Lazy<[DefIndex]>,
+    impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>,
 }
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
@@ -285,7 +285,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
-    unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>,
+    unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
index 85198482bd380a4b32c49aabb7d2ea1711e9b5eb..e982053948479c59c8b75130b5dbeaf0021441b6 100644 (file)
@@ -27,7 +27,7 @@ fn update_limit(
     default: usize,
 ) {
     for attr in &krate.attrs {
-        if !attr.check_name(name) {
+        if !sess.check_name(attr, name) {
             continue;
         }
 
index 82365ef6a73de8ebb2e5f05ad0af9d2717b3a328..6b1514da6441de474a19c738e3a9b92a7865105f 100644 (file)
@@ -4,8 +4,11 @@
 pub mod count_code_region_args {
     pub const FUNCTION_SOURCE_HASH: usize = 0;
     pub const COUNTER_ID: usize = 1;
-    pub const START_BYTE_POS: usize = 2;
-    pub const END_BYTE_POS: usize = 3;
+    pub const FILE_NAME: usize = 2;
+    pub const START_LINE: usize = 3;
+    pub const START_COL: usize = 4;
+    pub const END_LINE: usize = 5;
+    pub const END_COL: usize = 6;
 }
 
 /// Positional arguments to `libcore::coverage_counter_add()` and
@@ -14,12 +17,18 @@ pub mod coverage_counter_expression_args {
     pub const EXPRESSION_ID: usize = 0;
     pub const LEFT_ID: usize = 1;
     pub const RIGHT_ID: usize = 2;
-    pub const START_BYTE_POS: usize = 3;
-    pub const END_BYTE_POS: usize = 4;
+    pub const FILE_NAME: usize = 3;
+    pub const START_LINE: usize = 4;
+    pub const START_COL: usize = 5;
+    pub const END_LINE: usize = 6;
+    pub const END_COL: usize = 7;
 }
 
 /// Positional arguments to `libcore::coverage_unreachable()`
 pub mod coverage_unreachable_args {
-    pub const START_BYTE_POS: usize = 0;
-    pub const END_BYTE_POS: usize = 1;
+    pub const FILE_NAME: usize = 0;
+    pub const START_LINE: usize = 1;
+    pub const START_COL: usize = 2;
+    pub const END_LINE: usize = 3;
+    pub const END_COL: usize = 4;
 }
index 2c76f0b5ad0222bf6cc2cb3c598a36d13c9491b3..b4e7a5b98e33ba6296a957f4973a0ed8d53159f5 100644 (file)
@@ -56,6 +56,15 @@ pub fn try_to_scalar(&self) -> Option<Scalar> {
         }
     }
 
+    pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
+        if let ConstValue::Slice { data, start, end } = *self {
+            ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
+                .ok()
+        } else {
+            None
+        }
+    }
+
     pub fn try_to_bits(&self, size: Size) -> Option<u128> {
         self.try_to_scalar()?.to_bits(size).ok()
     }
index 31b8de500e0304c2a086c5057ba262c29390b73c..3b0c480f6d400458cb0f40b906fc9ceea216ab82 100644 (file)
@@ -2,7 +2,7 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
-use crate::mir::interpret::{GlobalAlloc, Scalar};
+use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -1842,6 +1842,33 @@ pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar {
         }
     }
 
+    /// Convenience helper to make a literal-like constant from a given `&str` slice.
+    /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+    pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> {
+        let tcx = tcx;
+        let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes());
+        let allocation = tcx.intern_const_alloc(allocation);
+        let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() };
+        let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_);
+        Operand::Constant(box Constant {
+            span,
+            user_ty: None,
+            literal: ty::Const::from_value(tcx, const_val, ty),
+        })
+    }
+
+    /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand`
+    /// wraps a constant value (such as a `&str` slice). Panics if this is not the case.
+    pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> {
+        match operand {
+            Operand::Constant(constant) => match constant.literal.val.try_to_value() {
+                Some(const_value) => const_value,
+                _ => panic!("{:?}: ConstValue expected", constant.literal.val),
+            },
+            _ => panic!("{:?}: Constant expected", operand),
+        }
+    }
+
     pub fn to_copy(&self) -> Self {
         match *self {
             Operand::Copy(_) | Operand::Constant(_) => self.clone(),
index 862c046358b8418f539c12c44158ae46127fab79..a8f6723a35605c281d5bb964dffe0798708d05f3 100644 (file)
@@ -1125,11 +1125,11 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
 
     TypeChecking {
         query implementations_of_trait(_: (CrateNum, DefId))
-            -> &'tcx [DefId] {
+            -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
             desc { "looking up implementations of a trait in a crate" }
         }
         query all_trait_implementations(_: CrateNum)
-            -> &'tcx [DefId] {
+            -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
             desc { "looking up all (?) trait implementations" }
         }
     }
@@ -1319,7 +1319,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
             desc { "codegen_unit" }
         }
-        query unused_generic_params(key: DefId) -> FiniteBitSet<u64> {
+        query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
             cache_on_disk_if { key.is_local() }
             desc {
                 |tcx| "determining which generic parameters are unused by `{}`",
index 69696ac9e93c062dbd36636b7394b39d149e3541..4b7663e9adec1364c8472f4ee0dd208c0596021a 100644 (file)
@@ -128,7 +128,7 @@ pub struct DropckOutlivesResult<'tcx> {
 
 impl<'tcx> DropckOutlivesResult<'tcx> {
     pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
-        if let Some(overflow_ty) = self.overflows.iter().next() {
+        if let Some(overflow_ty) = self.overflows.get(0) {
             let mut err = struct_span_err!(
                 tcx.sess,
                 span,
index 6cbf5db8373a074be799c098a1eea09b50b71fcb..d6bcfbf49cff12b2c67c7800d16231d9f637bc52 100644 (file)
@@ -1040,7 +1040,7 @@ pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
     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 attr = match attrs.iter().find(|a| a.check_name(name)) {
+            let attr = match attrs.iter().find(|a| self.sess.check_name(a, name)) {
                 Some(attr) => attr,
                 None => return Bound::Unbounded,
             };
@@ -1380,7 +1380,9 @@ pub fn borrowck_mode(self) -> BorrowckMode {
     /// we still evaluate them eagerly.
     #[inline]
     pub fn lazy_normalization(self) -> bool {
-        self.features().const_generics || self.features().lazy_normalization_consts
+        let features = self.features();
+        // Note: We do not enable lazy normalization for `features.min_const_generics`.
+        features.const_generics || features.lazy_normalization_consts
     }
 
     #[inline]
@@ -2736,11 +2738,11 @@ pub fn provide(providers: &mut ty::query::Providers) {
     };
     providers.is_panic_runtime = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
+        tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
     };
     providers.is_compiler_builtins = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
+        tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
     };
     providers.has_panic_handler = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
index 27f50c240db67e61233673ff82d45584b0cbe9e3..81f7474962c8d503a6f54c7d1368ac1c592b803e 100644 (file)
@@ -85,6 +85,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::Generator(_, ref substs, _) => {
+                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
                 let substs = substs.as_generator();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -107,6 +109,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::Closure(_, substs) => {
+                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
                 let substs = substs.as_closure();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -192,6 +196,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::FnDef(_, substs) => {
+                self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
                 self.add_substs(substs);
             }
 
index 492f8ce9ef1a9d1afd832535d5a91b7a7edf1b35..87434f3f26777606c905d4bea721d7676aeb8846 100644 (file)
@@ -150,6 +150,12 @@ fn still_further_specializable(&self) -> bool {
         self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
     }
 
+    /// Does this value contain closures, generators or functions such that it may require
+    /// polymorphization?
+    fn may_polymorphize(&self) -> bool {
+        self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE)
+    }
+
     /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
     fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {
         pub struct Visitor<F>(F);
index 289a9db7327e0d1e344996de1fd5af74b4d79dad..cf876db26bc76a66f4e8fa7dca30ea468f32051d 100644 (file)
@@ -474,26 +474,7 @@ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
         }
 
         if let InstanceDef::Item(def) = self.def {
-            let unused = tcx.unused_generic_params(def.did);
-
-            if unused.is_empty() {
-                // Exit early if every parameter was used.
-                return self;
-            }
-
-            debug!("polymorphize: unused={:?}", unused);
-            let polymorphized_substs =
-                InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
-                // If parameter is a const or type parameter..
-                ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
-                    // ..and is within range and unused..
-                    unused.contains(param.index).unwrap_or(false) =>
-                        // ..then use the identity for this parameter.
-                        tcx.mk_param_from_def(param),
-                // Otherwise, use the parameter as before.
-                _ => self.substs[param.index as usize],
-            });
-
+            let polymorphized_substs = polymorphize(tcx, def.did, self.substs);
             debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
             Self { def: self.def, substs: polymorphized_substs }
         } else {
@@ -502,6 +483,82 @@ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
     }
 }
 
+fn polymorphize<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    substs: SubstsRef<'tcx>,
+) -> SubstsRef<'tcx> {
+    debug!("polymorphize({:?}, {:?})", def_id, substs);
+    let unused = tcx.unused_generic_params(def_id);
+    debug!("polymorphize: unused={:?}", unused);
+
+    struct PolymorphizationFolder<'tcx> {
+        tcx: TyCtxt<'tcx>,
+    };
+
+    impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> {
+        fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+            debug!("fold_ty: ty={:?}", ty);
+            match ty.kind {
+                ty::Closure(def_id, substs) => {
+                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    if substs == polymorphized_substs {
+                        ty
+                    } else {
+                        self.tcx.mk_closure(def_id, polymorphized_substs)
+                    }
+                }
+                ty::FnDef(def_id, substs) => {
+                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    if substs == polymorphized_substs {
+                        ty
+                    } else {
+                        self.tcx.mk_fn_def(def_id, polymorphized_substs)
+                    }
+                }
+                ty::Generator(def_id, substs, movability) => {
+                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    if substs == polymorphized_substs {
+                        ty
+                    } else {
+                        self.tcx.mk_generator(def_id, polymorphized_substs, movability)
+                    }
+                }
+                _ => ty.super_fold_with(self),
+            }
+        }
+    }
+
+    InternalSubsts::for_item(tcx, def_id, |param, _| {
+        let is_unused = unused.contains(param.index).unwrap_or(false);
+        debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
+        match param.kind {
+            // If parameter is a const or type parameter..
+            ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
+                // ..and is within range and unused..
+                unused.contains(param.index).unwrap_or(false) =>
+                    // ..then use the identity for this parameter.
+                    tcx.mk_param_from_def(param),
+
+            // If the parameter does not contain any closures or generators, then use the
+            // substitution directly.
+            _ if !substs.may_polymorphize() => substs[param.index as usize],
+
+            // Otherwise, use the substitution after polymorphizing.
+            _ => {
+                let arg = substs[param.index as usize];
+                let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx });
+                debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg);
+                ty::GenericArg::from(polymorphized_arg)
+            }
+        }
+    })
+}
+
 fn needs_fn_once_adapter_shim(
     actual_closure_kind: ty::ClosureKind,
     trait_closure_kind: ty::ClosureKind,
index bd45f866abc8bbbdacd7f717ea086bcf2b391d0d..0102225b9b56773e790a396afb30be831cb8f17f 100644 (file)
@@ -575,6 +575,10 @@ pub struct TypeFlags: u32 {
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
         const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+
+        /// Does this value contain closures, generators or functions such that it may require
+        /// polymorphization?
+        const MAY_POLYMORPHIZE = 1 << 18;
     }
 }
 
@@ -2261,7 +2265,7 @@ pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
         let mut max_align: Option<Align> = None;
         let mut min_pack: Option<Align> = None;
         for attr in tcx.get_attrs(did).iter() {
-            for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) {
+            for r in attr::find_repr_attrs(&tcx.sess, attr) {
                 flags.insert(match r {
                     attr::ReprC => ReprFlags::IS_C,
                     attr::ReprPacked(pack) => {
@@ -2378,7 +2382,7 @@ fn new(
         }
 
         let attrs = tcx.get_attrs(did);
-        if attr::contains_name(&attrs, sym::fundamental) {
+        if tcx.sess.contains_name(&attrs, sym::fundamental) {
             flags |= AdtFlags::IS_FUNDAMENTAL;
         }
         if Some(did) == tcx.lang_items().phantom_data() {
@@ -3017,7 +3021,7 @@ pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> {
 
     /// Determines whether an item is annotated with an attribute.
     pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
-        attr::contains_name(&self.get_attrs(did), attr)
+        self.sess.contains_name(&self.get_attrs(did), attr)
     }
 
     /// Returns `true` if this is an `auto trait`.
index 1811d945a1d152fc26ed05b8f35d892458599e96..bd2e7747b7db8abb8e46db49284c550fb294fe97 100644 (file)
@@ -15,16 +15,12 @@ pub unsafe fn handle_deadlock() {
     rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
     let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
 
-    let span_session_globals = rustc_span::SESSION_GLOBALS.with(|ssg| ssg as *const _);
-    let span_session_globals = &*span_session_globals;
-    let ast_session_globals = rustc_ast::attr::SESSION_GLOBALS.with(|asg| asg as *const _);
-    let ast_session_globals = &*ast_session_globals;
+    let session_globals = rustc_span::SESSION_GLOBALS.with(|sg| sg as *const _);
+    let session_globals = &*session_globals;
     thread::spawn(move || {
         tls::enter_context(icx, |_| {
-            rustc_ast::attr::SESSION_GLOBALS.set(ast_session_globals, || {
-                rustc_span::SESSION_GLOBALS
-                    .set(span_session_globals, || tls::with(|tcx| deadlock(tcx, &registry)))
-            });
+            rustc_span::SESSION_GLOBALS
+                .set(session_globals, || tls::with(|tcx| deadlock(tcx, &registry)))
         })
     });
 }
index e9fd67a748c857835b2a8602d2f40f11966a2216..866b529f35ec381d4e751e0d835942b167ba859a 100644 (file)
@@ -425,8 +425,7 @@ fn subst_spanned(
         substs: &[GenericArg<'tcx>],
         span: Option<Span>,
     ) -> T {
-        let mut folder =
-            SubstFolder { tcx, substs, span, root_ty: None, ty_stack_depth: 0, binders_passed: 0 };
+        let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
         (*self).fold_with(&mut folder)
     }
 }
@@ -441,12 +440,6 @@ struct SubstFolder<'a, 'tcx> {
     /// The location for which the substitution is performed, if available.
     span: Option<Span>,
 
-    /// The root type that is being substituted, if available.
-    root_ty: Option<Ty<'tcx>>,
-
-    /// Depth of type stack
-    ty_stack_depth: usize,
-
     /// Number of region binders we have passed through while doing the substitution
     binders_passed: u32,
 }
@@ -478,9 +471,8 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                         let span = self.span.unwrap_or(DUMMY_SP);
                         let msg = format!(
                             "Region parameter out of range \
-                             when substituting in region {} (root type={:?}) \
-                             (index={})",
-                            data.name, self.root_ty, data.index
+                             when substituting in region {} (index={})",
+                            data.name, data.index
                         );
                         span_bug!(span, "{}", msg);
                     }
@@ -495,25 +487,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             return t;
         }
 
-        // track the root type we were asked to substitute
-        let depth = self.ty_stack_depth;
-        if depth == 0 {
-            self.root_ty = Some(t);
-        }
-        self.ty_stack_depth += 1;
-
-        let t1 = match t.kind {
+        match t.kind {
             ty::Param(p) => self.ty_for_param(p, t),
             _ => t.super_fold_with(self),
-        };
-
-        assert_eq!(depth + 1, self.ty_stack_depth);
-        self.ty_stack_depth -= 1;
-        if depth == 0 {
-            self.root_ty = None;
         }
-
-        t1
     }
 
     fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
@@ -540,12 +517,11 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
                 span_bug!(
                     span,
                     "expected type for `{:?}` ({:?}/{}) but found {:?} \
-                     when substituting (root type={:?}) substs={:?}",
+                     when substituting, substs={:?}",
                     p,
                     source_ty,
                     p.index,
                     kind,
-                    self.root_ty,
                     self.substs,
                 );
             }
@@ -554,11 +530,10 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
                 span_bug!(
                     span,
                     "type parameter `{:?}` ({:?}/{}) out of range \
-                     when substituting (root type={:?}) substs={:?}",
+                     when substituting, substs={:?}",
                     p,
                     source_ty,
                     p.index,
-                    self.root_ty,
                     self.substs,
                 );
             }
index 8f125098ee68483638ad83c7f2683a7cfc0c3952..f93cce3f4da7f1b1f786f3d883a3a94fb2f12526 100644 (file)
@@ -187,32 +187,38 @@ pub(super) fn all_local_trait_impls<'tcx>(
 pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
     let mut impls = TraitImpls::default();
 
-    {
-        let mut add_impl = |impl_def_id: DefId| {
-            let impl_self_ty = tcx.type_of(impl_def_id);
-            if impl_def_id.is_local() && impl_self_ty.references_error() {
-                return;
-            }
-
-            if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
-                impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
-            } else {
-                impls.blanket_impls.push(impl_def_id);
-            }
-        };
-
-        // Traits defined in the current crate can't have impls in upstream
-        // crates, so we don't bother querying the cstore.
-        if !trait_id.is_local() {
-            for &cnum in tcx.crates().iter() {
-                for &def_id in tcx.implementations_of_trait((cnum, trait_id)).iter() {
-                    add_impl(def_id);
+    // Traits defined in the current crate can't have impls in upstream
+    // crates, so we don't bother querying the cstore.
+    if !trait_id.is_local() {
+        for &cnum in tcx.crates().iter() {
+            for &(impl_def_id, simplified_self_ty) in
+                tcx.implementations_of_trait((cnum, trait_id)).iter()
+            {
+                if let Some(simplified_self_ty) = simplified_self_ty {
+                    impls
+                        .non_blanket_impls
+                        .entry(simplified_self_ty)
+                        .or_default()
+                        .push(impl_def_id);
+                } else {
+                    impls.blanket_impls.push(impl_def_id);
                 }
             }
         }
+    }
+
+    for &hir_id in tcx.hir().trait_impls(trait_id) {
+        let impl_def_id = tcx.hir().local_def_id(hir_id).to_def_id();
+
+        let impl_self_ty = tcx.type_of(impl_def_id);
+        if impl_self_ty.references_error() {
+            continue;
+        }
 
-        for &hir_id in tcx.hir().trait_impls(trait_id) {
-            add_impl(tcx.hir().local_def_id(hir_id).to_def_id());
+        if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
+            impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
+        } else {
+            impls.blanket_impls.push(impl_def_id);
         }
     }
 
index d8f6abd92f6b88a87dcc3fcacda7234a86f0cf77..ba74ffaa8d620f8536dda39b468ab48584061992 100644 (file)
@@ -868,7 +868,7 @@ pub(super) fn move_spans(
                 }
             }
         }
-        return normal_ret;
+        normal_ret
     }
 
     /// Finds the span of arguments of a closure (within `maybe_closure_span`)
index 2113d40a594ebd3b237d7c79c155f847ae9491c7..89e2d7088f7b6b75c29aad6438711857cead658b 100644 (file)
@@ -335,7 +335,7 @@ fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<Self, ()> {
 
         let rustc_mir_attrs = attrs
             .iter()
-            .filter(|attr| attr.check_name(sym::rustc_mir))
+            .filter(|attr| tcx.sess.check_name(attr, 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 8a9edb23a10ef45b2ccaeca6d8cb0c645848540d..fdec5729a542591688ea7e93ecee91d67f56fd50 100644 (file)
@@ -1,5 +1,6 @@
 use rustc_ast::ast::{self, MetaItem};
 use rustc_middle::ty;
+use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 
 pub(crate) use self::drop_flag_effects::*;
@@ -28,9 +29,13 @@ pub struct MoveDataParamEnv<'tcx> {
     pub(crate) param_env: ty::ParamEnv<'tcx>,
 }
 
-pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
+pub(crate) fn has_rustc_mir_with(
+    sess: &Session,
+    attrs: &[ast::Attribute],
+    name: Symbol,
+) -> Option<MetaItem> {
     for attr in attrs {
-        if attr.check_name(sym::rustc_mir) {
+        if sess.check_name(attr, sym::rustc_mir) {
             let items = attr.meta_item_list();
             for item in items.iter().flat_map(|l| l.iter()) {
                 match item.meta_item() {
index a9e6e324eb23a7a26b126741aec7db673f7c6bd0..7dfa913fd08bd07b45daf49c22a829de9313f11d 100644 (file)
@@ -952,7 +952,7 @@ pub fn copy_repeatedly(
 
         if compressed.no_bytes_init() {
             // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
-            // is marked as unititialized but we otherwise omit changing the byte representation which may
+            // is marked as uninitialized but we otherwise omit changing the byte representation which may
             // be arbitrary for uninitialized bytes.
             // This also avoids writing to the target bytes so that the backing allocation is never
             // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
index c0eac8a9305ee7a9a62432100af36da7f046653e..57c5fc59cc0b84aeecf88703d5e751ec6e062e59 100644 (file)
@@ -47,14 +47,26 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
                             unused_params.contains(index).map(|unused| !unused).unwrap_or(true);
                         // Only recurse when generic parameters in fns, closures and generators
                         // are used and require substitution.
-                        if is_used && subst.needs_subst() {
+                        match (is_used, subst.needs_subst()) {
                             // Just in case there are closures or generators within this subst,
                             // recurse.
-                            if subst.super_visit_with(self) {
+                            (true, true) if subst.super_visit_with(self) => {
                                 // Only return when we find a parameter so the remaining substs
                                 // are not skipped.
                                 return true;
                             }
+                            // Confirm that polymorphization replaced the parameter with
+                            // `ty::Param`/`ty::ConstKind::Param`.
+                            (false, true) if cfg!(debug_assertions) => match subst.unpack() {
+                                ty::subst::GenericArgKind::Type(ty) => {
+                                    assert!(matches!(ty.kind, ty::Param(_)))
+                                }
+                                ty::subst::GenericArgKind::Const(ct) => {
+                                    assert!(matches!(ct.val, ty::ConstKind::Param(_)))
+                                }
+                                ty::subst::GenericArgKind::Lifetime(..) => (),
+                            },
+                            _ => {}
                         }
                     }
                     false
index 562f512c5dacfee41c66541490a7822c71bb10d4..a996b6fb9d924bf2e7dfde606ce485b22765a94d 100644 (file)
@@ -15,6 +15,7 @@
     self,
     fold::{TypeFoldable, TypeVisitor},
     query::Providers,
+    subst::SubstsRef,
     Const, Ty, TyCtxt,
 };
 use rustc_span::symbol::sym;
@@ -28,7 +29,7 @@ pub fn provide(providers: &mut Providers) {
 /// Determine which generic parameters are used by the function/method/closure represented by
 /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
 /// indicates all parameters are used).
-fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> {
+fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
     debug!("unused_generic_params({:?})", def_id);
 
     if !tcx.sess.opts.debugging_opts.polymorphize {
@@ -36,6 +37,13 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> {
         return FiniteBitSet::new_empty();
     }
 
+    // Polymorphization results are stored in cross-crate metadata only when there are unused
+    // parameters, so assume that non-local items must have only used parameters (else this query
+    // would not be invoked, and the cross-crate metadata used instead).
+    if !def_id.is_local() {
+        return FiniteBitSet::new_empty();
+    }
+
     let generics = tcx.generics_of(def_id);
     debug!("unused_generic_params: generics={:?}", generics);
 
@@ -53,7 +61,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> {
     // Create a bitset with N rightmost ones for each parameter.
     let generics_count: u32 =
         generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
-    let mut unused_parameters = FiniteBitSet::<u64>::new_empty();
+    let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
     unused_parameters.set_range(0..generics_count);
     debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters);
     mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
@@ -84,7 +92,7 @@ fn mark_used_by_default_parameters<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     generics: &'tcx ty::Generics,
-    unused_parameters: &mut FiniteBitSet<u64>,
+    unused_parameters: &mut FiniteBitSet<u32>,
 ) {
     if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) {
         for param in &generics.params {
@@ -110,11 +118,11 @@ fn mark_used_by_default_parameters<'tcx>(
 fn mark_used_by_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
-    unused_parameters: &mut FiniteBitSet<u64>,
+    unused_parameters: &mut FiniteBitSet<u32>,
 ) {
     let def_id = tcx.closure_base_def_id(def_id);
 
-    let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u64>, self_ty: Ty<'tcx>| {
+    let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u32>, self_ty: Ty<'tcx>| {
         debug!("unused_generic_params: self_ty={:?}", self_ty);
         if let ty::Param(param) = self_ty.kind {
             !unused_parameters.contains(param.index).unwrap_or(false)
@@ -123,7 +131,7 @@ fn mark_used_by_predicates<'tcx>(
         }
     };
 
-    let mark_ty = |unused_parameters: &mut FiniteBitSet<u64>, ty: Ty<'tcx>| {
+    let mark_ty = |unused_parameters: &mut FiniteBitSet<u32>, ty: Ty<'tcx>| {
         let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters };
         ty.visit_with(&mut vis);
     };
@@ -159,11 +167,15 @@ fn emit_unused_generic_params_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     generics: &'tcx ty::Generics,
-    unused_parameters: &FiniteBitSet<u64>,
+    unused_parameters: &FiniteBitSet<u32>,
 ) {
     debug!("emit_unused_generic_params_error: def_id={:?}", def_id);
     let base_def_id = tcx.closure_base_def_id(def_id);
-    if !tcx.get_attrs(base_def_id).iter().any(|a| a.check_name(sym::rustc_polymorphize_error)) {
+    if !tcx
+        .get_attrs(base_def_id)
+        .iter()
+        .any(|a| tcx.sess.check_name(a, sym::rustc_polymorphize_error))
+    {
         return;
     }
 
@@ -195,7 +207,26 @@ fn emit_unused_generic_params_error<'tcx>(
 struct UsedGenericParametersVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
-    unused_parameters: &'a mut FiniteBitSet<u64>,
+    unused_parameters: &'a mut FiniteBitSet<u32>,
+}
+
+impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
+    /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
+    /// a closure, generator or constant).
+    fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
+        let unused = self.tcx.unused_generic_params(def_id);
+        debug!(
+            "visit_child_body: unused_parameters={:?} unused={:?}",
+            self.unused_parameters, unused
+        );
+        for (i, arg) in substs.iter().enumerate() {
+            let i = i.try_into().unwrap();
+            if !unused.contains(i).unwrap_or(false) {
+                arg.visit_with(self);
+            }
+        }
+        debug!("visit_child_body: unused_parameters={:?}", self.unused_parameters);
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
@@ -238,6 +269,17 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
                 self.unused_parameters.clear(param.index);
                 false
             }
+            ty::ConstKind::Unevaluated(_, _, Some(p)) => {
+                // If there is a promoted, don't look at the substs - since it will always contain
+                // the generic parameters, instead, traverse the promoted MIR.
+                let promoted = self.tcx.promoted_mir(self.def_id);
+                self.visit_body(&promoted[p]);
+                false
+            }
+            ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => {
+                self.visit_child_body(def_id.did, unevaluated_substs);
+                false
+            }
             _ => c.super_visit_with(self),
         }
     }
@@ -258,19 +300,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
 
                 // Consider any generic parameters used by any closures/generators as used in the
                 // parent.
-                let unused = self.tcx.unused_generic_params(def_id);
-                debug!(
-                    "visit_ty: unused_parameters={:?} unused={:?}",
-                    self.unused_parameters, unused
-                );
-                for (i, arg) in substs.iter().enumerate() {
-                    let i = i.try_into().unwrap();
-                    if !unused.contains(i).unwrap_or(false) {
-                        arg.visit_with(self);
-                    }
-                }
-                debug!("visit_ty: unused_parameters={:?}", self.unused_parameters);
-
+                self.visit_child_body(def_id, substs);
                 false
             }
             ty::Param(param) => {
index 8e2fd709d66f0102a0b0af4c8b6712776fdfde57..db0b0415728aec2d699d617e22e092d6bf6b245d 100644 (file)
@@ -34,7 +34,9 @@
 };
 use crate::transform::{MirPass, MirSource};
 
-/// The maximum number of bytes that we'll allocate space for a return value.
+/// The maximum number of bytes that we'll allocate space for a local or the return value.
+/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
+/// Severely regress performance.
 const MAX_ALLOC_LIMIT: u64 = 1024;
 
 /// Macro for machine-specific `InterpError` without allocation.
@@ -155,14 +157,19 @@ struct ConstPropMachine<'mir, 'tcx> {
     written_only_inside_own_block_locals: FxHashSet<Local>,
     /// Locals that need to be cleared after every block terminates.
     only_propagate_inside_block_locals: BitSet<Local>,
+    can_const_prop: IndexVec<Local, ConstPropMode>,
 }
 
 impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
-    fn new(only_propagate_inside_block_locals: BitSet<Local>) -> Self {
+    fn new(
+        only_propagate_inside_block_locals: BitSet<Local>,
+        can_const_prop: IndexVec<Local, ConstPropMode>,
+    ) -> Self {
         Self {
             stack: Vec::new(),
             written_only_inside_own_block_locals: Default::default(),
             only_propagate_inside_block_locals,
+            can_const_prop,
         }
     }
 }
@@ -241,6 +248,9 @@ fn access_local_mut<'a>(
         local: Local,
     ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
     {
+        if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
+            throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
+        }
         if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
             ecx.machine.written_only_inside_own_block_locals.insert(local);
         }
@@ -285,7 +295,6 @@ fn stack_mut(
 struct ConstPropagator<'mir, 'tcx> {
     ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
     tcx: TyCtxt<'tcx>,
-    can_const_prop: IndexVec<Local, ConstPropMode>,
     param_env: ParamEnv<'tcx>,
     // FIXME(eddyb) avoid cloning these two fields more than once,
     // by accessing them through `ecx` instead.
@@ -331,7 +340,10 @@ fn new(
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
         let span = tcx.def_span(def_id);
-        let can_const_prop = CanConstProp::check(body);
+        // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
+        // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
+        // `layout_of` query invocations.
+        let can_const_prop = CanConstProp::check(tcx, param_env, body);
         let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
         for (l, mode) in can_const_prop.iter_enumerated() {
             if *mode == ConstPropMode::OnlyInsideOwnBlock {
@@ -342,7 +354,7 @@ fn new(
             tcx,
             span,
             param_env,
-            ConstPropMachine::new(only_propagate_inside_block_locals),
+            ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
             (),
         );
 
@@ -368,7 +380,6 @@ fn new(
             ecx,
             tcx,
             param_env,
-            can_const_prop,
             // FIXME(eddyb) avoid cloning these two fields more than once,
             // by accessing them through `ecx` instead.
             source_scopes: body.source_scopes.clone(),
@@ -612,15 +623,9 @@ fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
     fn const_prop(
         &mut self,
         rvalue: &Rvalue<'tcx>,
-        place_layout: TyAndLayout<'tcx>,
         source_info: SourceInfo,
         place: Place<'tcx>,
     ) -> Option<()> {
-        // #66397: Don't try to eval into large places as that can cause an OOM
-        if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) {
-            return None;
-        }
-
         // Perform any special handling for specific Rvalue types.
         // Generally, checks here fall into one of two categories:
         //   1. Additional checking to provide useful lints to the user
@@ -893,7 +898,11 @@ struct CanConstProp {
 
 impl CanConstProp {
     /// Returns true if `local` can be propagated
-    fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> {
+    fn check(
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        body: &Body<'tcx>,
+    ) -> IndexVec<Local, ConstPropMode> {
         let mut cpv = CanConstProp {
             can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
             found_assignment: BitSet::new_empty(body.local_decls.len()),
@@ -903,6 +912,16 @@ fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> {
             ),
         };
         for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
+            let ty = body.local_decls[local].ty;
+            match tcx.layout_of(param_env.and(ty)) {
+                Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
+                // Either the layout fails to compute, then we can't use this local anyway
+                // or the local is too large, then we don't want to.
+                _ => {
+                    *val = ConstPropMode::NoPropagation;
+                    continue;
+                }
+            }
             // Cannot use args at all
             // Cannot use locals because if x < y { y - x } else { x - y } would
             //        lint for x != y
@@ -1018,61 +1037,52 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
         let source_info = statement.source_info;
         self.source_info = Some(source_info);
         if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
-            let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
-            if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
-                let can_const_prop = self.can_const_prop[place.local];
-                if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
-                    // This will return None if the above `const_prop` invocation only "wrote" a
-                    // type whose creation requires no write. E.g. a generator whose initial state
-                    // consists solely of uninitialized memory (so it doesn't capture any locals).
-                    if let Some(value) = self.get_const(place) {
-                        if self.should_const_prop(value) {
-                            trace!("replacing {:?} with {:?}", rval, value);
-                            self.replace_with_const(rval, value, source_info);
-                            if can_const_prop == ConstPropMode::FullConstProp
-                                || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
-                            {
-                                trace!("propagated into {:?}", place);
-                            }
+            let can_const_prop = self.ecx.machine.can_const_prop[place.local];
+            if let Some(()) = self.const_prop(rval, source_info, place) {
+                // This will return None if the above `const_prop` invocation only "wrote" a
+                // type whose creation requires no write. E.g. a generator whose initial state
+                // consists solely of uninitialized memory (so it doesn't capture any locals).
+                if let Some(value) = self.get_const(place) {
+                    if self.should_const_prop(value) {
+                        trace!("replacing {:?} with {:?}", rval, value);
+                        self.replace_with_const(rval, value, source_info);
+                        if can_const_prop == ConstPropMode::FullConstProp
+                            || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                        {
+                            trace!("propagated into {:?}", place);
                         }
                     }
-                    match can_const_prop {
-                        ConstPropMode::OnlyInsideOwnBlock => {
-                            trace!(
-                                "found local restricted to its block. \
+                }
+                match can_const_prop {
+                    ConstPropMode::OnlyInsideOwnBlock => {
+                        trace!(
+                            "found local restricted to its block. \
                                 Will remove it from const-prop after block is finished. Local: {:?}",
-                                place.local
-                            );
-                        }
-                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
-                            trace!("can't propagate into {:?}", place);
-                            if place.local != RETURN_PLACE {
-                                Self::remove_const(&mut self.ecx, place.local);
-                            }
+                            place.local
+                        );
+                    }
+                    ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+                        trace!("can't propagate into {:?}", place);
+                        if place.local != RETURN_PLACE {
+                            Self::remove_const(&mut self.ecx, place.local);
                         }
-                        ConstPropMode::FullConstProp => {}
                     }
-                } else {
-                    // Const prop failed, so erase the destination, ensuring that whatever happens
-                    // from here on, does not know about the previous value.
-                    // This is important in case we have
-                    // ```rust
-                    // let mut x = 42;
-                    // x = SOME_MUTABLE_STATIC;
-                    // // x must now be undefined
-                    // ```
-                    // FIXME: we overzealously erase the entire local, because that's easier to
-                    // implement.
-                    trace!(
-                        "propagation into {:?} failed.
-                        Nuking the entire site from orbit, it's the only way to be sure",
-                        place,
-                    );
-                    Self::remove_const(&mut self.ecx, place.local);
+                    ConstPropMode::FullConstProp => {}
                 }
             } else {
+                // Const prop failed, so erase the destination, ensuring that whatever happens
+                // from here on, does not know about the previous value.
+                // This is important in case we have
+                // ```rust
+                // let mut x = 42;
+                // x = SOME_MUTABLE_STATIC;
+                // // x must now be undefined
+                // ```
+                // FIXME: we overzealously erase the entire local, because that's easier to
+                // implement.
                 trace!(
-                    "cannot propagate into {:?}, because the type of the local is generic.",
+                    "propagation into {:?} failed.
+                        Nuking the entire site from orbit, it's the only way to be sure",
                     place,
                 );
                 Self::remove_const(&mut self.ecx, place.local);
index fe63a67fdbb34cd1041ce89ce95584d5a37a9c2f..5b2954dd5b0a3e08ebf228722ed6d056f35d9631 100644 (file)
@@ -5,18 +5,19 @@
 use rustc_hir::lang_items;
 use rustc_middle::hir;
 use rustc_middle::ich::StableHashingContext;
+use rustc_middle::mir;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::traversal;
 use rustc_middle::mir::{
-    self, traversal, BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo,
-    SourceScope, StatementKind, Terminator, TerminatorKind,
+    BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, SourceScope,
+    StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::FnDef;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{FnDef, TyCtxt};
 use rustc_span::def_id::DefId;
-use rustc_span::{Pos, Span};
+use rustc_span::{FileName, Pos, RealFileName, Span};
 
 /// Inserts call to count_code_region() as a placeholder to be replaced during code generation with
 /// the intrinsic llvm.instrprof.increment.
@@ -112,6 +113,7 @@ enum Op {
 struct InjectedCall<'tcx> {
     func: Operand<'tcx>,
     args: Vec<Operand<'tcx>>,
+    span: Span,
     inject_at: Span,
 }
 
@@ -179,12 +181,11 @@ fn inject_counters(&mut self) {
         let _ignore = mir_body;
         let id = self.next_counter();
         let function_source_hash = self.function_source_hash();
-        let code_region = body_span;
         let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE;
         let is_cleanup = false;
         let next_block = rustc_middle::mir::START_BLOCK;
         self.inject_call(
-            self.make_counter(id, function_source_hash, code_region),
+            self.make_counter(id, function_source_hash, body_span),
             scope,
             is_cleanup,
             next_block,
@@ -201,14 +202,13 @@ fn inject_counters(&mut self) {
             let op = if add { Op::Add } else { Op::Subtract };
             let rhs = 2;
 
-            let code_region = body_span;
             let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE;
             let is_cleanup = false;
             let next_block = rustc_middle::mir::START_BLOCK;
 
             let id = self.next_expression();
             self.inject_call(
-                self.make_expression(id, code_region, lhs, op, rhs),
+                self.make_expression(id, body_span, lhs, op, rhs),
                 scope,
                 is_cleanup,
                 next_block,
@@ -216,13 +216,8 @@ fn inject_counters(&mut self) {
         }
     }
 
-    fn make_counter(
-        &self,
-        id: u32,
-        function_source_hash: u64,
-        code_region: Span,
-    ) -> InjectedCall<'tcx> {
-        let inject_at = code_region.shrink_to_lo();
+    fn make_counter(&self, id: u32, function_source_hash: u64, span: Span) -> InjectedCall<'tcx> {
+        let inject_at = span.shrink_to_lo();
 
         let func = function_handle(
             self.tcx,
@@ -239,24 +234,18 @@ fn make_counter(
         debug_assert_eq!(COUNTER_ID, args.len());
         args.push(self.const_u32(id, inject_at));
 
-        debug_assert_eq!(START_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.lo().to_u32(), inject_at));
-
-        debug_assert_eq!(END_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.hi().to_u32(), inject_at));
-
-        InjectedCall { func, args, inject_at }
+        InjectedCall { func, args, span, inject_at }
     }
 
     fn make_expression(
         &self,
         id: u32,
-        code_region: Span,
+        span: Span,
         lhs: u32,
         op: Op,
         rhs: u32,
     ) -> InjectedCall<'tcx> {
-        let inject_at = code_region.shrink_to_lo();
+        let inject_at = span.shrink_to_lo();
 
         let func = function_handle(
             self.tcx,
@@ -282,13 +271,7 @@ fn make_expression(
         debug_assert_eq!(RIGHT_ID, args.len());
         args.push(self.const_u32(rhs, inject_at));
 
-        debug_assert_eq!(START_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.lo().to_u32(), inject_at));
-
-        debug_assert_eq!(END_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.hi().to_u32(), inject_at));
-
-        InjectedCall { func, args, inject_at }
+        InjectedCall { func, args, span, inject_at }
     }
 
     fn inject_call(
@@ -298,7 +281,7 @@ fn inject_call(
         is_cleanup: bool,
         next_block: BasicBlock,
     ) {
-        let InjectedCall { func, args, inject_at } = call;
+        let InjectedCall { func, mut args, span, inject_at } = call;
         debug!(
             "  injecting {}call to {:?}({:?}) at: {:?}, scope: {:?}",
             if is_cleanup { "cleanup " } else { "" },
@@ -310,6 +293,14 @@ fn inject_call(
 
         let mut patch = MirPatch::new(self.mir_body);
 
+        let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span);
+
+        args.push(self.const_str(&file_name, inject_at));
+        args.push(self.const_u32(start_line, inject_at));
+        args.push(self.const_u32(start_col, inject_at));
+        args.push(self.const_u32(end_line, inject_at));
+        args.push(self.const_u32(end_col, inject_at));
+
         let temp = patch.new_temp(self.tcx.mk_unit(), inject_at);
         let new_block = patch.new_block(placeholder_block(inject_at, scope, is_cleanup));
         patch.patch_terminator(
@@ -335,6 +326,43 @@ fn inject_call(
         self.mir_body.basic_blocks_mut().swap(next_block, new_block);
     }
 
+    /// Convert the Span into its file name, start line and column, and end line and column
+    fn code_region(&self, span: &Span) -> (String, u32, u32, u32, u32) {
+        let source_map = self.tcx.sess.source_map();
+        let start = source_map.lookup_char_pos(span.lo());
+        let end = if span.hi() == span.lo() {
+            start.clone()
+        } else {
+            let end = source_map.lookup_char_pos(span.hi());
+            debug_assert_eq!(
+                start.file.name,
+                end.file.name,
+                "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!",
+                span.lo(),
+                start,
+                span.hi(),
+                end
+            );
+            end
+        };
+        match &start.file.name {
+            FileName::Real(RealFileName::Named(path)) => (
+                path.to_string_lossy().to_string(),
+                start.line as u32,
+                start.col.to_u32() + 1,
+                end.line as u32,
+                end.col.to_u32() + 1,
+            ),
+            _ => {
+                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)
+            }
+        }
+    }
+
+    fn const_str(&self, value: &str, span: Span) -> Operand<'tcx> {
+        Operand::const_from_str(self.tcx, value, span)
+    }
+
     fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> {
         Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span)
     }
index f1a7338d11fd966180551bf5078984e23c5aae18..c0564105701575f20c9c00150f3be4d61ce602f9 100644 (file)
@@ -130,7 +130,7 @@ fn forces_explicit_promotion(&self) -> bool {
 
 fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
     let attrs = tcx.get_attrs(def_id);
-    let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
+    let attr = attrs.iter().find(|a| tcx.sess.check_name(a, sym::rustc_args_required_const))?;
     let mut ret = vec![];
     for meta in attr.meta_item_list()? {
         match meta.literal()?.kind {
index de7d7f27186f2b4f59a772db0dd7b3fcc7ad096f..dfd01e27d57c99bfbed9259f31104ae9ef2aa704 100644 (file)
@@ -193,7 +193,15 @@ fn check_rvalue(
             _,
         ) => Err((span, "function pointer casts are not allowed in const fn".into())),
         Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => {
-            let pointee_ty = cast_ty.builtin_deref(true).unwrap().ty;
+            let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
+                deref_ty.ty
+            } else {
+                // We cannot allow this for now.
+                return Err((
+                    span,
+                    "unsizing casts are only allowed for references right now".into(),
+                ));
+            };
             let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind {
                 check_operand(tcx, op, span, def_id, body)?;
@@ -334,7 +342,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo
 
     // However, we cannot allow stable `const fn`s to use unstable features without an explicit
     // opt-in via `allow_internal_unstable`.
-    attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+    attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
 
@@ -354,7 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo
 
     // However, we cannot allow stable `const fn`s to use unstable features without an explicit
     // opt-in via `allow_internal_unstable`.
-    attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+    attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
 
index 5eb374e7ee2f107b4c96d51abed5c723f498b2b5..729e22a94dcbb9a003dc72e40607b71a5a2fd92d 100644 (file)
@@ -35,8 +35,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
         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(&attributes, sym::rustc_peek_maybe_init).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() {
             let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body, def_id)
                 .iterate_to_fixpoint();
@@ -44,7 +45,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
             sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits);
         }
 
-        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() {
             let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body, def_id)
                 .iterate_to_fixpoint();
@@ -52,7 +53,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
             sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits);
         }
 
-        if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() {
             let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
                 .into_engine(tcx, body, def_id)
                 .iterate_to_fixpoint();
@@ -60,7 +61,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
             sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits);
         }
 
-        if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
             let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
                 .into_engine(tcx, body, def_id)
                 .iterate_to_fixpoint();
@@ -68,14 +69,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
             sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_mut_borrowed);
         }
 
-        if has_rustc_mir_with(&attributes, sym::rustc_peek_liveness).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
             let flow_liveness =
                 MaybeLiveLocals.into_engine(tcx, body, def_id).iterate_to_fixpoint();
 
             sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_liveness);
         }
 
-        if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() {
+        if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() {
             tcx.sess.fatal("stop_after_dataflow ended compilation");
         }
     }
index 97a01de867e1d4abcbe5895c9e7c21f0e6b66a2e..02896d7de357ff40524e740a303f75264bec4232 100644 (file)
@@ -361,7 +361,7 @@ fn optimization_applies<'tcx>(
     }
 
     trace!("SUCCESS: optimization applies!");
-    return true;
+    true
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
index b8a74f09409ca9822470012995b55b06c2f28e58..9296e2ca7008fdb4840830992c8c052576cf9063 100644 (file)
@@ -115,7 +115,7 @@ fn binders<T>(
             T: Relate<'tcx>,
         {
             self.relate(a.skip_binder(), b.skip_binder())?;
-            Ok(a.clone())
+            Ok(a)
         }
     }
 
index 3c4587119cd55453070a8989e4efe61a3e577413..f3f3c3e33a46d1f64d7191a8419bb2fb5eedfe91 100644 (file)
@@ -537,7 +537,7 @@ macro_rules! unpack {
 fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> bool {
     // Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
     let attrs = &tcx.get_attrs(fn_def_id.to_def_id());
-    let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs);
+    let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs);
 
     // We never unwind, so it's not relevant to stop an unwind.
     if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
index 21736df7b0710fbb3f0c60f42a829a766d009652..bb814ab8248836370c5ffd0ac4ad4c7a0cdaa294 100644 (file)
@@ -6,7 +6,6 @@
 use crate::thir::*;
 
 use rustc_ast::ast;
-use rustc_ast::attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
@@ -69,7 +68,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
         // the settings for the crate they are codegened in.
-        let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
+        let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
 
         // Respect -C overflow-checks.
         check_overflow |= tcx.sess.overflow_checks();
index 2b0e637c74e5ab2b640c73ff36392f0eb2008159..c3a79660eb9b9fb15e2d6dc3c00dc532673a1771 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, CommentKind, Token, TokenKind};
 use rustc_ast::util::comments;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError};
@@ -170,22 +170,20 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok
         match token {
             rustc_lexer::TokenKind::LineComment => {
                 let string = self.str_from(start);
-                // comments with only more "/"s are not doc comments
-                if comments::is_line_doc_comment(string) {
+                if let Some(attr_style) = comments::line_doc_comment_style(string) {
                     self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment");
-                    token::DocComment(Symbol::intern(string))
+                    // Opening delimiter of the length 3 is not included into the symbol.
+                    token::DocComment(CommentKind::Line, attr_style, Symbol::intern(&string[3..]))
                 } else {
                     token::Comment
                 }
             }
             rustc_lexer::TokenKind::BlockComment { terminated } => {
                 let string = self.str_from(start);
-                // block comments starting with "/**" or "/*!" are doc-comments
-                // but comments with only "*"s between two "/"s are not
-                let is_doc_comment = comments::is_block_doc_comment(string);
+                let attr_style = comments::block_doc_comment_style(string, terminated);
 
                 if !terminated {
-                    let msg = if is_doc_comment {
+                    let msg = if attr_style.is_some() {
                         "unterminated block doc-comment"
                     } else {
                         "unterminated block comment"
@@ -202,9 +200,15 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok
                     FatalError.raise();
                 }
 
-                if is_doc_comment {
+                if let Some(attr_style) = attr_style {
                     self.forbid_bare_cr(start, string, "bare CR not allowed in block doc-comment");
-                    token::DocComment(Symbol::intern(string))
+                    // Opening delimiter of the length 3 and closing delimiter of the length 2
+                    // are not included into the symbol.
+                    token::DocComment(
+                        CommentKind::Block,
+                        attr_style,
+                        Symbol::intern(&string[3..string.len() - if terminated { 2 } else { 0 }]),
+                    )
                 } else {
                     token::Comment
                 }
index 3319ca44da467caa38ad8226e918fc5d4a767ed1..723e4333790ae002b108b35591d9fb78d3b81788 100644 (file)
@@ -486,7 +486,9 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool {
 
         (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
 
-        (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b,
+        (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3,
+
+        (&Shebang(a), &Shebang(b)) => a == b,
 
         (&Literal(a), &Literal(b)) => a == b,
 
@@ -524,7 +526,7 @@ fn prepend_attrs(
 
         let item = match attr.kind {
             ast::AttrKind::Normal(ref item) => item,
-            ast::AttrKind::DocComment(_) => {
+            ast::AttrKind::DocComment(..) => {
                 let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
                 builder.push(stream);
                 continue;
index 8b67f4743c6b6e1fa02bec4129ccc1691c82b9a5..b6a8ee71beb0cc029e916498e814b295a78460dd 100644 (file)
@@ -2,10 +2,9 @@
 use rustc_ast::ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Nonterminal};
-use rustc_ast::util::comments;
 use rustc_ast_pretty::pprust;
 use rustc_errors::{error_code, PResult};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 
 use log::debug;
 
@@ -47,8 +46,8 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribut
                 let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                 attrs.push(attr);
                 just_parsed_doc_comment = false;
-            } else if let token::DocComment(s) = self.token.kind {
-                let attr = self.mk_doc_comment(s);
+            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
+                let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span);
                 if attr.style != ast::AttrStyle::Outer {
                     self.sess
                         .span_diagnostic
@@ -73,10 +72,6 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribut
         Ok(attrs)
     }
 
-    fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
-        attr::mk_doc_comment(comments::doc_comment_style(s), s, self.token.span)
-    }
-
     /// Matches `attribute = # ! [ meta_item ]`.
     ///
     /// If `permit_inner` is `true`, then a leading `!` indicates an inner
@@ -184,9 +179,9 @@ pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
                 let attr = self.parse_attribute(true)?;
                 assert_eq!(attr.style, ast::AttrStyle::Inner);
                 attrs.push(attr);
-            } else if let token::DocComment(s) = self.token.kind {
+            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                 // We need to get the position of this token before we bump.
-                let attr = self.mk_doc_comment(s);
+                let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span);
                 if attr.style == ast::AttrStyle::Inner {
                     attrs.push(attr);
                     self.bump();
index 5e9411327cabdd6d7dc3ea71cac17274008019c4..2854356ab0fc6cd89582b6308bebf60d91d1bf98 100644 (file)
@@ -1419,7 +1419,7 @@ pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
     }
 
     pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
-        if let token::DocComment(_) = self.token.kind {
+        if let token::DocComment(..) = self.token.kind {
             self.struct_span_err(
                 self.token.span,
                 "documentation comments cannot be applied to a function parameter's type",
index 47794746126daa02579ccc7fc822c80d03d3110b..be72ed6dffb7c6aa5a58e3ceb80bea0b5100541d 100644 (file)
@@ -54,7 +54,7 @@ fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a,
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
+        self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
 
         Ok(GenericParam {
             ident,
index 5923a185dcf939c167bc4b7c8b2875c073a068ab..10d214e52abdbdda46f4b6df3de9508b5db0abcb 100644 (file)
@@ -610,7 +610,7 @@ fn parse_item_list<T>(
 
     /// Recover on a doc comment before `}`.
     fn recover_doc_comment_before_brace(&mut self) -> bool {
-        if let token::DocComment(_) = self.token.kind {
+        if let token::DocComment(..) = self.token.kind {
             if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
                 struct_span_err!(
                     self.diagnostic(),
@@ -1231,7 +1231,7 @@ fn parse_single_struct_field(
                 self.bump();
             }
             token::CloseDelim(token::Brace) => {}
-            token::DocComment(_) => {
+            token::DocComment(..) => {
                 let previous_span = self.prev_token.span;
                 let mut err = self.span_fatal_err(self.token.span, Error::UselessDocComment);
                 self.bump(); // consume the doc comment
index 2509a9792215d553379da4acdf0ce201045c94e1..b33ae4bed828b95ad518c274e778244e3f9cacef 100644 (file)
@@ -22,7 +22,6 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, DelimToken, Token, TokenKind};
 use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint};
-use rustc_ast::util::comments::{doc_comment_style, strip_doc_comment_decoration};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
 use rustc_session::parse::ParseSess;
@@ -104,6 +103,8 @@ pub struct Parser<'a> {
     /// error.
     pub(super) unclosed_delims: Vec<UnmatchedBrace>,
     last_unexpected_token_span: Option<Span>,
+    /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it
+    /// looked like it could have been a mistyped path or literal `Option:Some(42)`).
     pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
     /// If present, this `Parser` is not parsing Rust code but rather a macro call.
     subparser_name: Option<&'static str>,
@@ -209,18 +210,18 @@ fn next(&mut self) -> Token {
     }
 
     fn next_desugared(&mut self) -> Token {
-        let (name, sp) = match self.next() {
-            Token { kind: token::DocComment(name), span } => (name, span),
+        let (data, attr_style, sp) = match self.next() {
+            Token { kind: token::DocComment(_, attr_style, data), span } => {
+                (data, attr_style, span)
+            }
             tok => return tok,
         };
 
-        let stripped = strip_doc_comment_decoration(name);
-
         // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
         // required to wrap the text.
         let mut num_of_hashes = 0;
         let mut count = 0;
-        for ch in stripped.chars() {
+        for ch in data.as_str().chars() {
             count = match ch {
                 '"' => 1,
                 '#' if count > 0 => count + 1,
@@ -236,10 +237,7 @@ fn next_desugared(&mut self) -> Token {
             [
                 TokenTree::token(token::Ident(sym::doc, false), sp),
                 TokenTree::token(token::Eq, sp),
-                TokenTree::token(
-                    TokenKind::lit(token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None),
-                    sp,
-                ),
+                TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp),
             ]
             .iter()
             .cloned()
@@ -251,7 +249,7 @@ fn next_desugared(&mut self) -> Token {
             TokenCursorFrame::new(
                 delim_span,
                 token::NoDelim,
-                &if doc_comment_style(name) == AttrStyle::Inner {
+                &if attr_style == AttrStyle::Inner {
                     [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
                         .iter()
                         .cloned()
index 7db62f3493ede969d97fc00309ab5080076c7641..ebb3aa3866e43641faae1f0f2e0529339b001bb5 100644 (file)
@@ -820,7 +820,7 @@ fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
     }
 
     let r_start = str_style.map(|r| r + 1).unwrap_or(0);
-    let r_end = str_style.map(|r| r).unwrap_or(0);
+    let r_end = str_style.unwrap_or(0);
     let s = &snippet[r_start + 1..snippet.len() - r_end - 1];
     (find_skips(s, str_style.is_some()), true)
 }
index 1ff47ee038d3bf9703f098431122dbc7d64dc93c..d438fe35ff488481daa12be6d01e69b5640ef545 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_middle::ty::TyCtxt;
 
 use rustc_ast::ast::{Attribute, NestedMetaItem};
-use rustc_ast::attr;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -60,17 +59,17 @@ fn check_attributes(
     ) {
         let mut is_valid = true;
         for attr in attrs {
-            is_valid &= if attr.check_name(sym::inline) {
+            is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
                 self.check_inline(hir_id, attr, span, target)
-            } else if attr.check_name(sym::non_exhaustive) {
+            } else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
                 self.check_non_exhaustive(attr, span, target)
-            } else if attr.check_name(sym::marker) {
+            } else if self.tcx.sess.check_name(attr, sym::marker) {
                 self.check_marker(attr, span, target)
-            } else if attr.check_name(sym::target_feature) {
+            } else if self.tcx.sess.check_name(attr, sym::target_feature) {
                 self.check_target_feature(attr, span, target)
-            } else if attr.check_name(sym::track_caller) {
+            } else if self.tcx.sess.check_name(attr, sym::track_caller) {
                 self.check_track_caller(&attr.span, attrs, span, target)
-            } else if attr.check_name(sym::doc) {
+            } else if self.tcx.sess.check_name(attr, sym::doc) {
                 self.check_doc_alias(attr)
             } else {
                 true
@@ -144,7 +143,7 @@ fn check_track_caller(
         target: Target,
     ) -> bool {
         match target {
-            _ if attr::contains_name(attrs, sym::naked) => {
+            _ if self.tcx.sess.contains_name(attrs, sym::naked) => {
                 struct_span_err!(
                     self.tcx.sess,
                     *attr_span,
@@ -262,7 +261,7 @@ fn check_repr(
         // ```
         let hints: Vec<_> = attrs
             .iter()
-            .filter(|attr| attr.check_name(sym::repr))
+            .filter(|attr| self.tcx.sess.check_name(attr, sym::repr))
             .filter_map(|attr| attr.meta_item_list())
             .flatten()
             .collect();
@@ -391,10 +390,10 @@ fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) {
         // When checking statements ignore expressions, they will be checked later
         if let hir::StmtKind::Local(ref l) = stmt.kind {
             for attr in l.attrs.iter() {
-                if attr.check_name(sym::inline) {
+                if self.tcx.sess.check_name(attr, sym::inline) {
                     self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement);
                 }
-                if attr.check_name(sym::repr) {
+                if self.tcx.sess.check_name(attr, sym::repr) {
                     self.emit_repr_error(
                         attr.span,
                         stmt.span,
@@ -412,10 +411,10 @@ fn check_expr_attributes(&self, expr: &hir::Expr<'_>) {
             _ => Target::Expression,
         };
         for attr in expr.attrs.iter() {
-            if attr.check_name(sym::inline) {
+            if self.tcx.sess.check_name(attr, sym::inline) {
                 self.check_inline(expr.hir_id, attr, &expr.span, target);
             }
-            if attr.check_name(sym::repr) {
+            if self.tcx.sess.check_name(attr, sym::repr) {
                 self.emit_repr_error(
                     attr.span,
                     expr.span,
@@ -431,7 +430,7 @@ fn check_expr_attributes(&self, expr: &hir::Expr<'_>) {
 
     fn check_used(&self, attrs: &'hir [Attribute], target: Target) {
         for attr in attrs {
-            if attr.check_name(sym::used) && target != Target::Static {
+            if self.tcx.sess.check_name(attr, sym::used) && target != Target::Static {
                 self.tcx
                     .sess
                     .span_err(attr.span, "attribute must be applied to a `static` variable");
index b1ebab3f2f8064de56ce69ea0aba654b6aa45a4f..dd0bcbf208d7c1d355a4d3469f2ec9007b9b62dc 100644 (file)
@@ -106,7 +106,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
 
             // However, we cannot allow stable `const fn`s to use unstable features without an explicit
             // opt-in via `allow_internal_unstable`.
-            attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+            attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
                 .map_or(false, |mut features| features.any(|name| name == feature_gate))
         };
 
index ab75c8ebf4c89f13469aa3c6d37243adf9b04e35..0e5298acc2cafbcd333218205c00a40ac56d5116 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
 
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
 use rustc_span::symbol::{sym, Symbol};
 
 // Any local node that may call something in its body block should be
@@ -331,17 +331,17 @@ fn has_allow_dead_code_or_lang_attr(
     id: hir::HirId,
     attrs: &[ast::Attribute],
 ) -> bool {
-    if attr::contains_name(attrs, sym::lang) {
+    if tcx.sess.contains_name(attrs, sym::lang) {
         return true;
     }
 
     // Stable attribute for #[lang = "panic_impl"]
-    if attr::contains_name(attrs, sym::panic_handler) {
+    if tcx.sess.contains_name(attrs, sym::panic_handler) {
         return true;
     }
 
     // (To be) stable attribute for #[lang = "oom"]
-    if attr::contains_name(attrs, sym::alloc_error_handler) {
+    if tcx.sess.contains_name(attrs, sym::alloc_error_handler) {
         return true;
     }
 
index 3cce4b8d00e8b8572593d9596c9251fa01c52fdd..fa59337b0f66b69bcdf88a16cb237f2a1692de5b 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 
 struct DiagnosticItemCollector<'tcx> {
@@ -44,7 +45,7 @@ fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
     }
 
     fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) {
-        if let Some(name) = extract(attrs) {
+        if let Some(name) = extract(&self.tcx.sess, attrs) {
             let def_id = self.tcx.hir().local_def_id(hir_id);
             // insert into our table
             collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
@@ -86,9 +87,9 @@ fn collect_item(
 }
 
 /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
-fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
+fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option<Symbol> {
     attrs.iter().find_map(|attr| {
-        if attr.check_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
+        if sess.check_name(attr, sym::rustc_diagnostic_item) { attr.value_str() } else { None }
     })
 }
 
index 11612101e377131a7db58e8eb28cc5035d2baf62..8aa6e7936bef61b391c65891539799dc6a00b320 100644 (file)
@@ -1,4 +1,3 @@
-use rustc_ast::attr;
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
 use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -58,7 +57,7 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
     }
 
     // If the user wants no main function at all, then stop here.
-    if attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_main) {
+    if tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_main) {
         return None;
     }
 
@@ -76,14 +75,14 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
     configure_main(tcx, &ctxt)
 }
 
-// Beware, this is duplicated in `librustc_ast/entry.rs`, so make sure to keep
-// them in sync.
-fn entry_point_type(item: &Item<'_>, at_root: bool) -> EntryPointType {
+// 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(sess: &Session, item: &Item<'_>, at_root: bool) -> EntryPointType {
     match item.kind {
         ItemKind::Fn(..) => {
-            if attr::contains_name(&item.attrs, sym::start) {
+            if sess.contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
-            } else if attr::contains_name(&item.attrs, sym::main) {
+            } else if sess.contains_name(&item.attrs, sym::main) {
                 EntryPointType::MainAttr
             } else if item.ident.name == sym::main {
                 if at_root {
@@ -101,7 +100,7 @@ fn entry_point_type(item: &Item<'_>, at_root: bool) -> EntryPointType {
 }
 
 fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
-    match entry_point_type(item, at_root) {
+    match entry_point_type(&ctxt.session, item, at_root) {
         EntryPointType::MainNamed => {
             if ctxt.main_fn.is_none() {
                 ctxt.main_fn = Some((item.hir_id, item.span));
index e07c71b41d82714ad13b1dafcfcb787cac87bef9..07415870549f172d1021ae1578915bf994548142 100644 (file)
@@ -56,7 +56,8 @@ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
     }
 
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
-        if let Some((value, span)) = extract(&attrs) {
+        let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+        if let Some((value, span)) = extract(check_name, &attrs) {
             match ITEM_REFS.get(&value).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
index 55a6d3f76457e3567aab727b1e32ef2a96f296f5..9450d75620a8bc52143575848fafac9874cff598 100644 (file)
@@ -29,7 +29,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             | ItemKind::Struct(..)
             | ItemKind::Union(..) => {
                 for attr in self.tcx.get_attrs(item_def_id.to_def_id()).iter() {
-                    if attr.check_name(sym::rustc_layout) {
+                    if self.tcx.sess.check_name(attr, sym::rustc_layout) {
                         self.dump_layout_of(item_def_id, item, attr);
                     }
                 }
index 922a475e5f4e480ad4ca700938883c5ba44cd43a..9a4aa6a68a6c6a5bf597ecbfe2c8256ff4f0bf5f 100644 (file)
@@ -34,7 +34,9 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
 
         // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
         // `#[rustc_const_unstable (..)]`).
-        if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.check_name(**stab_attr)) {
+        if let Some(stab_attr) =
+            stab_attrs.iter().find(|stab_attr| self.tcx.sess.check_name(attr, **stab_attr))
+        {
             let meta_item = attr.meta();
             if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item {
                 let mut feature = None;
index 45193c4556962bcac596243c78a3d8bd6f7a7a7c..6477f8da008adcf053c8a117fd3b0a5b6653384a 100644 (file)
@@ -355,7 +355,7 @@ fn visit_fn<'tcx>(
     if let FnKind::Method(..) = fk {
         let parent = ir.tcx.hir().get_parent_item(id);
         if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) {
-            if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) {
+            if i.attrs.iter().any(|a| ir.tcx.sess.check_name(a, sym::automatically_derived)) {
                 return;
             }
         }
index 830af8d31e7a6a3b48baa76f6f72ffb05624c9a6..1af77ae61c7f4c594111f0bd48631914523048d3 100644 (file)
@@ -65,11 +65,8 @@ fn annotate<F>(
             did_error = self.forbid_staged_api_attrs(hir_id, attrs);
         }
 
-        let depr = if did_error {
-            None
-        } else {
-            attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
-        };
+        let depr =
+            if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs, item_sp) };
         let mut is_deprecated = false;
         if let Some(depr) = &depr {
             is_deprecated = true;
@@ -88,7 +85,7 @@ fn annotate<F>(
         }
 
         if self.tcx.features().staged_api {
-            if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+            if let Some(..) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) {
                 self.tcx.sess.span_err(
                     item_sp,
                     "`#[deprecated]` cannot be used in staged API; \
@@ -105,7 +102,7 @@ fn annotate<F>(
             return;
         }
 
-        let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
+        let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
 
         let const_stab = const_stab.map(|const_stab| {
             let const_stab = self.tcx.intern_const_stability(const_stab);
@@ -252,7 +249,7 @@ fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> boo
         for attr in attrs {
             let name = attr.name_or_empty();
             if unstable_attrs.contains(&name) {
-                attr::mark_used(attr);
+                self.tcx.sess.mark_attr_used(attr);
                 struct_span_err!(
                     self.tcx.sess,
                     attr.span,
index 3b11fb379625f717b78521c34de778f7d69d04c0..2749b96bc85397be96a045dfdef9534701ae5c0b 100644 (file)
@@ -100,7 +100,8 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
-        if let Some((lang_item, _)) = hir::lang_items::extract(&i.attrs) {
+        let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+        if let Some((lang_item, _)) = hir::lang_items::extract(check_name, &i.attrs) {
             self.register(lang_item, i.span, i.hir_id);
         }
         intravisit::walk_foreign_item(self, i)
index db2363316cd1a71bd7b18005a94d04b70fd941a3..d16dd701a120bfa36a01133bdb112ecb99cdf4c7 100644 (file)
@@ -1,6 +1,5 @@
 //! Used by `rustc` when compiling a plugin crate.
 
-use rustc_ast::attr;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -9,14 +8,15 @@
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-struct RegistrarFinder {
+struct RegistrarFinder<'tcx> {
+    tcx: TyCtxt<'tcx>,
     registrars: Vec<(hir::HirId, Span)>,
 }
 
-impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
+impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Fn(..) = item.kind {
-            if attr::contains_name(&item.attrs, sym::plugin_registrar) {
+            if self.tcx.sess.contains_name(&item.attrs, sym::plugin_registrar) {
                 self.registrars.push((item.hir_id, item.span));
             }
         }
@@ -35,7 +35,7 @@ pub fn find_plugin_registrar(tcx: TyCtxt<'_>) -> Option<DefId> {
 fn plugin_registrar_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> {
     assert_eq!(cnum, LOCAL_CRATE);
 
-    let mut finder = RegistrarFinder { registrars: Vec::new() };
+    let mut finder = RegistrarFinder { tcx, registrars: Vec::new() };
     tcx.hir().krate().visit_all_item_likes(&mut finder);
 
     match finder.registrars.len() {
index 10712eb60b9e3bf21de86462d15a5f884b806c86..1eb65dd96ba57d7139b2eab9ca688a4c737c8fbf 100644 (file)
@@ -8,6 +8,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(nll)]
+#![recursion_limit = "256"]
 
 use rustc_lint::LintStore;
 
index 62a87b47a2f74e7215a85d1310841273289f7a16..2f307302db03ed677114f15f422f52e7a831b1d7 100644 (file)
@@ -32,7 +32,7 @@ pub fn load_plugins(
     let mut plugins = Vec::new();
 
     for attr in &krate.attrs {
-        if !attr.check_name(sym::plugin) {
+        if !sess.check_name(attr, sym::plugin) {
             continue;
         }
 
index fc00050f405182d1eddb93558a470572ed294e4b..2aa7780aaaf8370d84f4270714505c693b00ae23 100644 (file)
@@ -232,7 +232,7 @@ fn def_id_visibility<'tcx>(
                 Node::Item(item) => &item.vis,
                 Node::ForeignItem(foreign_item) => &foreign_item.vis,
                 Node::MacroDef(macro_def) => {
-                    if attr::contains_name(&macro_def.attrs, sym::macro_export) {
+                    if tcx.sess.contains_name(&macro_def.attrs, sym::macro_export) {
                         return (ty::Visibility::Public, macro_def.span, "public");
                     } else {
                         &macro_def.vis
@@ -271,8 +271,11 @@ fn def_id_visibility<'tcx>(
                                 ctor_vis =
                                     ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
                                 let attrs = tcx.get_attrs(variant.def_id);
-                                span =
-                                    attr::find_by_name(&attrs, sym::non_exhaustive).unwrap().span;
+                                span = tcx
+                                    .sess
+                                    .find_by_name(&attrs, sym::non_exhaustive)
+                                    .unwrap()
+                                    .span;
                                 descr = "crate-visible";
                             }
 
@@ -305,7 +308,9 @@ fn def_id_visibility<'tcx>(
                                 if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
                                     ctor_vis =
                                         ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-                                    span = attr::find_by_name(&item.attrs, sym::non_exhaustive)
+                                    span = tcx
+                                        .sess
+                                        .find_by_name(&item.attrs, sym::non_exhaustive)
                                         .unwrap()
                                         .span;
                                     descr = "crate-visible";
@@ -914,7 +919,9 @@ fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
-        if attr::find_transparency(&md.attrs, md.ast.macro_rules).0 != Transparency::Opaque {
+        if attr::find_transparency(&self.tcx.sess, &md.attrs, md.ast.macro_rules).0
+            != Transparency::Opaque
+        {
             self.update(md.hir_id, Some(AccessLevel::Public));
             return;
         }
index 737fd13812058bc9ab3aa1373a857a686260947e..11c7793b3ad9a3903471f69ee7595883e70a4e5a 100644 (file)
@@ -541,7 +541,7 @@ fn build_reduced_graph_for_use_tree(
             }
             ast::UseTreeKind::Glob => {
                 let kind = ImportKind::Glob {
-                    is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
+                    is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
                     max_vis: Cell::new(ty::Visibility::Invisible),
                 };
                 self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
@@ -712,7 +712,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                 let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
                 let module = self.r.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
-                        attr::contains_name(&item.attrs, sym::no_implicit_prelude)
+                        self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude)
                     },
                     ..ModuleData::new(
                         Some(parent),
@@ -789,7 +789,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
                     let mut ctor_vis = if vis == ty::Visibility::Public
-                        && attr::contains_name(&item.attrs, sym::non_exhaustive)
+                        && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
                         ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
                     } else {
@@ -991,7 +991,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
         let mut import_all = None;
         let mut single_imports = Vec::new();
         for attr in &item.attrs {
-            if attr.check_name(sym::macro_use) {
+            if self.r.session.check_name(attr, sym::macro_use) {
                 if self.parent_scope.module.parent.is_some() {
                     struct_span_err!(
                         self.r.session,
@@ -1097,7 +1097,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
     /// Returns `true` if this attribute list contains `macro_use`.
     fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
-            if attr.check_name(sym::macro_escape) {
+            if self.r.session.check_name(attr, sym::macro_escape) {
                 let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
                 let mut err = self.r.session.struct_span_warn(attr.span, msg);
                 if let ast::AttrStyle::Inner = attr.style {
@@ -1105,7 +1105,7 @@ fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
                 } else {
                     err.emit();
                 }
-            } else if !attr.check_name(sym::macro_use) {
+            } else if !self.r.session.check_name(attr, sym::macro_use) {
                 continue;
             }
 
@@ -1129,12 +1129,13 @@ fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScope<'a> {
         MacroRulesScope::Invocation(invoc_id)
     }
 
-    fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
-        if attr::contains_name(&item.attrs, sym::proc_macro) {
+    fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
+        if self.r.session.contains_name(&item.attrs, sym::proc_macro) {
             return Some((MacroKind::Bang, item.ident, item.span));
-        } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
+        } else if self.r.session.contains_name(&item.attrs, sym::proc_macro_attribute) {
             return Some((MacroKind::Attr, item.ident, item.span));
-        } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
+        } else if let Some(attr) = self.r.session.find_by_name(&item.attrs, sym::proc_macro_derive)
+        {
             if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
                 if let Some(ident) = nested_meta.ident() {
                     return Some((MacroKind::Derive, ident, ident.span));
@@ -1168,7 +1169,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
                 let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
                 (ext, item.ident, item.span, def.macro_rules)
             }
-            ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
+            ItemKind::Fn(..) => match self.proc_macro_stub(item) {
                 Some((macro_kind, ident, span)) => {
                     self.r.proc_macro_stubs.insert(def_id);
                     (self.r.dummy_ext(macro_kind), ident, span, false)
@@ -1185,7 +1186,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
         if macro_rules {
             let ident = ident.normalize_to_macros_2_0();
             self.r.macro_names.insert(ident);
-            let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
+            let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export);
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
@@ -1416,7 +1417,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         // If the variant is marked as non_exhaustive then lower the visibility to within the
         // crate.
         let mut ctor_vis = vis;
-        let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive);
+        let has_non_exhaustive = self.r.session.contains_name(&variant.attrs, sym::non_exhaustive);
         if has_non_exhaustive && vis == ty::Visibility::Public {
             ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
         }
index 81e29047dc5e24e14c9269a6b48154ef5e1cabca..9502be728de06a4052110ec2cfc35ec865bbcc35 100644 (file)
@@ -466,6 +466,23 @@ impl<'a> Resolver<'a> {
                 );
                 err
             }
+            ResolutionError::ParamInNonTrivialAnonConst(name) => {
+                let mut err = self.session.struct_span_err(
+                    span,
+                    "generic parameters must not be used inside of non trivial constant values",
+                );
+                err.span_label(
+                    span,
+                    &format!(
+                        "non-trivial anonymous constants must not depend on the parameter `{}`",
+                        name
+                    ),
+                );
+                err.help(
+                    &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
+                );
+                err
+            }
             ResolutionError::SelfInTyParamDefault => {
                 let mut err = struct_span_err!(
                     self.session,
@@ -1075,10 +1092,9 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
         ) = binding.kind
         {
             let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
-            if let Some(fields) = self.field_names.get(&def_id) {
-                let first_field = fields.first().expect("empty field list in the map");
-                return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
-            }
+            let fields = self.field_names.get(&def_id)?;
+            let first_field = fields.first()?; // Handle `struct Foo()`
+            return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
         }
         None
     }
index 44ff4209095418473d9f4a4d749cb9c7f3be9242..7ecfe2554ec8ab04e0d6bf7da75c21429dc0a5e7 100644 (file)
@@ -111,7 +111,7 @@ enum PatBoundCtx {
     ItemRibKind(HasGenericParams),
 
     /// We're in a constant item. Can't refer to dynamic stuff.
-    ConstantItemRibKind,
+    ConstantItemRibKind(bool),
 
     /// We passed through a module.
     ModuleRibKind(Module<'a>),
@@ -137,7 +137,7 @@ impl RibKind<'_> {
             NormalRibKind
             | ClosureOrAsyncRibKind
             | FnItemRibKind
-            | ConstantItemRibKind
+            | ConstantItemRibKind(_)
             | ModuleRibKind(_)
             | MacroDefinition(_)
             | ConstParamTyRibKind => false,
@@ -226,7 +226,7 @@ fn descr_expected(self) -> &'static str {
                 ValueNS => "method or associated constant",
                 MacroNS => bug!("associated macro"),
             },
-            PathSource::Expr(parent) => match &parent.as_ref().map(|p| &p.kind) {
+            PathSource::Expr(parent) => match parent.as_ref().map(|p| &p.kind) {
                 // "function" here means "anything callable" rather than `DefKind::Fn`,
                 // this is not precise but usually more helpful than just "value".
                 Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
@@ -426,7 +426,7 @@ fn visit_block(&mut self, block: &'ast Block) {
     }
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
         debug!("visit_anon_const {:?}", constant);
-        self.with_constant_rib(|this| {
+        self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
             visit::walk_anon_const(this, constant);
         });
     }
@@ -628,7 +628,7 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
                         if !check_ns(TypeNS) && check_ns(ValueNS) {
                             // This must be equivalent to `visit_anon_const`, but we cannot call it
                             // directly due to visitor lifetimes so we have to copy-paste some code.
-                            self.with_constant_rib(|this| {
+                            self.with_constant_rib(true, |this| {
                                 this.smart_resolve_path(
                                     ty.id,
                                     qself.as_ref(),
@@ -829,7 +829,7 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
                 | ClosureOrAsyncRibKind
                 | FnItemRibKind
                 | ItemRibKind(..)
-                | ConstantItemRibKind
+                | ConstantItemRibKind(_)
                 | ModuleRibKind(..)
                 | ForwardTyParamBanRibKind
                 | ConstParamTyRibKind => {
@@ -948,7 +948,14 @@ fn resolve_item(&mut self, item: &'ast Item) {
                                         // Only impose the restrictions of `ConstRibKind` for an
                                         // actual constant expression in a provided default.
                                         if let Some(expr) = default {
-                                            this.with_constant_rib(|this| this.visit_expr(expr));
+                                            // We allow arbitrary const expressions inside of associated consts,
+                                            // even if they are potentially not const evaluatable.
+                                            //
+                                            // Type parameters can already be used and as associated consts are
+                                            // not used as part of the type system, this is far less surprising.
+                                            this.with_constant_rib(true, |this| {
+                                                this.visit_expr(expr)
+                                            });
                                         }
                                     }
                                     AssocItemKind::Fn(_, _, generics, _) => {
@@ -989,7 +996,9 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
-                        this.with_constant_rib(|this| this.visit_expr(expr));
+                        this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
+                            this.visit_expr(expr)
+                        });
                     }
                 });
             }
@@ -1086,11 +1095,11 @@ fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce
         self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
-    fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
+    fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
         debug!("with_constant_rib");
-        self.with_rib(ValueNS, ConstantItemRibKind, |this| {
-            this.with_rib(TypeNS, ConstantItemRibKind, |this| {
-                this.with_label_rib(ConstantItemRibKind, f);
+        self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
+            this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
+                this.with_label_rib(ConstantItemRibKind(trivial), f);
             })
         });
     }
@@ -1220,7 +1229,7 @@ fn resolve_implementation(
                                 for item in impl_items {
                                     use crate::ResolutionError::*;
                                     match &item.kind {
-                                        AssocItemKind::Const(..) => {
+                                        AssocItemKind::Const(_default, _ty, _expr) => {
                                             debug!("resolve_implementation AssocItemKind::Const",);
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
@@ -1231,7 +1240,12 @@ fn resolve_implementation(
                                                 |n, s| ConstNotMemberOfTrait(n, s),
                                             );
 
-                                            this.with_constant_rib(|this| {
+                                            // We allow arbitrary const expressions inside of associated consts,
+                                            // even if they are potentially not const evaluatable.
+                                            //
+                                            // Type parameters can already be used and as associated consts are
+                                            // not used as part of the type system, this is far less surprising.
+                                            this.with_constant_rib(true, |this| {
                                                 visit::walk_assoc_item(this, item, AssocCtxt::Impl)
                                             });
                                         }
index 3fbb42ece47a0f904c8060e92ff1baefae69210e..0b881b089deaa830e12826c21f743a1f7b1a8f52 100644 (file)
@@ -6,7 +6,6 @@
 //! way. Therefore, we break lifetime name resolution into a separate pass.
 
 use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
-use rustc_ast::attr;
 use rustc_ast::walk_list;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -1179,7 +1178,7 @@ fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap<Vec<ObjectLifet
                 let result = object_lifetime_defaults_for_item(tcx, generics);
 
                 // Debugging aid.
-                if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) {
+                if tcx.sess.contains_name(&item.attrs, sym::rustc_object_lifetime_default) {
                     let object_lifetime_default_reprs: String = result
                         .iter()
                         .map(|set| match *set {
@@ -1540,13 +1539,9 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                             if let Some(def_id) = parent_def_id.as_local() {
                                 let parent_hir_id = self.tcx.hir().as_local_hir_id(def_id);
                                 // lifetimes in `derive` expansions don't count (Issue #53738)
-                                if self
-                                    .tcx
-                                    .hir()
-                                    .attrs(parent_hir_id)
-                                    .iter()
-                                    .any(|attr| attr.check_name(sym::automatically_derived))
-                                {
+                                if self.tcx.hir().attrs(parent_hir_id).iter().any(|attr| {
+                                    self.tcx.sess.check_name(attr, sym::automatically_derived)
+                                }) {
                                     continue;
                                 }
                             }
index 234fcd789eee4932242b5e389356ce43f5a827b0..79f5a27bb28ed178f7635f0d926d2dae2d969c98 100644 (file)
@@ -23,7 +23,6 @@
 use rustc_ast::ast::{self, FloatTy, IntTy, NodeId, UintTy};
 use rustc_ast::ast::{Crate, CRATE_NODE_ID};
 use rustc_ast::ast::{ItemKind, Path};
-use rustc_ast::attr;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
@@ -218,6 +217,10 @@ enum ResolutionError<'a> {
     ParamInTyOfConstParam(Symbol),
     /// constant values inside of type parameter defaults must not depend on generic parameters.
     ParamInAnonConstInTyDefault(Symbol),
+    /// generic parameters must not be used inside of non trivial constant values.
+    ///
+    /// This error is only emitted when using `min_const_generics`.
+    ParamInNonTrivialAnonConst(Symbol),
     /// Error E0735: type parameters with a default cannot use `Self`
     SelfInTyParamDefault,
     /// Error E0767: use of unreachable label
@@ -1194,7 +1197,7 @@ pub fn new(
         let root_def_id = DefId::local(CRATE_DEF_INDEX);
         let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
         let graph_root = arenas.alloc_module(ModuleData {
-            no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
+            no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
             ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
         });
         let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
@@ -1232,9 +1235,9 @@ pub fn new(
             .map(|(name, _)| (Ident::from_str(name), Default::default()))
             .collect();
 
-        if !attr::contains_name(&krate.attrs, sym::no_core) {
+        if !session.contains_name(&krate.attrs, sym::no_core) {
             extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
-            if !attr::contains_name(&krate.attrs, sym::no_std) {
+            if !session.contains_name(&krate.attrs, sym::no_std) {
                 extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
                 if session.rust_2018() {
                     extern_prelude.insert(Ident::with_dummy_span(sym::meta), Default::default());
@@ -2507,7 +2510,7 @@ fn validate_res_from_ribs(
                                 res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
                             }
                         }
-                        ConstantItemRibKind => {
+                        ConstantItemRibKind(_) => {
                             // Still doesn't deal with upvars
                             if record_used {
                                 self.report_error(span, AttemptToUseNonConstantValueInConstant);
@@ -2546,7 +2549,18 @@ fn validate_res_from_ribs(
                             in_ty_param_default = true;
                             continue;
                         }
-                        ConstantItemRibKind => {
+                        ConstantItemRibKind(trivial) => {
+                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+                            if !trivial && self.session.features_untracked().min_const_generics {
+                                if record_used {
+                                    self.report_error(
+                                        span,
+                                        ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+                                    );
+                                }
+                                return Res::Err;
+                            }
+
                             if in_ty_param_default {
                                 if record_used {
                                     self.report_error(
@@ -2612,7 +2626,18 @@ fn validate_res_from_ribs(
                             in_ty_param_default = true;
                             continue;
                         }
-                        ConstantItemRibKind => {
+                        ConstantItemRibKind(trivial) => {
+                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+                            if !trivial && self.session.features_untracked().min_const_generics {
+                                if record_used {
+                                    self.report_error(
+                                        span,
+                                        ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+                                    );
+                                }
+                                return Res::Err;
+                            }
+
                             if in_ty_param_default {
                                 if record_used {
                                     self.report_error(
index ccc7e16ae4cf667059a7e3c192d059311ce06de7..542025ac1f4990ad8e7db150d00aa25b7f4d2998 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_ast::ast::{self, NodeId};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, StabilityLevel};
+use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
 use rustc_expand::compile_declarative_macro;
@@ -105,7 +105,7 @@ fn registered_idents(
     descr: &str,
 ) -> FxHashSet<Ident> {
     let mut registered = FxHashSet::default();
-    for attr in attr::filter_by_name(attrs, attr_name) {
+    for attr in sess.filter_by_name(attrs, attr_name) {
         for nested_meta in attr.meta_item_list().unwrap_or_default() {
             match nested_meta.ident() {
                 Some(ident) => {
@@ -1068,7 +1068,7 @@ fn prohibit_imported_non_macro_attrs(
     /// its expander to a pre-defined one for built-in macros.
     crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
         let mut result = compile_declarative_macro(
-            &self.session.parse_sess,
+            &self.session,
             self.session.features_untracked(),
             item,
             edition,
index 8e379a3510038d916c88f34705ac5797fcb77710..6469971fce830e4ff7e5692a80cac0f767ba25c9 100644 (file)
@@ -10,7 +10,7 @@
 mod sig;
 
 use rustc_ast::ast::{self};
-use rustc_ast::util::comments::strip_doc_comment_decoration;
+use rustc_ast::util::comments::beautify_doc_string;
 use rustc_ast_pretty::pprust::attribute_to_string;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind as HirDefKind, Res};
@@ -702,7 +702,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
             Res::Def(HirDefKind::ConstParam, def_id) => {
                 Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def_id) })
             }
-            Res::Def(HirDefKind::Ctor(_, ..), def_id) => {
+            Res::Def(HirDefKind::Ctor(..), def_id) => {
                 // This is a reference to a tuple struct or an enum variant where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct or enum variant itself.
@@ -822,13 +822,10 @@ fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String {
 
         for attr in attrs {
             if let Some(val) = attr.doc_str() {
-                if attr.is_doc_comment() {
-                    result.push_str(&strip_doc_comment_decoration(val));
-                } else {
-                    result.push_str(&val.as_str());
-                }
+                // FIXME: Should save-analysis beautify doc strings itself or leave it to users?
+                result.push_str(&beautify_doc_string(val));
                 result.push('\n');
-            } else if attr.check_name(sym::doc) {
+            } else if self.tcx.sess.check_name(attr, sym::doc) {
                 if let Some(meta_list) = attr.meta_item_list() {
                     meta_list
                         .into_iter()
index 504490d938cfa576d77287643df8fe06111a7ffb..8fe71b71caed1f92944ef66db883b4b2b6d9a30d 100644 (file)
@@ -98,7 +98,7 @@ pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
         p.push(RUST_LIB_DIR);
         p.push(&self.triple);
         p.push("bin");
-        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
+        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
     }
 }
 
index 52216188397d7eb5d5a07c530bf090d9c67d893a..e4bce435c4b6d91e99922774f0288f35598cea02 100644 (file)
@@ -1,7 +1,7 @@
 //! Related to out filenames of compilation (e.g. save analysis, binaries).
 use crate::config::{CrateType, Input, OutputFilenames, OutputType};
 use crate::Session;
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use std::path::{Path, PathBuf};
@@ -45,7 +45,7 @@ fn is_writeable(p: &Path) -> bool {
     }
 }
 
-pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String {
+pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> String {
     let validate = |s: String, span: Option<Span>| {
         validate_crate_name(sess, &s, span);
         s
@@ -56,22 +56,20 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input:
     // the command line over one found in the #[crate_name] attribute. If we
     // find both we ensure that they're the same later on as well.
     let attr_crate_name =
-        attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
-
-    if let Some(sess) = sess {
-        if let Some(ref s) = sess.opts.crate_name {
-            if let Some((attr, name)) = attr_crate_name {
-                if name.as_str() != *s {
-                    let msg = format!(
-                        "`--crate-name` and `#[crate_name]` are \
-                                       required to match, but `{}` != `{}`",
-                        s, name
-                    );
-                    sess.span_err(attr.span, &msg);
-                }
+        sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
+
+    if let Some(ref s) = sess.opts.crate_name {
+        if let Some((attr, name)) = attr_crate_name {
+            if name.as_str() != *s {
+                let msg = format!(
+                    "`--crate-name` and `#[crate_name]` are \
+                                   required to match, but `{}` != `{}`",
+                    s, name
+                );
+                sess.span_err(attr.span, &msg);
             }
-            return validate(s.clone(), None);
         }
+        return validate(s.clone(), None);
     }
 
     if let Some((attr, s)) = attr_crate_name {
@@ -85,9 +83,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input:
                                    `{}` has a leading hyphen",
                     s
                 );
-                if let Some(sess) = sess {
-                    sess.err(&msg);
-                }
+                sess.err(&msg);
             } else {
                 return validate(s.replace("-", "_"), None);
             }
@@ -97,14 +93,13 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input:
     "rust_out".to_string()
 }
 
-pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
+pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
     let mut err_count = 0;
     {
         let mut say = |s: &str| {
-            match (sp, sess) {
-                (_, None) => panic!("{}", s),
-                (Some(sp), Some(sess)) => sess.span_err(sp, s),
-                (None, Some(sess)) => sess.err(s),
+            match sp {
+                Some(sp) => sess.span_err(sp, s),
+                None => sess.err(s),
             }
             err_count += 1;
         };
@@ -123,7 +118,7 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
     }
 
     if err_count > 0 {
-        sess.unwrap().abort_if_errors();
+        sess.abort_if_errors();
     }
 }
 
index e9077f40859097309703b30c8659d3ee8b8aef29..9191f7e8d76be85458c205e8c585432af937322b 100644 (file)
@@ -7,6 +7,8 @@
 use crate::parse::ParseSess;
 use crate::search_paths::{PathKind, SearchPath};
 
+pub use rustc_ast::ast::Attribute;
+pub use rustc_ast::attr::MarkedAttrs;
 pub use rustc_ast::crate_disambiguator::CrateDisambiguator;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -22,7 +24,7 @@
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
-use rustc_span::{SourceFileHashAlgorithm, Symbol};
+use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
 use rustc_target::asm::InlineAsmArch;
 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple, TlsModel};
@@ -208,6 +210,9 @@ pub struct Session {
 
     /// Set of enabled features for the current target.
     pub target_features: FxHashSet<Symbol>,
+
+    known_attrs: Lock<MarkedAttrs>,
+    used_attrs: Lock<MarkedAttrs>,
 }
 
 pub struct PerfStats {
@@ -1020,6 +1025,76 @@ pub fn emit_lifetime_markers(&self) -> bool {
         // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
         || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
     }
+
+    pub fn mark_attr_known(&self, attr: &Attribute) {
+        self.known_attrs.lock().mark(attr)
+    }
+
+    pub fn is_attr_known(&self, attr: &Attribute) -> bool {
+        self.known_attrs.lock().is_marked(attr)
+    }
+
+    pub fn mark_attr_used(&self, attr: &Attribute) {
+        self.used_attrs.lock().mark(attr)
+    }
+
+    pub fn is_attr_used(&self, attr: &Attribute) -> bool {
+        self.used_attrs.lock().is_marked(attr)
+    }
+
+    /// Returns `true` if the attribute's path matches the argument. If it matches, then the
+    /// attribute is marked as used.
+
+    /// Returns `true` if the attribute's path matches the argument. If it
+    /// matches, then the attribute is marked as used.
+    ///
+    /// This method should only be used by rustc, other tools can use
+    /// `Attribute::has_name` instead, because only rustc is supposed to report
+    /// the `unused_attributes` lint. (`MetaItem` and `NestedMetaItem` are
+    /// produced by lowering an `Attribute` and don't have identity, so they
+    /// only have the `has_name` method, and you need to mark the original
+    /// `Attribute` as used when necessary.)
+    pub fn check_name(&self, attr: &Attribute, name: Symbol) -> bool {
+        let matches = attr.has_name(name);
+        if matches {
+            self.mark_attr_used(attr);
+        }
+        matches
+    }
+
+    pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
+        [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
+            .iter()
+            .any(|kind| self.check_name(attr, *kind))
+    }
+
+    pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
+        attrs.iter().any(|item| self.check_name(item, name))
+    }
+
+    pub fn find_by_name<'a>(
+        &'a self,
+        attrs: &'a [Attribute],
+        name: Symbol,
+    ) -> Option<&'a Attribute> {
+        attrs.iter().find(|attr| self.check_name(attr, name))
+    }
+
+    pub fn filter_by_name<'a>(
+        &'a self,
+        attrs: &'a [Attribute],
+        name: Symbol,
+    ) -> impl Iterator<Item = &'a Attribute> {
+        attrs.iter().filter(move |attr| self.check_name(attr, name))
+    }
+
+    pub fn first_attr_value_str_by_name(
+        &self,
+        attrs: &[Attribute],
+        name: Symbol,
+    ) -> Option<Symbol> {
+        attrs.iter().find(|at| self.check_name(at, name)).and_then(|at| at.value_str())
+    }
 }
 
 fn default_emitter(
@@ -1283,6 +1358,8 @@ pub fn build_session(
         real_rust_source_base_dir,
         asm_arch,
         target_features: FxHashSet::default(),
+        known_attrs: Lock::new(MarkedAttrs::new()),
+        used_attrs: Lock::new(MarkedAttrs::new()),
     };
 
     validate_commandline_args_with_session_available(&sess);
index 74dc904b6e614b3df65fec50fa932801917d4de8..f52b2195c2f6e25d6bc797e24511808c43a08374 100644 (file)
@@ -80,8 +80,6 @@ pub enum Transparency {
     Opaque,
 }
 
-pub(crate) const NUM_TRANSPARENCIES: usize = 3;
-
 impl ExpnId {
     pub fn fresh(expn_data: Option<ExpnData>) -> Self {
         HygieneData::with(|data| data.fresh_expn(expn_data))
@@ -618,6 +616,11 @@ pub fn outer_expn_data(self) -> ExpnData {
         HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
     }
 
+    #[inline]
+    pub fn outer_mark(self) -> (ExpnId, Transparency) {
+        HygieneData::with(|data| data.outer_mark(self))
+    }
+
     #[inline]
     pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) {
         HygieneData::with(|data| {
@@ -667,7 +670,6 @@ pub struct ExpnData {
     /// The kind of this expansion - macro or compiler desugaring.
     pub kind: ExpnKind,
     /// The expansion that produced this expansion.
-    #[stable_hasher(ignore)]
     pub parent: ExpnId,
     /// The location of the actual macro invocation or syntax sugar , e.g.
     /// `let x = foo!();` or `if let Some(y) = x {}`
@@ -1030,7 +1032,7 @@ pub fn decode_expn_id<
         drop(expns);
         expn_id
     });
-    return Ok(expn_id);
+    Ok(expn_id)
 }
 
 // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext`
@@ -1103,7 +1105,7 @@ pub fn decode_syntax_context<
         assert_eq!(dummy.dollar_crate_name, kw::Invalid);
     });
 
-    return Ok(new_ctxt);
+    Ok(new_ctxt)
 }
 
 pub fn num_syntax_ctxts() -> usize {
index 7087dc80b1daf5a88298301d4106d6af6c4ff1f6..697d88ad0639598ea392fa345260a1eac0749ce0 100644 (file)
@@ -32,8 +32,8 @@
 use edition::Edition;
 pub mod hygiene;
 pub use hygiene::SyntaxContext;
+use hygiene::Transparency;
 pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
-use hygiene::{Transparency, NUM_TRANSPARENCIES};
 pub mod def_id;
 use def_id::{CrateNum, DefId, LOCAL_CRATE};
 mod span_encoding;
@@ -87,6 +87,15 @@ pub fn new(edition: Edition) -> SessionGlobals {
     }
 }
 
+pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
+    let session_globals = SessionGlobals::new(edition);
+    SESSION_GLOBALS.set(&session_globals, f)
+}
+
+pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
+    with_session_globals(edition::DEFAULT_EDITION, f)
+}
+
 // If this ever becomes non thread-local, `decode_syntax_context`
 // and `decode_expn_id` will need to be updated to handle concurrent
 // deserialization.
@@ -1814,47 +1823,51 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
             TAG_NO_EXPANSION.hash_stable(ctx, hasher);
         } else {
             TAG_EXPANSION.hash_stable(ctx, hasher);
+            let (expn_id, transparency) = self.outer_mark();
+            expn_id.hash_stable(ctx, hasher);
+            transparency.hash_stable(ctx, hasher);
+        }
+    }
+}
 
-            // Since the same expansion context is usually referenced many
-            // times, we cache a stable hash of it and hash that instead of
-            // recursing every time.
-            thread_local! {
-                static CACHE: RefCell<Vec<Option<[Option<u64>; NUM_TRANSPARENCIES]>>> = Default::default();
-            }
+impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        // Since the same expansion context is usually referenced many
+        // times, we cache a stable hash of it and hash that instead of
+        // recursing every time.
+        thread_local! {
+            static CACHE: RefCell<Vec<Option<Fingerprint>>> = Default::default();
+        }
 
-            let sub_hash: u64 = CACHE.with(|cache| {
-                let (expn_id, transparency, _) = self.outer_mark_with_data();
-                let index = expn_id.as_u32() as usize;
+        const TAG_ROOT: u8 = 0;
+        const TAG_NOT_ROOT: u8 = 1;
 
-                if let Some(sub_hash_cache) = cache.borrow().get(index).copied().flatten() {
-                    if let Some(sub_hash) = sub_hash_cache[transparency as usize] {
-                        return sub_hash;
-                    }
-                }
+        if *self == ExpnId::root() {
+            TAG_ROOT.hash_stable(ctx, hasher);
+            return;
+        }
 
-                let new_len = index + 1;
+        TAG_NOT_ROOT.hash_stable(ctx, hasher);
+        let index = self.as_u32() as usize;
 
-                let mut hasher = StableHasher::new();
-                expn_id.expn_data().hash_stable(ctx, &mut hasher);
-                transparency.hash_stable(ctx, &mut hasher);
+        let res = CACHE.with(|cache| cache.borrow().get(index).copied().flatten());
 
-                let sub_hash: Fingerprint = hasher.finish();
-                let sub_hash = sub_hash.to_smaller_hash();
+        if let Some(res) = res {
+            res.hash_stable(ctx, hasher);
+        } else {
+            let new_len = index + 1;
 
+            let mut sub_hasher = StableHasher::new();
+            self.expn_data().hash_stable(ctx, &mut sub_hasher);
+            let sub_hash: Fingerprint = sub_hasher.finish();
+
+            CACHE.with(|cache| {
                 let mut cache = cache.borrow_mut();
                 if cache.len() < new_len {
                     cache.resize(new_len, None);
                 }
-                if let Some(mut sub_hash_cache) = cache[index] {
-                    sub_hash_cache[transparency as usize] = Some(sub_hash);
-                } else {
-                    let mut sub_hash_cache = [None; NUM_TRANSPARENCIES];
-                    sub_hash_cache[transparency as usize] = Some(sub_hash);
-                    cache[index] = Some(sub_hash_cache);
-                }
-                sub_hash
+                cache[index].replace(sub_hash).expect_none("Cache slot was filled");
             });
-
             sub_hash.hash_stable(ctx, hasher);
         }
     }
index 98776a0478237495e80c53b76f93c7225ee39d8a..5203bfdb3b7ce8f43bc4579c5b1571a914c3ce1a 100644 (file)
         min_align_of,
         min_align_of_val,
         min_const_fn,
+        min_const_generics,
         min_const_unsafe_fn,
         min_specialization,
         minnumf32,
index 2f1c896ce2f1671f9d7442806f1bd0749f289993..24850a8a0d2533a17ad06914272d9e6657f8c89d 100644 (file)
@@ -34,16 +34,16 @@ fn process_attrs(&mut self, hir_id: hir::HirId) {
         let tcx = self.tcx;
         let def_id = tcx.hir().local_def_id(hir_id);
         for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
-            if attr.check_name(SYMBOL_NAME) {
+            if tcx.sess.check_name(attr, SYMBOL_NAME) {
                 // for now, can only use on monomorphic names
                 let instance = Instance::mono(tcx, def_id.to_def_id());
-                let mangled = self.tcx.symbol_name(instance);
+                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.check_name(DEF_PATH) {
+            } else if tcx.sess.check_name(attr, DEF_PATH) {
                 let path = tcx.def_path_str(def_id.to_def_id());
                 tcx.sess.span_err(attr.span, &format!("def-path({})", path));
             }
index 8423573b52d5111cc86419ba2c86fd9bb1098ace..62fc8f06183b727d62f1c467ebe92c96d88aa5ba 100644 (file)
@@ -10,13 +10,6 @@ pub fn options() -> TargetOptions {
         clang_args.push(format!("-Wl,{}", arg));
     };
 
-    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
-    // using threads causing weird hangs and bugs. Disable it entirely as
-    // this isn't yet the bottleneck of compilation at all anyway.
-    //
-    // FIXME: we should file an upstream issue with LLD about this
-    arg("--no-threads");
-
     // By default LLD only gives us one page of stack (64k) which is a
     // little small. Default to a larger stack closer to other PC platforms
     // (1MB) and users can always inject their own link-args to override this.
index cc971440feac52a20fb3b4eea7cf4b96f07f5624..02eefe5622384a8e4319a99c196466b2027f7897 100644 (file)
@@ -187,7 +187,7 @@ pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
     }
 
     pub fn span(&self) -> Span {
-        self.span.clone()
+        self.span
     }
 
     pub fn reached_recursion_limit(&self) -> bool {
index 13f8c71a629a905381bcf60822c4bdf8e4136505..e29e740f136697c58c7527ce184085e9ebd07f33 100644 (file)
@@ -495,7 +495,7 @@ fn suggest_dereferences(
                     if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
                         // Don't care about `&mut` because `DerefMut` is used less
                         // often and user will not expect autoderef happens.
-                        if src.starts_with("&") && !src.starts_with("&mut ") {
+                        if src.starts_with('&') && !src.starts_with("&mut ") {
                             let derefs = "*".repeat(steps);
                             err.span_suggestion(
                                 span,
index 446d5a489df48a6101c7547d638de1aabcea2dff..7a9ed4b72dd03820a56388560c648c87532ee07f 100644 (file)
@@ -164,7 +164,7 @@ pub fn of_item(
     ) -> Result<Option<Self>, ErrorReported> {
         let attrs = tcx.get_attrs(impl_def_id);
 
-        let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) {
+        let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) {
             item
         } else {
             return Ok(None);
index 75e11619924308ae39053483c9cd144d7ef3bd59..4c575f1c6ac4eab4a088a6da3e55bed75a8d7eec 100644 (file)
@@ -24,7 +24,6 @@
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectionCacheKeyExt;
-use rustc_ast::attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
@@ -440,7 +439,7 @@ fn evaluate_predicate_recursively<'o>(
             obligation
         );
 
-        // `previous_stack` stores a `TraitObligatiom`, while `obligation` is
+        // `previous_stack` stores a `TraitObligation`, while `obligation` is
         // a `PredicateObligation`. These are distinct types, so we can't
         // use any `Option` combinator method that would force them to be
         // the same.
@@ -980,7 +979,7 @@ fn filter_negative_and_reservation_impls(
                         &mut self.intercrate_ambiguity_causes
                     {
                         let attrs = tcx.get_attrs(def_id);
-                        let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
+                        let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
                         let value = attr.and_then(|a| a.value_str());
                         if let Some(value) = value {
                             debug!(
index 715e5299a37bda7ec2e9e83595276e8190061969..4c8be8eb610103d620c97e941f1b8befca09217e 100644 (file)
@@ -141,7 +141,7 @@ fn adt_datum(
 
         let predicates = self.tcx.predicates_of(adt_def.did).predicates;
         let where_clauses: Vec<_> = predicates
-            .into_iter()
+            .iter()
             .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
             .collect();
@@ -174,7 +174,7 @@ fn adt_datum(
                 phantom_data: adt_def.is_phantom_data(),
             },
         });
-        return struct_datum;
+        struct_datum
     }
 
     fn fn_def_datum(
@@ -187,7 +187,7 @@ fn fn_def_datum(
 
         let predicates = self.tcx.predicates_defined_on(def_id).predicates;
         let where_clauses: Vec<_> = predicates
-            .into_iter()
+            .iter()
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
@@ -276,7 +276,7 @@ fn impls_for_trait(
             parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
         });
 
-        let impls = matched_impls.map(|matched_impl| chalk_ir::ImplId(matched_impl)).collect();
+        let impls = matched_impls.map(chalk_ir::ImplId).collect();
         impls
     }
 
@@ -379,7 +379,7 @@ fn force_impl_for(
                         ty::AdtKind::Struct | ty::AdtKind::Union => None,
                         ty::AdtKind::Enum => {
                             let constraint = self.tcx.adt_sized_constraint(adt_def.did);
-                            if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
+                            if !constraint.0.is_empty() { unimplemented!() } else { Some(true) }
                         }
                     },
                     _ => None,
@@ -398,7 +398,7 @@ fn force_impl_for(
                         ty::AdtKind::Struct | ty::AdtKind::Union => None,
                         ty::AdtKind::Enum => {
                             let constraint = self.tcx.adt_sized_constraint(adt_def.did);
-                            if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
+                            if !constraint.0.is_empty() { unimplemented!() } else { Some(true) }
                         }
                     },
                     _ => None,
@@ -440,7 +440,7 @@ fn well_known_trait_id(
             FnOnce => self.tcx.lang_items().fn_once_trait(),
             Unsize => self.tcx.lang_items().unsize_trait(),
         };
-        def_id.map(|t| chalk_ir::TraitId(t))
+        def_id.map(chalk_ir::TraitId)
     }
 
     fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
index dfb28b473ff267c240981ae9f3bf78a58c4dcc33..b31f9f3c7b14f9c30f6fb91f103be0df2775f268 100644 (file)
@@ -443,7 +443,7 @@ fn opaque_type_projection_predicates(
 
     let bounds = tcx.predicates_of(def_id);
     let predicates =
-        util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
+        util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred));
 
     let filtered_predicates = predicates.filter_map(|obligation| {
         let pred = obligation.predicate;
index be83ab259c2ecc0bcc96bd9484b099a70a593434..258c5b77df25bc21c938fdee530147ba7f4b4a3c 100644 (file)
@@ -246,7 +246,7 @@ pub fn get_conversion_methods(
                     //
                     // FIXME? Other potential candidate methods: `as_ref` and
                     // `as_mut`?
-                    .any(|a| a.check_name(sym::rustc_conversion_suggestion))
+                    .any(|a| self.sess().check_name(a, sym::rustc_conversion_suggestion))
         });
 
         methods
index 88c47b38ccc40b4e3ade7e772416e6304abd54f0..9ef9164191675cf6432dd918200323153b8fc085 100644 (file)
@@ -368,6 +368,6 @@ fn binders<T>(
         let anon_b = self.tcx.anonymize_late_bound_regions(&b);
         self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
 
-        Ok(a.clone())
+        Ok(a)
     }
 }
index dc2172650e574d298b1196f0eecdf2999f64f4fb..b3287caa0bfc879ed32249a4be2db575a34dc71f 100644 (file)
@@ -379,17 +379,46 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 
             sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
 
-            sym::count_code_region => {
-                (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
-            }
+            sym::count_code_region => (
+                0,
+                vec![
+                    tcx.types.u64,
+                    tcx.types.u32,
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
+                tcx.mk_unit(),
+            ),
 
             sym::coverage_counter_add | sym::coverage_counter_subtract => (
                 0,
-                vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32],
+                vec![
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
                 tcx.mk_unit(),
             ),
 
-            sym::coverage_unreachable => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()),
+            sym::coverage_unreachable => (
+                0,
+                vec![
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
+                tcx.mk_unit(),
+            ),
 
             other => {
                 struct_span_err!(
index 6cefc99f7b1718a46a94158022c66a60e95fac7d..3d58fb30d91e409b75a30562712e54fad71ec512 100644 (file)
@@ -2603,7 +2603,7 @@ 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.parse_sess, attr) {
+            for r in attr::find_repr_attrs(&tcx.sess, attr) {
                 if let attr::ReprPacked(pack) = r {
                     if let Some(repr_pack) = repr.pack {
                         if pack as u64 != repr_pack.bytes() {
@@ -2814,7 +2814,7 @@ pub fn check_enum<'tcx>(
 
     if vs.is_empty() {
         let attributes = tcx.get_attrs(def_id.to_def_id());
-        if let Some(attr) = attr::find_by_name(&attributes, sym::repr) {
+        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
             struct_span_err!(
                 tcx.sess,
                 attr.span,
index 9c7ea34bf51b6b89c545223c5338f92b19e9e964..f598ada900feecfd2f6062cac615917acfecfa41 100644 (file)
@@ -1114,7 +1114,7 @@ fn check_struct_pat_fields(
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields));
+            unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
         }
         match (inexistent_fields_err, unmentioned_err) {
             (Some(mut i), Some(mut u)) => {
@@ -1237,13 +1237,13 @@ fn error_inexistent_fields(
         if tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "This error indicates that a struct pattern attempted to \
-                    extract a non-existent field from a struct. Struct fields \
-                    are identified by the name used before the colon : so struct \
-                    patterns should resemble the declaration of the struct type \
-                    being matched.\n\n\
-                    If you are using shorthand field patterns but want to refer \
-                    to the struct field by a different name, you should rename \
-                    it explicitly.",
+                 extract a non-existent field from a struct. Struct fields \
+                 are identified by the name used before the colon : so struct \
+                 patterns should resemble the declaration of the struct type \
+                 being matched.\n\n\
+                 If you are using shorthand field patterns but want to refer \
+                 to the struct field by a different name, you should rename \
+                 it explicitly.",
             );
         }
         err
@@ -1299,7 +1299,7 @@ fn error_tuple_variant_as_struct_pat(
 
     fn error_unmentioned_fields(
         &self,
-        span: Span,
+        pat: &Pat<'_>,
         unmentioned_fields: &[Ident],
     ) -> DiagnosticBuilder<'tcx> {
         let field_names = if unmentioned_fields.len() == 1 {
@@ -1312,23 +1312,23 @@ fn error_unmentioned_fields(
                 .join(", ");
             format!("fields {}", fields)
         };
-        let mut diag = struct_span_err!(
+        let mut err = struct_span_err!(
             self.tcx.sess,
-            span,
+            pat.span,
             E0027,
             "pattern does not mention {}",
             field_names
         );
-        diag.span_label(span, format!("missing {}", field_names));
-        if self.tcx.sess.teach(&diag.get_code().unwrap()) {
-            diag.note(
+        err.span_label(pat.span, format!("missing {}", field_names));
+        if self.tcx.sess.teach(&err.get_code().unwrap()) {
+            err.note(
                 "This error indicates that a pattern for a struct fails to specify a \
-                    sub-pattern for every one of the struct's fields. Ensure that each field \
-                    from the struct's definition is mentioned in the pattern, or use `..` to \
-                    ignore unwanted fields.",
+                 sub-pattern for every one of the struct's fields. Ensure that each field \
+                 from the struct's definition is mentioned in the pattern, or use `..` to \
+                 ignore unwanted fields.",
             );
         }
-        diag
+        err
     }
 
     fn check_pat_box(
index 12468750923554ffc79b4db2ff62b9c50cfa706f..84f34c0039a0a11c2c4bd90b52bd0f0457180818 100644 (file)
@@ -200,13 +200,11 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
         // Gather up expressions we want to munge.
         let mut exprs = vec![expr];
 
-        loop {
-            match exprs.last().unwrap().kind {
-                hir::ExprKind::Field(ref expr, _)
-                | hir::ExprKind::Index(ref expr, _)
-                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
-                _ => break,
-            }
+        while let hir::ExprKind::Field(ref expr, _)
+        | hir::ExprKind::Index(ref expr, _)
+        | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) = exprs.last().unwrap().kind
+        {
+            exprs.push(&expr);
         }
 
         debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
index 97df065500a1666885a4a0446705649ff9716893..c0f56a28172829c71f5ddc1f92f9afc9b4d33a8d 100644 (file)
@@ -20,7 +20,7 @@
 use crate::middle::resolve_lifetime as rl;
 use rustc_ast::ast;
 use rustc_ast::ast::MetaItemKind;
-use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
+use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability};
@@ -1238,6 +1238,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 // HACK(eddyb) this provides the correct generics when
                 // `feature(const_generics)` is enabled, so that const expressions
                 // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+                //
+                // Note that we do not supply the parent generics when using
+                // `feature(min_const_generics)`.
                 Some(parent_def_id.to_def_id())
             } else {
                 let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
@@ -2351,13 +2354,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     let mut link_ordinal_span = None;
     let mut no_sanitize_span = None;
     for attr in attrs.iter() {
-        if attr.check_name(sym::cold) {
+        if tcx.sess.check_name(attr, sym::cold) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
-        } else if attr.check_name(sym::rustc_allocator) {
+        } else if tcx.sess.check_name(attr, sym::rustc_allocator) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
-        } else if attr.check_name(sym::unwind) {
+        } else if tcx.sess.check_name(attr, sym::unwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
-        } else if attr.check_name(sym::ffi_returns_twice) {
+        } else if tcx.sess.check_name(attr, sym::ffi_returns_twice) {
             if tcx.is_foreign_item(id) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
             } else {
@@ -2370,9 +2373,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 )
                 .emit();
             }
-        } else if attr.check_name(sym::ffi_pure) {
+        } else if tcx.sess.check_name(attr, sym::ffi_pure) {
             if tcx.is_foreign_item(id) {
-                if attrs.iter().any(|a| a.check_name(sym::ffi_const)) {
+                if attrs.iter().any(|a| tcx.sess.check_name(a, sym::ffi_const)) {
                     // `#[ffi_const]` functions cannot be `#[ffi_pure]`
                     struct_span_err!(
                         tcx.sess,
@@ -2394,7 +2397,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 )
                 .emit();
             }
-        } else if attr.check_name(sym::ffi_const) {
+        } else if tcx.sess.check_name(attr, sym::ffi_const) {
             if tcx.is_foreign_item(id) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
             } else {
@@ -2407,25 +2410,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 )
                 .emit();
             }
-        } else if attr.check_name(sym::rustc_allocator_nounwind) {
+        } else if tcx.sess.check_name(attr, sym::rustc_allocator_nounwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
-        } else if attr.check_name(sym::naked) {
+        } else if tcx.sess.check_name(attr, sym::naked) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
-        } else if attr.check_name(sym::no_mangle) {
+        } else if tcx.sess.check_name(attr, sym::no_mangle) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
-        } else if attr.check_name(sym::rustc_std_internal_symbol) {
+        } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
-        } else if attr.check_name(sym::used) {
+        } else if tcx.sess.check_name(attr, sym::used) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
-        } else if attr.check_name(sym::thread_local) {
+        } else if tcx.sess.check_name(attr, sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
-        } else if attr.check_name(sym::track_caller) {
+        } else if tcx.sess.check_name(attr, sym::track_caller) {
             if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
                 struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
                     .emit();
             }
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
-        } else if attr.check_name(sym::export_name) {
+        } else if tcx.sess.check_name(attr, sym::export_name) {
             if let Some(s) = attr.value_str() {
                 if s.as_str().contains('\0') {
                     // `#[export_name = ...]` will be converted to a null-terminated string,
@@ -2440,7 +2443,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 }
                 codegen_fn_attrs.export_name = Some(s);
             }
-        } else if attr.check_name(sym::target_feature) {
+        } else if tcx.sess.check_name(attr, sym::target_feature) {
             if !tcx.features().target_feature_11 {
                 check_target_feature_safe_fn(tcx, id, attr.span);
             } else if let Some(local_id) = id.as_local() {
@@ -2455,11 +2458,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 &supported_target_features,
                 &mut codegen_fn_attrs.target_features,
             );
-        } else if attr.check_name(sym::linkage) {
+        } else if tcx.sess.check_name(attr, sym::linkage) {
             if let Some(val) = attr.value_str() {
                 codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
             }
-        } else if attr.check_name(sym::link_section) {
+        } else if tcx.sess.check_name(attr, sym::link_section) {
             if let Some(val) = attr.value_str() {
                 if val.as_str().bytes().any(|b| b == 0) {
                     let msg = format!(
@@ -2472,14 +2475,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                     codegen_fn_attrs.link_section = Some(val);
                 }
             }
-        } else if attr.check_name(sym::link_name) {
+        } else if tcx.sess.check_name(attr, sym::link_name) {
             codegen_fn_attrs.link_name = attr.value_str();
-        } else if attr.check_name(sym::link_ordinal) {
+        } else if tcx.sess.check_name(attr, sym::link_ordinal) {
             link_ordinal_span = Some(attr.span);
             if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
                 codegen_fn_attrs.link_ordinal = ordinal;
             }
-        } else if attr.check_name(sym::no_sanitize) {
+        } else if tcx.sess.check_name(attr, sym::no_sanitize) {
             no_sanitize_span = Some(attr.span);
             if let Some(list) = attr.meta_item_list() {
                 for item in list.iter() {
@@ -2506,11 +2509,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         }
         match attr.meta().map(|i| i.kind) {
             Some(MetaItemKind::Word) => {
-                mark_used(attr);
+                tcx.sess.mark_attr_used(attr);
                 InlineAttr::Hint
             }
             Some(MetaItemKind::List(ref items)) => {
-                mark_used(attr);
+                tcx.sess.mark_attr_used(attr);
                 inline_span = Some(attr.span);
                 if items.len() != 1 {
                     struct_span_err!(
@@ -2553,7 +2556,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 ia
             }
             Some(MetaItemKind::List(ref items)) => {
-                mark_used(attr);
+                tcx.sess.mark_attr_used(attr);
                 inline_span = Some(attr.span);
                 if items.len() != 1 {
                     err(attr.span, "expected one argument");
@@ -2614,7 +2617,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     if tcx.is_weak_lang_item(id) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
     }
-    if let Some(name) = weak_lang_items::link_name(&attrs) {
+    let check_name = |attr, sym| tcx.sess.check_name(attr, sym);
+    if let Some(name) = weak_lang_items::link_name(check_name, &attrs) {
         codegen_fn_attrs.export_name = Some(name);
         codegen_fn_attrs.link_name = Some(name);
     }
index 8c9cd50a17d6a63ba6b95102951e16b70d4e6b1f..17444c6d0ac957442c7760123e1a2f47bf7638a7 100644 (file)
@@ -326,21 +326,39 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
             GenericParamKind::Const { ty: ref hir_ty, .. } => {
                 let ty = icx.to_ty(hir_ty);
-                let err = match ty.peel_refs().kind {
-                    ty::FnPtr(_) => Some("function pointers"),
-                    ty::RawPtr(_) => Some("raw pointers"),
-                    _ => None,
+                let err_ty_str;
+                let err = if tcx.features().min_const_generics {
+                    match ty.kind {
+                        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
+                        ty::FnPtr(_) => Some("function pointers"),
+                        ty::RawPtr(_) => Some("raw pointers"),
+                        _ => {
+                            err_ty_str = format!("`{}`", ty);
+                            Some(err_ty_str.as_str())
+                        }
+                    }
+                } else {
+                    match ty.peel_refs().kind {
+                        ty::FnPtr(_) => Some("function pointers"),
+                        ty::RawPtr(_) => Some("raw pointers"),
+                        _ => None,
+                    }
                 };
                 if let Some(unsupported_type) = err {
-                    tcx.sess
-                        .struct_span_err(
-                            hir_ty.span,
-                            &format!(
-                                "using {} as const generic parameters is forbidden",
-                                unsupported_type
-                            ),
-                        )
-                        .emit();
+                    let mut err = tcx.sess.struct_span_err(
+                        hir_ty.span,
+                        &format!(
+                            "using {} as const generic parameters is forbidden",
+                            unsupported_type
+                        ),
+                    );
+
+                    if tcx.features().min_const_generics {
+                        err.note("the only supported types are integers, `bool` and `char`")
+                        .note("more complex types are supported with `#[feature(const_generics)]`").emit()
+                    } else {
+                        err.emit();
+                    }
                 };
                 if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
                     .is_some()
index 9ba2545ba63cbc8d98d512826a4679d9667f3f01..a8247e2f494ccf1a3fd6b2a2bc1c09c8e86dc7f9 100644 (file)
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util;
 use rustc_session::config::EntryFnType;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
@@ -194,6 +194,23 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
                         .emit();
                         error = true;
                     }
+
+                    for attr in it.attrs {
+                        if tcx.sess.check_name(attr, 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 {
                         return;
                     }
@@ -268,12 +285,29 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
                             tcx.sess,
                             span,
                             E0752,
-                            "start is not allowed to be `async`"
+                            "`start` is not allowed to be `async`"
                         )
-                        .span_label(span, "start is not allowed to be `async`")
+                        .span_label(span, "`start` is not allowed to be `async`")
                         .emit();
                         error = true;
                     }
+
+                    for attr in it.attrs {
+                        if tcx.sess.check_name(attr, sym::track_caller) {
+                            tcx.sess
+                                .struct_span_err(
+                                    attr.span,
+                                    "`start` is not allowed to be `#[track_caller]`",
+                                )
+                                .span_label(
+                                    start_span,
+                                    "`start` is not allowed to be `#[track_caller]`",
+                                )
+                                .emit();
+                            error = true;
+                        }
+                    }
+
                     if error {
                         return;
                     }
index afc7cb346eb428299fec3bb7093a749d2916e30c..8a6fe620af7a319758cf4d3c26960f2f908e2388 100644 (file)
@@ -583,7 +583,7 @@ fn total_fields_in_adt_variant(
                 self.tcx()
                     .sess
                     .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
-                return Err(());
+                Err(())
             }
         }
     }
@@ -596,7 +596,7 @@ fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<
             ty::Tuple(substs) => Ok(substs.len()),
             _ => {
                 self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
-                return Err(());
+                Err(())
             }
         }
     }
index 8d1193e7f82b51cce1c8c8b1746b2e502ca46ce5..b4ced412e5e5565dbb01e51ca0fc28f7dd975603 100644 (file)
@@ -2,8 +2,8 @@
 
 use rustc_ast::ast::*;
 use rustc_ast::attr;
-use rustc_ast::with_default_session_globals;
 use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::with_default_session_globals;
 use rustc_span::DUMMY_SP;
 
 fn word_cfg(s: &str) -> Cfg {
index 2a090d6efa5fd38a5bed05e08c4480e6d9bab3bb..7b1dd5b11ed0e014b97cc46674a2782eb3e5a6df 100644 (file)
@@ -1395,10 +1395,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
                                             _ => None,
                                         });
                                     if let Some(lt) = lifetime.cloned() {
-                                        if !lt.is_elided() {
-                                            let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
-                                            lt_substs.insert(lt_def_id.to_def_id(), lt.clean(cx));
-                                        }
+                                        let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+                                        let cleaned = if !lt.is_elided() {
+                                            lt.clean(cx)
+                                        } else {
+                                            self::types::Lifetime::elided()
+                                        };
+                                        lt_substs.insert(lt_def_id.to_def_id(), cleaned);
                                     }
                                     indices.lifetimes += 1;
                                 }
@@ -1957,21 +1960,17 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
                 output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None },
             }
         } else {
-            let elide_lifetimes = self.args.iter().all(|arg| match arg {
-                hir::GenericArg::Lifetime(lt) => lt.is_elided(),
-                _ => true,
-            });
             GenericArgs::AngleBracketed {
                 args: self
                     .args
                     .iter()
-                    .filter_map(|arg| match arg {
-                        hir::GenericArg::Lifetime(lt) if !elide_lifetimes => {
-                            Some(GenericArg::Lifetime(lt.clean(cx)))
+                    .map(|arg| match arg {
+                        hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+                            GenericArg::Lifetime(lt.clean(cx))
                         }
-                        hir::GenericArg::Lifetime(_) => None,
-                        hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
-                        hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
+                        hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                        hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+                        hir::GenericArg::Const(ct) => GenericArg::Const(ct.clean(cx)),
                     })
                     .collect(),
                 bindings: self.bindings.clean(cx),
index 1bea41b658532f2d29e9e6d973713e7fef8e8cdb..50eca75d7cab2cc211e19f0d6b5986b18326c3c7 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::attr;
-use rustc_ast::util::comments::strip_doc_comment_decoration;
+use rustc_ast::util::comments::beautify_doc_string;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -506,10 +506,11 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute])
             .iter()
             .filter_map(|attr| {
                 if let Some(value) = attr.doc_str() {
-                    let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() {
-                        (strip_doc_comment_decoration(value), DocFragment::SugaredDoc)
+                    let value = beautify_doc_string(value);
+                    let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() {
+                        DocFragment::SugaredDoc
                     } else {
-                        (value.to_string(), DocFragment::RawDoc)
+                        DocFragment::RawDoc
                     };
 
                     let line = doc_line;
@@ -749,6 +750,10 @@ pub fn get_ref<'a>(&'a self) -> &'a str {
     pub fn statik() -> Lifetime {
         Lifetime("'static".to_string())
     }
+
+    pub fn elided() -> Lifetime {
+        Lifetime("'_".to_string())
+    }
 }
 
 #[derive(Clone, Debug)]
index 52c306688268f51be4980e8e6e4ad0416672a573..c22538f21f69fbefb567942de1fc61e8bbdb63ee 100644 (file)
@@ -2,9 +2,9 @@
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::{
     inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
-    GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, MacroKind, Path,
-    PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, TypeBinding,
-    TypeKind, Visibility, WherePredicate,
+    GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime,
+    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type,
+    TypeBinding, TypeKind, Visibility, WherePredicate,
 };
 use crate::core::DocContext;
 
@@ -121,7 +121,10 @@ pub fn external_generic_args(
     let args: Vec<_> = substs
         .iter()
         .filter_map(|kind| match kind.unpack() {
-            GenericArgKind::Lifetime(lt) => lt.clean(cx).map(GenericArg::Lifetime),
+            GenericArgKind::Lifetime(lt) => match lt {
+                ty::ReLateBound(_, ty::BrAnon(_)) => Some(GenericArg::Lifetime(Lifetime::elided())),
+                _ => lt.clean(cx).map(GenericArg::Lifetime),
+            },
             GenericArgKind::Type(_) if skip_self => {
                 skip_self = false;
                 None
@@ -607,6 +610,9 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
         Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
         Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
         Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
+        Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+            (cx.tcx.parent(i).unwrap(), TypeKind::Trait)
+        }
         Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
         Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
         Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),
index 4ce6bcbe2749e0e7e4bb7a18954c0dce1ad809a6..8b52ce710a45fd329c59d5eac30cfe5eec1b1860 100644 (file)
@@ -69,14 +69,14 @@ pub fn write<P, C, E>(&self, path: P, contents: C) -> Result<(), E>
             let sender = self.errors.clone().expect("can't write after closing");
             rayon::spawn(move || {
                 fs::write(&path, contents).unwrap_or_else(|e| {
-                    sender
-                        .send(format!("\"{}\": {}", path.display(), e))
-                        .expect(&format!("failed to send error on \"{}\"", path.display()));
+                    sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
+                        panic!("failed to send error on \"{}\"", path.display())
+                    })
                 });
             });
-            Ok(())
         } else {
-            Ok(try_err!(fs::write(&path, contents), path))
+            try_err!(fs::write(&path, contents), path);
         }
+        Ok(())
     }
 }
index 01b25fd6be4ac9bce04084b695ef2423dd9cfd96..21e476cbe06883bf43b8b5511d47db3177bf6879 100644 (file)
@@ -1,6 +1,6 @@
-use rustc_ast::attr::with_session_globals;
 use rustc_session::parse::ParseSess;
 use rustc_span::edition::Edition;
+use rustc_span::with_session_globals;
 use rustc_span::FileName;
 
 use super::Classifier;
index 4f08452767a877011e96822de62b2ead67cf4272..d5f7ddcbdfbde6d7547aa280b0e272ed6feca84f 100644 (file)
 extern crate rustc_typeck;
 extern crate test as testing;
 #[macro_use]
-extern crate tracing as log;
+extern crate tracing;
 
 use std::default::Default;
 use std::env;
-use std::panic;
 use std::process;
 
+use rustc_errors::ErrorReported;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
 use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
@@ -82,22 +82,14 @@ struct Output {
 }
 
 pub fn main() {
-    let thread_stack_size: usize = if cfg!(target_os = "haiku") {
-        16_000_000 // 16MB on Haiku
-    } else {
-        32_000_000 // 32MB on other platforms
-    };
     rustc_driver::set_sigpipe_handler();
     rustc_driver::install_ice_hook();
     rustc_driver::init_env_logger("RUSTDOC_LOG");
-
-    let res = std::thread::Builder::new()
-        .stack_size(thread_stack_size)
-        .spawn(move || get_args().map(|args| main_args(&args)).unwrap_or(1))
-        .unwrap()
-        .join()
-        .unwrap_or(rustc_driver::EXIT_FAILURE);
-    process::exit(res);
+    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
+        Some(args) => main_args(&args),
+        _ => Err(ErrorReported),
+    });
+    process::exit(exit_code);
 }
 
 fn get_args() -> Option<Vec<String>> {
@@ -418,7 +410,10 @@ fn usage(argv0: &str) {
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
 }
 
-fn main_args(args: &[String]) -> i32 {
+/// A result type used by several functions under `main()`.
+type MainResult = Result<(), ErrorReported>;
+
+fn main_args(args: &[String]) -> MainResult {
     let mut options = getopts::Options::new();
     for option in opts() {
         (option.apply)(&mut options);
@@ -429,24 +424,27 @@ fn main_args(args: &[String]) -> i32 {
             early_error(ErrorOutputType::default(), &err.to_string());
         }
     };
+
+    // Note that we discard any distinction between different non-zero exit
+    // codes from `from_matches` here.
     let options = match config::Options::from_matches(&matches) {
         Ok(opts) => opts,
-        Err(code) => return code,
+        Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
     };
-    rustc_interface::interface::setup_callbacks_and_run_in_default_thread_pool_with_globals(
+    rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals(
         options.edition,
+        1, // this runs single-threaded, even in a parallel compiler
+        &None,
         move || main_options(options),
     )
 }
 
-fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> i32 {
+fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
     match res {
-        Ok(()) => 0,
+        Ok(()) => Ok(()),
         Err(err) => {
-            if !err.is_empty() {
-                diag.struct_err(&err).emit();
-            }
-            1
+            diag.struct_err(&err).emit();
+            Err(ErrorReported)
         }
     }
 }
@@ -457,9 +455,9 @@ fn run_renderer<T: formats::FormatRenderer>(
     render_info: config::RenderInfo,
     diag: &rustc_errors::Handler,
     edition: rustc_span::edition::Edition,
-) -> i32 {
+) -> MainResult {
     match formats::run_format::<T>(krate, renderopts, render_info, &diag, edition) {
-        Ok(_) => rustc_driver::EXIT_SUCCESS,
+        Ok(_) => Ok(()),
         Err(e) => {
             let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error));
             let file = e.file.display().to_string();
@@ -468,17 +466,17 @@ fn run_renderer<T: formats::FormatRenderer>(
             } else {
                 msg.note(&format!("failed to create or modify \"{}\"", file)).emit()
             }
-            rustc_driver::EXIT_FAILURE
+            Err(ErrorReported)
         }
     }
 }
 
-fn main_options(options: config::Options) -> i32 {
+fn main_options(options: config::Options) -> MainResult {
     let diag = core::new_handler(options.error_format, None, &options.debugging_options);
 
     match (options.should_test, options.markdown_input()) {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
-        (true, false) => return wrap_return(&diag, test::run(options)),
+        (true, false) => return test::run(options),
         (false, true) => {
             return wrap_return(
                 &diag,
@@ -500,44 +498,37 @@ fn main_options(options: config::Options) -> i32 {
     // compiler all the way through the analysis passes. The rustdoc output is
     // then generated from the cleaned AST of the crate. This runs all the
     // plug/cleaning passes.
-    let result = rustc_driver::catch_fatal_errors(move || {
-        let crate_name = options.crate_name.clone();
-        let crate_version = options.crate_version.clone();
-        let output_format = options.output_format;
-        let (mut krate, renderinfo, renderopts) = core::run_core(options);
+    let crate_name = options.crate_name.clone();
+    let crate_version = options.crate_version.clone();
+    let output_format = options.output_format;
+    let (mut krate, renderinfo, renderopts) = core::run_core(options);
 
-        info!("finished with rustc");
+    info!("finished with rustc");
 
-        if let Some(name) = crate_name {
-            krate.name = name
-        }
+    if let Some(name) = crate_name {
+        krate.name = name
+    }
 
-        krate.version = crate_version;
+    krate.version = crate_version;
 
-        let out = Output { krate, renderinfo, renderopts };
+    let out = Output { krate, renderinfo, renderopts };
 
-        if show_coverage {
-            // if we ran coverage, bail early, we don't need to also generate docs at this point
-            // (also we didn't load in any of the useful passes)
-            return rustc_driver::EXIT_SUCCESS;
-        }
+    if show_coverage {
+        // if we ran coverage, bail early, we don't need to also generate docs at this point
+        // (also we didn't load in any of the useful passes)
+        return Ok(());
+    }
 
-        let Output { krate, renderinfo, renderopts } = out;
-        info!("going to format");
-        let (error_format, edition, debugging_options) = diag_opts;
-        let diag = core::new_handler(error_format, None, &debugging_options);
-        match output_format {
-            None | Some(config::OutputFormat::Html) => {
-                run_renderer::<html::render::Context>(krate, renderopts, renderinfo, &diag, edition)
-            }
-            Some(config::OutputFormat::Json) => {
-                run_renderer::<json::JsonRenderer>(krate, renderopts, renderinfo, &diag, edition)
-            }
+    let Output { krate, renderinfo, renderopts } = out;
+    info!("going to format");
+    let (error_format, edition, debugging_options) = diag_opts;
+    let diag = core::new_handler(error_format, None, &debugging_options);
+    match output_format {
+        None | Some(config::OutputFormat::Html) => {
+            run_renderer::<html::render::Context>(krate, renderopts, renderinfo, &diag, edition)
+        }
+        Some(config::OutputFormat::Json) => {
+            run_renderer::<json::JsonRenderer>(krate, renderopts, renderinfo, &diag, edition)
         }
-    });
-
-    match result {
-        Ok(output) => output,
-        Err(_) => panic::resume_unwind(Box::new(rustc_errors::FatalErrorMarker)),
     }
 }
index 98300385c8fb8876fec63de84292ef5a02dc9f47..b722cfc8f7521f9bb3d46912cba0b8f145a40e15 100644 (file)
@@ -4,7 +4,6 @@
 use crate::fold::{self, DocFolder};
 use crate::passes::Pass;
 
-use rustc_ast::attr;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use serde::Serialize;
@@ -155,7 +154,10 @@ fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
                 return Some(i);
             }
             clean::ImplItem(ref impl_)
-                if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived)
+                if i.attrs
+                    .other_attrs
+                    .iter()
+                    .any(|item| item.has_name(sym::automatically_derived))
                     || impl_.synthetic
                     || impl_.blanket_impl.is_some() =>
             {
index bf7a43236e061dd1a6aa962aad9d94318e74f744..f84486347afcdbeca231eccb782e54ee83eec9a2 100644 (file)
@@ -17,6 +17,7 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
 
+use std::cell::Cell;
 use std::ops::Range;
 
 use crate::clean::*;
@@ -62,11 +63,15 @@ struct LinkCollector<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
     // NOTE: this may not necessarily be a module in the current crate
     mod_ids: Vec<DefId>,
+    /// This is used to store the kind of associated items,
+    /// because `clean` and the disambiguator code expect them to be different.
+    /// See the code for associated items on inherent impls for details.
+    kind_side_channel: Cell<Option<DefKind>>,
 }
 
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     fn new(cx: &'a DocContext<'tcx>) -> Self {
-        LinkCollector { cx, mod_ids: Vec::new() }
+        LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) }
     }
 
     fn variant_field(
@@ -174,7 +179,7 @@ fn macro_resolve(&self, path_str: &str, parent_id: Option<DefId>) -> Option<Res>
     fn resolve(
         &self,
         path_str: &str,
-        disambiguator: Option<&str>,
+        disambiguator: Option<Disambiguator>,
         ns: Namespace,
         current_item: &Option<String>,
         parent_id: Option<DefId>,
@@ -214,7 +219,7 @@ fn resolve(
                     Res::Def(DefKind::Mod, _) => {
                         // This resolved to a module, but if we were passed `type@`,
                         // we want primitive types to take precedence instead.
-                        if disambiguator == Some("type") {
+                        if disambiguator == Some(Disambiguator::Namespace(Namespace::TypeNS)) {
                             if let Some(prim) = is_primitive(path_str, ns) {
                                 if extra_fragment.is_some() {
                                     return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
@@ -347,6 +352,10 @@ fn resolve(
                                 AnchorFailure::AssocConstant
                             }))
                         } else {
+                            // HACK(jynelson): `clean` expects the type, not the associated item.
+                            // but the disambiguator logic expects the associated item.
+                            // Store the kind in a side channel so that only the disambiguator logic looks at it.
+                            self.kind_side_channel.replace(Some(item.kind.as_def_kind()));
                             Ok((ty_res, Some(format!("{}.{}", out, item_name))))
                         }
                     } else {
@@ -415,7 +424,8 @@ fn resolve(
                                 AnchorFailure::Method
                             }))
                         } else {
-                            Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
+                            let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+                            Ok((res, Some(format!("{}.{}", kind, item_name))))
                         }
                     } else {
                         self.variant_field(path_str, current_item, module_id)
@@ -574,46 +584,14 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             };
             let resolved_self;
             let mut path_str;
+            let disambiguator;
             let (res, fragment) = {
-                let mut kind = None;
-                let mut disambiguator = None;
-                path_str = if let Some(prefix) =
-                    ["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
-                        .iter()
-                        .find(|p| link.starts_with(**p))
-                {
-                    kind = Some(TypeNS);
-                    disambiguator = Some(&prefix[..prefix.len() - 1]);
-                    link.trim_start_matches(prefix)
-                } else if let Some(prefix) =
-                    ["const@", "static@", "value@", "function@", "fn@", "method@"]
-                        .iter()
-                        .find(|p| link.starts_with(**p))
-                {
-                    kind = Some(ValueNS);
-                    disambiguator = Some(&prefix[..prefix.len() - 1]);
-                    link.trim_start_matches(prefix)
-                } else if link.ends_with("!()") {
-                    kind = Some(MacroNS);
-                    link.trim_end_matches("!()")
-                } else if link.ends_with("()") {
-                    kind = Some(ValueNS);
-                    disambiguator = Some("fn");
-                    link.trim_end_matches("()")
-                } else if link.starts_with("macro@") {
-                    kind = Some(MacroNS);
-                    disambiguator = Some("macro");
-                    link.trim_start_matches("macro@")
-                } else if link.starts_with("derive@") {
-                    kind = Some(MacroNS);
-                    disambiguator = Some("derive");
-                    link.trim_start_matches("derive@")
-                } else if link.ends_with('!') {
-                    kind = Some(MacroNS);
-                    disambiguator = Some("macro");
-                    link.trim_end_matches('!')
+                path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
+                    disambiguator = Some(d);
+                    path
                 } else {
-                    &link[..]
+                    disambiguator = None;
+                    &link
                 }
                 .trim();
 
@@ -646,7 +624,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                     }
                 }
 
-                match kind {
+                match disambiguator.map(Disambiguator::ns) {
                     Some(ns @ ValueNS) => {
                         match self.resolve(
                             path_str,
@@ -789,6 +767,42 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             } else {
                 debug!("intra-doc link to {} resolved to {:?}", path_str, res);
 
+                // Disallow e.g. linking to enums with `struct@`
+                if let Res::Def(kind, id) = res {
+                    debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+                    match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) {
+                        | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+                        // NOTE: this allows 'method' to mean both normal functions and associated functions
+                        // This can't cause ambiguity because both are in the same namespace.
+                        | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+                        // These are namespaces; allow anything in the namespace to match
+                        | (_, Some(Disambiguator::Namespace(_)))
+                        // If no disambiguator given, allow anything
+                        | (_, None)
+                        // All of these are valid, so do nothing
+                        => {}
+                        (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+                        (_, Some(Disambiguator::Kind(expected))) => {
+                            // The resolved item did not match the disambiguator; give a better error than 'not found'
+                            let msg = format!("incompatible link kind for `{}`", path_str);
+                            report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| {
+                                // HACK(jynelson): by looking at the source I saw the DefId we pass
+                                // for `expected.descr()` doesn't matter, since it's not a crate
+                                let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id));
+                                let suggestion = Disambiguator::display_for(kind, path_str);
+                                let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id));
+                                diag.note(&note);
+                                if let Some(sp) = sp {
+                                    diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect);
+                                } else {
+                                    diag.help(&format!("{}: {}", help_msg, suggestion));
+                                }
+                            });
+                            continue;
+                        }
+                    }
+                }
+
                 // item can be non-local e.g. when using #[doc(primitive = "pointer")]
                 if let Some((src_id, dst_id)) = res
                     .opt_def_id()
@@ -837,6 +851,94 @@ fn fold_crate(&mut self, mut c: Crate) -> Crate {
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Disambiguator {
+    Kind(DefKind),
+    Namespace(Namespace),
+}
+
+impl Disambiguator {
+    /// (disambiguator, path_str)
+    fn from_str(link: &str) -> Result<(Self, &str), ()> {
+        use Disambiguator::{Kind, Namespace as NS};
+
+        let find_suffix = || {
+            let suffixes = [
+                ("!()", DefKind::Macro(MacroKind::Bang)),
+                ("()", DefKind::Fn),
+                ("!", DefKind::Macro(MacroKind::Bang)),
+            ];
+            for &(suffix, kind) in &suffixes {
+                if link.ends_with(suffix) {
+                    return Ok((Kind(kind), link.trim_end_matches(suffix)));
+                }
+            }
+            Err(())
+        };
+
+        if let Some(idx) = link.find('@') {
+            let (prefix, rest) = link.split_at(idx);
+            let d = match prefix {
+                "struct" => Kind(DefKind::Struct),
+                "enum" => Kind(DefKind::Enum),
+                "trait" => Kind(DefKind::Trait),
+                "union" => Kind(DefKind::Union),
+                "module" | "mod" => Kind(DefKind::Mod),
+                "const" | "constant" => Kind(DefKind::Const),
+                "static" => Kind(DefKind::Static),
+                "function" | "fn" | "method" => Kind(DefKind::Fn),
+                "derive" => Kind(DefKind::Macro(MacroKind::Derive)),
+                "type" => NS(Namespace::TypeNS),
+                "value" => NS(Namespace::ValueNS),
+                "macro" => NS(Namespace::MacroNS),
+                _ => return find_suffix(),
+            };
+            Ok((d, &rest[1..]))
+        } else {
+            find_suffix()
+        }
+    }
+
+    fn display_for(kind: DefKind, path_str: &str) -> String {
+        if kind == DefKind::Macro(MacroKind::Bang) {
+            return format!("{}!", path_str);
+        } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
+            return format!("{}()", path_str);
+        }
+        let prefix = match kind {
+            DefKind::Struct => "struct",
+            DefKind::Enum => "enum",
+            DefKind::Trait => "trait",
+            DefKind::Union => "union",
+            DefKind::Mod => "mod",
+            DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
+                "const"
+            }
+            DefKind::Static => "static",
+            DefKind::Macro(MacroKind::Derive) => "derive",
+            // Now handle things that don't have a specific disambiguator
+            _ => match kind
+                .ns()
+                .expect("tried to calculate a disambiguator for a def without a namespace?")
+            {
+                Namespace::TypeNS => "type",
+                Namespace::ValueNS => "value",
+                Namespace::MacroNS => "macro",
+            },
+        };
+        format!("{}@{}", prefix, path_str)
+    }
+
+    fn ns(self) -> Namespace {
+        match self {
+            Self::Namespace(n) => n,
+            Self::Kind(k) => {
+                k.ns().expect("only DefKinds with a valid namespace can be disambiguators")
+            }
+        }
+    }
+}
+
 /// Reports a diagnostic for an intra-doc link.
 ///
 /// If no link range is provided, or the source span of the link cannot be determined, the span of
index 0fdeefd79e9f24e6764ed754f6e69f0a74a78c35..3000afde0c25d6172fd91d4ce669fd5657c9a538 100644 (file)
@@ -28,7 +28,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     let mut new_items = Vec::new();
 
     for &cnum in cx.tcx.crates().iter() {
-        for &did in cx.tcx.all_trait_implementations(cnum).iter() {
+        for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
             inline::build_impl(cx, did, None, &mut new_items);
         }
     }
index ba1341e652c395cf7f289ffb43694daf9b7d07a7..62f52ea5213f357d445f04ada98ba219dc2c77e2 100644 (file)
@@ -42,7 +42,7 @@ pub struct TestOptions {
     pub attrs: Vec<String>,
 }
 
-pub fn run(options: Options) -> Result<(), String> {
+pub fn run(options: Options) -> Result<(), ErrorReported> {
     let input = config::Input::File(options.input.clone());
 
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
@@ -150,7 +150,7 @@ pub fn run(options: Options) -> Result<(), String> {
     });
     let tests = match tests {
         Ok(tests) => tests,
-        Err(ErrorReported) => return Err(String::new()),
+        Err(ErrorReported) => return Err(ErrorReported),
     };
 
     test_args.insert(0, "rustdoctest".to_string());
@@ -398,7 +398,7 @@ pub fn make_test(
     // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern
     // crate already is included.
     let result = rustc_driver::catch_fatal_errors(|| {
-        rustc_ast::with_session_globals(edition, || {
+        rustc_span::with_session_globals(edition, || {
             use rustc_errors::emitter::EmitterWriter;
             use rustc_errors::Handler;
             use rustc_parse::maybe_new_parser_from_source_str;
@@ -943,7 +943,12 @@ fn visit_testable<F: FnOnce(&mut Self)>(
         // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
         // anything else, this will combine them for us.
         if let Some(doc) = attrs.collapsed_doc_value() {
-            self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP));
+            // Use the outermost invocation, so that doctest names come from where the docs were written.
+            let span = attrs
+                .span
+                .map(|span| span.ctxt().outer_expn().expansion_cause().unwrap_or(span))
+                .unwrap_or(DUMMY_SP);
+            self.collector.set_position(span);
             markdown::find_testable_code(
                 &doc,
                 self.collector,
diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs
new file mode 100644 (file)
index 0000000..af47b44
--- /dev/null
@@ -0,0 +1,52 @@
+// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+
+// Test that only one copy of `Iter::map` and `iter::repeat` are generated.
+
+fn unused<T>() -> u64 {
+    42
+}
+
+fn foo<T>() {
+    let x = [1, 2, 3, std::mem::size_of::<T>()];
+    x.iter().map(|_| ());
+}
+
+//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0]<core::slice[0]::Iter[0]<usize>, pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.0[External]
+//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0]<core::slice[0]::Iter[0]<usize>, (), pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.1[Internal]
+
+fn bar<T>() {
+    std::iter::repeat(unused::<T>);
+}
+
+//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0]<fn() -> u64> @@ pr_75255-cgu.1[Internal]
+
+pub fn dispatch() {
+    foo::<String>();
+    foo::<Vec<String>>();
+
+    bar::<String>();
+    bar::<Vec<String>>();
+}
+
+// These are all the items that aren't relevant to the test.
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External]
+//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::bar[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::bar[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
diff --git a/src/test/codegen/some-global-nonnull.rs b/src/test/codegen/some-global-nonnull.rs
new file mode 100644 (file)
index 0000000..59c47de
--- /dev/null
@@ -0,0 +1,25 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test
+// CHECK-NEXT: start:
+// CHECK-NEXT: tail call void @ext_fn0()
+#[no_mangle]
+pub fn test() {
+    test_inner(Some(inner0));
+}
+
+fn test_inner(f_maybe: Option<fn()>) {
+    if let Some(f) = f_maybe {
+        f();
+    }
+}
+
+fn inner0() {
+    unsafe { ext_fn0() };
+}
+
+extern "C" {
+    fn ext_fn0();
+}
index e88a99b322ed56d5f050be1f8a50201d2e1b7fb2..5f3a1eb44e4e55179eeb49b90ae3182d6198aed7 100644 (file)
@@ -3,6 +3,9 @@
 // We have to ignore android because of this issue:
 // https://github.com/rust-lang/rust/issues/74847
 // ignore-android
+//
+// We need to use inline assembly, so just use one platform
+// only-x86_64
 
 // compile-flags:-g
 
@@ -24,6 +27,7 @@
 // lldb-command:continue
 
 
+#![feature(asm)]
 #![feature(naked_functions)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
@@ -33,8 +37,6 @@ fn main() {
 }
 
 #[naked]
-fn naked(x: usize, y: usize) {
-    zzz(); // #break
+extern "C" fn naked(x: usize, y: usize) {
+    unsafe { asm!("ret"); } // #break
 }
-
-fn zzz() { () }
index 361b300f28ced614337a106d108863ccb284a2ce..e8f52deabd80917992bbe3c43ccd0defabe45f64 100644 (file)
@@ -9,35 +9,35 @@
 // cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>]
 // cdb-check:    [size]           : 15 [Type: [...]]
 // cdb-check:    [capacity]       : [...]
-// cdb-check:    [[...]] [...]    : 0 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 0 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 1 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 1 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 2 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 2 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 3 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 3 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 4 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 4 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 5 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 5 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 6 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 6 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 7 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 7 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 8 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 8 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 9 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 9 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 10 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 10 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 11 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 11 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 12 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 12 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 13 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 13 [Type: u64]
 // cdb-command: dx hash_set,d
-// cdb-check:    [[...]] [...]    : 14 [Type: unsigned __int64]
+// cdb-check:    [[...]] [...]    : 14 [Type: u64]
 
 // cdb-command: dx hash_map,d
 // cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>]
index e63309a9bd2ad7a1647b3eb419c2b01065ad0044..9c30e0400312adc9889242428cc402a1394a421f 100644 (file)
@@ -1,7 +1,7 @@
+// ignore-endian-big
 extern "C" {
     static X: i32;
 }
-
 static Y: i32 = 42;
 
 // EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff
index bb1c48e8e3c81d8e2fdcfeb9301c689786738971..b0fcb86fcee0f25f6567ca42849cc90844f1929d 100644 (file)
@@ -1,5 +1,5 @@
+// ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-
 static FOO: &[(Option<i32>, &[&str])] =
     &[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
 
index 56839255c0e91770a4fc8f91235fc9ba178b158b..30afedffb39b3d817b0124701c56f8ede105c5a6 100644 (file)
@@ -1,5 +1,5 @@
+// ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-
 // EMIT_MIR const_allocation2.main.ConstProp.after.mir
 fn main() {
     FOO;
index 2ce289aea3fc9f14bba9cc8a7822c6413a5ba3e2..ddeb32ab9a583132579c132fcb1238bd97de3504 100644 (file)
@@ -1,5 +1,5 @@
+// ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-
 // EMIT_MIR const_allocation3.main.ConstProp.after.mir
 fn main() {
     FOO;
diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit
new file mode 100644 (file)
index 0000000..721766f
--- /dev/null
@@ -0,0 +1,85 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11
+      let _1: u8;                          // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+      let mut _2: [u8; 5000];              // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+      let _3: usize;                       // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+      let mut _4: usize;                   // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+      let mut _5: bool;                    // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+          StorageLive(_2);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+          _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:18: 6:22
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+          _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:30: 6:31
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
+          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x00001388))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:17: 6:32
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) }
+-         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+-         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++         assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x00001388))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) }
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x00000002))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
+      }
+  
+      bb1: {
+          _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+          StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+          StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:4:11: 7:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:4:11: 7:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:7:1: 7:2
+          return;                          // scope 0 at $DIR/large_array_index.rs:7:2: 7:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit
new file mode 100644 (file)
index 0000000..eae2ce6
--- /dev/null
@@ -0,0 +1,85 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11
+      let _1: u8;                          // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+      let mut _2: [u8; 5000];              // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+      let _3: usize;                       // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+      let mut _4: usize;                   // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+      let mut _5: bool;                    // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+          StorageLive(_2);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+          _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+                                           // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x00))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:18: 6:22
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+          StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+          _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x0000000000000002))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:30: 6:31
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
+          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+                                           // ty::Const
+                                           // + ty: usize
+                                           // + val: Value(Scalar(0x0000000000001388))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:6:17: 6:32
+                                           // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) }
+-         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+-         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++         assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++                                          // ty::Const
++                                          // + ty: bool
++                                          // + val: Value(Scalar(0x01))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x0000000000001388))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) }
++                                          // ty::Const
++                                          // + ty: usize
++                                          // + val: Value(Scalar(0x0000000000000002))
++                                          // mir::Constant
++                                          // + span: $DIR/large_array_index.rs:6:17: 6:32
++                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
+      }
+  
+      bb1: {
+          _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+          StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+          StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:4:11: 7:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/large_array_index.rs:4:11: 7:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:7:1: 7:2
+          return;                          // scope 0 at $DIR/large_array_index.rs:7:2: 7:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/large_array_index.rs b/src/test/mir-opt/const_prop/large_array_index.rs
new file mode 100644 (file)
index 0000000..48d1343
--- /dev/null
@@ -0,0 +1,7 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR large_array_index.main.ConstProp.diff
+fn main() {
+    // check that we don't propagate this, because it's too large
+    let x: u8 = [0_u8; 5000][2];
+}
index e78bc31b7748022470034a12db776e88d6f94a62..6e2ee0957ab332bd88a5f7f7b270221067eacab8 100644 (file)
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
-+                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002b))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
-+                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
           _2 = &mut _1;                    // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
index 30c9a5d6b8ff739644af6833492ac8b5bb17c3f8..57298605b18737546c5e7ee7ea3800d54a10ee3d 100644 (file)
@@ -1,8 +1,8 @@
+// ignore-endian-big
 // ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -Z mir-opt-level=3
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 #![feature(box_syntax)]
-
 // EMIT_MIR inline_into_box_place.main.Inline.diff
 fn main() {
     let _x: Box<Vec<u32>> = box Vec::new();
index 96df5c6a5189070b408279f9a83a1aefa6ef8869..9ca6f93c9bc08d21aeb506fe6e8fd795a346f67b 100644 (file)
@@ -2,58 +2,76 @@
 + // MIR for `bar` after InstrumentCoverage
   
   fn bar() -> bool {
-      let mut _0: bool;                    // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
-+     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
+      let mut _0: bool;                    // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17
++     let mut _1: ();                      // in scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
   
       bb0: {
-+         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
-+         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 529_u32, const 541_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
++         StorageLive(_1);                 // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
++         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 19_u32, const 18_u32, const 21_u32, const 2_u32) -> bb2; // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
 +                                          // ty::Const
 +                                          // + ty: u64
 +                                          // + val: Value(Scalar(0x8dabe565aaa2aefd))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
 +                                          // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
++                                          // + ty: &str
++                                          // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 })
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000013))
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000013)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000012))
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) }
++                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x00000211))
++                                          // + val: Value(Scalar(0x00000015))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000211)) }
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000015)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x0000021d))
++                                          // + val: Value(Scalar(0x00000002))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000021d)) }
++                                          // + span: /the/src/instrument_coverage.rs:19:18: 19:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
 +     }
 + 
 +     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++         resume;                          // scope 0 at /the/src/instrument_coverage.rs:19:1: 21:2
 +     }
 + 
 +     bb2: {
-+         StorageDead(_1);                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
-          _0 = const true;                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
++         StorageDead(_1);                 // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9
+          _0 = const true;                 // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9
                                            // ty::Const
                                            // + ty: bool
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:19:5: 19:9
+                                           // + span: /the/src/instrument_coverage.rs:20:5: 20:9
                                            // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-          return;                          // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
+          return;                          // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2
       }
   }
   
index 1bcc98de8d4f2072e221f38d201795e6dfb88caa..3f47aa13bf91fdc225b64ce624fe8a961e8dba22 100644 (file)
 + // MIR for `main` after InstrumentCoverage
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
-      let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
-      let mut _2: bool;                    // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-      let mut _3: !;                       // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
-+     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+      let mut _0: ();                      // return place in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
+      let mut _1: ();                      // in scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
+      let mut _2: bool;                    // in scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+      let mut _3: !;                       // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10
++     let mut _4: ();                      // in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
   
       bb0: {
--         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
-+         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 425_u32, const 493_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+-         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
++         StorageLive(_4);                 // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
++         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 10_u32, const 11_u32, const 16_u32, const 2_u32) -> bb7; // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
 +                                          // ty::Const
 +                                          // + ty: u64
 +                                          // + val: Value(Scalar(0xde1b3f75a72fc7f7))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
 +                                          // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
++                                          // + ty: &str
++                                          // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 })
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x0000000a))
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000000a)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x0000000b))
++                                          // mir::Constant
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000000b)) }
++                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001a9))
++                                          // + val: Value(Scalar(0x00000010))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001a9)) }
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000010)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001ed))
++                                          // + val: Value(Scalar(0x00000002))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001ed)) }
++                                          // + span: /the/src/instrument_coverage.rs:10:11: 10:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
       }
   
       bb1: {
-          StorageLive(_2);                 // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-          _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+          StorageLive(_2);                 // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+          _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
                                            // ty::Const
                                            // + ty: fn() -> bool {bar}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:11:12: 11:15
+                                           // + span: /the/src/instrument_coverage.rs:12:12: 12:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+          resume;                          // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
       }
   
       bb3: {
-          FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          FakeRead(ForMatchedPlace, _2);   // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
       }
   
       bb4: {
-          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
       }
   
       bb5: {
-          _1 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          _1 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:11:9: 13:10
+                                           // + span: /the/src/instrument_coverage.rs:12:9: 14:10
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
-          goto -> bb0;                     // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+          StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
+          goto -> bb0;                     // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   
       bb6: {
-          _0 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
+          _0 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:12:13: 12:18
+                                           // + span: /the/src/instrument_coverage.rs:13:13: 13:18
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
-          return;                          // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
+          StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
+          return;                          // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
 +     }
 + 
 +     bb7: {
-+         StorageDead(_4);                 // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++         StorageDead(_4);                 // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
++         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   }
   
index 4770ec9b66e8f18fda66761399dfc8d97b849e62..430573c7c05f474ee8692292a0e66ce2da5b966b 100644 (file)
@@ -3,7 +3,8 @@
 // intrinsics, during codegen.
 
 // needs-profiler-support
-// compile-flags: -Zinstrument-coverage
+// ignore-windows
+// compile-flags: -Zinstrument-coverage --remap-path-prefix={{src-base}}=/the/src
 // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff
 // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
 fn main() {
@@ -18,3 +19,18 @@ fn main() {
 fn bar() -> bool {
     true
 }
+
+// Note that the MIR with injected coverage intrinsics includes references to source locations,
+// including the source file absolute path. Typically, MIR pretty print output with file
+// references are safe because the file prefixes are substituted with `$DIR`, but in this case
+// the file references are encoded as function arguments, with an `Operand` type representation
+// (`Slice` `Allocation` interned byte array) that cannot be normalized by simple substitution.
+//
+// The first workaround is to use the `SourceMap`-supported `--remap-path-prefix` option; however,
+// the implementation of the `--remap-path-prefix` option currently joins the new prefix and the
+// remaining source path with an OS-specific path separator (`\` on Windows). This difference still
+// shows up in the byte array representation of the path, causing Windows tests to fail to match
+// blessed results baselined with a `/` path separator.
+//
+// Since this `mir-opt` test does not have any significant platform dependencies, other than the
+// path separator differences, the final workaround is to disable testing on Windows.
diff --git a/src/test/rustdoc-ui/auxiliary/extern_macros.rs b/src/test/rustdoc-ui/auxiliary/extern_macros.rs
new file mode 100644 (file)
index 0000000..ee1fec4
--- /dev/null
@@ -0,0 +1,7 @@
+#[macro_export]
+macro_rules! attrs_on_struct {
+    ( $( #[$attr:meta] )* ) => {
+        $( #[$attr] )*
+        pub struct ExpandedStruct;
+    }
+}
index f812263c252652e4891e267d4e4bf1b1fb4988d5..e0e1e061ac7dc43454f566b5ee5559d609123a84 100644 (file)
@@ -1,3 +1,5 @@
+// edition:2018
+// aux-build:extern_macros.rs
 // compile-flags:--test --test-args=--test-threads=1
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
 // check-pass
@@ -6,6 +8,10 @@
 //! assert_eq!(1 + 1, 2);
 //! ```
 
+extern crate extern_macros as macros;
+
+use macros::attrs_on_struct;
+
 pub mod foo {
 
     /// ```
@@ -13,3 +19,9 @@ pub mod foo {
     /// ```
     pub fn bar() {}
 }
+
+attrs_on_struct! {
+    /// ```
+    /// assert!(true);
+    /// ```
+}
index 9a55bf5019692753b7f175baaa59f573f1a7292f..c72bd91d1dd13b5225909d02a591ea3c798257b4 100644 (file)
@@ -1,7 +1,8 @@
 
-running 2 tests
-test $DIR/doctest-output.rs - (line 5) ... ok
-test $DIR/doctest-output.rs - foo::bar (line 11) ... ok
+running 3 tests
+test $DIR/doctest-output.rs - (line 7) ... ok
+test $DIR/doctest-output.rs - ExpandedStruct (line 23) ... ok
+test $DIR/doctest-output.rs - foo::bar (line 17) ... ok
 
-test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
 
diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs
new file mode 100644 (file)
index 0000000..1a7a2fc
--- /dev/null
@@ -0,0 +1,68 @@
+#![deny(broken_intra_doc_links)]
+//~^ NOTE lint level is defined
+pub enum S {}
+
+macro_rules! m {
+    () => {};
+}
+
+static s: usize = 0;
+const c: usize = 0;
+
+trait T {}
+
+/// Link to [struct@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [mod@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [union@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [trait@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [struct@T]
+//~^ ERROR incompatible link kind for `T`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [derive@m]
+//~^ ERROR incompatible link kind for `m`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [const@s]
+//~^ ERROR incompatible link kind for `s`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [static@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [fn@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [c()]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [const@f]
+//~^ ERROR incompatible link kind for `f`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr
new file mode 100644 (file)
index 0000000..9edf838
--- /dev/null
@@ -0,0 +1,95 @@
+error: incompatible link kind for `S`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:14:14
+   |
+LL | /// Link to [struct@S]
+   |              ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+   |
+note: the lint level is defined here
+  --> $DIR/intra-links-disambiguator-mismatch.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: this link resolved to an enum, which is not a struct
+
+error: incompatible link kind for `S`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:19:14
+   |
+LL | /// Link to [mod@S]
+   |              ^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+   |
+   = note: this link resolved to an enum, which is not a module
+
+error: incompatible link kind for `S`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:24:14
+   |
+LL | /// Link to [union@S]
+   |              ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+   |
+   = note: this link resolved to an enum, which is not a union
+
+error: incompatible link kind for `S`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:29:14
+   |
+LL | /// Link to [trait@S]
+   |              ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+   |
+   = note: this link resolved to an enum, which is not a trait
+
+error: incompatible link kind for `T`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:34:14
+   |
+LL | /// Link to [struct@T]
+   |              ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T`
+   |
+   = note: this link resolved to a trait, which is not a struct
+
+error: incompatible link kind for `m`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:39:14
+   |
+LL | /// Link to [derive@m]
+   |              ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!`
+   |
+   = note: this link resolved to a macro, which is not a derive macro
+
+error: incompatible link kind for `s`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:44:14
+   |
+LL | /// Link to [const@s]
+   |              ^^^^^^^ help: to link to the static, use its disambiguator: `static@s`
+   |
+   = note: this link resolved to a static, which is not a constant
+
+error: incompatible link kind for `c`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:49:14
+   |
+LL | /// Link to [static@c]
+   |              ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c`
+   |
+   = note: this link resolved to a constant, which is not a static
+
+error: incompatible link kind for `c`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:54:14
+   |
+LL | /// Link to [fn@c]
+   |              ^^^^ help: to link to the constant, use its disambiguator: `const@c`
+   |
+   = note: this link resolved to a constant, which is not a function
+
+error: incompatible link kind for `c`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:59:14
+   |
+LL | /// Link to [c()]
+   |              ^^^ help: to link to the constant, use its disambiguator: `const@c`
+   |
+   = note: this link resolved to a constant, which is not a function
+
+error: incompatible link kind for `f`
+  --> $DIR/intra-links-disambiguator-mismatch.rs:64:14
+   |
+LL | /// Link to [const@f]
+   |              ^^^^^^^ help: to link to the function, use its disambiguator: `f()`
+   |
+   = note: this link resolved to a function, which is not a constant
+
+error: aborting due to 11 previous errors
+
diff --git a/src/test/rustdoc/auxiliary/elided-lifetime.rs b/src/test/rustdoc/auxiliary/elided-lifetime.rs
new file mode 100644 (file)
index 0000000..4f2c933
--- /dev/null
@@ -0,0 +1,11 @@
+#![crate_name = "bar"]
+
+pub struct Ref<'a>(&'a u32);
+
+pub fn test5(a: &u32) -> Ref {
+    Ref(a)
+}
+
+pub fn test6(a: &u32) -> Ref<'_> {
+    Ref(a)
+}
diff --git a/src/test/rustdoc/elided-lifetime.rs b/src/test/rustdoc/elided-lifetime.rs
new file mode 100644 (file)
index 0000000..5a32554
--- /dev/null
@@ -0,0 +1,43 @@
+// aux-build:elided-lifetime.rs
+//
+// rust-lang/rust#75225
+//
+// Since Rust 2018 we encourage writing out <'_> explicitly to make it clear
+// that borrowing is occuring. Make sure rustdoc is following the same idiom.
+
+#![crate_name = "foo"]
+
+pub struct Ref<'a>(&'a u32);
+type ARef<'a> = Ref<'a>;
+
+// @has foo/fn.test1.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test1(a: &u32) -> Ref {
+    Ref(a)
+}
+
+// @has foo/fn.test2.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test2(a: &u32) -> Ref<'_> {
+    Ref(a)
+}
+
+// @has foo/fn.test3.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test3(a: &u32) -> ARef {
+    Ref(a)
+}
+
+// @has foo/fn.test4.html
+// @matches - "Ref</a>&lt;'_&gt;"
+pub fn test4(a: &u32) -> ARef<'_> {
+    Ref(a)
+}
+
+// Ensure external paths in inlined docs also display elided lifetime
+// @has foo/bar/fn.test5.html
+// @matches - "Ref</a>&lt;'_&gt;"
+// @has foo/bar/fn.test6.html
+// @matches - "Ref</a>&lt;'_&gt;"
+#[doc(inline)]
+pub extern crate bar;
diff --git a/src/test/rustdoc/intra-link-trait-item.rs b/src/test/rustdoc/intra-link-trait-item.rs
new file mode 100644 (file)
index 0000000..5427041
--- /dev/null
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+#![deny(broken_intra_doc_links)]
+
+/// Link to [S::assoc_fn()]
+/// Link to [Default::default()]
+// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+pub struct S;
+
+impl S {
+    pub fn assoc_fn() {}
+}
index bfb4da4c8f574e88338bef35ab383ab9bf1bfe04..736a8633dac53c24d7ee909637340847fdabcb30 100644 (file)
@@ -29,7 +29,7 @@ fn name(&self) -> &'static str {
         impl LateLintPass<'_> for $struct {
             fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
                 $(
-                    if !attr::contains_name(&krate.item.attrs, $attr) {
+                    if !cx.sess().contains_name(&krate.item.attrs, $attr) {
                         cx.lint(CRATE_NOT_OKAY, |lint| {
                              let msg = format!("crate is not marked with #![{}]", $attr);
                              lint.build(&msg).set_span(krate.item.span).emit()
index e6a6f73bd4755f025e44b1492f01160a9049fb8b..bd477b793fc709a9a986e7617b20db24f92dd60a 100644 (file)
@@ -27,7 +27,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for Pass {
     fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
-        if !attr::contains_name(&krate.item.attrs, Symbol::intern("crate_okay")) {
+        if !cx.sess().contains_name(&krate.item.attrs, Symbol::intern("crate_okay")) {
             cx.lint(CRATE_NOT_OKAY, |lint| {
                 lint.build("crate is not marked with #![crate_okay]")
                     .set_span(krate.item.span)
index 836cb07d5d17221d18df157f2d6c8ed76b37ebdc..448c57da754a0c31d374ec146834913acae39f02 100644 (file)
@@ -19,7 +19,7 @@
 mod gravy;
 
 pub fn main() {
-    rustc_ast::with_default_session_globals(|| parse());
+    rustc_span::with_default_session_globals(|| parse());
 
     assert_eq!(gravy::foo(), 10);
 }
index 8286b7fdb66984dfe28ac24919c7522d9c339b3c..f0e3ab308e9177eff2fff072982ff329ad978dea 100644 (file)
@@ -208,7 +208,7 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
 }
 
 fn main() {
-    rustc_ast::with_default_session_globals(|| run());
+    rustc_span::with_default_session_globals(|| run());
 }
 
 fn run() {
index 184e4706a4c867077bf86a53495a1a4e54594095..a6c2317c73669efeee0467bc1ad91cfcf1070e1d 100644 (file)
@@ -4,10 +4,11 @@
 // no-prefer-dynamic
 
 #![feature(allocator_api)]
+#![feature(slice_ptr_get)]
 
 extern crate helper;
 
-use std::alloc::{self, AllocInit, AllocRef, Global, Layout, System};
+use std::alloc::{self, AllocRef, Global, Layout, System};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
 static HITS: AtomicUsize = AtomicUsize::new(0);
@@ -37,10 +38,10 @@ fn main() {
     unsafe {
         let layout = Layout::from_size_align(4, 2).unwrap();
 
-        let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
-        helper::work_with(&memory.ptr);
+        let memory = Global.alloc(layout.clone()).unwrap();
+        helper::work_with(&memory);
         assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
-        Global.dealloc(memory.ptr, layout);
+        Global.dealloc(memory.as_non_null_ptr(), layout);
         assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
 
         let s = String::with_capacity(10);
@@ -49,10 +50,10 @@ fn main() {
         drop(s);
         assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
 
-        let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
+        let memory = System.alloc(layout.clone()).unwrap();
         assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
-        helper::work_with(&memory.ptr);
-        System.dealloc(memory.ptr, layout);
+        helper::work_with(&memory);
+        System.dealloc(memory.as_non_null_ptr(), layout);
         assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
     }
 }
index 7de1ab7a5531508111999f8a662c2b11f5d5a191..a1446b3664d4b3c442ceed2771381203a0e22406 100644 (file)
@@ -5,11 +5,12 @@
 // no-prefer-dynamic
 
 #![feature(allocator_api)]
+#![feature(slice_ptr_get)]
 
 extern crate custom;
 extern crate helper;
 
-use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
+use std::alloc::{AllocRef, Global, Layout, System};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
 #[global_allocator]
@@ -20,16 +21,16 @@ fn main() {
         let n = GLOBAL.0.load(Ordering::SeqCst);
         let layout = Layout::from_size_align(4, 2).unwrap();
 
-        let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
-        helper::work_with(&memory.ptr);
+        let memory = Global.alloc(layout.clone()).unwrap();
+        helper::work_with(&memory);
         assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
-        Global.dealloc(memory.ptr, layout);
+        Global.dealloc(memory.as_non_null_ptr(), layout);
         assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
 
-        let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
+        let memory = System.alloc(layout.clone()).unwrap();
         assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
-        helper::work_with(&memory.ptr);
-        System.dealloc(memory.ptr, layout);
+        helper::work_with(&memory);
+        System.dealloc(memory.as_non_null_ptr(), layout);
         assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
     }
 }
diff --git a/src/test/ui/asm/bad-arch.rs b/src/test/ui/asm/bad-arch.rs
new file mode 100644 (file)
index 0000000..1d21ae8
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: --target wasm32-unknown-unknown
+// needs-llvm-components: webassembly
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[lang = "sized"]
+trait Sized {}
+
+fn main() {
+    unsafe {
+        asm!("");
+        //~^ ERROR asm! is unsupported on this target
+    }
+}
diff --git a/src/test/ui/asm/bad-arch.stderr b/src/test/ui/asm/bad-arch.stderr
new file mode 100644 (file)
index 0000000..cb876f2
--- /dev/null
@@ -0,0 +1,8 @@
+error[E0472]: asm! is unsupported on this target
+  --> $DIR/bad-arch.rs:16:9
+   |
+LL |         asm!("");
+   |         ^^^^^^^^^
+
+error: aborting due to previous error
+
index 5988dffd68fa799a5e94421587235c82c48b26fa..2ced88a16cc45976ed2867dec511e25e219b0f3e 100644 (file)
@@ -4,6 +4,6 @@
 
 #[start]
 pub async fn start(_: isize, _: *const *const u8) -> isize {
-//~^ ERROR start is not allowed to be `async`
+//~^ ERROR `start` is not allowed to be `async`
     0
 }
index e471945900e7d462e06a627ce85042da162b012b..3a0a3b5dece10916742a8a1d64fb339db416cc43 100644 (file)
@@ -1,8 +1,8 @@
-error[E0752]: start is not allowed to be `async`
+error[E0752]: `start` is not allowed to be `async`
   --> $DIR/issue-68523-start.rs:6:1
    |
 LL | pub async fn start(_: isize, _: *const *const u8) -> isize {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ start is not allowed to be `async`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `start` is not allowed to be `async`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs b/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs
new file mode 100644 (file)
index 0000000..fda825b
--- /dev/null
@@ -0,0 +1,23 @@
+// check-pass
+
+use std::collections::{BTreeMap, HashMap};
+
+trait Map
+where
+    for<'a> &'a Self: IntoIterator<Item = (&'a Self::Key, &'a Self::Value)>,
+{
+    type Key;
+    type Value;
+}
+
+impl<K, V> Map for HashMap<K, V> {
+    type Key = K;
+    type Value = V;
+}
+
+impl<K, V> Map for BTreeMap<K, V> {
+  type Key = K;
+  type Value = V;
+}
+
+fn main() {}
index bdae6bc362c4727f72850fd1877e1ca61aec65a6..d53a4ac2d4c2359eb159565125c6bc2f88c1b6e6 100644 (file)
@@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
 LL | trait Trait<const T: ()> {}
    |                   ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
index 616f0fa8f1af0796df83ee863b48b71abc2771f0..5d379ff083ca70642f5ee8925f068e5a84c5fbb0 100644 (file)
@@ -10,8 +10,8 @@ error[E0658]: const generics are unstable
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    |                   ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/defaults/wrong-order.full.stderr b/src/test/ui/const-generics/defaults/wrong-order.full.stderr
new file mode 100644 (file)
index 0000000..c51028d
--- /dev/null
@@ -0,0 +1,19 @@
+error: type parameters with a default must be trailing
+  --> $DIR/wrong-order.rs:5:10
+   |
+LL | struct A<T = u32, const N: usize> {
+   |          ^
+   |
+   = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/wrong-order.rs:2:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/defaults/wrong-order.min.stderr b/src/test/ui/const-generics/defaults/wrong-order.min.stderr
new file mode 100644 (file)
index 0000000..29a4636
--- /dev/null
@@ -0,0 +1,10 @@
+error: type parameters with a default must be trailing
+  --> $DIR/wrong-order.rs:5:10
+   |
+LL | struct A<T = u32, const N: usize> {
+   |          ^
+   |
+   = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+error: aborting due to previous error
+
index 7f17c6358b7b6c8e21bdead470a1579912b9d872..cb36d456f3887de7f91e2c6c629649fb7b06b716 100644 (file)
@@ -1,4 +1,6 @@
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct A<T = u32, const N: usize> {
     //~^ ERROR type parameters with a default must be trailing
diff --git a/src/test/ui/const-generics/defaults/wrong-order.stderr b/src/test/ui/const-generics/defaults/wrong-order.stderr
deleted file mode 100644 (file)
index 283f665..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error: type parameters with a default must be trailing
-  --> $DIR/wrong-order.rs:3:10
-   |
-LL | struct A<T = u32, const N: usize> {
-   |          ^
-   |
-   = note: using type defaults and const parameters in the same parameter list is currently not permitted
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/wrong-order.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445.full.stderr
new file mode 100644 (file)
index 0000000..d853ec5
--- /dev/null
@@ -0,0 +1,20 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-56445.rs:3:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/issue-56445.rs:9:26
+   |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+   |                          ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0771`.
diff --git a/src/test/ui/const-generics/issues/issue-56445.min.stderr b/src/test/ui/const-generics/issues/issue-56445.min.stderr
new file mode 100644 (file)
index 0000000..ca35ee5
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/issue-56445.rs:9:26
+   |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+   |                          ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: using `&'static str` as const generic parameters is forbidden
+  --> $DIR/issue-56445.rs:9:25
+   |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+   |                         ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0771`.
index 26441512e3fbd0390d65575dea833428bd372082..174eb16abfc5f44755243dce1a80cc719f0ee140 100644 (file)
@@ -1,12 +1,13 @@
 // Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
-
-#![feature(const_generics)]
-//~^ WARN: the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 #![crate_type = "lib"]
 
 use std::marker::PhantomData;
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: use of non-static lifetime `'a` in const generic
+//[min]~| ERROR: using `&'static str` as const
 
 impl Bug<'_, ""> {}
diff --git a/src/test/ui/const-generics/issues/issue-56445.stderr b/src/test/ui/const-generics/issues/issue-56445.stderr
deleted file mode 100644 (file)
index fba638b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-56445.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0771]: use of non-static lifetime `'a` in const generic
-  --> $DIR/issue-56445.rs:9:26
-   |
-LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
-   |                          ^^
-   |
-   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0771`.
index 7b50c442d2f41f44dc68ede5972d1a405f2808a6..aeef296f38526eeff33552629e820df374fcfa1c 100644 (file)
@@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
 LL | struct B<const I: u8>;
    |                ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr
new file mode 100644 (file)
index 0000000..c03b725
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-60818-struct-constructors.rs:3:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
index 26d74ffb254cebe230785581e22e2995783639c6..ae2b0520fb1c1ee47885195a2120fcb9c2f930b6 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Generic<const V: usize>;
 
diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr
deleted file mode 100644 (file)
index 94a2b67..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-60818-struct-constructors.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr
new file mode 100644 (file)
index 0000000..f18728e
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61336-1.rs:3:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
index 2135c868bbc7013cd103295c415653dec1ff73f1..201c0d039d98f3dab979ece6c25def3d44a86586 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
-
 // build-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr
deleted file mode 100644 (file)
index b2c69d5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61336-1.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr
new file mode 100644 (file)
index 0000000..d21cd9d
--- /dev/null
@@ -0,0 +1,24 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61336-2.rs:2:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336-2.rs:10:5
+   |
+LL |     [x; { N }]
+   |     ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+   |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr
new file mode 100644 (file)
index 0000000..29ab7b1
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336-2.rs:10:5
+   |
+LL |     [x; { N }]
+   |     ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+   |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 52969056f00a5552cc768926ef7df712ab0d1fe0..25b9271105e245c9a58a0862427c0df9fcb272ca 100644 (file)
@@ -1,5 +1,6 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; { N }]
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr
deleted file mode 100644 (file)
index 5f33952..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61336-2.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:9:5
-   |
-LL |     [x; { N }]
-   |     ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = note: the `Copy` trait is required because the repeated element will be copied
-help: consider restricting type parameter `T`
-   |
-LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
-   |       ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr
new file mode 100644 (file)
index 0000000..d1b5d5e
--- /dev/null
@@ -0,0 +1,24 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61336.rs:2:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336.rs:10:5
+   |
+LL |     [x; N]
+   |     ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+   |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-61336.min.stderr b/src/test/ui/const-generics/issues/issue-61336.min.stderr
new file mode 100644 (file)
index 0000000..bced8bb
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-61336.rs:10:5
+   |
+LL |     [x; N]
+   |     ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+   |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index eb0f309762764f5eb79aa625ff1534d958ea4582..fb55542a1c9931dc5b89d6b66a82c5bd79cd5091 100644 (file)
@@ -1,5 +1,6 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
diff --git a/src/test/ui/const-generics/issues/issue-61422.full.stderr b/src/test/ui/const-generics/issues/issue-61422.full.stderr
new file mode 100644 (file)
index 0000000..ac6c378
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61422.rs:3:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
index 7e7ef6867ed075c2cd8e790575763d6164a8e321..649f8b4255b1216adb4d4f5461c4998fe86b9c7c 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 use std::mem;
 
diff --git a/src/test/ui/const-generics/issues/issue-61422.stderr b/src/test/ui/const-generics/issues/issue-61422.stderr
deleted file mode 100644 (file)
index 69bbaad..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61422.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-61432.full.stderr b/src/test/ui/const-generics/issues/issue-61432.full.stderr
new file mode 100644 (file)
index 0000000..82b36de
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61432.rs:3:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
index 0440468e9e6228e4782906ac91636a0e26c420eb..91a4794099c073bd463cc52e84678bceeb5abac8 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 fn promote<const N: i32>() {
     // works:
diff --git a/src/test/ui/const-generics/issues/issue-61432.stderr b/src/test/ui/const-generics/issues/issue-61432.stderr
deleted file mode 100644 (file)
index 1d547b1..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61432.rs:3:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-61747.full.stderr b/src/test/ui/const-generics/issues/issue-61747.full.stderr
new file mode 100644 (file)
index 0000000..3ccce56
--- /dev/null
@@ -0,0 +1,19 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-61747.rs:2:27
+   |
+LL | #![cfg_attr(full, feature(const_generics))]
+   |                           ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61747.rs:8:23
+   |
+LL |     fn successor() -> Const<{C + 1}> {
+   |                       ^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr
new file mode 100644 (file)
index 0000000..2061b6c
--- /dev/null
@@ -0,0 +1,10 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/issue-61747.rs:8:30
+   |
+LL |     fn successor() -> Const<{C + 1}> {
+   |                              ^ non-trivial anonymous constants must not depend on the parameter `C`
+   |
+   = help: it is currently only allowed to use either `C` or `{ C }` as generic constants
+
+error: aborting due to previous error
+
index cc671163e85a1388e2bf9bf2e07067194163344d..4e5cde17f39a963a9ccd7b68f5d6b6059174ab5d 100644 (file)
@@ -1,11 +1,13 @@
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const N: usize>;
 
 impl<const C: usize> Const<{C}> {
     fn successor() -> Const<{C + 1}> {
-        //~^ ERROR constant expression depends on a generic parameter
+        //[full]~^ ERROR constant expression depends on a generic parameter
+        //[min]~^^ ERROR generic parameters must not be used
         Const
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr
deleted file mode 100644 (file)
index 2685d9f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61747.rs:1:12
-   |
-LL | #![feature(const_generics)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-61747.rs:7:23
-   |
-LL |     fn successor() -> Const<{C + 1}> {
-   |                       ^^^^^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs
new file mode 100644 (file)
index 0000000..4c75553
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    const VAL: usize;
+}
+
+trait MyTrait {}
+
+trait True {}
+struct Is<const T: bool>;
+impl True for Is<{true}> {}
+
+impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
+//~^ ERROR constant expression depends on a generic parameter
+impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
+//~^ ERROR constant expression depends on a generic parameter
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-64494.stderr b/src/test/ui/const-generics/issues/issue-64494.stderr
new file mode 100644 (file)
index 0000000..30dca16
--- /dev/null
@@ -0,0 +1,18 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-64494.rs:14:53
+   |
+LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
+   |                                                     ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-64494.rs:16:53
+   |
+LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
+   |                                                     ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs
new file mode 100644 (file)
index 0000000..a368c22
--- /dev/null
@@ -0,0 +1,32 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+pub struct IsLessOrEqual<const LHS: u32, const RHS: u32>;
+pub struct Condition<const CONDITION: bool>;
+pub trait True {}
+
+impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
+    Condition<{ LHS <= RHS }>: True
+//~^ Error constant expression depends on a generic parameter
+{
+}
+impl True for Condition<true> {}
+
+struct S<const I: u32, const J: u32>;
+impl<const I: u32, const J: u32> S<I, J>
+where
+    IsLessOrEqual<I, 8>: True,
+    IsLessOrEqual<J, 8>: True,
+    IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+//~^ Error constant expression depends on a generic parameter
+//~| Error constant expression depends on a generic parameter
+//~| Error constant expression depends on a generic parameter
+//~| Error constant expression depends on a generic parameter
+    // Condition<{ 8 - I <= 8 - J }>: True,
+{
+    fn print() {
+        println!("I {} J {}", I, J);
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.stderr
new file mode 100644 (file)
index 0000000..ed892e4
--- /dev/null
@@ -0,0 +1,42 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-72787.rs:9:32
+   |
+LL |     Condition<{ LHS <= RHS }>: True
+   |                                ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-72787.rs:20:42
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-72787.rs:20:42
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-72787.rs:20:42
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-72787.rs:20:42
+   |
+LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
+   |                                          ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/const-generics/min_const_generics/assoc_const.rs b/src/test/ui/const-generics/min_const_generics/assoc_const.rs
new file mode 100644 (file)
index 0000000..fa75613
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(min_const_generics)]
+
+struct Foo<const N: usize>;
+
+impl<const N: usize> Foo<N> {
+    const VALUE: usize = N * 2;
+}
+
+trait Bar {
+    const ASSOC: usize;
+}
+
+impl<const N: usize> Bar for Foo<N> {
+    const ASSOC: usize = N * 3;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
new file mode 100644 (file)
index 0000000..f9cb0d2
--- /dev/null
@@ -0,0 +1,29 @@
+#![feature(min_const_generics)]
+
+fn test<const N: usize>() {}
+
+fn ok<const M: usize>() -> [u8; M] {
+    [0; { M }]
+}
+
+struct Break0<const N: usize>([u8; { N + 1 }]);
+//~^ ERROR generic parameters must not be used inside of non trivial constant values
+
+struct Break1<const N: usize>([u8; { { N } }]);
+//~^ ERROR generic parameters must not be used inside of non trivial constant values
+
+fn break2<const N: usize>() {
+    let _: [u8; N + 1];
+    //~^ ERROR generic parameters must not be used inside of non trivial constant values
+}
+
+fn break3<const N: usize>() {
+    let _ = [0; N + 1];
+    //~^ ERROR generic parameters must not be used inside of non trivial constant values
+}
+
+trait Foo {
+    const ASSOC: usize;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
new file mode 100644 (file)
index 0000000..baed8d1
--- /dev/null
@@ -0,0 +1,34 @@
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/complex-expression.rs:9:38
+   |
+LL | struct Break0<const N: usize>([u8; { N + 1 }]);
+   |                                      ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/complex-expression.rs:12:40
+   |
+LL | struct Break1<const N: usize>([u8; { { N } }]);
+   |                                        ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/complex-expression.rs:16:17
+   |
+LL |     let _: [u8; N + 1];
+   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+  --> $DIR/complex-expression.rs:21:17
+   |
+LL |     let _ = [0; N + 1];
+   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |
+   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs
new file mode 100644 (file)
index 0000000..a396fa8
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(min_const_generics)]
+
+struct Foo<const N: [u8; 0]>;
+//~^ ERROR using `[u8; 0]` as const generic parameters is forbidden
+
+struct Bar<const N: ()>;
+//~^ ERROR using `()` as const generic parameters is forbidden
+
+#[derive(PartialEq, Eq)]
+struct No;
+
+struct Fez<const N: No>;
+//~^ ERROR using `No` as const generic parameters is forbidden
+
+struct Faz<const N: &'static u8>;
+//~^ ERROR using `&'static u8` as const generic parameters is forbidden
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr
new file mode 100644 (file)
index 0000000..835b1f1
--- /dev/null
@@ -0,0 +1,38 @@
+error: using `[u8; 0]` as const generic parameters is forbidden
+  --> $DIR/complex-types.rs:3:21
+   |
+LL | struct Foo<const N: [u8; 0]>;
+   |                     ^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `()` as const generic parameters is forbidden
+  --> $DIR/complex-types.rs:6:21
+   |
+LL | struct Bar<const N: ()>;
+   |                     ^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `No` as const generic parameters is forbidden
+  --> $DIR/complex-types.rs:12:21
+   |
+LL | struct Fez<const N: No>;
+   |                     ^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+  --> $DIR/complex-types.rs:15:21
+   |
+LL | struct Faz<const N: &'static u8>;
+   |                     ^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs
new file mode 100644 (file)
index 0000000..423deae
--- /dev/null
@@ -0,0 +1,4 @@
+fn test<const N: usize>() {}
+//~^ ERROR const generics are unstable
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr
new file mode 100644 (file)
index 0000000..7f82a96
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: const generics are unstable
+  --> $DIR/feature-gate-min_const_generics.rs:1:15
+   |
+LL | fn test<const N: usize>() {}
+   |               ^
+   |
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index ae50252facd2514acc53b96bff9ed69054349a5f..3ccdd472613728351b030ba9bff54bce1f3aa9a8 100644 (file)
@@ -1,7 +1,8 @@
 // run-pass
-#![feature(const_generics)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
 #![allow(incomplete_features)]
-#![feature(const_fn)]
 
 struct Foo;
 
diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs
new file mode 100644 (file)
index 0000000..67d9f6b
--- /dev/null
@@ -0,0 +1,10 @@
+// Regression test for #75118.
+
+use std::ptr::NonNull;
+
+pub const fn dangling_slice<T>() -> NonNull<[T]> {
+    NonNull::<[T; 0]>::dangling()
+    //~^ ERROR: unsizing casts are only allowed for references right now
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr
new file mode 100644 (file)
index 0000000..6575355
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0723]: unsizing casts are only allowed for references right now
+  --> $DIR/unsizing-cast-non-null.rs:6:5
+   |
+LL |     NonNull::<[T; 0]>::dangling()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.
index 753e924f00495216de46d9094a7effa8a8552089..59f04372fff19218f45d30c178dde71c9349c31e 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten
+// only-x86_64
 
 fn main() {
     unsafe {
index e9349acb64394e149b9682c9647e5405026ba4f4..aa63aff1c5e3384a3c80d65bf102211d1f45a173 100644 (file)
@@ -1,4 +1,4 @@
-// ignore-emscripten
+// only-x86_64
 
 fn main() {
     unsafe {
index b2c96d3810f980fae1e4543247b354ebfc5bc33e..eef465318a390665f2a781ff2ebcf95c863039f3 100644 (file)
@@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
 LL | struct ConstFn<const F: fn()>;
    |                      ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error[E0658]: const generics are unstable
   --> $DIR/feature-gate-const_generics-ptr.rs:5:23
@@ -13,8 +13,8 @@ error[E0658]: const generics are unstable
 LL | struct ConstPtr<const P: *const u32>;
    |                       ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:1:25
index 02aa1f5a4d843d9d99384cfc65cef64907d2a0e9..f80362252f9236cfb09ea62ad58fd65124c9dfe5 100644 (file)
@@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
 LL | fn foo<const X: ()>() {}
    |              ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error[E0658]: const generics are unstable
   --> $DIR/feature-gate-const_generics.rs:3:18
@@ -13,8 +13,8 @@ error[E0658]: const generics are unstable
 LL | struct Foo<const X: usize>([(); X]);
    |                  ^
    |
-   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+   = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+   = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
new file mode 100644 (file)
index 0000000..1e1241c
--- /dev/null
@@ -0,0 +1,20 @@
+// Regression test for #59311. The test is taken from
+// rust-lang/rust/issues/71546#issuecomment-620638437
+// as they seem to have the same cause.
+
+// FIXME: It's not clear that this code ought to report
+// an error, but the regression test is here to ensure
+// that it does not ICE. See discussion on #74889 for details.
+
+pub trait T {
+    fn t<F: Fn()>(&self, _: F) {}
+}
+
+pub fn crash<V>(v: &V)
+where
+    for<'a> &'a V: T + 'static,
+{
+    v.t(|| {}); //~ ERROR: higher-ranked subtype error
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
new file mode 100644 (file)
index 0000000..ca63262
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-59311.rs:17:9
+   |
+LL |     v.t(|| {});
+   |         ^^^^^
+
+error: aborting due to previous error
+
index 2f3d48bf039074087c46d525c808800ff5120783..4d8a8edf4c9eae503c8d9bca3dcfe16c9a4a60dd 100644 (file)
@@ -17,20 +17,20 @@ LL | /  macro_rules! pong {
 LL | |      () => { syntax error };
    | |                     ^^^^^ expected one of 8 possible tokens
 LL | |  }
-   | |__- in this expansion of `pong!`
+   | |__- in this expansion of `pong!` (#2)
 ...
 LL |        ping!();
-   |        -------- in this macro invocation
+   |        -------- in this macro invocation (#1)
    | 
   ::: $DIR/auxiliary/ping.rs:5:1
    |
 LL |  / macro_rules! ping {
 LL |  |     () => {
 LL |  |         pong!();
-   |  |         -------- in this macro invocation
+   |  |         -------- in this macro invocation (#2)
 LL |  |     }
 LL |  | }
-   |  |_- in this expansion of `ping!`
+   |  |_- in this expansion of `ping!` (#1)
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error`
   --> $DIR/main.rs:10:20
diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs
new file mode 100644 (file)
index 0000000..1e8c38c
--- /dev/null
@@ -0,0 +1,18 @@
+// Regression test for #47429: short backtraces were not terminating correctly
+
+// compile-flags: -O
+// run-fail
+// check-run-results
+// exec-env:RUST_BACKTRACE=1
+
+// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
+// ignore-android FIXME #17520
+// ignore-cloudabi spawning processes is not supported
+// ignore-openbsd no support for libbacktrace without filename
+// ignore-wasm no panic or subprocess support
+// ignore-emscripten no panic or subprocess support
+// ignore-sgx no subprocess support
+
+fn main() {
+    panic!()
+}
diff --git a/src/test/ui/panics/issue-47429-short-backtraces.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr
new file mode 100644 (file)
index 0000000..99ee26f
--- /dev/null
@@ -0,0 +1,5 @@
+thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:17:5
+stack backtrace:
+   0: std::panicking::begin_panic
+   1: issue_47429_short_backtraces::main
+note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
diff --git a/src/test/ui/polymorphization/closure_in_upvar/fn.rs b/src/test/ui/polymorphization/closure_in_upvar/fn.rs
new file mode 100644 (file)
index 0000000..b0b39db
--- /dev/null
@@ -0,0 +1,29 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    let x = |_: ()| ();
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs
new file mode 100644 (file)
index 0000000..ba75f6c
--- /dev/null
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    // Mutate an upvar from `x` so that it implements `FnMut`.
+    let mut outer = 3;
+    let mut x = |_: ()| {
+        outer = 4;
+        ()
+    };
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let mut y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs
new file mode 100644 (file)
index 0000000..e9761ad
--- /dev/null
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    // Move a non-copy type into `x` so that it implements `FnOnce`.
+    let outer = Vec::<u32>::new();
+    let x = move |_: ()| {
+        let inner = outer;
+        ()
+    };
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/src/test/ui/polymorphization/closure_in_upvar/other.rs b/src/test/ui/polymorphization/closure_in_upvar/other.rs
new file mode 100644 (file)
index 0000000..7614aa8
--- /dev/null
@@ -0,0 +1,38 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn y_uses_f(f: impl Fn()) {
+    let x = |_: ()| ();
+
+    let y = || {
+        f();
+        x(());
+    };
+
+    f();
+    y();
+}
+
+fn x_uses_f(f: impl Fn()) {
+    let x = |_: ()| { f(); };
+
+    let y = || x(());
+
+    f();
+    y();
+}
+
+fn entry_a() {
+    x_uses_f(|| ());
+    y_uses_f(|| ());
+}
+
+fn entry_b() {
+    x_uses_f(|| ());
+    y_uses_f(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/src/test/ui/polymorphization/promoted-function-1.rs b/src/test/ui/polymorphization/promoted-function-1.rs
new file mode 100644 (file)
index 0000000..2cd0267
--- /dev/null
@@ -0,0 +1,12 @@
+// build-fail
+// compile-flags: -Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+fn foo<'a>(_: &'a ()) {}
+
+#[rustc_polymorphize_error]
+pub fn test<T>() {
+    //~^ ERROR item has unused generic parameters
+    foo(&());
+}
diff --git a/src/test/ui/polymorphization/promoted-function-1.stderr b/src/test/ui/polymorphization/promoted-function-1.stderr
new file mode 100644 (file)
index 0000000..fcbb869
--- /dev/null
@@ -0,0 +1,8 @@
+error: item has unused generic parameters
+  --> $DIR/promoted-function-1.rs:9:8
+   |
+LL | pub fn test<T>() {
+   |        ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/polymorphization/promoted-function-2.rs b/src/test/ui/polymorphization/promoted-function-2.rs
new file mode 100644 (file)
index 0000000..2831f86
--- /dev/null
@@ -0,0 +1,16 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(lazy_normalization_consts, rustc_attrs)]
+//~^ WARN the feature `lazy_normalization_consts` is incomplete
+
+#[rustc_polymorphize_error]
+fn test<T>() {
+    //~^ ERROR item has unused generic parameters
+    let x = [0; 3 + 4];
+}
+
+pub fn caller() {
+    test::<String>();
+    test::<Vec<String>>();
+}
diff --git a/src/test/ui/polymorphization/promoted-function-2.stderr b/src/test/ui/polymorphization/promoted-function-2.stderr
new file mode 100644 (file)
index 0000000..38d4808
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `lazy_normalization_consts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/promoted-function-2.rs:4:12
+   |
+LL | #![feature(lazy_normalization_consts, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information
+
+error: item has unused generic parameters
+  --> $DIR/promoted-function-2.rs:8:4
+   |
+LL | fn test<T>() {
+   |    ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
index 0d3af7a89c2aac2936426d8992c880c9dbd2511c..a56a8e70e4c50153cdb2cc2fa13c6a2390893940 100644 (file)
@@ -1,4 +1,6 @@
 // run-pass
+// compile-flags:-Zpolymorphize=on
+
 fn fop<T>() {}
 
 fn bar<T>() -> &'static fn() {
index b8facc16070102e414954e52cef47e8ceccacab4..b803fec2ccfdb17e4dcb9fee0b5592a0152c6e57 100644 (file)
@@ -17,6 +17,7 @@ fn foo<T: Default>() {
 fn foo2<T: Default>() {
     let _: T = Default::default();
     (|| {
+        //~^ ERROR item has unused generic parameters
         let call: extern "rust-call" fn(_, _) = Fn::call;
         call(&|| {}, ());
         //~^ ERROR item has unused generic parameters
index d4727acca9afd9169671d093879b179f101c401a..b51cc5c719f0b271d61ff68316243c4299809e40 100644 (file)
@@ -17,7 +17,7 @@ LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: item has unused generic parameters
-  --> $DIR/unsized_cast.rs:21:15
+  --> $DIR/unsized_cast.rs:22:15
    |
 LL | fn foo2<T: Default>() {
    |         - generic parameter `T` is unused
@@ -25,5 +25,19 @@ LL | fn foo2<T: Default>() {
 LL |         call(&|| {}, ());
    |               ^^^^^
 
-error: aborting due to 3 previous errors
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:19:5
+   |
+LL |   fn foo2<T: Default>() {
+   |           - generic parameter `T` is unused
+LL |       let _: T = Default::default();
+LL | /     (|| {
+LL | |
+LL | |         let call: extern "rust-call" fn(_, _) = Fn::call;
+LL | |         call(&|| {}, ());
+LL | |
+LL | |     })();
+   | |______^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs
new file mode 100644 (file)
index 0000000..4601a3d
--- /dev/null
@@ -0,0 +1,10 @@
+// Regression test for issue #75062
+// Tests that we don't ICE on a privacy error for a fieldless tuple struct.
+
+mod foo {
+    struct Bar();
+}
+
+fn main() {
+    foo::Bar(); //~ ERROR tuple struct
+}
diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr
new file mode 100644 (file)
index 0000000..14a1200
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0603]: tuple struct `Bar` is private
+  --> $DIR/issue-75062-fieldless-tuple-struct.rs:9:10
+   |
+LL |     foo::Bar();
+   |          ^^^ private tuple struct
+   |
+note: the tuple struct `Bar` is defined here
+  --> $DIR/issue-75062-fieldless-tuple-struct.rs:5:5
+   |
+LL |     struct Bar();
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/proc-macro/doc-comment-preserved.rs b/src/test/ui/proc-macro/doc-comment-preserved.rs
new file mode 100644 (file)
index 0000000..c2724ae
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+// aux-build:test-macros.rs
+
+// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
+// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
+// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
+
+#[macro_use]
+extern crate test_macros;
+
+print_bang! {
+
+/**
+*******
+* DOC *
+* DOC *
+* DOC *
+*******
+*/
+pub struct S;
+
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/doc-comment-preserved.stdout b/src/test/ui/proc-macro/doc-comment-preserved.stdout
new file mode 100644 (file)
index 0000000..f790453
--- /dev/null
@@ -0,0 +1,54 @@
+PRINT-BANG INPUT (DISPLAY): /**
+*******
+* DOC *
+* DOC *
+* DOC *
+*******
+*/
+ pub struct S ;
+PRINT-BANG RE-COLLECTED (DISPLAY): #[doc = "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n"] pub struct S ;
+PRINT-BANG INPUT (DEBUG): TokenStream [
+    Punct {
+        ch: '#',
+        spacing: Alone,
+        span: #0 bytes(LO..HI),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "doc",
+                span: #0 bytes(LO..HI),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #0 bytes(LO..HI),
+            },
+            Literal {
+                kind: Str,
+                symbol: "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n",
+                suffix: None,
+                span: #0 bytes(LO..HI),
+            },
+        ],
+        span: #0 bytes(LO..HI),
+    },
+    Ident {
+        ident: "pub",
+        span: #0 bytes(LO..HI),
+    },
+    Ident {
+        ident: "struct",
+        span: #0 bytes(LO..HI),
+    },
+    Ident {
+        ident: "S",
+        span: #0 bytes(LO..HI),
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: #0 bytes(LO..HI),
+    },
+]
index 0687a9ce454ccd84362491a6cac5e2e033afaa71..bdcd47a7260d30f22664b0ba720117a9bea2110b 100644 (file)
@@ -5,8 +5,9 @@
 // well enough to reproduce (and illustrate) the bug from #16687.
 
 #![feature(allocator_api)]
+#![feature(slice_ptr_get)]
 
-use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout, ReallocPlacement};
+use std::alloc::{handle_alloc_error, AllocRef, Global, Layout};
 use std::ptr::{self, NonNull};
 
 fn main() {
@@ -41,15 +42,13 @@ unsafe fn allocate(layout: Layout) -> *mut u8 {
             println!("allocate({:?})", layout);
         }
 
-        let memory = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| handle_alloc_error(layout));
+        let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
 
         if PRINT {
-            println!("allocate({:?}) = {:?}", layout, memory.ptr);
+            println!("allocate({:?}) = {:?}", layout, ptr);
         }
 
-        memory.ptr.cast().as_ptr()
+        ptr.as_non_null_ptr().as_ptr()
     }
 
     unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
@@ -70,21 +69,19 @@ unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
                 NonNull::new_unchecked(ptr),
                 old,
                 new.size(),
-                ReallocPlacement::MayMove,
-                AllocInit::Uninitialized,
             )
         } else {
-            Global.shrink(NonNull::new_unchecked(ptr), old, new.size(), ReallocPlacement::MayMove)
+            Global.shrink(NonNull::new_unchecked(ptr), old, new.size())
         };
 
-        let memory = memory.unwrap_or_else(|_| {
+        let ptr = memory.unwrap_or_else(|_| {
             handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align()))
         });
 
         if PRINT {
-            println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, memory.ptr);
+            println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr);
         }
-        memory.ptr.cast().as_ptr()
+        ptr.as_non_null_ptr().as_ptr()
     }
 
     fn idx_to_size(i: usize) -> usize {
index be55890c08c88598619337f96ed63a1f557e24db..7f197a238e5a0f2466d9c857d23bd06154350ddf 100644 (file)
@@ -1,7 +1,7 @@
-error[E0391]: cycle detected when computing layout of `std::option::Option<S>`
+error[E0391]: cycle detected when computing layout of `S`
    |
-   = note: ...which requires computing layout of `S`...
-   = note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle
+   = note: ...which requires computing layout of `std::option::Option<S>`...
+   = note: ...which again requires computing layout of `S`, completing the cycle
 note: cycle used when optimizing MIR for `main`
   --> $DIR/issue-26548-recursion-via-normalize.rs:15:1
    |
index 380310190be0124a9f229d46b134eb8996d9c9a4..ad4b9c352aefd278e8f3ec97664261b8b9f3a26c 100644 (file)
@@ -4,7 +4,7 @@
 // pretty-expanded FIXME #23616
 #![feature(allocator_api)]
 
-use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout};
+use std::alloc::{handle_alloc_error, AllocRef, Global, Layout};
 use std::ptr::NonNull;
 
 struct arena(());
@@ -25,10 +25,8 @@ struct Ccx {
 fn alloc(_bcx: &arena) -> &Bcx<'_> {
     unsafe {
         let layout = Layout::new::<Bcx>();
-        let memory = Global
-            .alloc(layout, AllocInit::Uninitialized)
-            .unwrap_or_else(|_| handle_alloc_error(layout));
-        &*(memory.ptr.as_ptr() as *const _)
+        let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
+        &*(ptr.as_ptr() as *const _)
     }
 }
 
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-main.rs b/src/test/ui/rfc-2091-track-caller/error-with-main.rs
new file mode 100644 (file)
index 0000000..b2ea31b
--- /dev/null
@@ -0,0 +1,4 @@
+#[track_caller] //~ ERROR `main` function is not allowed to be
+fn main() {
+    panic!("{}: oh no", std::panic::Location::caller());
+}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-main.stderr b/src/test/ui/rfc-2091-track-caller/error-with-main.stderr
new file mode 100644 (file)
index 0000000..f05f88e
--- /dev/null
@@ -0,0 +1,12 @@
+error: `main` function is not allowed to be `#[track_caller]`
+  --> $DIR/error-with-main.rs:1:1
+   |
+LL |   #[track_caller]
+   |   ^^^^^^^^^^^^^^^
+LL | / fn main() {
+LL | |     panic!("{}: oh no", std::panic::Location::caller());
+LL | | }
+   | |_- `main` function is not allowed to be `#[track_caller]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-start.rs b/src/test/ui/rfc-2091-track-caller/error-with-start.rs
new file mode 100644 (file)
index 0000000..0cab471
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(start)]
+
+#[start]
+#[track_caller] //~ ERROR `start` is not allowed to be `#[track_caller]`
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+    panic!("{}: oh no", std::panic::Location::caller());
+}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-start.stderr b/src/test/ui/rfc-2091-track-caller/error-with-start.stderr
new file mode 100644 (file)
index 0000000..1a1f3e0
--- /dev/null
@@ -0,0 +1,12 @@
+error: `start` is not allowed to be `#[track_caller]`
+  --> $DIR/error-with-start.rs:4:1
+   |
+LL |   #[track_caller]
+   |   ^^^^^^^^^^^^^^^
+LL | / fn start(_argc: isize, _argv: *const *const u8) -> isize {
+LL | |     panic!("{}: oh no", std::panic::Location::caller());
+LL | | }
+   | |_- `start` is not allowed to be `#[track_caller]`
+
+error: aborting due to previous error
+
index a323bd9e82b4a16992f95885f6a3ffd023ab7cf5..8c436841b44e8622be2aebda7f457ab458bdeaba 100644 (file)
@@ -2,6 +2,7 @@
 #![allow(non_camel_case_types)]
 
 // ignore-emscripten
+// ignore-endian-big behavior of simd_bitmask is endian-specific
 
 // Test that the simd_bitmask intrinsic produces correct results.
 
index 22bda4fc9d9194e911c95df19927529f3e3a0808..dc9ec5d2760fe02e2e32d0c6e69556b5f004ec7a 100644 (file)
@@ -2,10 +2,7 @@
 #![allow(non_camel_case_types)]
 
 // ignore-emscripten
-// ignore-mips       behavior of simd_select_bitmask is endian-specific
-// ignore-mips64     behavior of simd_select_bitmask is endian-specific
-// ignore-powerpc    behavior of simd_select_bitmask is endian-specific
-// ignore-powerpc64  behavior of simd_select_bitmask is endian-specific
+// ignore-endian-big behavior of simd_select_bitmask is endian-specific
 
 // Test that the simd_select intrinsics produces correct results.
 
index 2d5c2381e4e50484bf281fc1bfe19743aa9eb37a..1653f354644834073d6d2541e27fae94588e685e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2d5c2381e4e50484bf281fc1bfe19743aa9eb37a
+Subproject commit 1653f354644834073d6d2541e27fae94588e685e
index e87c33d1b09dd42d6e688b0e079a7760817b4a36..6ce36fd2360e1e9569cb748e566a3b38ce57ef4a 100644 (file)
@@ -2,6 +2,7 @@
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_ast::ast::{AttrKind, Attribute};
+use rustc_ast::token::CommentKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -249,7 +250,7 @@ fn lint_for_missing_headers<'tcx>(
     }
 }
 
-/// Cleanup documentation decoration (`///` and such).
+/// Cleanup documentation decoration.
 ///
 /// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
 /// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
@@ -257,54 +258,45 @@ fn lint_for_missing_headers<'tcx>(
 /// the spans but this function is inspired from the later.
 #[allow(clippy::cast_possible_truncation)]
 #[must_use]
-pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) {
+pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
     // one-line comments lose their prefix
-    const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
-    for prefix in ONELINERS {
-        if comment.starts_with(*prefix) {
-            let doc = &comment[prefix.len()..];
-            let mut doc = doc.to_owned();
-            doc.push('\n');
-            return (
-                doc.to_owned(),
-                vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))],
-            );
-        }
+    if comment_kind == CommentKind::Line {
+        let mut doc = doc.to_owned();
+        doc.push('\n');
+        let len = doc.len();
+        // +3 skips the opening delimiter
+        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
     }
 
-    if comment.starts_with("/*") {
-        let doc = &comment[3..comment.len() - 2];
-        let mut sizes = vec![];
-        let mut contains_initial_stars = false;
-        for line in doc.lines() {
-            let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
-            debug_assert_eq!(offset as u32 as usize, offset);
-            contains_initial_stars |= line.trim_start().starts_with('*');
-            // +1 for the newline
-            sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(offset as u32))));
-        }
-        if !contains_initial_stars {
-            return (doc.to_string(), sizes);
-        }
-        // remove the initial '*'s if any
-        let mut no_stars = String::with_capacity(doc.len());
-        for line in doc.lines() {
-            let mut chars = line.chars();
-            while let Some(c) = chars.next() {
-                if c.is_whitespace() {
-                    no_stars.push(c);
-                } else {
-                    no_stars.push(if c == '*' { ' ' } else { c });
-                    break;
-                }
+    let mut sizes = vec![];
+    let mut contains_initial_stars = false;
+    for line in doc.lines() {
+        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
+        debug_assert_eq!(offset as u32 as usize, offset);
+        contains_initial_stars |= line.trim_start().starts_with('*');
+        // +1 adds the newline, +3 skips the opening delimiter
+        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
+    }
+    if !contains_initial_stars {
+        return (doc.to_string(), sizes);
+    }
+    // remove the initial '*'s if any
+    let mut no_stars = String::with_capacity(doc.len());
+    for line in doc.lines() {
+        let mut chars = line.chars();
+        while let Some(c) = chars.next() {
+            if c.is_whitespace() {
+                no_stars.push(c);
+            } else {
+                no_stars.push(if c == '*' { ' ' } else { c });
+                break;
             }
-            no_stars.push_str(chars.as_str());
-            no_stars.push('\n');
         }
-        return (no_stars, sizes);
+        no_stars.push_str(chars.as_str());
+        no_stars.push('\n');
     }
 
-    panic!("not a doc-comment: {}", comment);
+    (no_stars, sizes)
 }
 
 #[derive(Copy, Clone)]
@@ -318,9 +310,8 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
     let mut spans = vec![];
 
     for attr in attrs {
-        if let AttrKind::DocComment(ref comment) = attr.kind {
-            let comment = comment.to_string();
-            let (comment, current_spans) = strip_doc_comment_decoration(&comment, attr.span);
+        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
+            let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
             spans.extend_from_slice(&current_spans);
             doc.push_str(&comment);
         } else if attr.has_name(sym!(doc)) {
index 3ee0b3f74b8c5a3bf96e3877fa6fbe91d757f9b8..6a141f1fc786d2548f11241faa5793d7111ff7e9 100644 (file)
@@ -239,7 +239,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                 return;
             }
             if cx.access_levels.is_exported(item.hir_id)
-                && !is_proc_macro(&item.attrs)
+                && !is_proc_macro(cx.sess(), &item.attrs)
                 && attr_by_name(&item.attrs, "no_mangle").is_none()
             {
                 check_must_use_candidate(
@@ -262,7 +262,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
                 let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
                 check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr);
             } else if cx.access_levels.is_exported(item.hir_id)
-                && !is_proc_macro(&item.attrs)
+                && !is_proc_macro(cx.sess(), &item.attrs)
                 && trait_ref_of_method(cx, item.hir_id).is_none()
             {
                 check_must_use_candidate(
@@ -294,7 +294,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte
                 let body = cx.tcx.hir().body(eid);
                 Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
 
-                if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(&item.attrs) {
+                if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(cx.sess(), &item.attrs) {
                     check_must_use_candidate(
                         cx,
                         &sig.decl,
index ca1381852daeead7d134f9edcebbc33d360c1e96..4e49bdbdd21bd02a8b04c50f3bfd1ed991eced46 100644 (file)
@@ -102,7 +102,7 @@ fn is_doc_hidden(attr: &Attribute) -> bool {
                 "this seems like a manual implementation of the non-exhaustive pattern",
                 |diag| {
                     if_chain! {
-                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
                         let header_span = cx.sess.source_map().span_until_char(item.span, '{');
                         if let Some(snippet) = snippet_opt(cx, header_span);
                         then {
@@ -154,7 +154,7 @@ fn find_header_span(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) -> S
                 "this seems like a manual implementation of the non-exhaustive pattern",
                 |diag| {
                     if_chain! {
-                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
                         let header_span = find_header_span(cx, item, data);
                         if let Some(snippet) = snippet_opt(cx, header_span);
                         then {
index 48ab98418e4fafe62381a541d80296af1fb9b8bc..603440c0f83763963e1bde30b9245b7a669c70f0 100644 (file)
@@ -2,7 +2,6 @@
 use rustc_ast::ast::{
     Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind,
 };
-use rustc_ast::attr;
 use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -385,7 +384,7 @@ fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
 }
 
 fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
-    if !attr::contains_name(attrs, sym!(test)) {
+    if !attrs.iter().any(|attr| attr.has_name(sym!(test))) {
         let mut visitor = SimilarNamesLocalVisitor {
             names: Vec::new(),
             cx,
index 7b673e15b764a101c0c267229575a952d472433a..74ccd9235de85d847daf593d4cc3a0018db586b1 100644 (file)
 
 impl TabsInDocComments {
     fn warn_if_tabs_in_doc(cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        if let ast::AttrKind::DocComment(comment) = attr.kind {
+        if let ast::AttrKind::DocComment(_, comment) = attr.kind {
             let comment = comment.as_str();
 
             for (lo, hi) in get_chunks_of_tabs(&comment) {
+                // +3 skips the opening delimiter
                 let new_span = Span::new(
-                    attr.span.lo() + BytePos(lo),
-                    attr.span.lo() + BytePos(hi),
+                    attr.span.lo() + BytePos(3 + lo),
+                    attr.span.lo() + BytePos(3 + hi),
                     attr.span.ctxt(),
                 );
                 span_lint_and_sugg(
index 58c1103da9f7dfed78e7039b107944057e7eecb9..ad02bc5fd8e7dba9d784c048e4edea729cc59cbb 100755 (executable)
@@ -506,7 +506,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
     use AttrKind::*;
     l.style == r.style
         && match (&l.kind, &r.kind) {
-            (DocComment(l), DocComment(r)) => l == r,
+            (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
             (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
             _ => false,
         }
index 4bb4b087c5566773b5dfa9249c936a486b103f98..407527251da225d4d2b454c8f5eb77f5a84b7812 100644 (file)
@@ -1,5 +1,4 @@
 use rustc_ast::ast;
-use rustc_ast::expand::is_proc_macro_attr;
 use rustc_errors::Applicability;
 use rustc_session::Session;
 use std::str::FromStr;
@@ -126,6 +125,6 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
 
 /// Return true if the attributes contain any of `proc_macro`,
 /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
-pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(is_proc_macro_attr)
+pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
+    attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
 }
index 3f8e15d90297d3035ef624e577725157cc950102..95a12fe193547d863783a5e6a2fbd4af9e8fed91 100644 (file)
@@ -932,7 +932,7 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut
 /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 /// implementations have.
 pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
-    attr::contains_name(attrs, sym!(automatically_derived))
+    attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived)))
 }
 
 /// Remove blocks around an expression.
index ac5f0d0a39e89aa7f57b2be61e34bb307a29eb91..2b3f9be2dfb9b030da728450f37fc3fac103268d 100644 (file)
@@ -1,23 +1,3 @@
-error: this operation will panic at runtime
-  --> $DIR/indexing_slicing_index.rs:11:5
-   |
-LL |     x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
-   |     ^^^^ index out of bounds: the len is 4 but the index is 4
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
-  --> $DIR/indexing_slicing_index.rs:12:5
-   |
-LL |     x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
-   |     ^^^^^^^^^ index out of bounds: the len is 4 but the index is 8
-
-error: this operation will panic at runtime
-  --> $DIR/indexing_slicing_index.rs:27:5
-   |
-LL |     x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
-   |     ^^^^ index out of bounds: the len is 4 but the index is 15
-
 error: indexing may panic.
   --> $DIR/indexing_slicing_index.rs:10:5
    |
@@ -75,5 +55,5 @@ LL |     v[M];
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
-error: aborting due to 10 previous errors
+error: aborting due to 7 previous errors
 
index 9269a63b41aab9d29f3904c534b6538e213cd4bc..848bd3a43e8906592fc9f9dabd76bb2ecc406844 100644 (file)
@@ -169,7 +169,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 /// Configuration for compiletest
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub struct Config {
     /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output.
     pub bless: bool,
index 047fbe9da14fe08e2cfcfc1f3f8b52f2e1af2876..edbb83726333b91f42cceda57dcaeb8303cc1c21 100644 (file)
@@ -827,6 +827,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
             name == util::get_pointer_width(&self.target) ||    // pointer width
             name == self.stage_id.split('-').next().unwrap() || // stage
             (self.target != self.host && name == "cross-compile") ||
+            (name == "endian-big" && util::is_big_endian(&self.target)) ||
             (self.remote_test_client.is_some() && name == "remote") ||
             match self.compare_mode {
                 Some(CompareMode::Nll) => name == "compare-mode-nll",
index 940e16720f6a98fef2a4ad503819b7245e2c81ad..7f49cb913b125244db5fbe4de6e1c479210e4cd5 100644 (file)
@@ -1885,7 +1885,8 @@ fn make_compile_args(
         emit_metadata: EmitMetadata,
         allow_unused: AllowUnused,
     ) -> Command {
-        let is_rustdoc = self.is_rustdoc();
+        let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
+        let is_rustdoc = self.is_rustdoc() && !is_aux;
         let mut rustc = if !is_rustdoc {
             Command::new(&self.config.rustc_path)
         } else {
@@ -3246,8 +3247,19 @@ fn check_mir_dump(&self) {
     }
 
     fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
-        let before = self.get_mir_dump_dir().join(before);
-        let after = self.get_mir_dump_dir().join(after);
+        let to_full_path = |path: PathBuf| {
+            let full = self.get_mir_dump_dir().join(&path);
+            if !full.exists() {
+                panic!(
+                    "the mir dump file for {} does not exist (requested in {})",
+                    path.display(),
+                    self.testpaths.file.display(),
+                );
+            }
+            full
+        };
+        let before = to_full_path(before);
+        let after = to_full_path(after);
         debug!("comparing the contents of: {} with {}", before.display(), after.display());
         let before = fs::read_to_string(before).unwrap();
         let after = fs::read_to_string(after).unwrap();
@@ -3573,6 +3585,7 @@ pub fn fatal(&self, err: Option<&str>) -> ! {
     }
 }
 
+#[derive(Debug)]
 enum TargetLocation {
     ThisFile(PathBuf),
     ThisDirectory(PathBuf),
index 0437ff8c9440a3cbfe8b59134c1491125584fe4e..ddd7941b11469d973f70c7201c6f2d62a7659b41 100644 (file)
 pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] =
     &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
 
+const BIG_ENDIAN: &'static [&'static str] = &[
+    "armebv7r",
+    "mips",
+    "mips64",
+    "mipsisa32r6",
+    "mipsisa64r6",
+    "powerpc",
+    "powerpc64",
+    "s390x",
+    "sparc",
+    "sparc64",
+    "sparcv9",
+];
+
 pub fn matches_os(triple: &str, name: &str) -> bool {
     // For the wasm32 bare target we ignore anything also ignored on emscripten
     // and then we also recognize `wasm32-bare` as the os for the target
@@ -125,6 +139,12 @@ pub fn get_arch(triple: &str) -> &'static str {
     panic!("Cannot determine Architecture from triple");
 }
 
+/// Determine the endianness from `triple`
+pub fn is_big_endian(triple: &str) -> bool {
+    let triple_arch = triple.split('-').next().unwrap();
+    BIG_ENDIAN.contains(&triple_arch)
+}
+
 pub fn matches_env(triple: &str, name: &str) -> bool {
     if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
 }
index bd9f8fb0450254d4a7deee97684a3f869c18b190..ff6923b3797ebf052ad5d3614441504fcd3dcdf3 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(rustc_private)]
 
-extern crate rustc_ast;
 extern crate rustc_driver;
 extern crate rustc_span;
 
@@ -284,7 +283,7 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 fn main() {
     rustc_driver::init_env_logger("RUST_LOG");
     let (format, dst) = parse_args();
-    let result = rustc_ast::with_default_session_globals(move || main_with_result(format, &dst));
+    let result = rustc_span::with_default_session_globals(move || main_with_result(format, &dst));
     if let Err(e) = result {
         panic!("{}", e.to_string());
     }
index 55bdb3174653039f47362742f8dc941bfc086e8f..cf633d0e897c065381b7b7d14984830176caf8b2 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 55bdb3174653039f47362742f8dc941bfc086e8f
+Subproject commit cf633d0e897c065381b7b7d14984830176caf8b2
index c0631fcedd34973d259fce507d914851284e1eac..55e2d7cf8278fff95c8793a6b473f557c73af943 100755 (executable)
@@ -42,7 +42,7 @@ MAINTAINERS = {
 LABELS = {
     'miri': ['A-miri', 'C-bug'],
     'rls': ['A-rls', 'C-bug'],
-    'rustfmt': ['C-bug'],
+    'rustfmt': ['A-rustfmt', 'C-bug'],
     'book': ['C-bug'],
     'nomicon': ['C-bug'],
     'reference': ['C-bug'],
index 51f135d37616125ad1b2e4a18aacf28631327c30..9c36d853ef78dc94728bd8a7852f1329fb20a407 100644 (file)
@@ -16,8 +16,7 @@
 ];
 
 // Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] =
-    &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749"];
 
 fn check_error_code_explanation(
     f: &str,
index eabbcee9d73fd2340ca0019b50af9e7ef2ff593d..d2d1807b3bb22cb27998099fe0e5d39e0b192582 100644 (file)
@@ -15,7 +15,7 @@
 //! We have two separate encoding schemes: a skiplist-like approach, and a
 //! compressed bitset. The datasets we consider mostly use the skiplist (it's
 //! smaller) but the lowercase and uppercase sets are sufficiently sparse for
-//! the bitset to be worthwhile -- for those sets the biset is a 2x size win.
+//! the bitset to be worthwhile -- for those sets the bitset is a 2x size win.
 //! Since the bitset is also faster, this seems an obvious choice. (As a
 //! historical note, the bitset was also the prior implementation, so its
 //! relative complexity had already been paid).