]> git.lizzy.rs Git - rust.git/commitdiff
Merge branch 'master' into feature/incorporate-tracing
authorpawanbisht62 <36775517+pawanbisht62@users.noreply.github.com>
Mon, 10 Aug 2020 07:49:24 +0000 (13:19 +0530)
committerGitHub <noreply@github.com>
Mon, 10 Aug 2020 07:49:24 +0000 (13:19 +0530)
365 files changed:
Cargo.lock
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/navigate.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/raw_vec.rs
library/alloc/tests/btree/map.rs
library/alloc/tests/lib.rs
library/core/src/array/iter.rs
library/core/src/hint.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/core/src/time.rs
library/panic_unwind/src/lib.rs
library/std/Cargo.toml
library/std/src/collections/hash/map.rs
library/std/src/keyword_docs.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/std/src/thread/local.rs
library/test/src/helpers/concurrency.rs
library/test/src/lib.rs
library/unwind/src/lib.rs
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_ssa/back/link.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/mir/place.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/transitive_relation.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/E0746.md
src/librustc_error_codes/error_codes/E0747.md
src/librustc_error_codes/error_codes/E0749.md
src/librustc_error_codes/error_codes/E0750.md
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_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_middle/middle/limits.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/query/on_disk_cache.rs
src/librustc_mir/borrow_check/borrow_set.rs
src/librustc_mir/borrow_check/constraint_generation.rs
src/librustc_mir/borrow_check/diagnostics/mod.rs
src/librustc_mir/borrow_check/invalidation.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll.rs
src/librustc_mir/borrow_check/region_infer/values.rs
src/librustc_mir/borrow_check/type_check/mod.rs
src/librustc_mir/dataflow/framework/engine.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/monomorphize/polymorphize.rs
src/librustc_mir/transform/const_prop.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/matches/mod.rs
src/librustc_mir_build/build/matches/test.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/expr.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/span_encoding.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/test.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/generator_interior.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/html/render/mod.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/ayu.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.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/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-prim-precedence.rs
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/asm/bad-arch.rs [new file with mode: 0644]
src/test/ui/asm/bad-arch.stderr [new file with mode: 0644]
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/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/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/issues/issue-40782.fixed
src/test/ui/issues/issue-40782.rs
src/test/ui/issues/issue-40782.stderr
src/test/ui/issues/issue-75283.rs [new file with mode: 0644]
src/test/ui/issues/issue-75283.stderr [new file with mode: 0644]
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/proc-macro/dollar-crate-issue-57089.rs
src/test/ui/proc-macro/dollar-crate-issue-57089.stdout
src/test/ui/proc-macro/dollar-crate-issue-62325.rs
src/test/ui/proc-macro/dollar-crate-issue-62325.stdout
src/test/ui/proc-macro/dollar-crate.rs
src/test/ui/proc-macro/dollar-crate.stdout
src/test/ui/proc-macro/input-interpolated.rs
src/test/ui/proc-macro/input-interpolated.stdout
src/test/ui/proc-macro/meta-macro-hygiene.rs
src/test/ui/proc-macro/meta-macro-hygiene.stdout
src/test/ui/proc-macro/meta-macro.rs
src/test/ui/proc-macro/meta-macro.stdout
src/test/ui/proc-macro/nested-macro-rules.rs
src/test/ui/proc-macro/nested-macro-rules.stdout
src/test/ui/proc-macro/nodelim-groups.rs
src/test/ui/proc-macro/nodelim-groups.stdout
src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
src/test/ui/simd/simd-intrinsic-generic-bitmask.rs
src/test/ui/simd/simd-intrinsic-generic-select.rs
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 d4f4ec7f6f0a3ae00a39e8fed136aeca559ef890..2685de2244e9414f7bb5134bc0dff7d00b3b030a 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",
@@ -1388,9 +1382,13 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.0.2"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
+checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
 
 [[package]]
 name = "installer"
@@ -2079,7 +2077,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 +3199,6 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
- "scoped-tls",
  "smallvec 1.4.0",
  "tracing",
 ]
@@ -4925,7 +4922,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 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 2abd7231711f3c4ebfeec9c53d78c8d444f809bd..247b636c808acf5e15a2b16acf212860872c73b3 100644 (file)
@@ -203,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
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 c680a3fc25bd40b84a656d7983903b0c23f7dcb6..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)]
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 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 acaedbd135e7c3c7d7cdeef7a807a475096af0a0..5741f8a53b522b96044120af538f41f58b4bfd12 100644 (file)
 /// nanosecond-level precision, APIs binding a system timeout will typically round up
 /// the number of nanoseconds.
 ///
-/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`.
+/// [`Duration`]s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits. It implements [`Default`] by returning a zero-length `Duration`.
 ///
-/// [`Add`]: ../../std/ops/trait.Add.html
-/// [`Sub`]: ../../std/ops/trait.Sub.html
-/// [`ops`]: ../../std/ops/index.html
+/// [`ops`]: crate::ops
 ///
 /// # Examples
 ///
@@ -293,7 +291,7 @@ pub const fn is_zero(&self) -> bool {
     ///            + duration.subsec_nanos() as f64 * 1e-9);
     /// ```
     ///
-    /// [`subsec_nanos`]: #method.subsec_nanos
+    /// [`subsec_nanos`]: Duration::subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
     #[rustc_const_stable(feature = "duration", since = "1.32.0")]
     #[inline]
@@ -421,8 +419,6 @@ pub const fn as_nanos(&self) -> u128 {
     /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
     /// if overflow occurred.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -457,8 +453,6 @@ pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
     /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
     /// if the result would be negative or if overflow occurred.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -494,8 +488,6 @@ pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
     /// Checked `Duration` multiplication. Computes `self * other`, returning
     /// [`None`] if overflow occurred.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -526,8 +518,6 @@ pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
     /// Checked `Duration` division. Computes `self / other`, returning [`None`]
     /// if `other == 0`.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
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 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 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..08d363a9a29649d1359f1de996bb8bcd64bc0661 100644 (file)
@@ -7,6 +7,8 @@
 //! * Executing a panic up to doing the actual implementation
 //! * Shims around "try"
 
+#![deny(unsafe_op_in_unsafe_fn)]
+
 use core::panic::{BoxMeUp, Location, PanicInfo};
 
 use crate::any::Any;
@@ -322,11 +324,22 @@ union Data<F, R> {
     let mut data = Data { f: ManuallyDrop::new(f) };
 
     let data_ptr = &mut data as *mut _ as *mut u8;
-    return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
-        Ok(ManuallyDrop::into_inner(data.r))
-    } else {
-        Err(ManuallyDrop::into_inner(data.p))
-    };
+    // SAFETY:
+    //
+    // Access to the union's fields: this is `std` and we know that the `r#try`
+    // intrinsic fills in the `r` or `p` union field based on its return value.
+    //
+    // The call to `intrinsics::r#try` is made safe by:
+    // - `do_call`, the first argument, can be called with the initial `data_ptr`.
+    // - `do_catch`, the second argument, can be called with the `data_ptr` as well.
+    // See their safety preconditions for more informations
+    unsafe {
+        return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
+            Ok(ManuallyDrop::into_inner(data.r))
+        } else {
+            Err(ManuallyDrop::into_inner(data.p))
+        };
+    }
 
     // We consider unwinding to be rare, so mark this function as cold. However,
     // do not mark it no-inline -- that decision is best to leave to the
@@ -334,13 +347,25 @@ union Data<F, R> {
     // non-cold function, though, as of the writing of this comment).
     #[cold]
     unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
-        let obj = Box::from_raw(__rust_panic_cleanup(payload));
+        // SAFETY: The whole unsafe block hinges on a correct implementation of
+        // the panic handler `__rust_panic_cleanup`. As such we can only
+        // assume it returns the correct thing for `Box::from_raw` to work
+        // without undefined behavior.
+        let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) };
         panic_count::decrease();
         obj
     }
 
+    // SAFETY:
+    // data must be non-NUL, correctly aligned, and a pointer to a `Data<F, R>`
+    // Its must contains a valid `f` (type: F) value that can be use to fill
+    // `data.r`.
+    //
+    // This function cannot be marked as `unsafe` because `intrinsics::r#try`
+    // expects normal function pointers.
     #[inline]
     fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+        // SAFETY: this is the responsibilty of the caller, see above.
         unsafe {
             let data = data as *mut Data<F, R>;
             let data = &mut (*data);
@@ -352,8 +377,21 @@ fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
     // We *do* want this part of the catch to be inlined: this allows the
     // compiler to properly track accesses to the Data union and optimize it
     // away most of the time.
+    //
+    // SAFETY:
+    // data must be non-NUL, correctly aligned, and a pointer to a `Data<F, R>`
+    // Since this uses `cleanup` it also hinges on a correct implementation of
+    // `__rustc_panic_cleanup`.
+    //
+    // This function cannot be marked as `unsafe` because `intrinsics::r#try`
+    // expects normal function pointers.
     #[inline]
     fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
+        // SAFETY: this is the responsibilty of the caller, see above.
+        //
+        // When `__rustc_panic_cleaner` is correctly implemented we can rely
+        // on `obj` being the correct thing to pass to `data.p` (after wrapping
+        // in `ManuallyDrop`).
         unsafe {
             let data = data as *mut Data<F, R>;
             let data = &mut (*data);
@@ -434,7 +472,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 +493,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..e3d529df7de1643732b64071a1fd5bf527d4ffde 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")));
@@ -2087,9 +2031,13 @@ fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
     /// assert!(path.starts_with("/etc"));
     /// assert!(path.starts_with("/etc/"));
     /// assert!(path.starts_with("/etc/passwd"));
-    /// assert!(path.starts_with("/etc/passwd/"));
+    /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
+    /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
     ///
     /// assert!(!path.starts_with("/e"));
+    /// assert!(!path.starts_with("/etc/passwd.txt"));
+    ///
+    /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
@@ -2124,7 +2072,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 +2081,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 +2103,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 +2122,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 +2145,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 +2171,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 +2181,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 +2227,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 +2247,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 +2269,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 +2292,6 @@ pub fn display(&self) -> Display<'_> {
     ///
     /// This is an alias to [`fs::metadata`].
     ///
-    /// [`fs::metadata`]: ../fs/fn.metadata.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -2378,8 +2310,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 +2329,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 +2346,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 +2361,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 +2395,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 +2426,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 +2458,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 +2467,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 +2505,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 e36a53084bae1874a92be0ba1056e7edf691f899..ba169b251b0bc7ad768593f8fef355ce8e800d39 100644 (file)
@@ -283,12 +283,12 @@ fn drop(&mut self) {
 #[cfg(test)]
 mod tests {
     use super::{FileDesc, IoSlice};
+    use core::mem::ManuallyDrop;
 
     #[test]
     fn limit_vector_count() {
-        let stdout = FileDesc { fd: 1 };
+        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 ecd6fbc6b9395aaa7dfdc6f8dfa4713856b8acc2..66508f06b2884ccb4de9147d890d3f08fa35e8cb 100644 (file)
@@ -172,7 +172,11 @@ unsafe fn __getit() -> $crate::option::Option<&'static $t> {
                 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
                     $crate::thread::__OsLocalKeyInner::new();
 
-                __KEY.get(__init)
+                // FIXME: remove the #[allow(...)] marker when macros don't
+                // raise warning for missing/extraneous unsafe blocks anymore.
+                // See https://github.com/rust-lang/rust/issues/74838.
+                #[allow(unused_unsafe)]
+                unsafe { __KEY.get(__init) }
             }
 
             unsafe {
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 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..7cfde3fc6d2dcd1e09e49b8f0dcd1ba614353de2 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};
@@ -574,7 +573,9 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
             .resolver
             .trait_map()
             .iter()
-            .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
+            .filter_map(|(&k, v)| {
+                self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
+            })
             .collect();
 
         let mut def_id_to_hir_id = IndexVec::default();
@@ -981,7 +982,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 +2216,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 +2237,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 de8f81bdadf0e00360eee07931791f022f94d047..00593c68cfc9a01dd03a04d1df04d872958b0cbf 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 3f7128d605d2544686b9ac00e04e5b7e936768dc..a80763d6ec8e8d0439e80b39ca0a487312772807 100644 (file)
@@ -2,13 +2,13 @@
 
 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 566fe1e15d4253950f1566f00ad77e24bec95a90..b977da733aa3290f2aec0f8e742b0ea9880f7f91 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 5d1bfd810b2fea3bcfdd06bd2a8913bb9c5bedb1..a39234c0b7f66cecdb1ad820451583d3cfd9d050 100644 (file)
@@ -5,7 +5,7 @@
 use llvm::coverageinfo::CounterMappingRegion;
 use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression, Region};
 use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_llvm::RustString;
 use tracing::debug;
 
@@ -76,13 +76,12 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
 }
 
 struct CoverageMapGenerator {
-    filenames: Vec<CString>,
-    filename_to_index: FxHashMap<CString, u32>,
+    filenames: FxIndexSet<CString>,
 }
 
 impl CoverageMapGenerator {
     fn new() -> Self {
-        Self { filenames: Vec::new(), filename_to_index: FxHashMap::default() }
+        Self { filenames: FxIndexSet::default() }
     }
 
     /// Using the `expressions` and `counter_regions` collected for the current function, generate
@@ -122,16 +121,8 @@ fn write_coverage_mappings(
                 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(c_filename.clone());
-                        self.filename_to_index.insert(c_filename.clone(), index);
-                        index
-                    }
-                };
-                virtual_file_mapping.push(filenames_index);
+                let (filenames_index, _) = self.filenames.insert_full(c_filename);
+                virtual_file_mapping.push(filenames_index as u32);
             }
             mapping_regions.push(CounterMappingRegion::code_region(
                 counter,
index 4d51f8b059166c6c6e343589216be48463cdd2e2..d7c98e9a62492807d717b02978007feda9fcae39 100644 (file)
@@ -97,8 +97,11 @@ fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'t
     }
 }
 
-pub(crate) fn write_filenames_section_to_buffer(filenames: &Vec<CString>, buffer: &RustString) {
-    let c_str_vec = filenames.iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
+pub(crate) fn write_filenames_section_to_buffer<'a>(
+    filenames: impl IntoIterator<Item = &'a CString>,
+    buffer: &RustString,
+) {
+    let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
     unsafe {
         llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
             c_str_vec.as_ptr(),
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 836e490c1d62dc885bfb66e46f6dea6e07cc95c8..f288135596265278f54604341f720544ac8b91ce 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 9191c68d4537aac7f7a43a8596d5adaa3d505680..6912667c391d0cff4a7eb815c381a9b4b833fb8a 100644 (file)
@@ -1295,7 +1295,9 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
         Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
         // FIXME: Find some heuristic for "native mingw toolchain is available",
         // likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429).
-        Some(CrtObjectsFallback::Mingw) => sess.target.target.target_vendor != "uwp",
+        Some(CrtObjectsFallback::Mingw) => {
+            sess.host == sess.target.target && sess.target.target.target_vendor != "uwp"
+        }
         // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
         Some(CrtObjectsFallback::Wasm) => true,
         None => false,
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 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 386096b416fb7c89d4b54908867fb16b64ba07a6..fda0fc5973bef3498447d8ed99bd714d53bd4e5e 100644 (file)
@@ -11,7 +11,7 @@ doctest = false
 
 [dependencies]
 ena = "0.14"
-indexmap = "1"
+indexmap = "1.5.1"
 tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 lazy_static = "1"
index 189da3395ad1b32999e43db90bd67b6e1ebc33f9..7d137a55033f7ac89ee6e3a038c3f78a1c451b5f 100644 (file)
@@ -1,4 +1,4 @@
-use crate::fx::FxHashMap;
+use crate::fx::FxIndexSet;
 use crate::stable_hasher::{HashStable, StableHasher};
 use crate::sync::Lock;
 use rustc_index::bit_set::BitMatrix;
 #[derive(Clone, Debug)]
 pub struct TransitiveRelation<T: Eq + Hash> {
     // List of elements. This is used to map from a T to a usize.
-    elements: Vec<T>,
-
-    // Maps each element to an index.
-    map: FxHashMap<T, Index>,
+    elements: FxIndexSet<T>,
 
     // List of base edges in the graph. Require to compute transitive
     // closure.
@@ -39,7 +36,6 @@ impl<T: Eq + Hash> Default for TransitiveRelation<T> {
     fn default() -> Self {
         TransitiveRelation {
             elements: Default::default(),
-            map: Default::default(),
             edges: Default::default(),
             closure: Default::default(),
         }
@@ -65,20 +61,16 @@ pub fn elements(&self) -> impl Iterator<Item = &T> {
     }
 
     fn index(&self, a: &T) -> Option<Index> {
-        self.map.get(a).cloned()
+        self.elements.get_index_of(a).map(Index)
     }
 
     fn add_index(&mut self, a: T) -> Index {
-        let &mut TransitiveRelation { ref mut elements, ref mut closure, ref mut map, .. } = self;
-
-        *map.entry(a.clone()).or_insert_with(|| {
-            elements.push(a);
-
+        let (index, added) = self.elements.insert_full(a);
+        if added {
             // if we changed the dimensions, clear the cache
-            *closure.get_mut() = None;
-
-            Index(elements.len() - 1)
-        })
+            *self.closure.get_mut() = None;
+        }
+        Index(index)
     }
 
     /// Applies the (partial) function to each edge and returns a new
@@ -430,14 +422,11 @@ impl<T> Decodable for TransitiveRelation<T>
 {
     fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
         d.read_struct("TransitiveRelation", 2, |d| {
-            let elements: Vec<T> = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
-            let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
-            let map = elements
-                .iter()
-                .enumerate()
-                .map(|(index, elem)| (elem.clone(), Index(index)))
-                .collect();
-            Ok(TransitiveRelation { elements, edges, map, closure: Lock::new(None) })
+            Ok(TransitiveRelation {
+                elements: d.read_struct_field("elements", 0, |d| Decodable::decode(d))?,
+                edges: d.read_struct_field("edges", 1, |d| Decodable::decode(d))?,
+                closure: Lock::new(None),
+            })
         })
     }
 }
@@ -452,8 +441,6 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         let TransitiveRelation {
             ref elements,
             ref edges,
-            // "map" is just a copy of elements vec
-            map: _,
             // "closure" is just a copy of the data above
             closure: _,
         } = *self;
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 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 9eb8ee4e3fdf78fdbbceda19e3876886827b3a59..7a1a745b53c12b606b49b93d7ae2bdb0ae158734 100644 (file)
@@ -1,4 +1,19 @@
-Negative impls are not allowed to have any items. Negative impls
-declare that a trait is **not** implemented (and never will be) and
-hence there is no need to specify the values for trait methods or
-other items.
+An item was added on a negative impl.
+
+Erroneous code example:
+
+```compile_fail,E0749
+# #![feature(negative_impls)]
+trait MyTrait {
+    type Foo;
+}
+
+impl !MyTrait for u32 {
+    type Foo = i32; // error!
+}
+# fn main() {}
+```
+
+Negative impls are not allowed to have any items. Negative impls declare that a
+trait is **not** implemented (and never will be) and hence there is no need to
+specify the values for trait methods or other items.
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 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 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 ad30f5eda4d69f93cb797c362cf648e9534b988f..4dccf273dd90fc69f6b17a343222a7aa13323da9 100644 (file)
@@ -73,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| {
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 9fb4e08e2844a1908218271bcb337e6de815dcb7..8aea9a9f5885061312aa0c18e9710bf22bf57cb9 100644 (file)
@@ -742,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,
@@ -1102,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);
                                 }
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 acae44e6bf7c92ae0339c80719a1f1fedfec4100..6723e236a1fe981e0fb9a9b022eb457231183eb9 100644 (file)
@@ -3,9 +3,8 @@
 
 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::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{join, Lrc};
 use rustc_hir as hir;
@@ -49,8 +48,7 @@ struct EncodeContext<'a, 'tcx> {
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
 
-    interpret_allocs: FxHashMap<interpret::AllocId, usize>,
-    interpret_allocs_inverse: Vec<interpret::AllocId>,
+    interpret_allocs: FxIndexSet<interpret::AllocId>,
 
     // This is used to speed up Span encoding.
     // The `usize` is an index into the `MonotonicVec`
@@ -162,7 +160,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,
         )
@@ -280,6 +278,10 @@ fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
         // cross-crate inconsistencies (getting one behavior in the same
         // crate, and a different behavior in another crate) due to the
         // limited surface that proc-macros can expose.
+        //
+        // IMPORTANT: If this is ever changed, be sure to update
+        // `rustc_span::hygiene::raw_encode_expn_id` to handle
+        // encoding `ExpnData` for proc-macro crates.
         if self.is_proc_macro {
             SyntaxContext::root().encode(self)?;
         } else {
@@ -328,17 +330,7 @@ fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Se
 
 impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
     fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
-        use std::collections::hash_map::Entry;
-        let index = match self.interpret_allocs.entry(*alloc_id) {
-            Entry::Occupied(e) => *e.get(),
-            Entry::Vacant(e) => {
-                let idx = self.interpret_allocs_inverse.len();
-                self.interpret_allocs_inverse.push(*alloc_id);
-                e.insert(idx);
-                idx
-            }
-        };
-
+        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
         index.encode(self)
     }
 }
@@ -580,7 +572,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
             let mut n = 0;
             trace!("beginning to encode alloc ids");
             loop {
-                let new_n = self.interpret_allocs_inverse.len();
+                let new_n = self.interpret_allocs.len();
                 // if we have found new ids, serialize those, too
                 if n == new_n {
                     // otherwise, abort
@@ -588,7 +580,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
                 }
                 trace!("encoding {} further alloc ids", new_n - n);
                 for idx in n..new_n {
-                    let id = self.interpret_allocs_inverse[idx];
+                    let id = self.interpret_allocs[idx];
                     let pos = self.position() as u32;
                     interpret_alloc_index.push(pos);
                     interpret::specialized_encode_alloc_id(self, tcx, id).unwrap();
@@ -633,7 +625,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),
@@ -659,12 +651,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,
@@ -2016,7 +2008,6 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
         predicate_shorthands: Default::default(),
         source_file_cache: (source_map_files[0].clone(), 0),
         interpret_allocs: Default::default(),
-        interpret_allocs_inverse: Default::default(),
         required_source_files: Some(GrowableBitSet::with_capacity(source_map_files.len())),
         is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
         hygiene_ctxt: &hygiene_ctxt,
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 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 643fbe793ab8072540f6ca078aa4b279e6768877..08b0bfecf49099ec0642a466c1e3d4c80fdc8dec 100644 (file)
@@ -5,7 +5,7 @@
 use crate::ty::context::TyCtxt;
 use crate::ty::{self, Ty};
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
@@ -212,7 +212,6 @@ pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(
                 type_shorthands: Default::default(),
                 predicate_shorthands: Default::default(),
                 interpret_allocs: Default::default(),
-                interpret_allocs_inverse: Vec::new(),
                 source_map: CachingSourceMapView::new(tcx.sess.source_map()),
                 file_to_file_index,
                 hygiene_context: &hygiene_encode_context,
@@ -267,7 +266,7 @@ macro_rules! encode_queries {
                 let mut interpret_alloc_index = Vec::new();
                 let mut n = 0;
                 loop {
-                    let new_n = encoder.interpret_allocs_inverse.len();
+                    let new_n = encoder.interpret_allocs.len();
                     // If we have found new IDs, serialize those too.
                     if n == new_n {
                         // Otherwise, abort.
@@ -275,7 +274,7 @@ macro_rules! encode_queries {
                     }
                     interpret_alloc_index.reserve(new_n - n);
                     for idx in n..new_n {
-                        let id = encoder.interpret_allocs_inverse[idx];
+                        let id = encoder.interpret_allocs[idx];
                         let pos = encoder.position() as u32;
                         interpret_alloc_index.push(pos);
                         interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
@@ -767,8 +766,7 @@ struct CacheEncoder<'a, 'tcx, E: ty_codec::TyEncoder> {
     encoder: &'a mut E,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
-    interpret_allocs: FxHashMap<interpret::AllocId, usize>,
-    interpret_allocs_inverse: Vec<interpret::AllocId>,
+    interpret_allocs: FxIndexSet<interpret::AllocId>,
     source_map: CachingSourceMapView<'tcx>,
     file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
     hygiene_context: &'a HygieneEncodeContext,
@@ -807,17 +805,7 @@ impl<'a, 'tcx, E> SpecializedEncoder<interpret::AllocId> for CacheEncoder<'a, 't
     E: 'a + TyEncoder,
 {
     fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
-        use std::collections::hash_map::Entry;
-        let index = match self.interpret_allocs.entry(*alloc_id) {
-            Entry::Occupied(e) => *e.get(),
-            Entry::Vacant(e) => {
-                let idx = self.interpret_allocs_inverse.len();
-                self.interpret_allocs_inverse.push(*alloc_id);
-                e.insert(idx);
-                idx
-            }
-        };
-
+        let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
         index.encode(self)
     }
 }
index ef9af7bace96f4f1af8109c01a0bd34328281c59..b4299fbc5a1fe8128e5710c8cfb742d3d6095526 100644 (file)
@@ -3,9 +3,8 @@
 use crate::borrow_check::place_ext::PlaceExt;
 use crate::dataflow::indexes::BorrowIndex;
 use crate::dataflow::move_paths::MoveData;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Body, Local, Location};
 
 crate struct BorrowSet<'tcx> {
     /// The fundamental map relating bitvector indexes to the borrows
-    /// in the MIR.
-    crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
-
-    /// Each borrow is also uniquely identified in the MIR by the
-    /// `Location` of the assignment statement in which it appears on
-    /// the right hand side; we map each such location to the
-    /// corresponding `BorrowIndex`.
-    crate location_map: FxHashMap<Location, BorrowIndex>,
+    /// in the MIR. Each borrow is also uniquely identified in the MIR
+    /// by the `Location` of the assignment statement in which it
+    /// appears on the right hand side. Thus the location is the map
+    /// key, and its position in the map corresponds to `BorrowIndex`.
+    crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
 
     /// Locations which activate borrows.
     /// NOTE: a given location may activate more than one borrow in the future
@@ -40,7 +36,7 @@ impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
     type Output = BorrowData<'tcx>;
 
     fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
-        &self.borrows[index]
+        &self.location_map[index.as_usize()]
     }
 }
 
@@ -129,7 +125,6 @@ pub fn build(
         let mut visitor = GatherBorrows {
             tcx,
             body: &body,
-            idx_vec: IndexVec::new(),
             location_map: Default::default(),
             activation_map: Default::default(),
             local_map: Default::default(),
@@ -146,7 +141,6 @@ pub fn build(
         }
 
         BorrowSet {
-            borrows: visitor.idx_vec,
             location_map: visitor.location_map,
             activation_map: visitor.activation_map,
             local_map: visitor.local_map,
@@ -157,13 +151,32 @@ pub fn build(
     crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
         self.activation_map.get(&location).map(|activations| &activations[..]).unwrap_or(&[])
     }
+
+    crate fn len(&self) -> usize {
+        self.location_map.len()
+    }
+
+    crate fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
+        BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len())
+    }
+
+    crate fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
+        self.indices().zip(self.location_map.values())
+    }
+
+    crate fn get_index_of(&self, location: &Location) -> Option<BorrowIndex> {
+        self.location_map.get_index_of(location).map(BorrowIndex::from)
+    }
+
+    crate fn contains(&self, location: &Location) -> bool {
+        self.location_map.contains_key(location)
+    }
 }
 
 struct GatherBorrows<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
-    idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
-    location_map: FxHashMap<Location, BorrowIndex>,
+    location_map: FxIndexMap<Location, BorrowData<'tcx>>,
     activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
     local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
 
@@ -203,8 +216,8 @@ fn visit_assign(
                 borrowed_place: *borrowed_place,
                 assigned_place: *assigned_place,
             };
-            let idx = self.idx_vec.push(borrow);
-            self.location_map.insert(location, idx);
+            let (idx, _) = self.location_map.insert_full(location, borrow);
+            let idx = BorrowIndex::from(idx);
 
             self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
 
@@ -224,7 +237,7 @@ fn visit_local(&mut self, temp: &Local, context: PlaceContext, location: Locatio
         //
         //     TMP = &mut place
         if let Some(&borrow_index) = self.pending_activations.get(temp) {
-            let borrow_data = &mut self.idx_vec[borrow_index];
+            let borrow_data = &mut self.location_map[borrow_index.as_usize()];
 
             // Watch out: the use of TMP in the borrow itself
             // doesn't count as an activation. =)
@@ -265,8 +278,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location)
         if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
             // double-check that we already registered a BorrowData for this
 
-            let borrow_index = self.location_map[&location];
-            let borrow_data = &self.idx_vec[borrow_index];
+            let borrow_data = &self.location_map[&location];
             assert_eq!(borrow_data.reserve_location, location);
             assert_eq!(borrow_data.kind, kind);
             assert_eq!(borrow_data.region, region.to_region_vid());
@@ -316,7 +328,7 @@ fn insert_as_pending_if_two_phase(
         // Consider the borrow not activated to start. When we find an activation, we'll update
         // this field.
         {
-            let borrow_data = &mut self.idx_vec[borrow_index];
+            let borrow_data = &mut self.location_map[borrow_index.as_usize()];
             borrow_data.activation_location = TwoPhaseActivation::NotActivated;
         }
 
@@ -332,7 +344,7 @@ fn insert_as_pending_if_two_phase(
                        at borrow_index: {:?} with associated data {:?}",
                 temp,
                 old_index,
-                self.idx_vec[old_index]
+                self.location_map[old_index.as_usize()]
             );
         }
     }
index e0420d974fbdf3cdc93d35e8a43d5210c487a251..33b09dcb888ed680cfa676663cd5010b850e35da 100644 (file)
@@ -217,7 +217,7 @@ fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Loca
                             let places_conflict = places_conflict::places_conflict(
                                 self.infcx.tcx,
                                 self.body,
-                                self.borrow_set.borrows[borrow_index].borrowed_place,
+                                self.borrow_set[borrow_index].borrowed_place,
                                 place,
                                 places_conflict::PlaceConflictBias::NoOverlap,
                             );
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 fd8f17718e795b48f5bacc0e569eb8e8932bf9e2..2de2124dc5e0eaab2cc85e6590422bc2f06ec330 100644 (file)
@@ -166,8 +166,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 // Invalidate all borrows of local places
                 let borrow_set = self.borrow_set.clone();
                 let resume = self.location_table.start_index(resume.start_location());
-                for i in borrow_set.borrows.indices() {
-                    if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
+                for (i, data) in borrow_set.iter_enumerated() {
+                    if borrow_of_local_data(data.borrowed_place) {
                         self.all_facts.invalidates.push((resume, i));
                     }
                 }
@@ -178,8 +178,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 // Invalidate all borrows of local places
                 let borrow_set = self.borrow_set.clone();
                 let start = self.location_table.start_index(location);
-                for i in borrow_set.borrows.indices() {
-                    if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
+                for (i, data) in borrow_set.iter_enumerated() {
+                    if borrow_of_local_data(data.borrowed_place) {
                         self.all_facts.invalidates.push((start, i));
                     }
                 }
@@ -369,7 +369,7 @@ fn check_access_for_conflict(
         let tcx = self.tcx;
         let body = self.body;
         let borrow_set = self.borrow_set.clone();
-        let indices = self.borrow_set.borrows.indices();
+        let indices = self.borrow_set.indices();
         each_borrow_involving_path(
             self,
             tcx,
index 76cc03fa60909ba58b605fa105b6928bac3a6ea0..6e211b42a052ee36575f983a59931655fa14e334 100644 (file)
@@ -1131,11 +1131,8 @@ fn check_access_for_conflict(
                 (
                     Reservation(WriteKind::MutableBorrow(bk)),
                     BorrowKind::Shallow | BorrowKind::Shared,
-                ) if {
-                    tcx.migrate_borrowck() && this.borrow_set.location_map.contains_key(&location)
-                } =>
-                {
-                    let bi = this.borrow_set.location_map[&location];
+                ) if { tcx.migrate_borrowck() && this.borrow_set.contains(&location) } => {
+                    let bi = this.borrow_set.get_index_of(&location).unwrap();
                     debug!(
                         "recording invalid reservation of place: {:?} with \
                          borrow index {:?} as warning",
index f6b3be59d9576acc36cb5eb5e3e7de764036fc96..66a17cba6bb010b225a28b8d651531fbb3c0112c 100644 (file)
@@ -206,7 +206,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
         //   added to the existing number of loans, as if they succeeded them in the set.
         //
-        let borrow_count = borrow_set.borrows.len();
+        let borrow_count = borrow_set.len();
         debug!(
             "compute_regions: polonius placeholders, num_universals={}, borrow_count={}",
             universal_regions.len(),
index 6cd814962c6133fac8e86a8d544b5984327c19d8..8a5a600cfdd8a76863167cc4e1dda98412b7e019 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
@@ -193,26 +193,25 @@ impl<N: Idx> LivenessValues<N> {
 /// NLL.
 #[derive(Default)]
 crate struct PlaceholderIndices {
-    to_index: FxHashMap<ty::PlaceholderRegion, PlaceholderIndex>,
-    from_index: IndexVec<PlaceholderIndex, ty::PlaceholderRegion>,
+    indices: FxIndexSet<ty::PlaceholderRegion>,
 }
 
 impl PlaceholderIndices {
     crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
-        let PlaceholderIndices { to_index, from_index } = self;
-        *to_index.entry(placeholder).or_insert_with(|| from_index.push(placeholder))
+        let (index, _) = self.indices.insert_full(placeholder);
+        index.into()
     }
 
     crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
-        self.to_index[&placeholder]
+        self.indices.get_index_of(&placeholder).unwrap().into()
     }
 
     crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion {
-        self.from_index[placeholder]
+        self.indices[placeholder.index()]
     }
 
     crate fn len(&self) -> usize {
-        self.from_index.len()
+        self.indices.len()
     }
 }
 
index bc5c144cd742c42fb81df884d39f33f1896f97cf..ff98de5475ecff8076a2b9b64ccc64568d834466 100644 (file)
@@ -2469,11 +2469,11 @@ fn add_reborrow_constraint(
         // example).
         if let Some(all_facts) = all_facts {
             let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
-            if let Some(borrow_index) = borrow_set.location_map.get(&location) {
+            if let Some(borrow_index) = borrow_set.get_index_of(&location) {
                 let region_vid = borrow_region.to_region_vid();
                 all_facts.borrow_region.push((
                     region_vid,
-                    *borrow_index,
+                    borrow_index,
                     location_table.mid_index(location),
                 ));
             }
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 dfca270396de923368a79c6c2c57e25c581fbd36..7e7b7f2cc76fae2849c7db753683a930a49cf2ad 100644 (file)
@@ -136,9 +136,9 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         borrow_set: &Rc<BorrowSet<'tcx>>,
     ) -> Self {
         let mut borrows_out_of_scope_at_location = FxHashMap::default();
-        for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() {
+        for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
             let borrow_region = borrow_data.region.to_region_vid();
-            let location = borrow_set.borrows[borrow_index].reserve_location;
+            let location = borrow_data.reserve_location;
 
             precompute_borrows_out_of_scope(
                 body,
@@ -160,7 +160,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     }
 
     pub fn location(&self, idx: BorrowIndex) -> &Location {
-        &self.borrow_set.borrows[idx].reserve_location
+        &self.borrow_set[idx].reserve_location
     }
 
     /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
@@ -216,7 +216,7 @@ fn kill_borrows_on_place(&self, trans: &mut impl GenKill<BorrowIndex>, place: Pl
             places_conflict(
                 self.tcx,
                 self.body,
-                self.borrow_set.borrows[i].borrowed_place,
+                self.borrow_set[i].borrowed_place,
                 place,
                 PlaceConflictBias::NoOverlap,
             )
@@ -232,7 +232,7 @@ impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
     const NAME: &'static str = "borrows";
 
     fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.borrow_set.borrows.len() * 2
+        self.borrow_set.len() * 2
     }
 
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
@@ -271,11 +271,11 @@ fn statement_effect(
                     ) {
                         return;
                     }
-                    let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
+                    let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| {
                         panic!("could not find BorrowIndex for location {:?}", location);
                     });
 
-                    trans.gen(*index);
+                    trans.gen(index);
                 }
 
                 // Make sure there are no remaining borrows for variables
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 8fc1458f592054ee47064dbc4bc3fb63e8b74163..a996b6fb9d924bf2e7dfde606ce485b22765a94d 100644 (file)
@@ -15,6 +15,7 @@
     self,
     fold::{TypeFoldable, TypeVisitor},
     query::Providers,
+    subst::SubstsRef,
     Const, Ty, TyCtxt,
 };
 use rustc_span::symbol::sym;
@@ -170,7 +171,11 @@ fn emit_unused_generic_params_error<'tcx>(
 ) {
     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;
     }
 
@@ -205,6 +210,25 @@ struct UsedGenericParametersVisitor<'a, 'tcx> {
     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> {
     fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         debug!("visit_local_decl: local_decl={:?}", local_decl);
@@ -245,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),
         }
     }
@@ -265,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 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 34fa840408f79a7d213bf4e25c40fccc7b975d4b..dfd01e27d57c99bfbed9259f31104ae9ef2aa704 100644 (file)
@@ -342,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))
 }
 
@@ -362,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 77c0fe8dda5346dd0bbf5010dfcc37e84b7c87b0..5f87cb364b891de29159e869aed9739529ee79d7 100644 (file)
@@ -11,7 +11,7 @@
 use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use crate::thir::{self, *};
 use rustc_data_structures::{
-    fx::{FxHashMap, FxHashSet},
+    fx::{FxHashSet, FxIndexMap},
     stack::ensure_sufficient_stack,
 };
 use rustc_hir::HirId;
@@ -817,9 +817,7 @@ enum TestKind<'tcx> {
         ///
         /// For `bool` we always generate two edges, one for `true` and one for
         /// `false`.
-        options: Vec<u128>,
-        /// Reverse map used to ensure that the values in `options` are unique.
-        indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+        options: FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
     },
 
     /// Test for equality with value, possibly after an unsizing coercion to
@@ -1396,14 +1394,13 @@ fn test_candidates<'pat, 'b, 'c>(
         // may want to add cases based on the candidates that are
         // available
         match test.kind {
-            TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
+            TestKind::SwitchInt { switch_ty, ref mut options } => {
                 for candidate in candidates.iter() {
                     if !self.add_cases_to_switch(
                         &match_place,
                         candidate,
                         switch_ty,
                         options,
-                        indices,
                     ) {
                         break;
                     }
index 158ad78a1bf36c4fc629465c3c9bc61f66c1fe2c..87977d6fe8904e84a7996150c9ec992c82960e92 100644 (file)
@@ -9,7 +9,7 @@
 use crate::build::Builder;
 use crate::thir::pattern::compare_const_vals;
 use crate::thir::*;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::RangeEnd;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
@@ -44,8 +44,7 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
 
                         // these maps are empty to start; cases are
                         // added below in add_cases_to_switch
-                        options: vec![],
-                        indices: Default::default(),
+                        options: Default::default(),
                     },
                 }
             }
@@ -83,8 +82,7 @@ pub(super) fn add_cases_to_switch<'pat>(
         test_place: &Place<'tcx>,
         candidate: &Candidate<'pat, 'tcx>,
         switch_ty: Ty<'tcx>,
-        options: &mut Vec<u128>,
-        indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+        options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
     ) -> bool {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
             Some(match_pair) => match_pair,
@@ -95,9 +93,8 @@ pub(super) fn add_cases_to_switch<'pat>(
 
         match *match_pair.pattern.kind {
             PatKind::Constant { value } => {
-                indices.entry(value).or_insert_with(|| {
-                    options.push(value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty));
-                    options.len() - 1
+                options.entry(value).or_insert_with(|| {
+                    value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty)
                 });
                 true
             }
@@ -106,7 +103,7 @@ pub(super) fn add_cases_to_switch<'pat>(
             }
             PatKind::Range(range) => {
                 // Check that none of the switch values are in the range.
-                self.values_not_contained_in_range(range, indices).unwrap_or(false)
+                self.values_not_contained_in_range(range, options).unwrap_or(false)
             }
             PatKind::Slice { .. }
             | PatKind::Array { .. }
@@ -216,7 +213,7 @@ pub(super) fn perform_test(
                 );
             }
 
-            TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
+            TestKind::SwitchInt { switch_ty, ref options } => {
                 let target_blocks = make_target_blocks(self);
                 let terminator = if switch_ty.kind == ty::Bool {
                     assert!(!options.is_empty() && options.len() <= 2);
@@ -236,7 +233,7 @@ pub(super) fn perform_test(
                     TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place),
                         switch_ty,
-                        values: options.clone().into(),
+                        values: options.values().copied().collect(),
                         targets: target_blocks,
                     }
                 };
@@ -532,20 +529,20 @@ pub(super) fn sort_candidate<'pat>(
             // FIXME(#29623) we could use PatKind::Range to rule
             // things out here, in some cases.
             (
-                &TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
+                &TestKind::SwitchInt { switch_ty: _, ref options },
                 &PatKind::Constant { ref value },
             ) if is_switch_ty(match_pair.pattern.ty) => {
-                let index = indices[value];
+                let index = options.get_index_of(value).unwrap();
                 self.candidate_without_match_pair(match_pair_index, candidate);
                 Some(index)
             }
 
             (
-                &TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
+                &TestKind::SwitchInt { switch_ty: _, ref options },
                 &PatKind::Range(range),
             ) => {
                 let not_contained =
-                    self.values_not_contained_in_range(range, indices).unwrap_or(false);
+                    self.values_not_contained_in_range(range, options).unwrap_or(false);
 
                 if not_contained {
                     // No switch values are contained in the pattern range,
@@ -777,9 +774,9 @@ fn const_range_contains(
     fn values_not_contained_in_range(
         &self,
         range: PatRange<'tcx>,
-        indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+        options: &FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
     ) -> Option<bool> {
-        for &val in indices.keys() {
+        for &val in options.keys() {
             if self.const_range_contains(range, val)? {
                 return Some(false);
             }
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 3aec300d86d4f5dcb6bb6cf386fb3b8c9d1d64e4..55a134ae09115ae5b32ced5f3e43e112ba03f2e1 100644 (file)
@@ -1733,13 +1733,20 @@ fn parse_for_expr(
         Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs))
     }
 
-    fn error_missing_in_for_loop(&self) {
-        let in_span = self.prev_token.span.between(self.token.span);
-        self.struct_span_err(in_span, "missing `in` in `for` loop")
+    fn error_missing_in_for_loop(&mut self) {
+        let (span, msg, sugg) = if self.token.is_ident_named(sym::of) {
+            // Possibly using JS syntax (#75311).
+            let span = self.token.span;
+            self.bump();
+            (span, "try using `in` here instead", "in")
+        } else {
+            (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ")
+        };
+        self.struct_span_err(span, "missing `in` in `for` loop")
             .span_suggestion_short(
-                in_span,
-                "try adding `in` here",
-                " in ".into(),
+                span,
+                msg,
+                sugg.into(),
                 // Has been misleading, at least in the past (closed Issue #48492).
                 Applicability::MaybeIncorrect,
             )
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 a03ac4e1fdba1638c7f5adff9bcb76f2094db332..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 {
@@ -1170,13 +1172,30 @@ pub fn raw_encode_expn_id<E: Encoder>(
     mode: ExpnDataEncodeMode,
     e: &mut E,
 ) -> Result<(), E::Error> {
-    if !context.serialized_expns.lock().contains(&expn) {
-        context.latest_expns.lock().insert(expn);
-    }
+    // Record the fact that we need to serialize the corresponding
+    // `ExpnData`
+    let needs_data = || {
+        if !context.serialized_expns.lock().contains(&expn) {
+            context.latest_expns.lock().insert(expn);
+        }
+    };
+
     match mode {
-        ExpnDataEncodeMode::IncrComp => expn.0.encode(e),
+        ExpnDataEncodeMode::IncrComp => {
+            // Always serialize the `ExpnData` in incr comp mode
+            needs_data();
+            expn.0.encode(e)
+        }
         ExpnDataEncodeMode::Metadata => {
             let data = expn.expn_data();
+            // We only need to serialize the ExpnData
+            // if it comes from this crate.
+            // We currently don't serialize any hygiene information data for
+            // proc-macro crates: see the `SpecializedEncoder<Span>` impl
+            // for crate metadata.
+            if data.krate == LOCAL_CRATE {
+                needs_data();
+            }
             data.orig_id.expect("Missing orig_id").encode(e)?;
             data.krate.encode(e)
         }
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 6b672d344fa512104403bfddd16987c3bf9c83d2..b05e01d666bd6917e32f4451640c4c4748a7f0ce 100644 (file)
@@ -8,7 +8,7 @@
 use crate::SESSION_GLOBALS;
 use crate::{BytePos, SpanData};
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
 
 /// A compressed span.
 ///
@@ -111,25 +111,18 @@ pub fn data(self) -> SpanData {
 
 #[derive(Default)]
 pub struct SpanInterner {
-    spans: FxHashMap<SpanData, u32>,
-    span_data: Vec<SpanData>,
+    spans: FxIndexSet<SpanData>,
 }
 
 impl SpanInterner {
     fn intern(&mut self, span_data: &SpanData) -> u32 {
-        if let Some(index) = self.spans.get(span_data) {
-            return *index;
-        }
-
-        let index = self.spans.len() as u32;
-        self.span_data.push(*span_data);
-        self.spans.insert(*span_data, index);
-        index
+        let (index, _) = self.spans.insert_full(*span_data);
+        index as u32
     }
 
     #[inline]
     fn get(&self, index: u32) -> &SpanData {
-        &self.span_data[index as usize]
+        &self.spans[index as usize]
     }
 }
 
index 98776a0478237495e80c53b76f93c7225ee39d8a..caa6de09664bcf1a38607114bcd31d980c3b89ae 100644 (file)
         min_align_of,
         min_align_of_val,
         min_const_fn,
+        min_const_generics,
         min_const_unsafe_fn,
         min_specialization,
         minnumf32,
         not,
         note,
         object_safe_for_dispatch,
+        of,
         offset,
         omit_gdb_pretty_printer_section,
         on,
@@ -1480,6 +1482,10 @@ fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr {
 }
 
 // The `&'static str`s in this type actually point into the arena.
+//
+// The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
+// found that to regress performance up to 2% in some cases. This might be
+// revisited after further improvements to `indexmap`.
 #[derive(Default)]
 pub struct Interner {
     arena: DroplessArena,
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 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 c5004e4ce119b4ba75d46f94a3d438b51809e44b..93fdf93e9e3944af3f8d8eecbf5f2dda7e267e46 100644 (file)
@@ -4,7 +4,7 @@
 //! types computed here.
 
 use super::FnCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -16,7 +16,7 @@
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
-    types: FxHashMap<ty::GeneratorInteriorTypeCause<'tcx>, usize>,
+    types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
     region_scope_tree: &'tcx region::ScopeTree,
     expr_count: usize,
     kind: hir::GeneratorKind,
@@ -88,18 +88,15 @@ fn record(
                     .span_note(yield_data.span, &*note)
                     .emit();
             } else {
-                // Map the type to the number of types added before it
-                let entries = self.types.len();
+                // Insert the type into the ordered set.
                 let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
-                self.types
-                    .entry(ty::GeneratorInteriorTypeCause {
-                        span: source_span,
-                        ty: &ty,
-                        scope_span,
-                        yield_span: yield_data.span,
-                        expr: expr.map(|e| e.hir_id),
-                    })
-                    .or_insert(entries);
+                self.types.insert(ty::GeneratorInteriorTypeCause {
+                    span: source_span,
+                    ty: &ty,
+                    scope_span,
+                    yield_span: yield_data.span,
+                    expr: expr.map(|e| e.hir_id),
+                });
             }
         } else {
             debug!(
@@ -132,7 +129,7 @@ pub fn resolve_interior<'a, 'tcx>(
     let body = fcx.tcx.hir().body(body_id);
     let mut visitor = InteriorVisitor {
         fcx,
-        types: FxHashMap::default(),
+        types: FxIndexSet::default(),
         region_scope_tree: fcx.tcx.region_scope_tree(def_id),
         expr_count: 0,
         kind,
@@ -144,10 +141,8 @@ pub fn resolve_interior<'a, 'tcx>(
     let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
     assert_eq!(region_expr_count, visitor.expr_count);
 
-    let mut types: Vec<_> = visitor.types.drain().collect();
-
-    // Sort types by insertion order
-    types.sort_by_key(|t| t.1);
+    // The types are already kept in insertion order.
+    let types = visitor.types;
 
     // The types in the generator interior contain lifetimes local to the generator itself,
     // which should not be exposed outside of the generator. Therefore, we replace these
@@ -164,7 +159,7 @@ pub fn resolve_interior<'a, 'tcx>(
     let mut captured_tys = FxHashSet::default();
     let type_causes: Vec<_> = types
         .into_iter()
-        .filter_map(|(mut cause, _)| {
+        .filter_map(|mut cause| {
             // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
             // can.
             let erased = fcx.tcx.erase_regions(&cause.ty);
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..b47ef34600404c1c7e5d37d48af1fb8fca744eee 100644 (file)
@@ -20,9 +20,9 @@
 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_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -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));
@@ -1715,21 +1718,17 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
     /// A data structure with unique elements, which preserves order of insertion.
     /// Preserving the order of insertion is important here so as not to break
     /// compile-fail UI tests.
-    // FIXME(eddyb) just use `IndexSet` from `indexmap`.
     struct UniquePredicates<'tcx> {
-        predicates: Vec<(ty::Predicate<'tcx>, Span)>,
-        uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>,
+        predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
     }
 
     impl<'tcx> UniquePredicates<'tcx> {
         fn new() -> Self {
-            UniquePredicates { predicates: vec![], uniques: FxHashSet::default() }
+            UniquePredicates { predicates: FxIndexSet::default() }
         }
 
         fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) {
-            if self.uniques.insert(value) {
-                self.predicates.push(value);
-            }
+            self.predicates.insert(value);
         }
 
         fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter: I) {
@@ -2011,7 +2010,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
         }))
     }
 
-    let mut predicates = predicates.predicates;
+    let mut predicates: Vec<_> = predicates.predicates.into_iter().collect();
 
     // Subtle: before we store the predicates into the tcx, we
     // sort them so that predicates like `T: Foo<Item=U>` come
@@ -2351,13 +2350,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 +2369,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 +2393,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 +2406,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 +2439,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 +2454,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 +2471,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 +2505,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 +2552,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 +2613,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 e203d51f612aa5a8d93ce2f2d0a2eb7431088202..a8247e2f494ccf1a3fd6b2a2bc1c09c8e86dc7f9 100644 (file)
@@ -196,7 +196,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
                     }
 
                     for attr in it.attrs {
-                        if attr.check_name(sym::track_caller) {
+                        if tcx.sess.check_name(attr, sym::track_caller) {
                             tcx.sess
                                 .struct_span_err(
                                     attr.span,
@@ -293,7 +293,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
                     }
 
                     for attr in it.attrs {
-                        if attr.check_name(sym::track_caller) {
+                        if tcx.sess.check_name(attr, sym::track_caller) {
                             tcx.sess
                                 .struct_span_err(
                                     attr.span,
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 5fb2d9f6f917c929746c3f1c1a1bea65b866db82..4cbc56333b1553476ad7bef1b58793ad7e9830e8 100644 (file)
@@ -3450,7 +3450,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
                 if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
                     if out.is_empty() {
                         out.push_str(&format!(
-                            "<h3 class=\"important\">Important traits for {}</h3>\
+                            "<h3 class=\"notable\">Notable traits for {}</h3>\
                                       <code class=\"content\">",
                             impl_.for_.print()
                         ));
@@ -3485,7 +3485,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String {
     if !out.is_empty() {
         out.insert_str(
             0,
-            "<span class=\"important-traits\"><span class=\"important-traits-tooltip\">ⓘ<div class='important-traits-tooltiptext'><span class=\"docblock\">"
+            "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ<div class='notable-traits-tooltiptext'><span class=\"docblock\">"
 
         );
         out.push_str("</code></span></div></span></span>");
index 082f9cca064f133560460d5496d472223a2c2bcd..19284018a30db91372837389dde62fb02769945f 100644 (file)
@@ -2636,9 +2636,9 @@ function defocusSearchBar() {
         });
     }());
 
-    onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
+    onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
         e.onclick = function() {
-            this.getElementsByClassName('important-traits-tooltiptext')[0]
+            this.getElementsByClassName('notable-traits-tooltiptext')[0]
                 .classList.toggle("force-tooltip");
         };
     });
index d0312d77a7c5d5867e5c027b76ae27957b910454..db0e4f4d31df81c8ad81fa5025d7ab26c1fdf3d1 100644 (file)
@@ -91,7 +91,7 @@ h2 {
 h3 {
        font-size: 1.3em;
 }
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important),
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
 h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
        font-weight: 500;
        margin: 20px 0 15px 0;
@@ -528,7 +528,7 @@ h4 > code, h3 > code, .invisible > code {
        font-size: 0.8em;
 }
 
-.content .methods > div:not(.important-traits) {
+.content .methods > div:not(.notable-traits) {
        margin-left: 40px;
        margin-bottom: 15px;
 }
@@ -1099,17 +1099,17 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        font-size: 20px;
 }
 
-.important-traits-tooltip {
+.notable-traits-tooltip {
        display: inline-block;
        cursor: pointer;
 }
 
-.important-traits:hover .important-traits-tooltiptext,
-.important-traits .important-traits-tooltiptext.force-tooltip {
+.notable-traits:hover .notable-traits-tooltiptext,
+.notable-traits .notable-traits-tooltiptext.force-tooltip {
        display: inline-block;
 }
 
-.important-traits .important-traits-tooltiptext {
+.notable-traits .notable-traits-tooltiptext {
        display: none;
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
@@ -1121,18 +1121,18 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        border: 1px solid;
 }
 
-.important-traits-tooltip::after {
+.notable-traits-tooltip::after {
        /* The margin on the tooltip does not capture hover events,
           this extends the area of hover enough so that mouse hover is not
           lost when moving the mouse to the tooltip */
        content: "\00a0\00a0\00a0";
 }
 
-.important-traits .important, .important-traits .docblock {
+.notable-traits .notable, .notable-traits .docblock {
        margin: 0;
 }
 
-.important-traits .docblock code.content{
+.notable-traits .docblock code.content{
        margin: 0;
        padding: 0;
        font-size: 20px;
@@ -1183,13 +1183,13 @@ pre.rust {
        font-size: 16px;
 }
 
-.important-traits {
+.notable-traits {
        cursor: pointer;
        z-index: 2;
        margin-left: 5px;
 }
 
-h4 > .important-traits {
+h4 > .notable-traits {
        position: absolute;
        left: -44px;
        top: 2px;
@@ -1431,7 +1431,7 @@ h4 > .important-traits {
                z-index: 1;
        }
 
-       h4 > .important-traits {
+       h4 > .notable-traits {
                position: absolute;
                left: -22px;
                top: 24px;
@@ -1522,7 +1522,7 @@ h4 > .important-traits {
                margin-top: 0;
        }
 
-       .important-traits .important-traits-tooltiptext {
+       .notable-traits .notable-traits-tooltiptext {
                left: 0;
                top: 100%;
        }
@@ -1544,7 +1544,7 @@ h4 > .important-traits {
        }
 }
 
-h3.important {
+h3.notable {
        margin: 0;
        margin-bottom: 13px;
        font-size: 19px;
index f4710f6ae873aef882d6387c255e0553ca75f5e8..60f0d25b219e7a6d62c2f9f26994477e85a9b619 100644 (file)
@@ -389,7 +389,7 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: transparent #314559 transparent transparent;
 }
 
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
        background-color: #314559;
        border-color: #5c6773;
 }
index b3b586ba362fa475b9f7c5c392bcf126305527c8..34c6cbbf4fa21e1dcc668c435a0999fa9ed561bd 100644 (file)
@@ -339,7 +339,7 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: transparent black transparent transparent;
 }
 
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
        background-color: #111;
        border-color: #777;
 }
index b0c5715604baab86ea5d29eab697f5b3b6a0701f..137aad4ed4398ed23220ac0ba9f00e2449d62d3e 100644 (file)
@@ -333,7 +333,7 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: transparent black transparent transparent;
 }
 
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
        background-color: #eee;
        border-color: #999;
 }
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..062bd61a7d00279b22ac8a581da9698fbf8e256e 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>,
@@ -212,9 +217,11 @@ fn resolve(
                         return Ok((res, Some(path_str.to_owned())));
                     }
                     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") {
+                        // This resolved to a module, but we want primitive types to take precedence instead.
+                        if matches!(
+                            disambiguator,
+                            None | 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 +354,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 +426,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 +586,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 +626,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 +769,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 +853,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 b86a105ff7664b22b0daca867544ad71236896bb..62f52ea5213f357d445f04ada98ba219dc2c77e2 100644 (file)
@@ -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();
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;
index 5f10c1ec4a75c1600e0748ec559045f8cc1eec20..15ea1232fd6fb826b746ac042e88eaca15aa0caa 100644 (file)
@@ -8,5 +8,10 @@ pub mod char {}
 pub struct MyString;
 
 /// See also [char]
-// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'intra_link_prim_precedence/char/index.html'
+// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
 pub struct MyString2;
+
+/// See also [crate::char] and [mod@char]
+// @has intra_link_prim_precedence/struct.MyString3.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char'
+// @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char'
+pub struct MyString3;
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() {
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
+
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/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;
 
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 d61c248c6ec62d9946c50942ebf2597b43ac2c9a..305a9c3292a4cc5e61d4df6d2da86c7cc2d77d0f 100644 (file)
@@ -3,4 +3,6 @@
 fn main() {
     for _i in 0..2 { //~ ERROR missing `in`
     }
+    for _i in 0..2 { //~ ERROR missing `in`
+    }
 }
index 3688c69fbc613c2931466bf992cb716d307c114b..43460ec1535ce44b85b9157acfa70ac563801109 100644 (file)
@@ -3,4 +3,6 @@
 fn main() {
     for _i 0..2 { //~ ERROR missing `in`
     }
+    for _i of 0..2 { //~ ERROR missing `in`
+    }
 }
index 9d7776f32b34572a722cac4266f1a69218d20721..81f419bf687f437319777f28335a9e62c0696012 100644 (file)
@@ -4,5 +4,11 @@ error: missing `in` in `for` loop
 LL |     for _i 0..2 {
    |           ^ help: try adding `in` here
 
-error: aborting due to previous error
+error: missing `in` in `for` loop
+  --> $DIR/issue-40782.rs:6:12
+   |
+LL |     for _i of 0..2 {
+   |            ^^ help: try using `in` here instead
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-75283.rs b/src/test/ui/issues/issue-75283.rs
new file mode 100644 (file)
index 0000000..d556132
--- /dev/null
@@ -0,0 +1,6 @@
+extern "C" {
+    fn lol() { //~ ERROR incorrect function inside `extern` block
+        println!("");
+    }
+}
+fn main() {}
diff --git a/src/test/ui/issues/issue-75283.stderr b/src/test/ui/issues/issue-75283.stderr
new file mode 100644 (file)
index 0000000..da3800a
--- /dev/null
@@ -0,0 +1,18 @@
+error: incorrect function inside `extern` block
+  --> $DIR/issue-75283.rs:2:8
+   |
+LL |   extern "C" {
+   |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |       fn lol() {
+   |  ________^^^___-
+   | |        |
+   | |        cannot have a body
+LL | |         println!("");
+LL | |     }
+   | |_____- help: remove the invalid body: `;`
+   |
+   = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to previous error
+
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..ed8ca99
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+// compile-flags: -Z span-debug
+// aux-build:test-macros.rs
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[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..f4160d7
--- /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: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+    },
+    Group {
+        delimiter: Bracket,
+        stream: TokenStream [
+            Ident {
+                ident: "doc",
+                span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+            },
+            Literal {
+                kind: Str,
+                symbol: "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n",
+                suffix: None,
+                span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+            },
+        ],
+        span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+    },
+    Ident {
+        ident: "pub",
+        span: $DIR/doc-comment-preserved.rs:20:1: 20:4 (#0),
+    },
+    Ident {
+        ident: "struct",
+        span: $DIR/doc-comment-preserved.rs:20:5: 20:11 (#0),
+    },
+    Ident {
+        ident: "S",
+        span: $DIR/doc-comment-preserved.rs:20:12: 20:13 (#0),
+    },
+    Punct {
+        ch: ';',
+        spacing: Alone,
+        span: $DIR/doc-comment-preserved.rs:20:13: 20:14 (#0),
+    },
+]
index 9ce90e42069fbd7820fd938fcb2733bbf79090ab..27bfa099f211a929db46dce92df9f9ab39d93952 100644 (file)
@@ -1,11 +1,10 @@
 // check-pass
 // edition:2018
+// compile-flags: -Z span-debug
 // 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)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
 
 #[macro_use]
 extern crate test_macros;
index c36c75603876ddeadb17244f2436ba04fac2ada1..9a5afbd604f42f532bc92f6976449d3a85661fa3 100644 (file)
@@ -2,79 +2,79 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#3),
     },
     Ident {
         ident: "M",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#3),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#3),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#3),
     },
 ]
index 2a9ff4c20cdec9530b4481aab0d1c9726a1fab01..d828fb9fd805dcc43518759ee84f0b3d10152f62 100644 (file)
@@ -1,12 +1,12 @@
 // check-pass
 // edition:2018
+// compile-flags: -Z span-debug
 // aux-build:test-macros.rs
 // aux-build:dollar-crate-external.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)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
 
 #[macro_use]
 extern crate test_macros;
index 456940b89da2b04026afd0526e21748e00110bda..fc62eadd31376d72dfe12959fa2e9bf0954ad51c 100644 (file)
@@ -2,109 +2,109 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity ! ($crate :: S)) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#3),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "identity",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#3),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#3),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "$crate",
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#3),
                     },
                     Punct {
                         ch: ':',
                         spacing: Joint,
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3),
                     },
                     Punct {
                         ch: ':',
                         spacing: Alone,
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3),
                     },
                     Ident {
                         ident: "S",
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#3),
                     },
                 ],
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#3),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#10),
     },
     Ident {
         ident: "B",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#10),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "identity",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#10),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#10),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "$crate",
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#10),
                     },
                     Punct {
                         ch: ':',
                         spacing: Joint,
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10),
                     },
                     Punct {
                         ch: ':',
                         spacing: Alone,
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10),
                     },
                     Ident {
                         ident: "S",
-                        span: #CTXT bytes(LO..HI),
+                        span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#10),
                     },
                 ],
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#10),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#10),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#10),
     },
 ]
index 1a5223d3d4190c24ae1be664cd39b8ffba625e13..ac27dfa1aeb4480775764c1e57c9a66862e7918a 100644 (file)
@@ -1,12 +1,11 @@
 // check-pass
 // edition:2018
+// compile-flags: -Z span-debug
 // aux-build:test-macros.rs
 // aux-build:dollar-crate-external.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)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
 
 #[macro_use]
 extern crate test_macros;
index deef102afb2d9faad8fc8623eb5e713f0645c1ff..72fc6588583041ccb30ad0992efc01305361a125 100644 (file)
@@ -2,239 +2,239 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:20:17: 20:23 (#3),
     },
     Ident {
         ident: "M",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:20:24: 20:25 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:20:26: 20:32 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:20:32: 20:34 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:20:32: 20:34 (#3),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:20:34: 20:35 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:20:25: 20:36 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:20:36: 20:37 (#3),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:24:13: 24:19 (#3),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:24:20: 24:21 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:24:22: 24:28 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:24:28: 24:30 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:24:28: 24:30 (#3),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:24:30: 24:31 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:24:21: 24:32 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:24:32: 24:33 (#3),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:27:13: 27:19 (#3),
     },
     Ident {
         ident: "D",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:27:20: 27:21 (#3),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:27:22: 27:28 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:27:28: 27:30 (#3),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:27:28: 27:30 (#3),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/dollar-crate.rs:27:30: 27:31 (#3),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:27:21: 27:32 (#3),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/dollar-crate.rs:27:32: 27:33 (#3),
     },
 ]
 PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#13),
     },
     Ident {
         ident: "M",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#13),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#13),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#13),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#13),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#13),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#13),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#13),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#13),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#13),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#13),
     },
     Ident {
         ident: "D",
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#13),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
             Ident {
                 ident: "$crate",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Joint,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13),
             },
             Ident {
                 ident: "S",
-                span: #CTXT bytes(LO..HI),
+                span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#13),
             },
         ],
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#13),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(LO..HI),
+        span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#13),
     },
 ]
index 41c829d9d889945bdef0227c3065ed767823b89a..5e49e330cacfa211680ee44149ca64e0154e2e04 100644 (file)
@@ -1,9 +1,12 @@
 // Check what token streams proc macros see when interpolated tokens are passed to them as input.
 
 // check-pass
-// normalize-stdout-test "#\d+" -> "#CTXT"
+// edition:2018
 // aux-build:test-macros.rs
 
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 #[macro_use]
 extern crate test_macros;
 
index d98f52249a7812d837f077a7f25032d012fac089..9cf33ba4a9df46b74eae828cb7cf99a8659b4204 100644 (file)
@@ -5,61 +5,61 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         stream: TokenStream [
             Ident {
                 ident: "A",
-                span: #CTXT bytes(445..446),
+                span: #0 bytes(503..504),
             },
         ],
-        span: #CTXT bytes(312..314),
+        span: #3 bytes(370..372),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "const",
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Punct {
         ch: ':',
         spacing: Alone,
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Ident {
         ident: "u8",
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Punct {
         ch: '=',
         spacing: Alone,
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Literal {
         kind: Integer,
         symbol: "0",
         suffix: None,
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct A { }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Ident {
         ident: "A",
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: #CTXT bytes(0..0),
+        span: #0 bytes(0..0),
     },
 ]
index 4b1787453cb55c6609d675ab4651fc21dff8adba..c11cf42956f2175315d687768320efe7ed18ecaf 100644 (file)
@@ -1,13 +1,16 @@
 // aux-build:make-macro.rs
 // aux-build:meta-macro.rs
 // edition:2018
-// compile-flags: -Z span-debug -Z macro-backtrace
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
 // check-pass
-// normalize-stdout-test "#\d+" -> "#CTXT"
 // normalize-stdout-test "\d+#" -> "0#"
 //
 // We don't care about symbol ids, so we set them all to 0
 // in the stdout
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 extern crate meta_macro;
 
 macro_rules! produce_it {
index e162bdd7fc090594f60006c972d7d37e80b517fc..dfd3e6a839a806cfccfa12c77b17126725b23c8e 100644 (file)
@@ -1,3 +1,63 @@
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
-Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:20:37: 20:43 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:20:45: 20:50 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:50: 20:51 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:20:51: 20:53 (#CTXT) }]
-Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }]
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4)
+Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#3) }]
+Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }]
+#![feature /* 0#0 */(prelude_import)]
+// aux-build:make-macro.rs
+// aux-build:meta-macro.rs
+// edition:2018
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
+// check-pass
+// normalize-stdout-test "\d+#" -> "0#"
+//
+// We don't care about symbol ids, so we set them all to 0
+// in the stdout
+
+#![no_std /* 0#0 */]
+#[prelude_import /* 0#1 */]
+use core /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*;
+#[macro_use /* 0#1 */]
+extern crate core /* 0#1 */;
+#[macro_use /* 0#1 */]
+extern crate compiler_builtins /* 0#1 */;
+// Don't load unnecessary hygiene information from std
+extern crate std /* 0#0 */;
+
+extern crate meta_macro /* 0#0 */;
+
+macro_rules! produce_it
+    /*
+    0#0
+    */ {
+    () =>
+    {
+        meta_macro :: print_def_site ! ($ crate :: dummy ! ()) ;
+        // `print_def_site!` will respan the `$crate` identifier
+        // with `Span::def_site()`. This should cause it to resolve
+        // relative to `meta_macro`, *not* `make_macro` (despite
+        // the fact that that `print_def_site` is produced by
+        // a `macro_rules!` macro in `make_macro`).
+    }
+}
+
+fn main /* 0#0 */() { }
+
+/*
+Expansions:
+0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
+2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
+3: parent: ExpnId(2), call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
+4: parent: ExpnId(3), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
+#1: parent: #0, outer_mark: (ExpnId(1), Opaque)
+#2: parent: #0, outer_mark: (ExpnId(1), Transparent)
+#3: parent: #0, outer_mark: (ExpnId(2), SemiTransparent)
+#4: parent: #0, outer_mark: (ExpnId(3), Opaque)
+#5: parent: #3, outer_mark: (ExpnId(3), Transparent)
+#6: parent: #0, outer_mark: (ExpnId(3), SemiTransparent)
+#7: parent: #0, outer_mark: (ExpnId(4), Opaque)
+#8: parent: #4, outer_mark: (ExpnId(4), Transparent)
+#9: parent: #4, outer_mark: (ExpnId(4), SemiTransparent)
+*/
index 579e232c0d92beb64b22619cc16fbc1ed97cef04..dbac90382d1d7477d421ca2824026cb4778e415f 100644 (file)
@@ -2,9 +2,11 @@
 // aux-build:meta-macro.rs
 // edition:2018
 // compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
 // run-pass
 
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 extern crate meta_macro;
 
 fn main() {
index a9847a25d9273df411e8f47b084d2834529ef07e..71aa565f4dd6d83198d93b3dd553455776f3244f 100644 (file)
@@ -1,3 +1,3 @@
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#3)
 Input: TokenStream []
 Respanned: TokenStream []
index 62c3dd84ce1a4b4172ef8df8a4e28178471344c1..2fef0e5fad0748477396478eaccf9770f51a9d4a 100644 (file)
@@ -2,9 +2,11 @@
 // aux-build:nested-macro-rules.rs
 // aux-build:test-macros.rs
 // compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
 // edition:2018
 
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 extern crate nested_macro_rules;
 extern crate test_macros;
 
index 337b9863def1b0c5b00e7fa7877aeb0bd699f58b..7feea56c5d8601ea9363176b75d87fae5bb37c33 100644 (file)
@@ -5,10 +5,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         stream: TokenStream [
             Ident {
                 ident: "FirstStruct",
-                span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#CTXT),
+                span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#5),
             },
         ],
-        span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
+        span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#4),
     },
 ]
 PRINT-BANG INPUT (DISPLAY): SecondStruct
@@ -18,9 +18,9 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         stream: TokenStream [
             Ident {
                 ident: "SecondStruct",
-                span: $DIR/nested-macro-rules.rs:19:38: 19:50 (#CTXT),
+                span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#11),
             },
         ],
-        span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
+        span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#10),
     },
 ]
index 1dc8796de90f9df7ac62bda677f20df004923cfe..db2a879f405040c77a9d4b2537e4b51b3a240d08 100644 (file)
@@ -1,11 +1,13 @@
 // run-pass
 // aux-build:test-macros.rs
 // compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
 // edition:2018
 //
 // Tests the pretty-printing behavior of inserting `NoDelim` groups
 
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
 extern crate test_macros;
 use test_macros::print_bang_consume;
 
index 79cdf2b53b52e8481cf28af9e5891bf61d0f89ab..2fcd41f6da05603341e44f0d434e40197d31e998 100644 (file)
@@ -4,7 +4,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         kind: Str,
         symbol: "hi",
         suffix: None,
-        span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:42: 16:46 (#3),
     },
     Group {
         delimiter: None,
@@ -13,12 +13,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:18:16: 18:17 (#CTXT),
+                span: $DIR/nodelim-groups.rs:20:16: 20:17 (#0),
             },
             Punct {
                 ch: '+',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:18:18: 18:19 (#CTXT),
+                span: $DIR/nodelim-groups.rs:20:18: 20:19 (#0),
             },
             Group {
                 delimiter: Parenthesis,
@@ -27,24 +27,24 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                         kind: Integer,
                         symbol: "25",
                         suffix: None,
-                        span: $DIR/nodelim-groups.rs:18:21: 18:23 (#CTXT),
+                        span: $DIR/nodelim-groups.rs:20:21: 20:23 (#0),
                     },
                 ],
-                span: $DIR/nodelim-groups.rs:18:20: 18:24 (#CTXT),
+                span: $DIR/nodelim-groups.rs:20:20: 20:24 (#0),
             },
             Punct {
                 ch: '+',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:18:25: 18:26 (#CTXT),
+                span: $DIR/nodelim-groups.rs:20:25: 20:26 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:18:27: 18:28 (#CTXT),
+                span: $DIR/nodelim-groups.rs:20:27: 20:28 (#0),
             },
         ],
-        span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:47: 16:51 (#3),
     },
     Group {
         delimiter: Parenthesis,
@@ -53,21 +53,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:53: 16:54 (#3),
             },
             Punct {
                 ch: '+',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:55: 16:56 (#3),
             },
             Literal {
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:57: 16:58 (#3),
             },
         ],
-        span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:52: 16:59 (#3),
     },
 ]
 PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
@@ -77,7 +77,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         kind: Str,
         symbol: "hi",
         suffix: None,
-        span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:42: 16:46 (#8),
     },
     Group {
         delimiter: None,
@@ -86,49 +86,49 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 kind: Str,
                 symbol: "hello",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Punct {
                 ch: '.',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Ident {
                 ident: "len",
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [],
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Punct {
                 ch: '+',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Literal {
                 kind: Str,
                 symbol: "world",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Punct {
                 ch: '.',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Ident {
                 ident: "len",
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [],
-                span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
             },
         ],
-        span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
     },
     Group {
         delimiter: Parenthesis,
@@ -137,20 +137,20 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:53: 16:54 (#8),
             },
             Punct {
                 ch: '+',
                 spacing: Alone,
-                span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:55: 16:56 (#8),
             },
             Literal {
                 kind: Integer,
                 symbol: "1",
                 suffix: None,
-                span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
+                span: $DIR/nodelim-groups.rs:16:57: 16:58 (#8),
             },
         ],
-        span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
+        span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8),
     },
 ]
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 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 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..2fa0f12d7e8dc5d0c3636e2e33a86a78cb697e10 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"];
 
 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).